diff --git a/[refs] b/[refs] index cf43c37ca1b4..c060f41a24bf 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 933b44732caad0c3b65224453c54846c75d97936 +refs/heads/master: ccbae55e1c6dc18e95d72c044cf9345ea08abf7b diff --git a/trunk/Documentation/ABI/stable/vdso b/trunk/Documentation/ABI/stable/vdso deleted file mode 100644 index 8a1cbb594497..000000000000 --- a/trunk/Documentation/ABI/stable/vdso +++ /dev/null @@ -1,27 +0,0 @@ -On some architectures, when the kernel loads any userspace program it -maps an ELF DSO into that program's address space. This DSO is called -the vDSO and it often contains useful and highly-optimized alternatives -to real syscalls. - -These functions are called just like ordinary C function according to -your platform's ABI. Call them from a sensible context. (For example, -if you set CS on x86 to something strange, the vDSO functions are -within their rights to crash.) In addition, if you pass a bad -pointer to a vDSO function, you might get SIGSEGV instead of -EFAULT. - -To find the DSO, parse the auxiliary vector passed to the program's -entry point. The AT_SYSINFO_EHDR entry will point to the vDSO. - -The vDSO uses symbol versioning; whenever you request a symbol from the -vDSO, specify the version you are expecting. - -Programs that dynamically link to glibc will use the vDSO automatically. -Otherwise, you can use the reference parser in Documentation/vDSO/parse_vdso.c. - -Unless otherwise noted, the set of symbols with any given version and the -ABI of those symbols is considered stable. It may vary across architectures, -though. - -(As of this writing, this ABI documentation as been confirmed for x86_64. - The maintainers of the other vDSO-using architectures should confirm - that it is correct for their architecture.) \ No newline at end of file diff --git a/trunk/Documentation/DocBook/kernel-hacking.tmpl b/trunk/Documentation/DocBook/kernel-hacking.tmpl index 07a9c48de5a2..7b3f49363413 100644 --- a/trunk/Documentation/DocBook/kernel-hacking.tmpl +++ b/trunk/Documentation/DocBook/kernel-hacking.tmpl @@ -409,7 +409,7 @@ cond_resched(); /* Will sleep */ You should always compile your kernel - CONFIG_DEBUG_ATOMIC_SLEEP on, and it will warn + CONFIG_DEBUG_SPINLOCK_SLEEP on, and it will warn you if you break these rules. If you do break the rules, you will eventually lock up your box. diff --git a/trunk/Documentation/DocBook/writing-an-alsa-driver.tmpl b/trunk/Documentation/DocBook/writing-an-alsa-driver.tmpl index 598c22f3b3ac..58ced2346e67 100644 --- a/trunk/Documentation/DocBook/writing-an-alsa-driver.tmpl +++ b/trunk/Documentation/DocBook/writing-an-alsa-driver.tmpl @@ -1164,7 +1164,7 @@ } chip->port = pci_resource_start(pci, 0); if (request_irq(pci->irq, snd_mychip_interrupt, - IRQF_SHARED, KBUILD_MODNAME, chip)) { + IRQF_SHARED, "My Chip", chip)) { printk(KERN_ERR "cannot grab irq %d\n", pci->irq); snd_mychip_free(chip); return -EBUSY; @@ -1197,7 +1197,7 @@ /* pci_driver definition */ static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "My Own Chip", .id_table = snd_mychip_ids, .probe = snd_mychip_probe, .remove = __devexit_p(snd_mychip_remove), @@ -1340,7 +1340,7 @@ irq, snd_mychip_interrupt, - IRQF_SHARED, KBUILD_MODNAME, chip)) { + IRQF_SHARED, "My Chip", chip)) { printk(KERN_ERR "cannot grab irq %d\n", pci->irq); snd_mychip_free(chip); return -EBUSY; @@ -1616,7 +1616,7 @@ = 1 (from kernel version 2.6.12). - -kuser_cmpxchg -------------- - -Location: 0xffff0fc0 - -Reference prototype: - - int __kuser_cmpxchg(int32_t oldval, int32_t newval, volatile int32_t *ptr); - -Input: - - r0 = oldval - r1 = newval - r2 = ptr - lr = return address - -Output: - - r0 = success code (zero or non-zero) - C flag = set if r0 == 0, clear if r0 != 0 - -Clobbered registers: - - r3, ip, flags - -Definition: - - Atomically store newval in *ptr only if *ptr is equal to oldval. - Return zero if *ptr was changed or non-zero if no exchange happened. - The C flag is also set if *ptr was changed to allow for assembly - optimization in the calling code. - -Usage example: - -typedef int (__kuser_cmpxchg_t)(int oldval, int newval, volatile int *ptr); -#define __kuser_cmpxchg (*(__kuser_cmpxchg_t *)0xffff0fc0) - -int atomic_add(volatile int *ptr, int val) -{ - int old, new; - - do { - old = *ptr; - new = old + val; - } while(__kuser_cmpxchg(old, new, ptr)); - - return new; -} - -Notes: - - - This routine already includes memory barriers as needed. - - - Valid only if __kuser_helper_version >= 2 (from kernel version 2.6.12). - -kuser_memory_barrier --------------------- - -Location: 0xffff0fa0 - -Reference prototype: - - void __kuser_memory_barrier(void); - -Input: - - lr = return address - -Output: - - none - -Clobbered registers: - - none - -Definition: - - Apply any needed memory barrier to preserve consistency with data modified - manually and __kuser_cmpxchg usage. - -Usage example: - -typedef void (__kuser_dmb_t)(void); -#define __kuser_dmb (*(__kuser_dmb_t *)0xffff0fa0) - -Notes: - - - Valid only if __kuser_helper_version >= 3 (from kernel version 2.6.15). - -kuser_cmpxchg64 ---------------- - -Location: 0xffff0f60 - -Reference prototype: - - int __kuser_cmpxchg64(const int64_t *oldval, - const int64_t *newval, - volatile int64_t *ptr); - -Input: - - r0 = pointer to oldval - r1 = pointer to newval - r2 = pointer to target value - lr = return address - -Output: - - r0 = success code (zero or non-zero) - C flag = set if r0 == 0, clear if r0 != 0 - -Clobbered registers: - - r3, lr, flags - -Definition: - - Atomically store the 64-bit value pointed by *newval in *ptr only if *ptr - is equal to the 64-bit value pointed by *oldval. Return zero if *ptr was - changed or non-zero if no exchange happened. - - The C flag is also set if *ptr was changed to allow for assembly - optimization in the calling code. - -Usage example: - -typedef int (__kuser_cmpxchg64_t)(const int64_t *oldval, - const int64_t *newval, - volatile int64_t *ptr); -#define __kuser_cmpxchg64 (*(__kuser_cmpxchg64_t *)0xffff0f60) - -int64_t atomic_add64(volatile int64_t *ptr, int64_t val) -{ - int64_t old, new; - - do { - old = *ptr; - new = old + val; - } while(__kuser_cmpxchg64(&old, &new, ptr)); - - return new; -} - -Notes: - - - This routine already includes memory barriers as needed. - - - Due to the length of this sequence, this spans 2 conventional kuser - "slots", therefore 0xffff0f80 is not used as a valid entry point. - - - Valid only if __kuser_helper_version >= 5 (from kernel version 3.1). diff --git a/trunk/Documentation/blackfin/bfin-spi-notes.txt b/trunk/Documentation/blackfin/bfin-spi-notes.txt index eae6eaf2a09d..556fa877f2e8 100644 --- a/trunk/Documentation/blackfin/bfin-spi-notes.txt +++ b/trunk/Documentation/blackfin/bfin-spi-notes.txt @@ -9,8 +9,6 @@ the entire SPI transfer. - And not just bits_per_word duration. In most cases you can utilize SPI MODE_3 instead of MODE_0 to work-around this behavior. If your SPI slave device in question requires SPI MODE_0 or MODE_2 timing, you can utilize the GPIO controlled SPI Slave Select option instead. -In this case, you should use GPIO based CS for all of your slaves and not just -the ones using mode 0 or 2 in order to guarantee correct CS toggling behavior. You can even use the same pin whose peripheral role is a SSEL, but use it as a GPIO instead. diff --git a/trunk/Documentation/cgroups/cpuacct.txt b/trunk/Documentation/cgroups/cpuacct.txt index 9d73cc0cadb9..9ad85df4b983 100644 --- a/trunk/Documentation/cgroups/cpuacct.txt +++ b/trunk/Documentation/cgroups/cpuacct.txt @@ -23,7 +23,7 @@ New accounting groups can be created under the parent group /sys/fs/cgroup. # cd /sys/fs/cgroup # mkdir g1 -# echo $$ > g1/tasks +# echo $$ > g1 The above steps create a new group g1 and move the current shell process (bash) into it. CPU time consumed by this bash and its children diff --git a/trunk/Documentation/cgroups/cpusets.txt b/trunk/Documentation/cgroups/cpusets.txt index 5c51ed406d1d..5b0d78e55ccc 100644 --- a/trunk/Documentation/cgroups/cpusets.txt +++ b/trunk/Documentation/cgroups/cpusets.txt @@ -180,7 +180,7 @@ files describing that cpuset: - cpuset.sched_load_balance flag: if set, load balance within CPUs on that cpuset - cpuset.sched_relax_domain_level: the searching range when migrating tasks -In addition, only the root cpuset has the following file: +In addition, the root cpuset only has the following file: - cpuset.memory_pressure_enabled flag: compute memory_pressure? New cpusets are created using the mkdir system call or shell diff --git a/trunk/Documentation/development-process/4.Coding b/trunk/Documentation/development-process/4.Coding index 83f5f5b365a3..f3f1a469443c 100644 --- a/trunk/Documentation/development-process/4.Coding +++ b/trunk/Documentation/development-process/4.Coding @@ -244,7 +244,7 @@ testing purposes. In particular, you should turn on: - DEBUG_SLAB can find a variety of memory allocation and use errors; it should be used on most development kernels. - - DEBUG_SPINLOCK, DEBUG_ATOMIC_SLEEP, and DEBUG_MUTEXES will find a + - DEBUG_SPINLOCK, DEBUG_SPINLOCK_SLEEP, and DEBUG_MUTEXES will find a number of common locking errors. There are quite a few other debugging options, some of which will be diff --git a/trunk/Documentation/devicetree/bindings/arm/pmu.txt b/trunk/Documentation/devicetree/bindings/arm/pmu.txt deleted file mode 100644 index 1c044eb320cc..000000000000 --- a/trunk/Documentation/devicetree/bindings/arm/pmu.txt +++ /dev/null @@ -1,21 +0,0 @@ -* ARM Performance Monitor Units - -ARM cores often have a PMU for counting cpu and cache events like cache misses -and hits. The interface to the PMU is part of the ARM ARM. The ARM PMU -representation in the device tree should be done as under:- - -Required properties: - -- compatible : should be one of - "arm,cortex-a9-pmu" - "arm,cortex-a8-pmu" - "arm,arm1176-pmu" - "arm,arm1136-pmu" -- interrupts : 1 combined interrupt or 1 per core. - -Example: - -pmu { - compatible = "arm,cortex-a9-pmu"; - interrupts = <100 101>; -}; diff --git a/trunk/Documentation/filesystems/Locking b/trunk/Documentation/filesystems/Locking index ca7e25292542..57d827d6071d 100644 --- a/trunk/Documentation/filesystems/Locking +++ b/trunk/Documentation/filesystems/Locking @@ -52,7 +52,7 @@ ata *); void (*put_link) (struct dentry *, struct nameidata *, void *); void (*truncate) (struct inode *); int (*permission) (struct inode *, int, unsigned int); - int (*check_acl)(struct inode *, int); + int (*check_acl)(struct inode *, int, unsigned int); int (*setattr) (struct dentry *, struct iattr *); int (*getattr) (struct vfsmount *, struct dentry *, struct kstat *); int (*setxattr) (struct dentry *, const char *,const void *,size_t,int); @@ -412,7 +412,7 @@ prototypes: int (*open) (struct inode *, struct file *); int (*flush) (struct file *); int (*release) (struct inode *, struct file *); - int (*fsync) (struct file *, loff_t start, loff_t end, int datasync); + int (*fsync) (struct file *, int datasync); int (*aio_fsync) (struct kiocb *, int datasync); int (*fasync) (int, struct file *, int); int (*lock) (struct file *, int, struct file_lock *); @@ -438,7 +438,9 @@ prototypes: locking rules: All may block except for ->setlease. - No VFS locks held on entry except for ->setlease. + No VFS locks held on entry except for ->fsync and ->setlease. + +->fsync() has i_mutex on inode. ->setlease has the file_list_lock held and must not sleep. diff --git a/trunk/Documentation/filesystems/porting b/trunk/Documentation/filesystems/porting index 7f8861d341ea..6e29954851a2 100644 --- a/trunk/Documentation/filesystems/porting +++ b/trunk/Documentation/filesystems/porting @@ -398,33 +398,12 @@ Currently you can only have FALLOC_FL_PUNCH_HOLE with FALLOC_FL_KEEP_SIZE set, so the i_size should not change when hole punching, even when puching the end of a file off. +-- +[mandatory] + -- [mandatory] ->get_sb() is gone. Switch to use of ->mount(). Typically it's just a matter of switching from calling get_sb_... to mount_... and changing the function type. If you were doing it manually, just switch from setting ->mnt_root to some pointer to returning that pointer. On errors return ERR_PTR(...). - --- -[mandatory] - ->permission(), generic_permission() and ->check_acl() have lost flags -argument; instead of passing IPERM_FLAG_RCU we add MAY_NOT_BLOCK into mask. - generic_permission() has also lost the check_acl argument; if you want -non-NULL to be used for that inode, put it into ->i_op->check_acl. - --- -[mandatory] - If you implement your own ->llseek() you must handle SEEK_HOLE and -SEEK_DATA. You can hanle this by returning -EINVAL, but it would be nicer to -support it in some way. The generic handler assumes that the entire file is -data and there is a virtual hole at the end of the file. So if the provided -offset is less than i_size and SEEK_DATA is specified, return the same offset. -If the above is true for the offset and you are given SEEK_HOLE, return the end -of the file. If the offset is i_size or greater return -ENXIO in either case. - -[mandatory] - If you have your own ->fsync() you must make sure to call -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. diff --git a/trunk/Documentation/filesystems/vfs.txt b/trunk/Documentation/filesystems/vfs.txt index eff6617c9a0f..88b9f5519af9 100644 --- a/trunk/Documentation/filesystems/vfs.txt +++ b/trunk/Documentation/filesystems/vfs.txt @@ -229,8 +229,6 @@ struct super_operations { ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t); ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t); - int (*nr_cached_objects)(struct super_block *); - void (*free_cached_objects)(struct super_block *, int); }; All methods are called without any locks being held, unless otherwise @@ -303,26 +301,6 @@ or bottom half). quota_write: called by the VFS to write to filesystem quota file. - nr_cached_objects: called by the sb cache shrinking function for the - filesystem to return the number of freeable cached objects it contains. - Optional. - - free_cache_objects: called by the sb cache shrinking function for the - filesystem to scan the number of objects indicated to try to free them. - Optional, but any filesystem implementing this method needs to also - implement ->nr_cached_objects for it to be called correctly. - - We can't do anything with any errors that the filesystem might - encountered, hence the void return type. This will never be called if - the VM is trying to reclaim under GFP_NOFS conditions, hence this - method does not need to handle that situation itself. - - Implementations must include conditional reschedule calls inside any - scanning loop that is done. This allows the VFS to determine - appropriate scan batch sizes without having to worry about whether - implementations will cause holdoff problems due to large scan batch - sizes. - Whoever sets up the inode is responsible for filling in the "i_op" field. This is a pointer to a "struct inode_operations" which describes the methods that can be performed on individual inodes. @@ -355,8 +333,8 @@ struct inode_operations { void * (*follow_link) (struct dentry *, struct nameidata *); void (*put_link) (struct dentry *, struct nameidata *, void *); void (*truncate) (struct inode *); - int (*permission) (struct inode *, int); - int (*check_acl)(struct inode *, int); + int (*permission) (struct inode *, int, unsigned int); + int (*check_acl)(struct inode *, int, unsigned int); int (*setattr) (struct dentry *, struct iattr *); int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *); int (*setxattr) (struct dentry *, const char *,const void *,size_t,int); @@ -445,7 +423,7 @@ otherwise noted. permission: called by the VFS to check for access rights on a POSIX-like filesystem. - May be called in rcu-walk mode (mask & MAY_NOT_BLOCK). If in rcu-walk + May be called in rcu-walk mode (flags & IPERM_FLAG_RCU). If in rcu-walk mode, the filesystem must check the permission without blocking or storing to the inode. @@ -777,7 +755,7 @@ struct file_operations { int (*open) (struct inode *, struct file *); int (*flush) (struct file *); int (*release) (struct inode *, struct file *); - int (*fsync) (struct file *, loff_t, loff_t, int datasync); + int (*fsync) (struct file *, int datasync); int (*aio_fsync) (struct kiocb *, int datasync); int (*fasync) (int, struct file *, int); int (*lock) (struct file *, int, struct file_lock *); diff --git a/trunk/Documentation/ja_JP/SubmitChecklist b/trunk/Documentation/ja_JP/SubmitChecklist index cb5507b1ac81..2df4576f1173 100644 --- a/trunk/Documentation/ja_JP/SubmitChecklist +++ b/trunk/Documentation/ja_JP/SubmitChecklist @@ -68,7 +68,7 @@ Linux カーネルパッチ投稿者向けチェックリスト 12: CONFIG_PREEMPT, CONFIG_DEBUG_PREEMPT, CONFIG_DEBUG_SLAB, CONFIG_DEBUG_PAGEALLOC, CONFIG_DEBUG_MUTEXES, CONFIG_DEBUG_SPINLOCK, - CONFIG_DEBUG_ATOMIC_SLEEP これら全てを同時に有効にして動作確認を + CONFIG_DEBUG_SPINLOCK_SLEEP これら全てを同時に有効にして動作確認を 行ってください。 13: CONFIG_SMP, CONFIG_PREEMPT を有効にした場合と無効にした場合の両方で diff --git a/trunk/Documentation/kernel-parameters.txt b/trunk/Documentation/kernel-parameters.txt index 40cc653984ee..aa47be71df4c 100644 --- a/trunk/Documentation/kernel-parameters.txt +++ b/trunk/Documentation/kernel-parameters.txt @@ -1159,6 +1159,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted. for all guests. Default is 1 (enabled) if in 64bit or 32bit-PAE mode + kvm-intel.bypass_guest_pf= + [KVM,Intel] Disables bypassing of guest page faults + on Intel chips. Default is 1 (enabled) + kvm-intel.ept= [KVM,Intel] Disable extended page tables (virtualized MMU) support on capable Intel chips. Default is 1 (enabled) @@ -1733,10 +1737,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted. no-kvmapf [X86,KVM] Disable paravirtualized asynchronous page fault handling. - no-steal-acc [X86,KVM] Disable paravirtualized steal time accounting. - steal time is computed, but won't influence scheduler - behaviour - nolapic [X86-32,APIC] Do not enable or use the local APIC. nolapic_timer [X86-32,APIC] Do not use the local APIC timer. diff --git a/trunk/Documentation/rbtree.txt b/trunk/Documentation/rbtree.txt index 8d32d85a5234..19f8278c3854 100644 --- a/trunk/Documentation/rbtree.txt +++ b/trunk/Documentation/rbtree.txt @@ -196,20 +196,15 @@ Support for Augmented rbtrees Augmented rbtree is an rbtree with "some" additional data stored in each node. This data can be used to augment some new functionality to rbtree. Augmented rbtree is an optional feature built on top of basic rbtree -infrastructure. An rbtree user who wants this feature will have to call the -augmentation functions with the user provided augmentation callback -when inserting and erasing nodes. - -On insertion, the user must call rb_augment_insert() once the new node is in -place. This will cause the augmentation function callback to be called for -each node between the new node and the root which has been affected by the -insertion. - -When erasing a node, the user must call rb_augment_erase_begin() first to -retrieve the deepest node on the rebalance path. Then, after erasing the -original node, the user must call rb_augment_erase_end() with the deepest -node found earlier. This will cause the augmentation function to be called -for each affected node between the deepest node and the root. +infrastructure. rbtree user who wants this feature will have an augment +callback function in rb_root initialized. + +This callback function will be called from rbtree core routines whenever +a node has a change in one or both of its children. It is the responsibility +of the callback function to recalculate the additional data that is in the +rb node using new children information. Note that if this new additional +data affects the parent node's additional data, then callback function has +to handle it and do the recursive updates. Interval tree is an example of augmented rb tree. Reference - diff --git a/trunk/Documentation/s390/TAPE b/trunk/Documentation/s390/TAPE new file mode 100644 index 000000000000..c639aa5603ff --- /dev/null +++ b/trunk/Documentation/s390/TAPE @@ -0,0 +1,122 @@ +Channel attached Tape device driver + +-----------------------------WARNING----------------------------------------- +This driver is considered to be EXPERIMENTAL. Do NOT use it in +production environments. Feel free to test it and report problems back to us. +----------------------------------------------------------------------------- + +The LINUX for zSeries tape device driver manages channel attached tape drives +which are compatible to IBM 3480 or IBM 3490 magnetic tape subsystems. This +includes various models of these devices (for example the 3490E). + + +Tape driver features + +The device driver supports a maximum of 128 tape devices. +No official LINUX device major number is assigned to the zSeries tape device +driver. It allocates major numbers dynamically and reports them on system +startup. +Typically it will get major number 254 for both the character device front-end +and the block device front-end. + +The tape device driver needs no kernel parameters. All supported devices +present are detected on driver initialization at system startup or module load. +The devices detected are ordered by their subchannel numbers. The device with +the lowest subchannel number becomes device 0, the next one will be device 1 +and so on. + + +Tape character device front-end + +The usual way to read or write to the tape device is through the character +device front-end. The zSeries tape device driver provides two character devices +for each physical device -- the first of these will rewind automatically when +it is closed, the second will not rewind automatically. + +The character device nodes are named /dev/rtibm0 (rewinding) and /dev/ntibm0 +(non-rewinding) for the first device, /dev/rtibm1 and /dev/ntibm1 for the +second, and so on. + +The character device front-end can be used as any other LINUX tape device. You +can write to it and read from it using LINUX facilities such as GNU tar. The +tool mt can be used to perform control operations, such as rewinding the tape +or skipping a file. + +Most LINUX tape software should work with either tape character device. + + +Tape block device front-end + +The tape device may also be accessed as a block device in read-only mode. +This could be used for software installation in the same way as it is used with +other operation systems on the zSeries platform (and most LINUX +distributions are shipped on compact disk using ISO9660 filesystems). + +One block device node is provided for each physical device. These are named +/dev/btibm0 for the first device, /dev/btibm1 for the second and so on. +You should only use the ISO9660 filesystem on LINUX for zSeries tapes because +the physical tape devices cannot perform fast seeks and the ISO9660 system is +optimized for this situation. + + +Tape block device example + +In this example a tape with an ISO9660 filesystem is created using the first +tape device. ISO9660 filesystem support must be built into your system kernel +for this. +The mt command is used to issue tape commands and the mkisofs command to +create an ISO9660 filesystem: + +- create a LINUX directory (somedir) with the contents of the filesystem + mkdir somedir + cp contents somedir + +- insert a tape + +- ensure the tape is at the beginning + mt -f /dev/ntibm0 rewind + +- set the blocksize of the character driver. The blocksize 2048 bytes + is commonly used on ISO9660 CD-Roms + mt -f /dev/ntibm0 setblk 2048 + +- write the filesystem to the character device driver + mkisofs -o /dev/ntibm0 somedir + +- rewind the tape again + mt -f /dev/ntibm0 rewind + +- Now you can mount your new filesystem as a block device: + mount -t iso9660 -o ro,block=2048 /dev/btibm0 /mnt + +TODO List + + - Driver has to be stabilized still + +BUGS + +This driver is considered BETA, which means some weaknesses may still +be in it. +If an error occurs which cannot be handled by the code you will get a +sense-data dump.In that case please do the following: + +1. set the tape driver debug level to maximum: + echo 6 >/proc/s390dbf/tape/level + +2. re-perform the actions which produced the bug. (Hopefully the bug will + reappear.) + +3. get a snapshot from the debug-feature: + cat /proc/s390dbf/tape/hex_ascii >somefile + +4. Now put the snapshot together with a detailed description of the situation + that led to the bug: + - Which tool did you use? + - Which hardware do you have? + - Was your tape unit online? + - Is it a shared tape unit? + +5. Send an email with your bug report to: + mailto:Linux390@de.ibm.com + + diff --git a/trunk/Documentation/sound/alsa/HD-Audio-Controls.txt b/trunk/Documentation/sound/alsa/HD-Audio-Controls.txt deleted file mode 100644 index 1482035243e6..000000000000 --- a/trunk/Documentation/sound/alsa/HD-Audio-Controls.txt +++ /dev/null @@ -1,100 +0,0 @@ -This file explains the codec-specific mixer controls. - -Realtek codecs --------------- - -* Channel Mode - This is an enum control to change the surround-channel setup, - appears only when the surround channels are available. - It gives the number of channels to be used, "2ch", "4ch", "6ch", - and "8ch". According to the configuration, this also controls the - jack-retasking of multi-I/O jacks. - -* Auto-Mute Mode - This is an enum control to change the auto-mute behavior of the - headphone and line-out jacks. If built-in speakers and headphone - and/or line-out jacks are available on a machine, this controls - appears. - When there are only either headphones or line-out jacks, it gives - "Disabled" and "Enabled" state. When enabled, the speaker is muted - automatically when a jack is plugged. - - When both headphone and line-out jacks are present, it gives - "Disabled", "Speaker Only" and "Line-Out+Speaker". When - speaker-only is chosen, plugging into a headphone or a line-out jack - mutes the speakers, but not line-outs. When line-out+speaker is - selected, plugging to a headphone jack mutes both speakers and - line-outs. - - -IDT/Sigmatel codecs -------------------- - -* Analog Loopback - This control enables/disables the analog-loopback circuit. This - appears only when "loopback" is set to true in a codec hint - (see HD-Audio.txt). Note that on some codecs the analog-loopback - and the normal PCM playback are exclusive, i.e. when this is on, you - won't hear any PCM stream. - -* Swap Center/LFE - Swaps the center and LFE channel order. Normally, the left - corresponds to the center and the right to the LFE. When this is - ON, the left to the LFE and the right to the center. - -* Headphone as Line Out - When this control is ON, treat the headphone jacks as line-out - jacks. That is, the headphone won't auto-mute the other line-outs, - and no HP-amp is set to the pins. - -* Mic Jack Mode, Line Jack Mode, etc - These enum controls the direction and the bias of the input jack - pins. Depending on the jack type, it can set as "Mic In" and "Line - In", for determining the input bias, or it can be set to "Line Out" - when the pin is a multi-I/O jack for surround channels. - - -VIA codecs ----------- - -* Smart 5.1 - An enum control to re-task the multi-I/O jacks for surround outputs. - When it's ON, the corresponding input jacks (usually a line-in and a - mic-in) are switched as the surround and the CLFE output jacks. - -* Independent HP - When this enum control is enabled, the headphone output is routed - from an individual stream (the third PCM such as hw:0,2) instead of - the primary stream. In the case the headphone DAC is shared with a - side or a CLFE-channel DAC, the DAC is switched to the headphone - automatically. - -* Loopback Mixing - An enum control to determine whether the analog-loopback route is - enabled or not. When it's enabled, the analog-loopback is mixed to - the front-channel. Also, the same route is used for the headphone - and speaker outputs. As a side-effect, when this mode is set, the - individual volume controls will be no longer available for - headphones and speakers because there is only one DAC connected to a - mixer widget. - -* Dynamic Power-Control - This control determines whether the dynamic power-control per jack - detection is enabled or not. When enabled, the widgets power state - (D0/D3) are changed dynamically depending on the jack plugging - state for saving power consumptions. However, if your system - doesn't provide a proper jack-detection, this won't work; in such a - case, turn this control OFF. - -* Jack Detect - This control is provided only for VT1708 codec which gives no proper - unsolicited event per jack plug. When this is on, the driver polls - the jack detection so that the headphone auto-mute can work, while - turning this off would reduce the power consumption. - - -Conexant codecs ---------------- - -* Auto-Mute Mode - See Reatek codecs. diff --git a/trunk/Documentation/sysctl/kernel.txt b/trunk/Documentation/sysctl/kernel.txt index 1c7fb0a94e28..5e7cb39ad195 100644 --- a/trunk/Documentation/sysctl/kernel.txt +++ b/trunk/Documentation/sysctl/kernel.txt @@ -17,21 +17,23 @@ before actually making adjustments. Currently, these files might (depending on your configuration) show up in /proc/sys/kernel: - -- acct - acpi_video_flags -- auto_msgmni +- acct - bootloader_type [ X86 only ] - bootloader_version [ X86 only ] - callhome [ S390 only ] +- auto_msgmni - core_pattern - core_pipe_limit - core_uses_pid - ctrl-alt-del +- dentry-state - dmesg_restrict - domainname - hostname - hotplug +- java-appletviewer [ binfmt_java, obsolete ] +- java-interpreter [ binfmt_java, obsolete ] - kptr_restrict - kstack_depth_to_print [ X86 only ] - l2cr [ PPC only ] @@ -46,14 +48,10 @@ show up in /proc/sys/kernel: - overflowgid - overflowuid - panic -- panic_on_oops -- panic_on_unrecovered_nmi - pid_max - powersave-nap [ PPC only ] +- panic_on_unrecovered_nmi - printk -- printk_delay -- printk_ratelimit -- printk_ratelimit_burst - randomize_va_space - real-root-dev ==> Documentation/initrd.txt - reboot-cmd [ SPARC only ] @@ -64,7 +62,6 @@ show up in /proc/sys/kernel: - shmall - shmmax [ sysv ipc ] - shmmni -- softlockup_thresh - stop-a [ SPARC only ] - sysrq ==> Documentation/sysrq.txt - tainted @@ -74,6 +71,15 @@ show up in /proc/sys/kernel: ============================================================== +acpi_video_flags: + +flags + +See Doc*/kernel/power/video.txt, it allows mode of video boot to be +set during run time. + +============================================================== + acct: highwater lowwater frequency @@ -89,25 +95,6 @@ That is, suspend accounting if there left <= 2% free; resume it if we got >=4%; consider information about amount of free space valid for 30 seconds. -============================================================== - -acpi_video_flags: - -flags - -See Doc*/kernel/power/video.txt, it allows mode of video boot to be -set during run time. - -============================================================== - -auto_msgmni: - -Enables/Disables automatic recomputing of msgmni upon memory add/remove -or upon ipc namespace creation/removal (see the msgmni description -above). Echoing "1" into this file enables msgmni automatic recomputing. -Echoing "0" turns it off. auto_msgmni default value is 1. - - ============================================================== bootloader_type: @@ -185,24 +172,22 @@ core_pattern is used to specify a core dumpfile pattern name. core_pipe_limit: -This sysctl is only applicable when core_pattern is configured to pipe -core files to a user space helper (when the first character of -core_pattern is a '|', see above). When collecting cores via a pipe -to an application, it is occasionally useful for the collecting -application to gather data about the crashing process from its -/proc/pid directory. In order to do this safely, the kernel must wait -for the collecting process to exit, so as not to remove the crashing -processes proc files prematurely. This in turn creates the -possibility that a misbehaving userspace collecting process can block -the reaping of a crashed process simply by never exiting. This sysctl -defends against that. It defines how many concurrent crashing -processes may be piped to user space applications in parallel. If -this value is exceeded, then those crashing processes above that value -are noted via the kernel log and their cores are skipped. 0 is a -special value, indicating that unlimited processes may be captured in -parallel, but that no waiting will take place (i.e. the collecting -process is not guaranteed access to /proc//). This -value defaults to 0. +This sysctl is only applicable when core_pattern is configured to pipe core +files to a user space helper (when the first character of core_pattern is a '|', +see above). When collecting cores via a pipe to an application, it is +occasionally useful for the collecting application to gather data about the +crashing process from its /proc/pid directory. In order to do this safely, the +kernel must wait for the collecting process to exit, so as not to remove the +crashing processes proc files prematurely. This in turn creates the possibility +that a misbehaving userspace collecting process can block the reaping of a +crashed process simply by never exiting. This sysctl defends against that. It +defines how many concurrent crashing processes may be piped to user space +applications in parallel. If this value is exceeded, then those crashing +processes above that value are noted via the kernel log and their cores are +skipped. 0 is a special value, indicating that unlimited processes may be +captured in parallel, but that no waiting will take place (i.e. the collecting +process is not guaranteed access to /proc//). This value defaults +to 0. ============================================================== @@ -233,14 +218,14 @@ to decide what to do with it. dmesg_restrict: -This toggle indicates whether unprivileged users are prevented -from using dmesg(8) to view messages from the kernel's log buffer. -When dmesg_restrict is set to (0) there are no restrictions. When +This toggle indicates whether unprivileged users are prevented from using +dmesg(8) to view messages from the kernel's log buffer. When +dmesg_restrict is set to (0) there are no restrictions. When dmesg_restrict is set set to (1), users must have CAP_SYSLOG to use dmesg(8). -The kernel config option CONFIG_SECURITY_DMESG_RESTRICT sets the -default value of dmesg_restrict. +The kernel config option CONFIG_SECURITY_DMESG_RESTRICT sets the default +value of dmesg_restrict. ============================================================== @@ -271,6 +256,13 @@ Default value is "/sbin/hotplug". ============================================================== +l2cr: (PPC only) + +This flag controls the L2 cache of G3 processor boards. If +0, the cache is disabled. Enabled if nonzero. + +============================================================== + kptr_restrict: This toggle indicates whether restrictions are placed on @@ -291,13 +283,6 @@ kernel stack. ============================================================== -l2cr: (PPC only) - -This flag controls the L2 cache of G3 processor boards. If -0, the cache is disabled. Enabled if nonzero. - -============================================================== - modules_disabled: A toggle value indicating if modules are allowed to be loaded @@ -308,21 +293,6 @@ to false. ============================================================== -nmi_watchdog: - -Enables/Disables the NMI watchdog on x86 systems. When the value is -non-zero the NMI watchdog is enabled and will continuously test all -online cpus to determine whether or not they are still functioning -properly. Currently, passing "nmi_watchdog=" parameter at boot time is -required for this function to work. - -If LAPIC NMI watchdog method is in use (nmi_watchdog=2 kernel -parameter), the NMI watchdog shares registers with oprofile. By -disabling the NMI watchdog, oprofile may have more registers to -utilize. - -============================================================== - osrelease, ostype & version: # cat osrelease @@ -342,10 +312,10 @@ The only way to tune these values is to rebuild the kernel :-) overflowgid & overflowuid: -if your architecture did not always support 32-bit UIDs (i.e. arm, -i386, m68k, sh, and sparc32), a fixed UID and GID will be returned to -applications that use the old 16-bit UID/GID system calls, if the -actual UID or GID would exceed 65535. +if your architecture did not always support 32-bit UIDs (i.e. arm, i386, +m68k, sh, and sparc32), a fixed UID and GID will be returned to +applications that use the old 16-bit UID/GID system calls, if the actual +UID or GID would exceed 65535. These sysctls allow you to change the value of the fixed UID and GID. The default is 65534. @@ -354,22 +324,9 @@ The default is 65534. panic: -The value in this file represents the number of seconds the kernel -waits before rebooting on a panic. When you use the software watchdog, -the recommended setting is 60. - -============================================================== - -panic_on_unrecovered_nmi: - -The default Linux behaviour on an NMI of either memory or unknown is -to continue operation. For many environments such as scientific -computing it is preferable that the box is taken out and the error -dealt with than an uncorrected parity/ECC error get propagated. - -A small number of systems do generate NMI's for bizarre random reasons -such as power management so the default is off. That sysctl works like -the existing panic controls already in that directory. +The value in this file represents the number of seconds the +kernel waits before rebooting on a panic. When you use the +software watchdog, the recommended setting is 60. ============================================================== @@ -419,14 +376,6 @@ the different loglevels. ============================================================== -printk_delay: - -Delay each printk message in printk_delay milliseconds - -Value from 0 - 10000 is allowed. - -============================================================== - printk_ratelimit: Some warning messages are rate limited. printk_ratelimit specifies @@ -446,7 +395,15 @@ send before ratelimiting kicks in. ============================================================== -randomize_va_space: +printk_delay: + +Delay each printk message in printk_delay milliseconds + +Value from 0 - 10000 is allowed. + +============================================================== + +randomize-va-space: This option can be used to select the type of process address space randomization that is used in the system, for architectures @@ -509,11 +466,11 @@ are doing anyway :) ============================================================== -shmmax: +shmmax: This value can be used to query and set the run time limit on the maximum shared memory segment size that can be created. -Shared memory segments up to 1Gb are now supported in the +Shared memory segments up to 1Gb are now supported in the kernel. This value defaults to SHMMAX. ============================================================== @@ -527,7 +484,7 @@ tunable to zero will disable the softlockup detection altogether. ============================================================== -tainted: +tainted: Non-zero if the kernel has been tainted. Numeric values, which can be ORed together: @@ -552,11 +509,49 @@ can be ORed together: ============================================================== +auto_msgmni: + +Enables/Disables automatic recomputing of msgmni upon memory add/remove or +upon ipc namespace creation/removal (see the msgmni description above). +Echoing "1" into this file enables msgmni automatic recomputing. +Echoing "0" turns it off. +auto_msgmni default value is 1. + +============================================================== + +nmi_watchdog: + +Enables/Disables the NMI watchdog on x86 systems. When the value is non-zero +the NMI watchdog is enabled and will continuously test all online cpus to +determine whether or not they are still functioning properly. Currently, +passing "nmi_watchdog=" parameter at boot time is required for this function +to work. + +If LAPIC NMI watchdog method is in use (nmi_watchdog=2 kernel parameter), the +NMI watchdog shares registers with oprofile. By disabling the NMI watchdog, +oprofile may have more registers to utilize. + +============================================================== + unknown_nmi_panic: -The value in this file affects behavior of handling NMI. When the -value is non-zero, unknown NMI is trapped and then panic occurs. At -that time, kernel debugging information is displayed on console. +The value in this file affects behavior of handling NMI. When the value is +non-zero, unknown NMI is trapped and then panic occurs. At that time, kernel +debugging information is displayed on console. + +NMI switch that most IA32 servers have fires unknown NMI up, for example. +If a system hangs up, try pressing the NMI switch. + +============================================================== + +panic_on_unrecovered_nmi: + +The default Linux behaviour on an NMI of either memory or unknown is to continue +operation. For many environments such as scientific computing it is preferable +that the box is taken out and the error dealt with than an uncorrected +parity/ECC error get propogated. + +A small number of systems do generate NMI's for bizarre random reasons such as +power management so the default is off. That sysctl works like the existing +panic controls already in that directory. -NMI switch that most IA32 servers have fires unknown NMI up, for -example. If a system hangs up, try pressing the NMI switch. diff --git a/trunk/Documentation/trace/kprobetrace.txt b/trunk/Documentation/trace/kprobetrace.txt index d0d0bb9e3e25..c83bd6b4e6e8 100644 --- a/trunk/Documentation/trace/kprobetrace.txt +++ b/trunk/Documentation/trace/kprobetrace.txt @@ -22,15 +22,14 @@ current_tracer. Instead of that, add probe points via Synopsis of kprobe_events ------------------------- - p[:[GRP/]EVENT] [MOD:]SYM[+offs]|MEMADDR [FETCHARGS] : Set a probe - r[:[GRP/]EVENT] [MOD:]SYM[+0] [FETCHARGS] : Set a return probe + p[:[GRP/]EVENT] SYMBOL[+offs]|MEMADDR [FETCHARGS] : Set a probe + r[:[GRP/]EVENT] SYMBOL[+0] [FETCHARGS] : Set a return probe -:[GRP/]EVENT : Clear a probe GRP : Group name. If omitted, use "kprobes" for it. EVENT : Event name. If omitted, the event name is generated - based on SYM+offs or MEMADDR. - MOD : Module name which has given SYM. - SYM[+offs] : Symbol+offset where the probe is inserted. + based on SYMBOL+offs or MEMADDR. + SYMBOL[+offs] : Symbol+offset where the probe is inserted. MEMADDR : Address where the probe is inserted. FETCHARGS : Arguments. Each probe can have up to 128 args. diff --git a/trunk/Documentation/vDSO/parse_vdso.c b/trunk/Documentation/vDSO/parse_vdso.c deleted file mode 100644 index 85870208edcf..000000000000 --- a/trunk/Documentation/vDSO/parse_vdso.c +++ /dev/null @@ -1,256 +0,0 @@ -/* - * parse_vdso.c: Linux reference vDSO parser - * Written by Andrew Lutomirski, 2011. - * - * This code is meant to be linked in to various programs that run on Linux. - * As such, it is available with as few restrictions as possible. This file - * is licensed under the Creative Commons Zero License, version 1.0, - * available at http://creativecommons.org/publicdomain/zero/1.0/legalcode - * - * The vDSO is a regular ELF DSO that the kernel maps into user space when - * it starts a program. It works equally well in statically and dynamically - * linked binaries. - * - * This code is tested on x86_64. In principle it should work on any 64-bit - * architecture that has a vDSO. - */ - -#include -#include -#include -#include - -/* - * To use this vDSO parser, first call one of the vdso_init_* functions. - * If you've already parsed auxv, then pass the value of AT_SYSINFO_EHDR - * to vdso_init_from_sysinfo_ehdr. Otherwise pass auxv to vdso_init_from_auxv. - * Then call vdso_sym for each symbol you want. For example, to look up - * gettimeofday on x86_64, use: - * - * = vdso_sym("LINUX_2.6", "gettimeofday"); - * or - * = vdso_sym("LINUX_2.6", "__vdso_gettimeofday"); - * - * vdso_sym will return 0 if the symbol doesn't exist or if the init function - * failed or was not called. vdso_sym is a little slow, so its return value - * should be cached. - * - * vdso_sym is threadsafe; the init functions are not. - * - * These are the prototypes: - */ -extern void vdso_init_from_auxv(void *auxv); -extern void vdso_init_from_sysinfo_ehdr(uintptr_t base); -extern void *vdso_sym(const char *version, const char *name); - - -/* And here's the code. */ - -#ifndef __x86_64__ -# error Not yet ported to non-x86_64 architectures -#endif - -static struct vdso_info -{ - bool valid; - - /* Load information */ - uintptr_t load_addr; - uintptr_t load_offset; /* load_addr - recorded vaddr */ - - /* Symbol table */ - Elf64_Sym *symtab; - const char *symstrings; - Elf64_Word *bucket, *chain; - Elf64_Word nbucket, nchain; - - /* Version table */ - Elf64_Versym *versym; - Elf64_Verdef *verdef; -} vdso_info; - -/* Straight from the ELF specification. */ -static unsigned long elf_hash(const unsigned char *name) -{ - unsigned long h = 0, g; - while (*name) - { - h = (h << 4) + *name++; - if (g = h & 0xf0000000) - h ^= g >> 24; - h &= ~g; - } - return h; -} - -void vdso_init_from_sysinfo_ehdr(uintptr_t base) -{ - size_t i; - bool found_vaddr = false; - - vdso_info.valid = false; - - vdso_info.load_addr = base; - - Elf64_Ehdr *hdr = (Elf64_Ehdr*)base; - Elf64_Phdr *pt = (Elf64_Phdr*)(vdso_info.load_addr + hdr->e_phoff); - Elf64_Dyn *dyn = 0; - - /* - * We need two things from the segment table: the load offset - * and the dynamic table. - */ - for (i = 0; i < hdr->e_phnum; i++) - { - if (pt[i].p_type == PT_LOAD && !found_vaddr) { - found_vaddr = true; - vdso_info.load_offset = base - + (uintptr_t)pt[i].p_offset - - (uintptr_t)pt[i].p_vaddr; - } else if (pt[i].p_type == PT_DYNAMIC) { - dyn = (Elf64_Dyn*)(base + pt[i].p_offset); - } - } - - if (!found_vaddr || !dyn) - return; /* Failed */ - - /* - * Fish out the useful bits of the dynamic table. - */ - Elf64_Word *hash = 0; - vdso_info.symstrings = 0; - vdso_info.symtab = 0; - vdso_info.versym = 0; - vdso_info.verdef = 0; - for (i = 0; dyn[i].d_tag != DT_NULL; i++) { - switch (dyn[i].d_tag) { - case DT_STRTAB: - vdso_info.symstrings = (const char *) - ((uintptr_t)dyn[i].d_un.d_ptr - + vdso_info.load_offset); - break; - case DT_SYMTAB: - vdso_info.symtab = (Elf64_Sym *) - ((uintptr_t)dyn[i].d_un.d_ptr - + vdso_info.load_offset); - break; - case DT_HASH: - hash = (Elf64_Word *) - ((uintptr_t)dyn[i].d_un.d_ptr - + vdso_info.load_offset); - break; - case DT_VERSYM: - vdso_info.versym = (Elf64_Versym *) - ((uintptr_t)dyn[i].d_un.d_ptr - + vdso_info.load_offset); - break; - case DT_VERDEF: - vdso_info.verdef = (Elf64_Verdef *) - ((uintptr_t)dyn[i].d_un.d_ptr - + vdso_info.load_offset); - break; - } - } - if (!vdso_info.symstrings || !vdso_info.symtab || !hash) - return; /* Failed */ - - if (!vdso_info.verdef) - vdso_info.versym = 0; - - /* Parse the hash table header. */ - vdso_info.nbucket = hash[0]; - vdso_info.nchain = hash[1]; - vdso_info.bucket = &hash[2]; - vdso_info.chain = &hash[vdso_info.nbucket + 2]; - - /* That's all we need. */ - vdso_info.valid = true; -} - -static bool vdso_match_version(Elf64_Versym ver, - const char *name, Elf64_Word hash) -{ - /* - * This is a helper function to check if the version indexed by - * ver matches name (which hashes to hash). - * - * The version definition table is a mess, and I don't know how - * to do this in better than linear time without allocating memory - * to build an index. I also don't know why the table has - * variable size entries in the first place. - * - * For added fun, I can't find a comprehensible specification of how - * to parse all the weird flags in the table. - * - * So I just parse the whole table every time. - */ - - /* First step: find the version definition */ - ver &= 0x7fff; /* Apparently bit 15 means "hidden" */ - Elf64_Verdef *def = vdso_info.verdef; - while(true) { - if ((def->vd_flags & VER_FLG_BASE) == 0 - && (def->vd_ndx & 0x7fff) == ver) - break; - - if (def->vd_next == 0) - return false; /* No definition. */ - - def = (Elf64_Verdef *)((char *)def + def->vd_next); - } - - /* Now figure out whether it matches. */ - Elf64_Verdaux *aux = (Elf64_Verdaux*)((char *)def + def->vd_aux); - return def->vd_hash == hash - && !strcmp(name, vdso_info.symstrings + aux->vda_name); -} - -void *vdso_sym(const char *version, const char *name) -{ - unsigned long ver_hash; - if (!vdso_info.valid) - return 0; - - ver_hash = elf_hash(version); - Elf64_Word chain = vdso_info.bucket[elf_hash(name) % vdso_info.nbucket]; - - for (; chain != STN_UNDEF; chain = vdso_info.chain[chain]) { - Elf64_Sym *sym = &vdso_info.symtab[chain]; - - /* Check for a defined global or weak function w/ right name. */ - if (ELF64_ST_TYPE(sym->st_info) != STT_FUNC) - continue; - if (ELF64_ST_BIND(sym->st_info) != STB_GLOBAL && - ELF64_ST_BIND(sym->st_info) != STB_WEAK) - continue; - if (sym->st_shndx == SHN_UNDEF) - continue; - if (strcmp(name, vdso_info.symstrings + sym->st_name)) - continue; - - /* Check symbol version. */ - if (vdso_info.versym - && !vdso_match_version(vdso_info.versym[chain], - version, ver_hash)) - continue; - - return (void *)(vdso_info.load_offset + sym->st_value); - } - - return 0; -} - -void vdso_init_from_auxv(void *auxv) -{ - Elf64_auxv_t *elf_auxv = auxv; - for (int i = 0; elf_auxv[i].a_type != AT_NULL; i++) - { - if (elf_auxv[i].a_type == AT_SYSINFO_EHDR) { - vdso_init_from_sysinfo_ehdr(elf_auxv[i].a_un.a_val); - return; - } - } - - vdso_info.valid = false; -} diff --git a/trunk/Documentation/vDSO/vdso_test.c b/trunk/Documentation/vDSO/vdso_test.c deleted file mode 100644 index fff633432dff..000000000000 --- a/trunk/Documentation/vDSO/vdso_test.c +++ /dev/null @@ -1,111 +0,0 @@ -/* - * vdso_test.c: Sample code to test parse_vdso.c on x86_64 - * Copyright (c) 2011 Andy Lutomirski - * Subject to the GNU General Public License, version 2 - * - * You can amuse yourself by compiling with: - * gcc -std=gnu99 -nostdlib - * -Os -fno-asynchronous-unwind-tables -flto - * vdso_test.c parse_vdso.c -o vdso_test - * to generate a small binary with no dependencies at all. - */ - -#include -#include -#include -#include - -extern void *vdso_sym(const char *version, const char *name); -extern void vdso_init_from_sysinfo_ehdr(uintptr_t base); -extern void vdso_init_from_auxv(void *auxv); - -/* We need a libc functions... */ -int strcmp(const char *a, const char *b) -{ - /* This implementation is buggy: it never returns -1. */ - while (*a || *b) { - if (*a != *b) - return 1; - if (*a == 0 || *b == 0) - return 1; - a++; - b++; - } - - return 0; -} - -/* ...and two syscalls. This is x86_64-specific. */ -static inline long linux_write(int fd, const void *data, size_t len) -{ - - long ret; - asm volatile ("syscall" : "=a" (ret) : "a" (__NR_write), - "D" (fd), "S" (data), "d" (len) : - "cc", "memory", "rcx", - "r8", "r9", "r10", "r11" ); - return ret; -} - -static inline void linux_exit(int code) -{ - asm volatile ("syscall" : : "a" (__NR_exit), "D" (code)); -} - -void to_base10(char *lastdig, uint64_t n) -{ - while (n) { - *lastdig = (n % 10) + '0'; - n /= 10; - lastdig--; - } -} - -__attribute__((externally_visible)) void c_main(void **stack) -{ - /* Parse the stack */ - long argc = (long)*stack; - stack += argc + 2; - - /* Now we're pointing at the environment. Skip it. */ - while(*stack) - stack++; - stack++; - - /* Now we're pointing at auxv. Initialize the vDSO parser. */ - vdso_init_from_auxv((void *)stack); - - /* Find gettimeofday. */ - typedef long (*gtod_t)(struct timeval *tv, struct timezone *tz); - gtod_t gtod = (gtod_t)vdso_sym("LINUX_2.6", "__vdso_gettimeofday"); - - if (!gtod) - linux_exit(1); - - struct timeval tv; - long ret = gtod(&tv, 0); - - if (ret == 0) { - char buf[] = "The time is .000000\n"; - to_base10(buf + 31, tv.tv_sec); - to_base10(buf + 38, tv.tv_usec); - linux_write(1, buf, sizeof(buf) - 1); - } else { - linux_exit(ret); - } - - linux_exit(0); -} - -/* - * This is the real entry point. It passes the initial stack into - * the C entry point. - */ -asm ( - ".text\n" - ".global _start\n" - ".type _start,@function\n" - "_start:\n\t" - "mov %rsp,%rdi\n\t" - "jmp c_main" - ); diff --git a/trunk/Documentation/virtual/kvm/api.txt b/trunk/Documentation/virtual/kvm/api.txt index b0e4b9cd6a66..42542eb802ca 100644 --- a/trunk/Documentation/virtual/kvm/api.txt +++ b/trunk/Documentation/virtual/kvm/api.txt @@ -180,19 +180,6 @@ KVM_CHECK_EXTENSION ioctl() to determine the value for max_vcpus at run-time. If the KVM_CAP_NR_VCPUS does not exist, you should assume that max_vcpus is 4 cpus max. -On powerpc using book3s_hv mode, the vcpus are mapped onto virtual -threads in one or more virtual CPU cores. (This is because the -hardware requires all the hardware threads in a CPU core to be in the -same partition.) The KVM_CAP_PPC_SMT capability indicates the number -of vcpus per virtual core (vcore). The vcore id is obtained by -dividing the vcpu id by the number of vcpus per vcore. The vcpus in a -given vcore will always be in the same physical core as each other -(though that might be a different physical core from time to time). -Userspace can control the threading (SMT) mode of the guest by its -allocation of vcpu ids. For example, if userspace wants -single-threaded guest vcpus, it should make all vcpu ids be a multiple -of the number of vcpus per vcore. - 4.8 KVM_GET_DIRTY_LOG (vm ioctl) Capability: basic @@ -1156,10 +1143,15 @@ Assigns an IRQ to a passed-through device. struct kvm_assigned_irq { __u32 assigned_dev_id; - __u32 host_irq; /* ignored (legacy field) */ + __u32 host_irq; __u32 guest_irq; __u32 flags; union { + struct { + __u32 addr_lo; + __u32 addr_hi; + __u32 data; + } guest_msi; __u32 reserved[12]; }; }; @@ -1247,10 +1239,8 @@ Type: vm ioctl Parameters: struct kvm_assigned_msix_nr (in) Returns: 0 on success, -1 on error -Set the number of MSI-X interrupts for an assigned device. The number is -reset again by terminating the MSI-X assignment of the device via -KVM_DEASSIGN_DEV_IRQ. Calling this service more than once at any earlier -point will fail. +Set the number of MSI-X interrupts for an assigned device. This service can +only be called once in the lifetime of an assigned device. struct kvm_assigned_msix_nr { __u32 assigned_dev_id; @@ -1301,135 +1291,6 @@ Returns the tsc frequency of the guest. The unit of the return value is KHz. If the host has unstable tsc this ioctl returns -EIO instead as an error. -4.56 KVM_GET_LAPIC - -Capability: KVM_CAP_IRQCHIP -Architectures: x86 -Type: vcpu ioctl -Parameters: struct kvm_lapic_state (out) -Returns: 0 on success, -1 on error - -#define KVM_APIC_REG_SIZE 0x400 -struct kvm_lapic_state { - char regs[KVM_APIC_REG_SIZE]; -}; - -Reads the Local APIC registers and copies them into the input argument. The -data format and layout are the same as documented in the architecture manual. - -4.57 KVM_SET_LAPIC - -Capability: KVM_CAP_IRQCHIP -Architectures: x86 -Type: vcpu ioctl -Parameters: struct kvm_lapic_state (in) -Returns: 0 on success, -1 on error - -#define KVM_APIC_REG_SIZE 0x400 -struct kvm_lapic_state { - char regs[KVM_APIC_REG_SIZE]; -}; - -Copies the input argument into the the Local APIC registers. The data format -and layout are the same as documented in the architecture manual. - -4.58 KVM_IOEVENTFD - -Capability: KVM_CAP_IOEVENTFD -Architectures: all -Type: vm ioctl -Parameters: struct kvm_ioeventfd (in) -Returns: 0 on success, !0 on error - -This ioctl attaches or detaches an ioeventfd to a legal pio/mmio address -within the guest. A guest write in the registered address will signal the -provided event instead of triggering an exit. - -struct kvm_ioeventfd { - __u64 datamatch; - __u64 addr; /* legal pio/mmio address */ - __u32 len; /* 1, 2, 4, or 8 bytes */ - __s32 fd; - __u32 flags; - __u8 pad[36]; -}; - -The following flags are defined: - -#define KVM_IOEVENTFD_FLAG_DATAMATCH (1 << kvm_ioeventfd_flag_nr_datamatch) -#define KVM_IOEVENTFD_FLAG_PIO (1 << kvm_ioeventfd_flag_nr_pio) -#define KVM_IOEVENTFD_FLAG_DEASSIGN (1 << kvm_ioeventfd_flag_nr_deassign) - -If datamatch flag is set, the event will be signaled only if the written value -to the registered address is equal to datamatch in struct kvm_ioeventfd. - -4.62 KVM_CREATE_SPAPR_TCE - -Capability: KVM_CAP_SPAPR_TCE -Architectures: powerpc -Type: vm ioctl -Parameters: struct kvm_create_spapr_tce (in) -Returns: file descriptor for manipulating the created TCE table - -This creates a virtual TCE (translation control entry) table, which -is an IOMMU for PAPR-style virtual I/O. It is used to translate -logical addresses used in virtual I/O into guest physical addresses, -and provides a scatter/gather capability for PAPR virtual I/O. - -/* for KVM_CAP_SPAPR_TCE */ -struct kvm_create_spapr_tce { - __u64 liobn; - __u32 window_size; -}; - -The liobn field gives the logical IO bus number for which to create a -TCE table. The window_size field specifies the size of the DMA window -which this TCE table will translate - the table will contain one 64 -bit TCE entry for every 4kiB of the DMA window. - -When the guest issues an H_PUT_TCE hcall on a liobn for which a TCE -table has been created using this ioctl(), the kernel will handle it -in real mode, updating the TCE table. H_PUT_TCE calls for other -liobns will cause a vm exit and must be handled by userspace. - -The return value is a file descriptor which can be passed to mmap(2) -to map the created TCE table into userspace. This lets userspace read -the entries written by kernel-handled H_PUT_TCE calls, and also lets -userspace update the TCE table directly which is useful in some -circumstances. - -4.63 KVM_ALLOCATE_RMA - -Capability: KVM_CAP_PPC_RMA -Architectures: powerpc -Type: vm ioctl -Parameters: struct kvm_allocate_rma (out) -Returns: file descriptor for mapping the allocated RMA - -This allocates a Real Mode Area (RMA) from the pool allocated at boot -time by the kernel. An RMA is a physically-contiguous, aligned region -of memory used on older POWER processors to provide the memory which -will be accessed by real-mode (MMU off) accesses in a KVM guest. -POWER processors support a set of sizes for the RMA that usually -includes 64MB, 128MB, 256MB and some larger powers of two. - -/* for KVM_ALLOCATE_RMA */ -struct kvm_allocate_rma { - __u64 rma_size; -}; - -The return value is a file descriptor which can be passed to mmap(2) -to map the allocated RMA into userspace. The mapped area can then be -passed to the KVM_SET_USER_MEMORY_REGION ioctl to establish it as the -RMA for a virtual machine. The size of the RMA in bytes (which is -fixed at host kernel boot time) is returned in the rma_size field of -the argument structure. - -The KVM_CAP_PPC_RMA capability is 1 or 2 if the KVM_ALLOCATE_RMA ioctl -is supported; 2 if the processor requires all virtual machines to have -an RMA, or 1 if the processor can use an RMA but doesn't require it, -because it supports the Virtual RMA (VRMA) facility. - 5. The kvm_run structure Application code obtains a pointer to the kvm_run structure by @@ -1612,23 +1473,6 @@ Userspace can now handle the hypercall and when it's done modify the gprs as necessary. Upon guest entry all guest GPRs will then be replaced by the values in this struct. - /* KVM_EXIT_PAPR_HCALL */ - struct { - __u64 nr; - __u64 ret; - __u64 args[9]; - } papr_hcall; - -This is used on 64-bit PowerPC when emulating a pSeries partition, -e.g. with the 'pseries' machine type in qemu. It occurs when the -guest does a hypercall using the 'sc 1' instruction. The 'nr' field -contains the hypercall number (from the guest R3), and 'args' contains -the arguments (from the guest R4 - R12). Userspace should put the -return code in 'ret' and any extra returned values in args[]. -The possible hypercalls are defined in the Power Architecture Platform -Requirements (PAPR) document available from www.power.org (free -developer registration required to access it). - /* Fix the size of the union. */ char padding[256]; }; diff --git a/trunk/Documentation/virtual/kvm/mmu.txt b/trunk/Documentation/virtual/kvm/mmu.txt index 5dc972c09b55..f46aa58389ca 100644 --- a/trunk/Documentation/virtual/kvm/mmu.txt +++ b/trunk/Documentation/virtual/kvm/mmu.txt @@ -165,10 +165,6 @@ Shadow pages contain the following information: Contains the value of efer.nxe for which the page is valid. role.cr0_wp: Contains the value of cr0.wp for which the page is valid. - role.smep_andnot_wp: - Contains the value of cr4.smep && !cr0.wp for which the page is valid - (pages for which this is true are different from other pages; see the - treatment of cr0.wp=0 below). gfn: Either the guest page table containing the translations shadowed by this page, or the base page frame for linear translations. See role.direct. @@ -321,20 +317,6 @@ on fault type: (user write faults generate a #PF) -In the first case there is an additional complication if CR4.SMEP is -enabled: since we've turned the page into a kernel page, the kernel may now -execute it. We handle this by also setting spte.nx. If we get a user -fetch or read fault, we'll change spte.u=1 and spte.nx=gpte.nx back. - -To prevent an spte that was converted into a kernel page with cr0.wp=0 -from being written by the kernel after cr0.wp has changed to 1, we make -the value of cr0.wp part of the page role. This means that an spte created -with one value of cr0.wp cannot be used when cr0.wp has a different value - -it will simply be missed by the shadow page lookup code. A similar issue -exists when an spte created with cr0.wp=0 and cr4.smep=0 is used after -changing cr4.smep to 1. To avoid this, the value of !cr0.wp && cr4.smep -is also made a part of the page role. - Large pages =========== diff --git a/trunk/Documentation/virtual/kvm/msr.txt b/trunk/Documentation/virtual/kvm/msr.txt index 50317809113d..d079aed27e03 100644 --- a/trunk/Documentation/virtual/kvm/msr.txt +++ b/trunk/Documentation/virtual/kvm/msr.txt @@ -185,37 +185,3 @@ MSR_KVM_ASYNC_PF_EN: 0x4b564d02 Currently type 2 APF will be always delivered on the same vcpu as type 1 was, but guest should not rely on that. - -MSR_KVM_STEAL_TIME: 0x4b564d03 - - data: 64-byte alignment physical address of a memory area which must be - in guest RAM, plus an enable bit in bit 0. This memory is expected to - hold a copy of the following structure: - - struct kvm_steal_time { - __u64 steal; - __u32 version; - __u32 flags; - __u32 pad[12]; - } - - whose data will be filled in by the hypervisor periodically. Only one - write, or registration, is needed for each VCPU. The interval between - updates of this structure is arbitrary and implementation-dependent. - The hypervisor may update this structure at any time it sees fit until - anything with bit0 == 0 is written to it. Guest is required to make sure - this structure is initialized to zero. - - Fields have the following meanings: - - version: a sequence counter. In other words, guest has to check - this field before and after grabbing time information and make - sure they are both equal and even. An odd version indicates an - in-progress update. - - flags: At this point, always zero. May be used to indicate - changes in this structure in the future. - - steal: the amount of time in which this vCPU did not run, in - nanoseconds. Time during which the vcpu is idle, will not be - reported as steal time. diff --git a/trunk/Documentation/virtual/kvm/nested-vmx.txt b/trunk/Documentation/virtual/kvm/nested-vmx.txt deleted file mode 100644 index 8ed937de1163..000000000000 --- a/trunk/Documentation/virtual/kvm/nested-vmx.txt +++ /dev/null @@ -1,251 +0,0 @@ -Nested VMX -========== - -Overview ---------- - -On Intel processors, KVM uses Intel's VMX (Virtual-Machine eXtensions) -to easily and efficiently run guest operating systems. Normally, these guests -*cannot* themselves be hypervisors running their own guests, because in VMX, -guests cannot use VMX instructions. - -The "Nested VMX" feature adds this missing capability - of running guest -hypervisors (which use VMX) with their own nested guests. It does so by -allowing a guest to use VMX instructions, and correctly and efficiently -emulating them using the single level of VMX available in the hardware. - -We describe in much greater detail the theory behind the nested VMX feature, -its implementation and its performance characteristics, in the OSDI 2010 paper -"The Turtles Project: Design and Implementation of Nested Virtualization", -available at: - - http://www.usenix.org/events/osdi10/tech/full_papers/Ben-Yehuda.pdf - - -Terminology ------------ - -Single-level virtualization has two levels - the host (KVM) and the guests. -In nested virtualization, we have three levels: The host (KVM), which we call -L0, the guest hypervisor, which we call L1, and its nested guest, which we -call L2. - - -Known limitations ------------------ - -The current code supports running Linux guests under KVM guests. -Only 64-bit guest hypervisors are supported. - -Additional patches for running Windows under guest KVM, and Linux under -guest VMware server, and support for nested EPT, are currently running in -the lab, and will be sent as follow-on patchsets. - - -Running nested VMX ------------------- - -The nested VMX feature is disabled by default. It can be enabled by giving -the "nested=1" option to the kvm-intel module. - -No modifications are required to user space (qemu). However, qemu's default -emulated CPU type (qemu64) does not list the "VMX" CPU feature, so it must be -explicitly enabled, by giving qemu one of the following options: - - -cpu host (emulated CPU has all features of the real CPU) - - -cpu qemu64,+vmx (add just the vmx feature to a named CPU type) - - -ABIs ----- - -Nested VMX aims to present a standard and (eventually) fully-functional VMX -implementation for the a guest hypervisor to use. As such, the official -specification of the ABI that it provides is Intel's VMX specification, -namely volume 3B of their "Intel 64 and IA-32 Architectures Software -Developer's Manual". Not all of VMX's features are currently fully supported, -but the goal is to eventually support them all, starting with the VMX features -which are used in practice by popular hypervisors (KVM and others). - -As a VMX implementation, nested VMX presents a VMCS structure to L1. -As mandated by the spec, other than the two fields revision_id and abort, -this structure is *opaque* to its user, who is not supposed to know or care -about its internal structure. Rather, the structure is accessed through the -VMREAD and VMWRITE instructions. -Still, for debugging purposes, KVM developers might be interested to know the -internals of this structure; This is struct vmcs12 from arch/x86/kvm/vmx.c. - -The name "vmcs12" refers to the VMCS that L1 builds for L2. In the code we -also have "vmcs01", the VMCS that L0 built for L1, and "vmcs02" is the VMCS -which L0 builds to actually run L2 - how this is done is explained in the -aforementioned paper. - -For convenience, we repeat the content of struct vmcs12 here. If the internals -of this structure changes, this can break live migration across KVM versions. -VMCS12_REVISION (from vmx.c) should be changed if struct vmcs12 or its inner -struct shadow_vmcs is ever changed. - - typedef u64 natural_width; - struct __packed vmcs12 { - /* According to the Intel spec, a VMCS region must start with - * these two user-visible fields */ - u32 revision_id; - u32 abort; - - u32 launch_state; /* set to 0 by VMCLEAR, to 1 by VMLAUNCH */ - u32 padding[7]; /* room for future expansion */ - - u64 io_bitmap_a; - u64 io_bitmap_b; - u64 msr_bitmap; - u64 vm_exit_msr_store_addr; - u64 vm_exit_msr_load_addr; - u64 vm_entry_msr_load_addr; - u64 tsc_offset; - u64 virtual_apic_page_addr; - u64 apic_access_addr; - u64 ept_pointer; - u64 guest_physical_address; - u64 vmcs_link_pointer; - u64 guest_ia32_debugctl; - u64 guest_ia32_pat; - u64 guest_ia32_efer; - u64 guest_pdptr0; - u64 guest_pdptr1; - u64 guest_pdptr2; - u64 guest_pdptr3; - u64 host_ia32_pat; - u64 host_ia32_efer; - u64 padding64[8]; /* room for future expansion */ - natural_width cr0_guest_host_mask; - natural_width cr4_guest_host_mask; - natural_width cr0_read_shadow; - natural_width cr4_read_shadow; - natural_width cr3_target_value0; - natural_width cr3_target_value1; - natural_width cr3_target_value2; - natural_width cr3_target_value3; - natural_width exit_qualification; - natural_width guest_linear_address; - natural_width guest_cr0; - natural_width guest_cr3; - natural_width guest_cr4; - natural_width guest_es_base; - natural_width guest_cs_base; - natural_width guest_ss_base; - natural_width guest_ds_base; - natural_width guest_fs_base; - natural_width guest_gs_base; - natural_width guest_ldtr_base; - natural_width guest_tr_base; - natural_width guest_gdtr_base; - natural_width guest_idtr_base; - natural_width guest_dr7; - natural_width guest_rsp; - natural_width guest_rip; - natural_width guest_rflags; - natural_width guest_pending_dbg_exceptions; - natural_width guest_sysenter_esp; - natural_width guest_sysenter_eip; - natural_width host_cr0; - natural_width host_cr3; - natural_width host_cr4; - natural_width host_fs_base; - natural_width host_gs_base; - natural_width host_tr_base; - natural_width host_gdtr_base; - natural_width host_idtr_base; - natural_width host_ia32_sysenter_esp; - natural_width host_ia32_sysenter_eip; - natural_width host_rsp; - natural_width host_rip; - natural_width paddingl[8]; /* room for future expansion */ - u32 pin_based_vm_exec_control; - u32 cpu_based_vm_exec_control; - u32 exception_bitmap; - u32 page_fault_error_code_mask; - u32 page_fault_error_code_match; - u32 cr3_target_count; - u32 vm_exit_controls; - u32 vm_exit_msr_store_count; - u32 vm_exit_msr_load_count; - u32 vm_entry_controls; - u32 vm_entry_msr_load_count; - u32 vm_entry_intr_info_field; - u32 vm_entry_exception_error_code; - u32 vm_entry_instruction_len; - u32 tpr_threshold; - u32 secondary_vm_exec_control; - u32 vm_instruction_error; - u32 vm_exit_reason; - u32 vm_exit_intr_info; - u32 vm_exit_intr_error_code; - u32 idt_vectoring_info_field; - u32 idt_vectoring_error_code; - u32 vm_exit_instruction_len; - u32 vmx_instruction_info; - u32 guest_es_limit; - u32 guest_cs_limit; - u32 guest_ss_limit; - u32 guest_ds_limit; - u32 guest_fs_limit; - u32 guest_gs_limit; - u32 guest_ldtr_limit; - u32 guest_tr_limit; - u32 guest_gdtr_limit; - u32 guest_idtr_limit; - u32 guest_es_ar_bytes; - u32 guest_cs_ar_bytes; - u32 guest_ss_ar_bytes; - u32 guest_ds_ar_bytes; - u32 guest_fs_ar_bytes; - u32 guest_gs_ar_bytes; - u32 guest_ldtr_ar_bytes; - u32 guest_tr_ar_bytes; - u32 guest_interruptibility_info; - u32 guest_activity_state; - u32 guest_sysenter_cs; - u32 host_ia32_sysenter_cs; - u32 padding32[8]; /* room for future expansion */ - u16 virtual_processor_id; - u16 guest_es_selector; - u16 guest_cs_selector; - u16 guest_ss_selector; - u16 guest_ds_selector; - u16 guest_fs_selector; - u16 guest_gs_selector; - u16 guest_ldtr_selector; - u16 guest_tr_selector; - u16 host_es_selector; - u16 host_cs_selector; - u16 host_ss_selector; - u16 host_ds_selector; - u16 host_fs_selector; - u16 host_gs_selector; - u16 host_tr_selector; - }; - - -Authors -------- - -These patches were written by: - Abel Gordon, abelg il.ibm.com - Nadav Har'El, nyh il.ibm.com - Orit Wasserman, oritw il.ibm.com - Ben-Ami Yassor, benami il.ibm.com - Muli Ben-Yehuda, muli il.ibm.com - -With contributions by: - Anthony Liguori, aliguori us.ibm.com - Mike Day, mdday us.ibm.com - Michael Factor, factor il.ibm.com - Zvi Dubitzky, dubi il.ibm.com - -And valuable reviews by: - Avi Kivity, avi redhat.com - Gleb Natapov, gleb redhat.com - Marcelo Tosatti, mtosatti redhat.com - Kevin Tian, kevin.tian intel.com - and others. diff --git a/trunk/Documentation/virtual/kvm/ppc-pv.txt b/trunk/Documentation/virtual/kvm/ppc-pv.txt index 2b7ce190cde4..3ab969c59046 100644 --- a/trunk/Documentation/virtual/kvm/ppc-pv.txt +++ b/trunk/Documentation/virtual/kvm/ppc-pv.txt @@ -68,11 +68,9 @@ page that contains parts of supervisor visible register state. The guest can map this shared page using the KVM hypercall KVM_HC_PPC_MAP_MAGIC_PAGE. With this hypercall issued the guest always gets the magic page mapped at the -desired location. The first parameter indicates the effective address when the -MMU is enabled. The second parameter indicates the address in real mode, if -applicable to the target. For now, we always map the page to -4096. This way we -can access it using absolute load and store functions. The following -instruction reads the first field of the magic page: +desired location in effective and physical address space. For now, we always +map the page to -4096. This way we can access it using absolute load and store +functions. The following instruction reads the first field of the magic page: ld rX, -4096(0) diff --git a/trunk/Documentation/x86/entry_64.txt b/trunk/Documentation/x86/entry_64.txt deleted file mode 100644 index 7869f14d055c..000000000000 --- a/trunk/Documentation/x86/entry_64.txt +++ /dev/null @@ -1,98 +0,0 @@ -This file documents some of the kernel entries in -arch/x86/kernel/entry_64.S. A lot of this explanation is adapted from -an email from Ingo Molnar: - -http://lkml.kernel.org/r/<20110529191055.GC9835%40elte.hu> - -The x86 architecture has quite a few different ways to jump into -kernel code. Most of these entry points are registered in -arch/x86/kernel/traps.c and implemented in arch/x86/kernel/entry_64.S -and arch/x86/ia32/ia32entry.S. - -The IDT vector assignments are listed in arch/x86/include/irq_vectors.h. - -Some of these entries are: - - - system_call: syscall instruction from 64-bit code. - - - ia32_syscall: int 0x80 from 32-bit or 64-bit code; compat syscall - either way. - - - ia32_syscall, ia32_sysenter: syscall and sysenter from 32-bit - code - - - interrupt: An array of entries. Every IDT vector that doesn't - explicitly point somewhere else gets set to the corresponding - value in interrupts. These point to a whole array of - magically-generated functions that make their way to do_IRQ with - the interrupt number as a parameter. - - - emulate_vsyscall: int 0xcc, a special non-ABI entry used by - vsyscall emulation. - - - APIC interrupts: Various special-purpose interrupts for things - like TLB shootdown. - - - Architecturally-defined exceptions like divide_error. - -There are a few complexities here. The different x86-64 entries -have different calling conventions. The syscall and sysenter -instructions have their own peculiar calling conventions. Some of -the IDT entries push an error code onto the stack; others don't. -IDT entries using the IST alternative stack mechanism need their own -magic to get the stack frames right. (You can find some -documentation in the AMD APM, Volume 2, Chapter 8 and the Intel SDM, -Volume 3, Chapter 6.) - -Dealing with the swapgs instruction is especially tricky. Swapgs -toggles whether gs is the kernel gs or the user gs. The swapgs -instruction is rather fragile: it must nest perfectly and only in -single depth, it should only be used if entering from user mode to -kernel mode and then when returning to user-space, and precisely -so. If we mess that up even slightly, we crash. - -So when we have a secondary entry, already in kernel mode, we *must -not* use SWAPGS blindly - nor must we forget doing a SWAPGS when it's -not switched/swapped yet. - -Now, there's a secondary complication: there's a cheap way to test -which mode the CPU is in and an expensive way. - -The cheap way is to pick this info off the entry frame on the kernel -stack, from the CS of the ptregs area of the kernel stack: - - xorl %ebx,%ebx - testl $3,CS+8(%rsp) - je error_kernelspace - SWAPGS - -The expensive (paranoid) way is to read back the MSR_GS_BASE value -(which is what SWAPGS modifies): - - movl $1,%ebx - movl $MSR_GS_BASE,%ecx - rdmsr - testl %edx,%edx - js 1f /* negative -> in kernel */ - SWAPGS - xorl %ebx,%ebx -1: ret - -and the whole paranoid non-paranoid macro complexity is about whether -to suffer that RDMSR cost. - -If we are at an interrupt or user-trap/gate-alike boundary then we can -use the faster check: the stack will be a reliable indicator of -whether SWAPGS was already done: if we see that we are a secondary -entry interrupting kernel mode execution, then we know that the GS -base has already been switched. If it says that we interrupted -user-space execution then we must do the SWAPGS. - -But if we are in an NMI/MCE/DEBUG/whatever super-atomic entry context, -which might have triggered right after a normal entry wrote CS to the -stack but before we executed SWAPGS, then the only safe way to check -for GS is the slower method: the RDMSR. - -So we try only to mark those entry methods 'paranoid' that absolutely -need the more expensive check for the GS base - and we generate all -'normal' entry points with the regular (faster) entry macros. diff --git a/trunk/Documentation/zh_CN/SubmitChecklist b/trunk/Documentation/zh_CN/SubmitChecklist index 4c741d6bc048..951415bbab0c 100644 --- a/trunk/Documentation/zh_CN/SubmitChecklist +++ b/trunk/Documentation/zh_CN/SubmitChecklist @@ -67,7 +67,7 @@ Linux 12ѾͨCONFIG_PREEMPT, CONFIG_DEBUG_PREEMPT, CONFIG_DEBUG_SLAB, CONFIG_DEBUG_PAGEALLOC, CONFIG_DEBUG_MUTEXES, - CONFIG_DEBUG_SPINLOCK, CONFIG_DEBUG_ATOMIC_SLEEPԣͬʱ + CONFIG_DEBUG_SPINLOCK, CONFIG_DEBUG_SPINLOCK_SLEEPԣͬʱ ʹܡ 13Ѿʹû߲ʹ CONFIG_SMP CONFIG_PREEMPTִʱ䡣 diff --git a/trunk/MAINTAINERS b/trunk/MAINTAINERS index 43392c9ef4c3..41ec646d8a98 100644 --- a/trunk/MAINTAINERS +++ b/trunk/MAINTAINERS @@ -534,8 +534,6 @@ L: device-drivers-devel@blackfin.uclinux.org L: alsa-devel@alsa-project.org (moderated for non-subscribers) W: http://wiki.analog.com/ S: Supported -F: sound/soc/codecs/adau* -F: sound/soc/codecs/adav* F: sound/soc/codecs/ad1* F: sound/soc/codecs/ssm* @@ -1553,12 +1551,6 @@ L: linux-wireless@vger.kernel.org S: Supported F: drivers/staging/brcm80211/ -BROADCOM BNX2FC 10 GIGABIT FCOE DRIVER -M: Bhanu Prakash Gollapudi -L: linux-scsi@vger.kernel.org -S: Supported -F: drivers/scsi/bnx2fc/ - BROCADE BFA FC SCSI DRIVER M: Jing Huang L: linux-scsi@vger.kernel.org @@ -1781,8 +1773,7 @@ F: include/linux/clk.h CISCO FCOE HBA DRIVER M: Abhijeet Joglekar -M: Venkata Siva Vijayendra Bhamidipati -M: Brian Uchino +M: Joe Eykholt L: linux-scsi@vger.kernel.org S: Supported F: drivers/scsi/fnic/ @@ -4688,14 +4679,6 @@ F: drivers/of F: include/linux/of*.h K: of_get_property -OPENRISC ARCHITECTURE -M: Jonas Bonn -W: http://openrisc.net -L: linux@lists.openrisc.net -S: Maintained -T: git git://openrisc.net/~jonas/linux -F: arch/openrisc - OPL4 DRIVER M: Clemens Ladisch L: alsa-devel@alsa-project.org (moderated for non-subscribers) @@ -5335,13 +5318,6 @@ L: reiserfs-devel@vger.kernel.org S: Supported F: fs/reiserfs/ -REGISTER MAP ABSTRACTION -M: Mark Brown -T: git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git -S: Supported -F: drivers/base/regmap/ -F: include/linux/regmap.h - RFKILL M: Johannes Berg L: linux-wireless@vger.kernel.org diff --git a/trunk/Makefile b/trunk/Makefile index d0189560613c..6a5bdad524af 100644 --- a/trunk/Makefile +++ b/trunk/Makefile @@ -1290,7 +1290,6 @@ help: @echo ' make O=dir [targets] Locate all output files in "dir", including .config' @echo ' make C=1 [targets] Check all c source with $$CHECK (sparse by default)' @echo ' make C=2 [targets] Force check of all c source with $$CHECK' - @echo ' make RECORDMCOUNT_WARN=1 [targets] Warn about ignored mcount sections' @echo ' make W=n [targets] Enable extra gcc checks, n=1,2,3 where' @echo ' 1: warnings which may be relevant and do not occur too often' @echo ' 2: warnings which occur quite often but may still be relevant' diff --git a/trunk/arch/alpha/Kconfig b/trunk/arch/alpha/Kconfig index ca2da8da6e9c..60219bf94198 100644 --- a/trunk/arch/alpha/Kconfig +++ b/trunk/arch/alpha/Kconfig @@ -6,7 +6,6 @@ config ALPHA select HAVE_OPROFILE select HAVE_SYSCALL_WRAPPERS select HAVE_IRQ_WORK - select HAVE_PCSPKR_PLATFORM select HAVE_PERF_EVENTS select HAVE_DMA_ATTRS select HAVE_GENERIC_HARDIRQS diff --git a/trunk/arch/alpha/include/asm/8253pit.h b/trunk/arch/alpha/include/asm/8253pit.h new file mode 100644 index 000000000000..a71c9c1455a7 --- /dev/null +++ b/trunk/arch/alpha/include/asm/8253pit.h @@ -0,0 +1,3 @@ +/* + * 8253/8254 Programmable Interval Timer + */ diff --git a/trunk/arch/alpha/kernel/module.c b/trunk/arch/alpha/kernel/module.c index 2fd00b7077e4..ebc3c894b5a2 100644 --- a/trunk/arch/alpha/kernel/module.c +++ b/trunk/arch/alpha/kernel/module.c @@ -29,6 +29,20 @@ #define DEBUGP(fmt...) #endif +void * +module_alloc(unsigned long size) +{ + if (size == 0) + return NULL; + return vmalloc(size); +} + +void +module_free(struct module *mod, void *module_region) +{ + vfree(module_region); +} + /* Allocate the GOT at the end of the core sections. */ struct got_entry { @@ -141,6 +155,14 @@ module_frob_arch_sections(Elf64_Ehdr *hdr, Elf64_Shdr *sechdrs, return 0; } +int +apply_relocate(Elf64_Shdr *sechdrs, const char *strtab, unsigned int symindex, + unsigned int relsec, struct module *me) +{ + printk(KERN_ERR "module %s: REL relocation unsupported\n", me->name); + return -ENOEXEC; +} + int apply_relocate_add(Elf64_Shdr *sechdrs, const char *strtab, unsigned int symindex, unsigned int relsec, @@ -280,3 +302,15 @@ apply_relocate_add(Elf64_Shdr *sechdrs, const char *strtab, return 0; } + +int +module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, + struct module *me) +{ + return 0; +} + +void +module_arch_cleanup(struct module *mod) +{ +} diff --git a/trunk/arch/alpha/kernel/perf_event.c b/trunk/arch/alpha/kernel/perf_event.c index 8e47709160f8..90561c45e7d8 100644 --- a/trunk/arch/alpha/kernel/perf_event.c +++ b/trunk/arch/alpha/kernel/perf_event.c @@ -847,7 +847,7 @@ static void alpha_perf_event_irq_handler(unsigned long la_ptr, data.period = event->hw.last_period; if (alpha_perf_event_set_period(event, hwc, idx)) { - if (perf_event_overflow(event, &data, regs)) { + if (perf_event_overflow(event, 1, &data, regs)) { /* Interrupts coming too quickly; "throttle" the * counter, i.e., disable it for a little while. */ diff --git a/trunk/arch/alpha/kernel/sys_ruffian.c b/trunk/arch/alpha/kernel/sys_ruffian.c index f33648e4e8cf..8de1046fe91e 100644 --- a/trunk/arch/alpha/kernel/sys_ruffian.c +++ b/trunk/arch/alpha/kernel/sys_ruffian.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "proto.h" #include "irq_impl.h" diff --git a/trunk/arch/alpha/kernel/time.c b/trunk/arch/alpha/kernel/time.c index e336694ca042..818e74ed45dc 100644 --- a/trunk/arch/alpha/kernel/time.c +++ b/trunk/arch/alpha/kernel/time.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -90,7 +91,7 @@ DEFINE_PER_CPU(u8, irq_work_pending); #define test_irq_work_pending() __get_cpu_var(irq_work_pending) #define clear_irq_work_pending() __get_cpu_var(irq_work_pending) = 0 -void arch_irq_work_raise(void) +void set_irq_work_pending(void) { set_irq_work_pending_flag(); } diff --git a/trunk/arch/arm/Kconfig b/trunk/arch/arm/Kconfig index 1478c6171b00..e04fa9d7637c 100644 --- a/trunk/arch/arm/Kconfig +++ b/trunk/arch/arm/Kconfig @@ -10,7 +10,7 @@ config ARM select GENERIC_ATOMIC64 if (CPU_V6 || !CPU_32v6K || !AEABI) select HAVE_OPROFILE if (HAVE_PERF_EVENTS) select HAVE_ARCH_KGDB - select HAVE_KPROBES if !XIP_KERNEL + select HAVE_KPROBES if (!XIP_KERNEL && !THUMB2_KERNEL) select HAVE_KRETPROBES if (HAVE_KPROBES) select HAVE_FUNCTION_TRACER if (!XIP_KERNEL) select HAVE_FTRACE_MCOUNT_RECORD if (!XIP_KERNEL) @@ -37,9 +37,6 @@ config ARM Europe. There is an ARM Linux project with a web page at . -config ARM_HAS_SG_CHAIN - bool - config HAVE_PWM bool @@ -1350,6 +1347,7 @@ config SMP_ON_UP config HAVE_ARM_SCU bool + depends on SMP help This option enables support for the ARM system coherency unit @@ -1718,34 +1716,17 @@ config ZBOOT_ROM Say Y here if you intend to execute your compressed kernel image (zImage) directly from ROM or flash. If unsure, say N. -choice - prompt "Include SD/MMC loader in zImage (EXPERIMENTAL)" - depends on ZBOOT_ROM && ARCH_SH7372 && EXPERIMENTAL - default ZBOOT_ROM_NONE - help - Include experimental SD/MMC loading code in the ROM-able zImage. - With this enabled it is possible to write the the ROM-able zImage - kernel image to an MMC or SD card and boot the kernel straight - from the reset vector. At reset the processor Mask ROM will load - the first part of the the ROM-able zImage which in turn loads the - rest the kernel image to RAM. - -config ZBOOT_ROM_NONE - bool "No SD/MMC loader in zImage (EXPERIMENTAL)" - help - Do not load image from SD or MMC - config ZBOOT_ROM_MMCIF bool "Include MMCIF loader in zImage (EXPERIMENTAL)" + depends on ZBOOT_ROM && ARCH_SH7372 && EXPERIMENTAL help - Load image from MMCIF hardware block. - -config ZBOOT_ROM_SH_MOBILE_SDHI - bool "Include SuperH Mobile SDHI loader in zImage (EXPERIMENTAL)" - help - Load image from SDHI hardware block - -endchoice + Say Y here to include experimental MMCIF loading code in the + ROM-able zImage. With this enabled it is possible to write the + the ROM-able zImage kernel image to an MMC card and boot the + kernel straight from the reset vector. At reset the processor + Mask ROM will load the first part of the the ROM-able zImage + which in turn loads the rest the kernel image to RAM using the + MMCIF hardware block. config CMDLINE string "Default kernel command string" diff --git a/trunk/arch/arm/boot/compressed/Makefile b/trunk/arch/arm/boot/compressed/Makefile index 0c74a6fab952..23aad0722303 100644 --- a/trunk/arch/arm/boot/compressed/Makefile +++ b/trunk/arch/arm/boot/compressed/Makefile @@ -6,19 +6,13 @@ OBJS = -# Ensure that MMCIF loader code appears early in the image +# Ensure that mmcif loader code appears early in the image # to minimise that number of bocks that have to be read in # order to load it. ifeq ($(CONFIG_ZBOOT_ROM_MMCIF),y) +ifeq ($(CONFIG_ARCH_SH7372),y) OBJS += mmcif-sh7372.o endif - -# Ensure that SDHI loader code appears early in the image -# to minimise that number of bocks that have to be read in -# order to load it. -ifeq ($(CONFIG_ZBOOT_ROM_SH_MOBILE_SDHI),y) -OBJS += sdhi-shmobile.o -OBJS += sdhi-sh7372.o endif AFLAGS_head.o += -DTEXT_OFFSET=$(TEXT_OFFSET) diff --git a/trunk/arch/arm/boot/compressed/head-shmobile.S b/trunk/arch/arm/boot/compressed/head-shmobile.S index fe3719b516fd..c943d2e7da9d 100644 --- a/trunk/arch/arm/boot/compressed/head-shmobile.S +++ b/trunk/arch/arm/boot/compressed/head-shmobile.S @@ -25,14 +25,14 @@ /* load board-specific initialization code */ #include -#if defined(CONFIG_ZBOOT_ROM_MMCIF) || defined(CONFIG_ZBOOT_ROM_SH_MOBILE_SDHI) - /* Load image from MMC/SD */ - adr sp, __tmp_stack + 256 +#ifdef CONFIG_ZBOOT_ROM_MMCIF + /* Load image from MMC */ + adr sp, __tmp_stack + 128 ldr r0, __image_start ldr r1, __image_end subs r1, r1, r0 ldr r0, __load_base - bl mmc_loader + bl mmcif_loader /* Jump to loaded code */ ldr r0, __loaded @@ -51,9 +51,9 @@ __loaded: .long __continue .align __tmp_stack: - .space 256 + .space 128 __continue: -#endif /* CONFIG_ZBOOT_ROM_MMC || CONFIG_ZBOOT_ROM_SH_MOBILE_SDHI */ +#endif /* CONFIG_ZBOOT_ROM_MMCIF */ b 1f __atags:@ tag #1 diff --git a/trunk/arch/arm/boot/compressed/head.S b/trunk/arch/arm/boot/compressed/head.S index e95a5989602a..940b20178107 100644 --- a/trunk/arch/arm/boot/compressed/head.S +++ b/trunk/arch/arm/boot/compressed/head.S @@ -353,8 +353,7 @@ not_relocated: mov r0, #0 mov r0, #0 @ must be zero mov r1, r7 @ restore architecture number mov r2, r8 @ restore atags pointer - ARM( mov pc, r4 ) @ call kernel - THUMB( bx r4 ) @ entry point is always ARM + mov pc, r4 @ call kernel .align 2 .type LC0, #object diff --git a/trunk/arch/arm/boot/compressed/mmcif-sh7372.c b/trunk/arch/arm/boot/compressed/mmcif-sh7372.c index b6f61d9a5a1b..7453c8337b83 100644 --- a/trunk/arch/arm/boot/compressed/mmcif-sh7372.c +++ b/trunk/arch/arm/boot/compressed/mmcif-sh7372.c @@ -40,7 +40,7 @@ * to an MMC card * # dd if=vrl4.out of=/dev/sdx bs=512 seek=1 */ -asmlinkage void mmc_loader(unsigned char *buf, unsigned long len) +asmlinkage void mmcif_loader(unsigned char *buf, unsigned long len) { mmc_init_progress(); mmc_update_progress(MMC_PROGRESS_ENTER); diff --git a/trunk/arch/arm/boot/compressed/sdhi-sh7372.c b/trunk/arch/arm/boot/compressed/sdhi-sh7372.c deleted file mode 100644 index d403a8b24d7f..000000000000 --- a/trunk/arch/arm/boot/compressed/sdhi-sh7372.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * SuperH Mobile SDHI - * - * Copyright (C) 2010 Magnus Damm - * Copyright (C) 2010 Kuninori Morimoto - * Copyright (C) 2010 Simon Horman - * - * 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. - * - * Parts inspired by u-boot - */ - -#include -#include -#include -#include - -#include "sdhi-shmobile.h" - -#define PORT179CR 0xe60520b3 -#define PORT180CR 0xe60520b4 -#define PORT181CR 0xe60520b5 -#define PORT182CR 0xe60520b6 -#define PORT183CR 0xe60520b7 -#define PORT184CR 0xe60520b8 - -#define SMSTPCR3 0xe615013c - -#define CR_INPUT_ENABLE 0x10 -#define CR_FUNCTION1 0x01 - -#define SDHI1_BASE (void __iomem *)0xe6860000 -#define SDHI_BASE SDHI1_BASE - -/* SuperH Mobile SDHI loader - * - * loads the zImage from an SD card starting from block 0 - * on physical partition 1 - * - * The image must be start with a vrl4 header and - * the zImage must start at offset 512 of the image. That is, - * at block 1 (=byte 512) of physical partition 1 - * - * Use the following line to write the vrl4 formated zImage - * to an SD card - * # dd if=vrl4.out of=/dev/sdx bs=512 - */ -asmlinkage void mmc_loader(unsigned short *buf, unsigned long len) -{ - int high_capacity; - - mmc_init_progress(); - - mmc_update_progress(MMC_PROGRESS_ENTER); - /* Initialise SDHI1 */ - /* PORT184CR: GPIO_FN_SDHICMD1 Control */ - __raw_writeb(CR_FUNCTION1, PORT184CR); - /* PORT179CR: GPIO_FN_SDHICLK1 Control */ - __raw_writeb(CR_INPUT_ENABLE|CR_FUNCTION1, PORT179CR); - /* PORT181CR: GPIO_FN_SDHID1_3 Control */ - __raw_writeb(CR_FUNCTION1, PORT183CR); - /* PORT182CR: GPIO_FN_SDHID1_2 Control */ - __raw_writeb(CR_FUNCTION1, PORT182CR); - /* PORT183CR: GPIO_FN_SDHID1_1 Control */ - __raw_writeb(CR_FUNCTION1, PORT181CR); - /* PORT180CR: GPIO_FN_SDHID1_0 Control */ - __raw_writeb(CR_FUNCTION1, PORT180CR); - - /* Enable clock to SDHI1 hardware block */ - __raw_writel(__raw_readl(SMSTPCR3) & ~(1 << 13), SMSTPCR3); - - /* setup SDHI hardware */ - mmc_update_progress(MMC_PROGRESS_INIT); - high_capacity = sdhi_boot_init(SDHI_BASE); - if (high_capacity < 0) - goto err; - - mmc_update_progress(MMC_PROGRESS_LOAD); - /* load kernel */ - if (sdhi_boot_do_read(SDHI_BASE, high_capacity, - 0, /* Kernel is at block 1 */ - (len + TMIO_BBS - 1) / TMIO_BBS, buf)) - goto err; - - /* Disable clock to SDHI1 hardware block */ - __raw_writel(__raw_readl(SMSTPCR3) & (1 << 13), SMSTPCR3); - - mmc_update_progress(MMC_PROGRESS_DONE); - - return; -err: - for(;;); -} diff --git a/trunk/arch/arm/boot/compressed/sdhi-shmobile.c b/trunk/arch/arm/boot/compressed/sdhi-shmobile.c deleted file mode 100644 index bd3d46980955..000000000000 --- a/trunk/arch/arm/boot/compressed/sdhi-shmobile.c +++ /dev/null @@ -1,449 +0,0 @@ -/* - * SuperH Mobile SDHI - * - * Copyright (C) 2010 Magnus Damm - * Copyright (C) 2010 Kuninori Morimoto - * Copyright (C) 2010 Simon Horman - * - * 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. - * - * Parts inspired by u-boot - */ - -#include -#include -#include -#include -#include -#include -#include - -#define OCR_FASTBOOT (1<<29) -#define OCR_HCS (1<<30) -#define OCR_BUSY (1<<31) - -#define RESP_CMD12 0x00000030 - -static inline u16 sd_ctrl_read16(void __iomem *base, int addr) -{ - return __raw_readw(base + addr); -} - -static inline u32 sd_ctrl_read32(void __iomem *base, int addr) -{ - return __raw_readw(base + addr) | - __raw_readw(base + addr + 2) << 16; -} - -static inline void sd_ctrl_write16(void __iomem *base, int addr, u16 val) -{ - __raw_writew(val, base + addr); -} - -static inline void sd_ctrl_write32(void __iomem *base, int addr, u32 val) -{ - __raw_writew(val, base + addr); - __raw_writew(val >> 16, base + addr + 2); -} - -#define ALL_ERROR (TMIO_STAT_CMD_IDX_ERR | TMIO_STAT_CRCFAIL | \ - TMIO_STAT_STOPBIT_ERR | TMIO_STAT_DATATIMEOUT | \ - TMIO_STAT_RXOVERFLOW | TMIO_STAT_TXUNDERRUN | \ - TMIO_STAT_CMDTIMEOUT | TMIO_STAT_ILL_ACCESS | \ - TMIO_STAT_ILL_FUNC) - -static int sdhi_intr(void __iomem *base) -{ - unsigned long state = sd_ctrl_read32(base, CTL_STATUS); - - if (state & ALL_ERROR) { - sd_ctrl_write32(base, CTL_STATUS, ~ALL_ERROR); - sd_ctrl_write32(base, CTL_IRQ_MASK, - ALL_ERROR | - sd_ctrl_read32(base, CTL_IRQ_MASK)); - return -EINVAL; - } - if (state & TMIO_STAT_CMDRESPEND) { - sd_ctrl_write32(base, CTL_STATUS, ~TMIO_STAT_CMDRESPEND); - sd_ctrl_write32(base, CTL_IRQ_MASK, - TMIO_STAT_CMDRESPEND | - sd_ctrl_read32(base, CTL_IRQ_MASK)); - return 0; - } - if (state & TMIO_STAT_RXRDY) { - sd_ctrl_write32(base, CTL_STATUS, ~TMIO_STAT_RXRDY); - sd_ctrl_write32(base, CTL_IRQ_MASK, - TMIO_STAT_RXRDY | TMIO_STAT_TXUNDERRUN | - sd_ctrl_read32(base, CTL_IRQ_MASK)); - return 0; - } - if (state & TMIO_STAT_DATAEND) { - sd_ctrl_write32(base, CTL_STATUS, ~TMIO_STAT_DATAEND); - sd_ctrl_write32(base, CTL_IRQ_MASK, - TMIO_STAT_DATAEND | - sd_ctrl_read32(base, CTL_IRQ_MASK)); - return 0; - } - - return -EAGAIN; -} - -static int sdhi_boot_wait_resp_end(void __iomem *base) -{ - int err = -EAGAIN, timeout = 10000000; - - while (timeout--) { - err = sdhi_intr(base); - if (err != -EAGAIN) - break; - udelay(1); - } - - return err; -} - -/* SDHI_CLK_CTRL */ -#define CLK_MMC_ENABLE (1 << 8) -#define CLK_MMC_INIT (1 << 6) /* clk / 256 */ - -static void sdhi_boot_mmc_clk_stop(void __iomem *base) -{ - sd_ctrl_write16(base, CTL_CLK_AND_WAIT_CTL, 0x0000); - msleep(10); - sd_ctrl_write16(base, CTL_SD_CARD_CLK_CTL, ~CLK_MMC_ENABLE & - sd_ctrl_read16(base, CTL_SD_CARD_CLK_CTL)); - msleep(10); -} - -static void sdhi_boot_mmc_clk_start(void __iomem *base) -{ - sd_ctrl_write16(base, CTL_SD_CARD_CLK_CTL, CLK_MMC_ENABLE | - sd_ctrl_read16(base, CTL_SD_CARD_CLK_CTL)); - msleep(10); - sd_ctrl_write16(base, CTL_CLK_AND_WAIT_CTL, CLK_MMC_ENABLE); - msleep(10); -} - -static void sdhi_boot_reset(void __iomem *base) -{ - sd_ctrl_write16(base, CTL_RESET_SD, 0x0000); - msleep(10); - sd_ctrl_write16(base, CTL_RESET_SD, 0x0001); - msleep(10); -} - -/* Set MMC clock / power. - * Note: This controller uses a simple divider scheme therefore it cannot - * run a MMC card at full speed (20MHz). The max clock is 24MHz on SD, but as - * MMC wont run that fast, it has to be clocked at 12MHz which is the next - * slowest setting. - */ -static int sdhi_boot_mmc_set_ios(void __iomem *base, struct mmc_ios *ios) -{ - if (sd_ctrl_read32(base, CTL_STATUS) & TMIO_STAT_CMD_BUSY) - return -EBUSY; - - if (ios->clock) - sd_ctrl_write16(base, CTL_SD_CARD_CLK_CTL, - ios->clock | CLK_MMC_ENABLE); - - /* Power sequence - OFF -> ON -> UP */ - switch (ios->power_mode) { - case MMC_POWER_OFF: /* power down SD bus */ - sdhi_boot_mmc_clk_stop(base); - break; - case MMC_POWER_ON: /* power up SD bus */ - break; - case MMC_POWER_UP: /* start bus clock */ - sdhi_boot_mmc_clk_start(base); - break; - } - - switch (ios->bus_width) { - case MMC_BUS_WIDTH_1: - sd_ctrl_write16(base, CTL_SD_MEM_CARD_OPT, 0x80e0); - break; - case MMC_BUS_WIDTH_4: - sd_ctrl_write16(base, CTL_SD_MEM_CARD_OPT, 0x00e0); - break; - } - - /* Let things settle. delay taken from winCE driver */ - udelay(140); - - return 0; -} - -/* These are the bitmasks the tmio chip requires to implement the MMC response - * types. Note that R1 and R6 are the same in this scheme. */ -#define RESP_NONE 0x0300 -#define RESP_R1 0x0400 -#define RESP_R1B 0x0500 -#define RESP_R2 0x0600 -#define RESP_R3 0x0700 -#define DATA_PRESENT 0x0800 -#define TRANSFER_READ 0x1000 - -static int sdhi_boot_request(void __iomem *base, struct mmc_command *cmd) -{ - int err, c = cmd->opcode; - - switch (mmc_resp_type(cmd)) { - case MMC_RSP_NONE: c |= RESP_NONE; break; - case MMC_RSP_R1: c |= RESP_R1; break; - case MMC_RSP_R1B: c |= RESP_R1B; break; - case MMC_RSP_R2: c |= RESP_R2; break; - case MMC_RSP_R3: c |= RESP_R3; break; - default: - return -EINVAL; - } - - /* No interrupts so this may not be cleared */ - sd_ctrl_write32(base, CTL_STATUS, ~TMIO_STAT_CMDRESPEND); - - sd_ctrl_write32(base, CTL_IRQ_MASK, TMIO_STAT_CMDRESPEND | - sd_ctrl_read32(base, CTL_IRQ_MASK)); - sd_ctrl_write32(base, CTL_ARG_REG, cmd->arg); - sd_ctrl_write16(base, CTL_SD_CMD, c); - - - sd_ctrl_write32(base, CTL_IRQ_MASK, - ~(TMIO_STAT_CMDRESPEND | ALL_ERROR) & - sd_ctrl_read32(base, CTL_IRQ_MASK)); - - err = sdhi_boot_wait_resp_end(base); - if (err) - return err; - - cmd->resp[0] = sd_ctrl_read32(base, CTL_RESPONSE); - - return 0; -} - -static int sdhi_boot_do_read_single(void __iomem *base, int high_capacity, - unsigned long block, unsigned short *buf) -{ - int err, i; - - /* CMD17 - Read */ - { - struct mmc_command cmd; - - cmd.opcode = MMC_READ_SINGLE_BLOCK | \ - TRANSFER_READ | DATA_PRESENT; - if (high_capacity) - cmd.arg = block; - else - cmd.arg = block * TMIO_BBS; - cmd.flags = MMC_RSP_R1; - err = sdhi_boot_request(base, &cmd); - if (err) - return err; - } - - sd_ctrl_write32(base, CTL_IRQ_MASK, - ~(TMIO_STAT_DATAEND | TMIO_STAT_RXRDY | - TMIO_STAT_TXUNDERRUN) & - sd_ctrl_read32(base, CTL_IRQ_MASK)); - err = sdhi_boot_wait_resp_end(base); - if (err) - return err; - - sd_ctrl_write16(base, CTL_SD_XFER_LEN, TMIO_BBS); - for (i = 0; i < TMIO_BBS / sizeof(*buf); i++) - *buf++ = sd_ctrl_read16(base, RESP_CMD12); - - err = sdhi_boot_wait_resp_end(base); - if (err) - return err; - - return 0; -} - -int sdhi_boot_do_read(void __iomem *base, int high_capacity, - unsigned long offset, unsigned short count, - unsigned short *buf) -{ - unsigned long i; - int err = 0; - - for (i = 0; i < count; i++) { - err = sdhi_boot_do_read_single(base, high_capacity, offset + i, - buf + (i * TMIO_BBS / - sizeof(*buf))); - if (err) - return err; - } - - return 0; -} - -#define VOLTAGES (MMC_VDD_32_33 | MMC_VDD_33_34) - -int sdhi_boot_init(void __iomem *base) -{ - bool sd_v2 = false, sd_v1_0 = false; - unsigned short cid; - int err, high_capacity = 0; - - sdhi_boot_mmc_clk_stop(base); - sdhi_boot_reset(base); - - /* mmc0: clock 400000Hz busmode 1 powermode 2 cs 0 Vdd 21 width 0 timing 0 */ - { - struct mmc_ios ios; - ios.power_mode = MMC_POWER_ON; - ios.bus_width = MMC_BUS_WIDTH_1; - ios.clock = CLK_MMC_INIT; - err = sdhi_boot_mmc_set_ios(base, &ios); - if (err) - return err; - } - - /* CMD0 */ - { - struct mmc_command cmd; - msleep(1); - cmd.opcode = MMC_GO_IDLE_STATE; - cmd.arg = 0; - cmd.flags = MMC_RSP_NONE; - err = sdhi_boot_request(base, &cmd); - if (err) - return err; - msleep(2); - } - - /* CMD8 - Test for SD version 2 */ - { - struct mmc_command cmd; - cmd.opcode = SD_SEND_IF_COND; - cmd.arg = (VOLTAGES != 0) << 8 | 0xaa; - cmd.flags = MMC_RSP_R1; - err = sdhi_boot_request(base, &cmd); /* Ignore error */ - if ((cmd.resp[0] & 0xff) == 0xaa) - sd_v2 = true; - } - - /* CMD55 - Get OCR (SD) */ - { - int timeout = 1000; - struct mmc_command cmd; - - cmd.arg = 0; - - do { - cmd.opcode = MMC_APP_CMD; - cmd.flags = MMC_RSP_R1; - cmd.arg = 0; - err = sdhi_boot_request(base, &cmd); - if (err) - break; - - cmd.opcode = SD_APP_OP_COND; - cmd.flags = MMC_RSP_R3; - cmd.arg = (VOLTAGES & 0xff8000); - if (sd_v2) - cmd.arg |= OCR_HCS; - cmd.arg |= OCR_FASTBOOT; - err = sdhi_boot_request(base, &cmd); - if (err) - break; - - msleep(1); - } while((!(cmd.resp[0] & OCR_BUSY)) && --timeout); - - if (!err && timeout) { - if (!sd_v2) - sd_v1_0 = true; - high_capacity = (cmd.resp[0] & OCR_HCS) == OCR_HCS; - } - } - - /* CMD1 - Get OCR (MMC) */ - if (!sd_v2 && !sd_v1_0) { - int timeout = 1000; - struct mmc_command cmd; - - do { - cmd.opcode = MMC_SEND_OP_COND; - cmd.arg = VOLTAGES | OCR_HCS; - cmd.flags = MMC_RSP_R3; - err = sdhi_boot_request(base, &cmd); - if (err) - return err; - - msleep(1); - } while((!(cmd.resp[0] & OCR_BUSY)) && --timeout); - - if (!timeout) - return -EAGAIN; - - high_capacity = (cmd.resp[0] & OCR_HCS) == OCR_HCS; - } - - /* CMD2 - Get CID */ - { - struct mmc_command cmd; - cmd.opcode = MMC_ALL_SEND_CID; - cmd.arg = 0; - cmd.flags = MMC_RSP_R2; - err = sdhi_boot_request(base, &cmd); - if (err) - return err; - } - - /* CMD3 - * MMC: Set the relative address - * SD: Get the relative address - * Also puts the card into the standby state - */ - { - struct mmc_command cmd; - cmd.opcode = MMC_SET_RELATIVE_ADDR; - cmd.arg = 0; - cmd.flags = MMC_RSP_R1; - err = sdhi_boot_request(base, &cmd); - if (err) - return err; - cid = cmd.resp[0] >> 16; - } - - /* CMD9 - Get CSD */ - { - struct mmc_command cmd; - cmd.opcode = MMC_SEND_CSD; - cmd.arg = cid << 16; - cmd.flags = MMC_RSP_R2; - err = sdhi_boot_request(base, &cmd); - if (err) - return err; - } - - /* CMD7 - Select the card */ - { - struct mmc_command cmd; - cmd.opcode = MMC_SELECT_CARD; - //cmd.arg = rca << 16; - cmd.arg = cid << 16; - //cmd.flags = MMC_RSP_R1B; - cmd.flags = MMC_RSP_R1; - err = sdhi_boot_request(base, &cmd); - if (err) - return err; - } - - /* CMD16 - Set the block size */ - { - struct mmc_command cmd; - cmd.opcode = MMC_SET_BLOCKLEN; - cmd.arg = TMIO_BBS; - cmd.flags = MMC_RSP_R1; - err = sdhi_boot_request(base, &cmd); - if (err) - return err; - } - - return high_capacity; -} diff --git a/trunk/arch/arm/boot/compressed/sdhi-shmobile.h b/trunk/arch/arm/boot/compressed/sdhi-shmobile.h deleted file mode 100644 index 92eaa09f985e..000000000000 --- a/trunk/arch/arm/boot/compressed/sdhi-shmobile.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef SDHI_MOBILE_H -#define SDHI_MOBILE_H - -#include - -int sdhi_boot_do_read(void __iomem *base, int high_capacity, - unsigned long offset, unsigned short count, - unsigned short *buf); -int sdhi_boot_init(void __iomem *base); - -#endif diff --git a/trunk/arch/arm/boot/compressed/vmlinux.lds.in b/trunk/arch/arm/boot/compressed/vmlinux.lds.in index 4e728834a1b9..ea80abe78844 100644 --- a/trunk/arch/arm/boot/compressed/vmlinux.lds.in +++ b/trunk/arch/arm/boot/compressed/vmlinux.lds.in @@ -33,24 +33,20 @@ SECTIONS *(.text.*) *(.fixup) *(.gnu.warning) - *(.glue_7t) - *(.glue_7) - } - .rodata : { *(.rodata) *(.rodata.*) - } - .piggydata : { + *(.glue_7) + *(.glue_7t) *(.piggydata) + . = ALIGN(4); } - . = ALIGN(4); _etext = .; - .got.plt : { *(.got.plt) } _got_start = .; .got : { *(.got) } _got_end = .; + .got.plt : { *(.got.plt) } _edata = .; . = BSS_START; diff --git a/trunk/arch/arm/common/dmabounce.c b/trunk/arch/arm/common/dmabounce.c index 595ecd290ebf..841df7d21c2f 100644 --- a/trunk/arch/arm/common/dmabounce.c +++ b/trunk/arch/arm/common/dmabounce.c @@ -79,8 +79,6 @@ struct dmabounce_device_info { struct dmabounce_pool large; rwlock_t lock; - - int (*needs_bounce)(struct device *, dma_addr_t, size_t); }; #ifdef STATS @@ -212,91 +210,114 @@ static struct safe_buffer *find_safe_buffer_dev(struct device *dev, if (!dev || !dev->archdata.dmabounce) return NULL; if (dma_mapping_error(dev, dma_addr)) { - dev_err(dev, "Trying to %s invalid mapping\n", where); + if (dev) + dev_err(dev, "Trying to %s invalid mapping\n", where); + else + pr_err("unknown device: Trying to %s invalid mapping\n", where); return NULL; } return find_safe_buffer(dev->archdata.dmabounce, dma_addr); } -static int needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size) +static inline dma_addr_t map_single(struct device *dev, void *ptr, size_t size, + enum dma_data_direction dir) { - if (!dev || !dev->archdata.dmabounce) - return 0; + struct dmabounce_device_info *device_info = dev->archdata.dmabounce; + dma_addr_t dma_addr; + int needs_bounce = 0; + + if (device_info) + DO_STATS ( device_info->map_op_count++ ); + + dma_addr = virt_to_dma(dev, ptr); if (dev->dma_mask) { - unsigned long limit, mask = *dev->dma_mask; + unsigned long mask = *dev->dma_mask; + unsigned long limit; limit = (mask + 1) & ~mask; if (limit && size > limit) { dev_err(dev, "DMA mapping too big (requested %#x " "mask %#Lx)\n", size, *dev->dma_mask); - return -E2BIG; + return ~0; } - /* Figure out if we need to bounce from the DMA mask. */ - if ((dma_addr | (dma_addr + size - 1)) & ~mask) - return 1; + /* + * Figure out if we need to bounce from the DMA mask. + */ + needs_bounce = (dma_addr | (dma_addr + size - 1)) & ~mask; } - return !!dev->archdata.dmabounce->needs_bounce(dev, dma_addr, size); -} - -static inline dma_addr_t map_single(struct device *dev, void *ptr, size_t size, - enum dma_data_direction dir) -{ - struct dmabounce_device_info *device_info = dev->archdata.dmabounce; - struct safe_buffer *buf; + if (device_info && (needs_bounce || dma_needs_bounce(dev, dma_addr, size))) { + struct safe_buffer *buf; - if (device_info) - DO_STATS ( device_info->map_op_count++ ); + buf = alloc_safe_buffer(device_info, ptr, size, dir); + if (buf == 0) { + dev_err(dev, "%s: unable to map unsafe buffer %p!\n", + __func__, ptr); + return ~0; + } - buf = alloc_safe_buffer(device_info, ptr, size, dir); - if (buf == NULL) { - dev_err(dev, "%s: unable to map unsafe buffer %p!\n", - __func__, ptr); - return ~0; - } + dev_dbg(dev, + "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n", + __func__, buf->ptr, virt_to_dma(dev, buf->ptr), + buf->safe, buf->safe_dma_addr); - dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n", - __func__, buf->ptr, virt_to_dma(dev, buf->ptr), - buf->safe, buf->safe_dma_addr); + if ((dir == DMA_TO_DEVICE) || + (dir == DMA_BIDIRECTIONAL)) { + dev_dbg(dev, "%s: copy unsafe %p to safe %p, size %d\n", + __func__, ptr, buf->safe, size); + memcpy(buf->safe, ptr, size); + } + ptr = buf->safe; - if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL) { - dev_dbg(dev, "%s: copy unsafe %p to safe %p, size %d\n", - __func__, ptr, buf->safe, size); - memcpy(buf->safe, ptr, size); + dma_addr = buf->safe_dma_addr; + } else { + /* + * We don't need to sync the DMA buffer since + * it was allocated via the coherent allocators. + */ + __dma_single_cpu_to_dev(ptr, size, dir); } - return buf->safe_dma_addr; + return dma_addr; } -static inline void unmap_single(struct device *dev, struct safe_buffer *buf, +static inline void unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, enum dma_data_direction dir) { - BUG_ON(buf->size != size); - BUG_ON(buf->direction != dir); + struct safe_buffer *buf = find_safe_buffer_dev(dev, dma_addr, "unmap"); - dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n", - __func__, buf->ptr, virt_to_dma(dev, buf->ptr), - buf->safe, buf->safe_dma_addr); + if (buf) { + BUG_ON(buf->size != size); + BUG_ON(buf->direction != dir); - DO_STATS(dev->archdata.dmabounce->bounce_count++); + dev_dbg(dev, + "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n", + __func__, buf->ptr, virt_to_dma(dev, buf->ptr), + buf->safe, buf->safe_dma_addr); - if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) { - void *ptr = buf->ptr; + DO_STATS(dev->archdata.dmabounce->bounce_count++); - dev_dbg(dev, "%s: copy back safe %p to unsafe %p size %d\n", - __func__, buf->safe, ptr, size); - memcpy(ptr, buf->safe, size); + if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) { + void *ptr = buf->ptr; - /* - * Since we may have written to a page cache page, - * we need to ensure that the data will be coherent - * with user mappings. - */ - __cpuc_flush_dcache_area(ptr, size); + dev_dbg(dev, + "%s: copy back safe %p to unsafe %p size %d\n", + __func__, buf->safe, ptr, size); + memcpy(ptr, buf->safe, size); + + /* + * Since we may have written to a page cache page, + * we need to ensure that the data will be coherent + * with user mappings. + */ + __cpuc_flush_dcache_area(ptr, size); + } + free_safe_buffer(dev->archdata.dmabounce, buf); + } else { + __dma_single_dev_to_cpu(dma_to_virt(dev, dma_addr), size, dir); } - free_safe_buffer(dev->archdata.dmabounce, buf); } /* ************************************************** */ @@ -307,28 +328,45 @@ static inline void unmap_single(struct device *dev, struct safe_buffer *buf, * substitute the safe buffer for the unsafe one. * (basically move the buffer from an unsafe area to a safe one) */ +dma_addr_t __dma_map_single(struct device *dev, void *ptr, size_t size, + enum dma_data_direction dir) +{ + dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n", + __func__, ptr, size, dir); + + BUG_ON(!valid_dma_direction(dir)); + + return map_single(dev, ptr, size, dir); +} +EXPORT_SYMBOL(__dma_map_single); + +/* + * see if a mapped address was really a "safe" buffer and if so, copy + * the data from the safe buffer back to the unsafe buffer and free up + * the safe buffer. (basically return things back to the way they + * should be) + */ +void __dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, + enum dma_data_direction dir) +{ + dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n", + __func__, (void *) dma_addr, size, dir); + + unmap_single(dev, dma_addr, size, dir); +} +EXPORT_SYMBOL(__dma_unmap_single); + dma_addr_t __dma_map_page(struct device *dev, struct page *page, unsigned long offset, size_t size, enum dma_data_direction dir) { - dma_addr_t dma_addr; - int ret; - dev_dbg(dev, "%s(page=%p,off=%#lx,size=%zx,dir=%x)\n", __func__, page, offset, size, dir); - dma_addr = pfn_to_dma(dev, page_to_pfn(page)) + offset; - - ret = needs_bounce(dev, dma_addr, size); - if (ret < 0) - return ~0; - - if (ret == 0) { - __dma_page_cpu_to_dev(page, offset, size, dir); - return dma_addr; - } + BUG_ON(!valid_dma_direction(dir)); if (PageHighMem(page)) { - dev_err(dev, "DMA buffer bouncing of HIGHMEM pages is not supported\n"); + dev_err(dev, "DMA buffer bouncing of HIGHMEM pages " + "is not supported\n"); return ~0; } @@ -345,19 +383,10 @@ EXPORT_SYMBOL(__dma_map_page); void __dma_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size, enum dma_data_direction dir) { - struct safe_buffer *buf; - - dev_dbg(dev, "%s(dma=%#x,size=%d,dir=%x)\n", - __func__, dma_addr, size, dir); - - buf = find_safe_buffer_dev(dev, dma_addr, __func__); - if (!buf) { - __dma_page_dev_to_cpu(pfn_to_page(dma_to_pfn(dev, dma_addr)), - dma_addr & ~PAGE_MASK, size, dir); - return; - } + dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n", + __func__, (void *) dma_addr, size, dir); - unmap_single(dev, buf, size, dir); + unmap_single(dev, dma_addr, size, dir); } EXPORT_SYMBOL(__dma_unmap_page); @@ -432,8 +461,7 @@ static int dmabounce_init_pool(struct dmabounce_pool *pool, struct device *dev, } int dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size, - unsigned long large_buffer_size, - int (*needs_bounce_fn)(struct device *, dma_addr_t, size_t)) + unsigned long large_buffer_size) { struct dmabounce_device_info *device_info; int ret; @@ -469,7 +497,6 @@ int dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size, device_info->dev = dev; INIT_LIST_HEAD(&device_info->safe_buffers); rwlock_init(&device_info->lock); - device_info->needs_bounce = needs_bounce_fn; #ifdef STATS device_info->total_allocs = 0; diff --git a/trunk/arch/arm/common/gic.c b/trunk/arch/arm/common/gic.c index 7bdd91766d65..4ddd0a6ac7ff 100644 --- a/trunk/arch/arm/common/gic.c +++ b/trunk/arch/arm/common/gic.c @@ -179,21 +179,22 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, { void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) & ~3); unsigned int shift = (d->irq % 4) * 8; - unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask); + unsigned int cpu = cpumask_first(mask_val); u32 val, mask, bit; - if (cpu >= 8 || cpu >= nr_cpu_ids) + if (cpu >= 8) return -EINVAL; mask = 0xff << shift; bit = 1 << (cpu + shift); spin_lock(&irq_controller_lock); + d->node = cpu; val = readl_relaxed(reg) & ~mask; writel_relaxed(val | bit, reg); spin_unlock(&irq_controller_lock); - return IRQ_SET_MASK_OK; + return 0; } #endif diff --git a/trunk/arch/arm/common/it8152.c b/trunk/arch/arm/common/it8152.c index 14ad62e16dd1..7a21927c52e1 100644 --- a/trunk/arch/arm/common/it8152.c +++ b/trunk/arch/arm/common/it8152.c @@ -243,12 +243,6 @@ static struct resource it8152_mem = { * ITE8152 chip can address up to 64MByte, so all the devices * connected to ITE8152 (PCI and USB) should have limited DMA window */ -static int it8152_needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size) -{ - dev_dbg(dev, "%s: dma_addr %08x, size %08x\n", - __func__, dma_addr, size); - return (dma_addr + size - PHYS_OFFSET) >= SZ_64M; -} /* * Setup DMA mask to 64MB on devices connected to ITE8152. Ignore all @@ -260,7 +254,7 @@ static int it8152_pci_platform_notify(struct device *dev) if (dev->dma_mask) *dev->dma_mask = (SZ_64M - 1) | PHYS_OFFSET; dev->coherent_dma_mask = (SZ_64M - 1) | PHYS_OFFSET; - dmabounce_register_dev(dev, 2048, 4096, it8152_needs_bounce); + dmabounce_register_dev(dev, 2048, 4096); } return 0; } @@ -273,6 +267,14 @@ static int it8152_pci_platform_notify_remove(struct device *dev) return 0; } +int dma_needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size) +{ + dev_dbg(dev, "%s: dma_addr %08x, size %08x\n", + __func__, dma_addr, size); + return (dev->bus == &pci_bus_type) && + ((dma_addr + size - PHYS_OFFSET) >= SZ_64M); +} + int dma_set_coherent_mask(struct device *dev, u64 mask) { if (mask >= PHYS_OFFSET + SZ_64M - 1) diff --git a/trunk/arch/arm/common/sa1111.c b/trunk/arch/arm/common/sa1111.c index 0569de6acfba..9c49a46a2b7a 100644 --- a/trunk/arch/arm/common/sa1111.c +++ b/trunk/arch/arm/common/sa1111.c @@ -579,36 +579,7 @@ sa1111_configure_smc(struct sa1111 *sachip, int sdram, unsigned int drac, sachip->dev->coherent_dma_mask &= sa1111_dma_mask[drac >> 2]; } -#endif -#ifdef CONFIG_DMABOUNCE -/* - * According to the "Intel StrongARM SA-1111 Microprocessor Companion - * Chip Specification Update" (June 2000), erratum #7, there is a - * significant bug in the SA1111 SDRAM shared memory controller. If - * an access to a region of memory above 1MB relative to the bank base, - * it is important that address bit 10 _NOT_ be asserted. Depending - * on the configuration of the RAM, bit 10 may correspond to one - * of several different (processor-relative) address bits. - * - * This routine only identifies whether or not a given DMA address - * is susceptible to the bug. - * - * This should only get called for sa1111_device types due to the - * way we configure our device dma_masks. - */ -static int sa1111_needs_bounce(struct device *dev, dma_addr_t addr, size_t size) -{ - /* - * Section 4.6 of the "Intel StrongARM SA-1111 Development Module - * User's Guide" mentions that jumpers R51 and R52 control the - * target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or - * SDRAM bank 1 on Neponset). The default configuration selects - * Assabet, so any address in bank 1 is necessarily invalid. - */ - return (machine_is_assabet() || machine_is_pfs168()) && - (addr >= 0xc8000000 || (addr + size) >= 0xc8000000); -} #endif static void sa1111_dev_release(struct device *_dev) @@ -673,8 +644,7 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent, dev->dev.dma_mask = &dev->dma_mask; if (dev->dma_mask != 0xffffffffUL) { - ret = dmabounce_register_dev(&dev->dev, 1024, 4096, - sa1111_needs_bounce); + ret = dmabounce_register_dev(&dev->dev, 1024, 4096); if (ret) { dev_err(&dev->dev, "SA1111: Failed to register" " with dmabounce\n"); @@ -848,6 +818,34 @@ static void __sa1111_remove(struct sa1111 *sachip) kfree(sachip); } +/* + * According to the "Intel StrongARM SA-1111 Microprocessor Companion + * Chip Specification Update" (June 2000), erratum #7, there is a + * significant bug in the SA1111 SDRAM shared memory controller. If + * an access to a region of memory above 1MB relative to the bank base, + * it is important that address bit 10 _NOT_ be asserted. Depending + * on the configuration of the RAM, bit 10 may correspond to one + * of several different (processor-relative) address bits. + * + * This routine only identifies whether or not a given DMA address + * is susceptible to the bug. + * + * This should only get called for sa1111_device types due to the + * way we configure our device dma_masks. + */ +int dma_needs_bounce(struct device *dev, dma_addr_t addr, size_t size) +{ + /* + * Section 4.6 of the "Intel StrongARM SA-1111 Development Module + * User's Guide" mentions that jumpers R51 and R52 control the + * target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or + * SDRAM bank 1 on Neponset). The default configuration selects + * Assabet, so any address in bank 1 is necessarily invalid. + */ + return ((machine_is_assabet() || machine_is_pfs168()) && + (addr >= 0xc8000000 || (addr + size) >= 0xc8000000)); +} + struct sa1111_save_data { unsigned int skcr; unsigned int skpcr; diff --git a/trunk/arch/arm/include/asm/assembler.h b/trunk/arch/arm/include/asm/assembler.h index 29035e86a59d..65c3f2474f5e 100644 --- a/trunk/arch/arm/include/asm/assembler.h +++ b/trunk/arch/arm/include/asm/assembler.h @@ -293,13 +293,4 @@ .macro ldrusr, reg, ptr, inc, cond=al, rept=1, abort=9001f usracc ldr, \reg, \ptr, \inc, \cond, \rept, \abort .endm - -/* Utility macro for declaring string literals */ - .macro string name:req, string - .type \name , #object -\name: - .asciz "\string" - .size \name , . - \name - .endm - #endif /* __ASM_ASSEMBLER_H__ */ diff --git a/trunk/arch/arm/include/asm/bitops.h b/trunk/arch/arm/include/asm/bitops.h index f4280593dfa3..b4892a06442c 100644 --- a/trunk/arch/arm/include/asm/bitops.h +++ b/trunk/arch/arm/include/asm/bitops.h @@ -26,8 +26,8 @@ #include #include -#define smp_mb__before_clear_bit() smp_mb() -#define smp_mb__after_clear_bit() smp_mb() +#define smp_mb__before_clear_bit() mb() +#define smp_mb__after_clear_bit() mb() /* * These functions are the basis of our bit ops. diff --git a/trunk/arch/arm/include/asm/dma-mapping.h b/trunk/arch/arm/include/asm/dma-mapping.h index 7a21d0bf7134..4fff837363ed 100644 --- a/trunk/arch/arm/include/asm/dma-mapping.h +++ b/trunk/arch/arm/include/asm/dma-mapping.h @@ -115,8 +115,39 @@ static inline void __dma_page_dev_to_cpu(struct page *page, unsigned long off, ___dma_page_dev_to_cpu(page, off, size, dir); } -extern int dma_supported(struct device *, u64); -extern int dma_set_mask(struct device *, u64); +/* + * Return whether the given device DMA address mask can be supported + * properly. For example, if your device can only drive the low 24-bits + * during bus mastering, then you would pass 0x00ffffff as the mask + * to this function. + * + * FIXME: This should really be a platform specific issue - we should + * return false if GFP_DMA allocations may not satisfy the supplied 'mask'. + */ +static inline int dma_supported(struct device *dev, u64 mask) +{ + if (mask < ISA_DMA_THRESHOLD) + return 0; + return 1; +} + +static inline int dma_set_mask(struct device *dev, u64 dma_mask) +{ +#ifdef CONFIG_DMABOUNCE + if (dev->archdata.dmabounce) { + if (dma_mask >= ISA_DMA_THRESHOLD) + return 0; + else + return -EIO; + } +#endif + if (!dev->dma_mask || !dma_supported(dev, dma_mask)) + return -EIO; + + *dev->dma_mask = dma_mask; + + return 0; +} /* * DMA errors are defined by all-bits-set in the DMA address. @@ -225,14 +256,14 @@ int dma_mmap_writecombine(struct device *, struct vm_area_struct *, * @dev: valid struct device pointer * @small_buf_size: size of buffers to use with small buffer pool * @large_buf_size: size of buffers to use with large buffer pool (can be 0) - * @needs_bounce_fn: called to determine whether buffer needs bouncing * * This function should be called by low-level platform code to register * a device as requireing DMA buffer bouncing. The function will allocate * appropriate DMA pools for the device. + * */ extern int dmabounce_register_dev(struct device *, unsigned long, - unsigned long, int (*)(struct device *, dma_addr_t, size_t)); + unsigned long); /** * dmabounce_unregister_dev @@ -246,9 +277,31 @@ extern int dmabounce_register_dev(struct device *, unsigned long, */ extern void dmabounce_unregister_dev(struct device *); +/** + * dma_needs_bounce + * + * @dev: valid struct device pointer + * @dma_handle: dma_handle of unbounced buffer + * @size: size of region being mapped + * + * Platforms that utilize the dmabounce mechanism must implement + * this function. + * + * The dmabounce routines call this function whenever a dma-mapping + * is requested to determine whether a given buffer needs to be bounced + * or not. The function must return 0 if the buffer is OK for + * DMA access and 1 if the buffer needs to be bounced. + * + */ +extern int dma_needs_bounce(struct device*, dma_addr_t, size_t); + /* * The DMA API, implemented by dmabounce.c. See below for descriptions. */ +extern dma_addr_t __dma_map_single(struct device *, void *, size_t, + enum dma_data_direction); +extern void __dma_unmap_single(struct device *, dma_addr_t, size_t, + enum dma_data_direction); extern dma_addr_t __dma_map_page(struct device *, struct page *, unsigned long, size_t, enum dma_data_direction); extern void __dma_unmap_page(struct device *, dma_addr_t, size_t, @@ -275,6 +328,13 @@ static inline int dmabounce_sync_for_device(struct device *d, dma_addr_t addr, } +static inline dma_addr_t __dma_map_single(struct device *dev, void *cpu_addr, + size_t size, enum dma_data_direction dir) +{ + __dma_single_cpu_to_dev(cpu_addr, size, dir); + return virt_to_dma(dev, cpu_addr); +} + static inline dma_addr_t __dma_map_page(struct device *dev, struct page *page, unsigned long offset, size_t size, enum dma_data_direction dir) { @@ -282,6 +342,12 @@ static inline dma_addr_t __dma_map_page(struct device *dev, struct page *page, return pfn_to_dma(dev, page_to_pfn(page)) + offset; } +static inline void __dma_unmap_single(struct device *dev, dma_addr_t handle, + size_t size, enum dma_data_direction dir) +{ + __dma_single_dev_to_cpu(dma_to_virt(dev, handle), size, dir); +} + static inline void __dma_unmap_page(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir) { @@ -307,18 +373,14 @@ static inline void __dma_unmap_page(struct device *dev, dma_addr_t handle, static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, size_t size, enum dma_data_direction dir) { - unsigned long offset; - struct page *page; dma_addr_t addr; - BUG_ON(!virt_addr_valid(cpu_addr)); - BUG_ON(!virt_addr_valid(cpu_addr + size - 1)); BUG_ON(!valid_dma_direction(dir)); - page = virt_to_page(cpu_addr); - offset = (unsigned long)cpu_addr & ~PAGE_MASK; - addr = __dma_map_page(dev, page, offset, size, dir); - debug_dma_map_page(dev, page, offset, size, dir, addr, true); + addr = __dma_map_single(dev, cpu_addr, size, dir); + debug_dma_map_page(dev, virt_to_page(cpu_addr), + (unsigned long)cpu_addr & ~PAGE_MASK, size, + dir, addr, true); return addr; } @@ -368,7 +430,7 @@ static inline void dma_unmap_single(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir) { debug_dma_unmap_page(dev, handle, size, dir, true); - __dma_unmap_page(dev, handle, size, dir); + __dma_unmap_single(dev, handle, size, dir); } /** diff --git a/trunk/arch/arm/include/asm/dma.h b/trunk/arch/arm/include/asm/dma.h index 628670e9d7c9..42005542932b 100644 --- a/trunk/arch/arm/include/asm/dma.h +++ b/trunk/arch/arm/include/asm/dma.h @@ -1,16 +1,15 @@ #ifndef __ASM_ARM_DMA_H #define __ASM_ARM_DMA_H +#include + /* * This is the maximum virtual address which can be DMA'd from. */ -#ifndef CONFIG_ZONE_DMA -#define MAX_DMA_ADDRESS 0xffffffffUL +#ifndef ARM_DMA_ZONE_SIZE +#define MAX_DMA_ADDRESS 0xffffffff #else -#define MAX_DMA_ADDRESS ({ \ - extern unsigned long arm_dma_zone_size; \ - arm_dma_zone_size ? \ - (PAGE_OFFSET + arm_dma_zone_size) : 0xffffffffUL; }) +#define MAX_DMA_ADDRESS (PAGE_OFFSET + ARM_DMA_ZONE_SIZE) #endif #ifdef CONFIG_ISA_DMA_API diff --git a/trunk/arch/arm/include/asm/entry-macro-multi.S b/trunk/arch/arm/include/asm/entry-macro-multi.S index 2f1e2098dfe7..2da8547de6d6 100644 --- a/trunk/arch/arm/include/asm/entry-macro-multi.S +++ b/trunk/arch/arm/include/asm/entry-macro-multi.S @@ -4,8 +4,8 @@ * Interrupt handling. Preserves r7, r8, r9 */ .macro arch_irq_handler_default - get_irqnr_preamble r6, lr -1: get_irqnr_and_base r0, r2, r6, lr + get_irqnr_preamble r5, lr +1: get_irqnr_and_base r0, r6, r5, lr movne r1, sp @ @ routine called with r0 = irq number, r1 = struct pt_regs * @@ -17,17 +17,17 @@ /* * XXX * - * this macro assumes that irqstat (r2) and base (r6) are + * this macro assumes that irqstat (r6) and base (r5) are * preserved from get_irqnr_and_base above */ - ALT_SMP(test_for_ipi r0, r2, r6, lr) + ALT_SMP(test_for_ipi r0, r6, r5, lr) ALT_UP_B(9997f) movne r1, sp adrne lr, BSYM(1b) bne do_IPI #ifdef CONFIG_LOCAL_TIMERS - test_for_ltirq r0, r2, r6, lr + test_for_ltirq r0, r6, r5, lr movne r0, sp adrne lr, BSYM(1b) bne do_local_timer @@ -40,7 +40,7 @@ .align 5 .global \symbol_name \symbol_name: - mov r8, lr + mov r4, lr arch_irq_handler_default - mov pc, r8 + mov pc, r4 .endm diff --git a/trunk/arch/arm/include/asm/hwcap.h b/trunk/arch/arm/include/asm/hwcap.h index c93a22a8b924..c1062c317103 100644 --- a/trunk/arch/arm/include/asm/hwcap.h +++ b/trunk/arch/arm/include/asm/hwcap.h @@ -4,26 +4,22 @@ /* * HWCAP flags - for elf_hwcap (in kernel) and AT_HWCAP */ -#define HWCAP_SWP (1 << 0) -#define HWCAP_HALF (1 << 1) -#define HWCAP_THUMB (1 << 2) -#define HWCAP_26BIT (1 << 3) /* Play it safe */ -#define HWCAP_FAST_MULT (1 << 4) -#define HWCAP_FPA (1 << 5) -#define HWCAP_VFP (1 << 6) -#define HWCAP_EDSP (1 << 7) -#define HWCAP_JAVA (1 << 8) -#define HWCAP_IWMMXT (1 << 9) -#define HWCAP_CRUNCH (1 << 10) -#define HWCAP_THUMBEE (1 << 11) -#define HWCAP_NEON (1 << 12) -#define HWCAP_VFPv3 (1 << 13) -#define HWCAP_VFPv3D16 (1 << 14) -#define HWCAP_TLS (1 << 15) -#define HWCAP_VFPv4 (1 << 16) -#define HWCAP_IDIVA (1 << 17) -#define HWCAP_IDIVT (1 << 18) -#define HWCAP_IDIV (HWCAP_IDIVA | HWCAP_IDIVT) +#define HWCAP_SWP 1 +#define HWCAP_HALF 2 +#define HWCAP_THUMB 4 +#define HWCAP_26BIT 8 /* Play it safe */ +#define HWCAP_FAST_MULT 16 +#define HWCAP_FPA 32 +#define HWCAP_VFP 64 +#define HWCAP_EDSP 128 +#define HWCAP_JAVA 256 +#define HWCAP_IWMMXT 512 +#define HWCAP_CRUNCH 1024 +#define HWCAP_THUMBEE 2048 +#define HWCAP_NEON 4096 +#define HWCAP_VFPv3 8192 +#define HWCAP_VFPv3D16 16384 +#define HWCAP_TLS 32768 #if defined(__KERNEL__) && !defined(__ASSEMBLY__) /* diff --git a/trunk/arch/arm/include/asm/i8253.h b/trunk/arch/arm/include/asm/i8253.h new file mode 100644 index 000000000000..70656b69d5ce --- /dev/null +++ b/trunk/arch/arm/include/asm/i8253.h @@ -0,0 +1,15 @@ +#ifndef __ASMARM_I8253_H +#define __ASMARM_I8253_H + +/* i8253A PIT registers */ +#define PIT_MODE 0x43 +#define PIT_CH0 0x40 + +#define PIT_LATCH ((PIT_TICK_RATE + HZ / 2) / HZ) + +extern raw_spinlock_t i8253_lock; + +#define outb_pit outb_p +#define inb_pit inb_p + +#endif diff --git a/trunk/arch/arm/include/asm/kprobes.h b/trunk/arch/arm/include/asm/kprobes.h index feec86768f9c..e46bdd0097eb 100644 --- a/trunk/arch/arm/include/asm/kprobes.h +++ b/trunk/arch/arm/include/asm/kprobes.h @@ -24,6 +24,12 @@ #define MAX_INSN_SIZE 2 #define MAX_STACK_SIZE 64 /* 32 would probably be OK */ +/* + * This undefined instruction must be unique and + * reserved solely for kprobes' use. + */ +#define KPROBE_BREAKPOINT_INSTRUCTION 0xe7f001f8 + #define regs_return_value(regs) ((regs)->ARM_r0) #define flush_insn_slot(p) do { } while (0) #define kretprobe_blacklist_size 0 @@ -32,17 +38,14 @@ typedef u32 kprobe_opcode_t; struct kprobe; typedef void (kprobe_insn_handler_t)(struct kprobe *, struct pt_regs *); + typedef unsigned long (kprobe_check_cc)(unsigned long); -typedef void (kprobe_insn_singlestep_t)(struct kprobe *, struct pt_regs *); -typedef void (kprobe_insn_fn_t)(void); /* Architecture specific copy of original instruction. */ struct arch_specific_insn { - kprobe_opcode_t *insn; - kprobe_insn_handler_t *insn_handler; - kprobe_check_cc *insn_check_cc; - kprobe_insn_singlestep_t *insn_singlestep; - kprobe_insn_fn_t *insn_fn; + kprobe_opcode_t *insn; + kprobe_insn_handler_t *insn_handler; + kprobe_check_cc *insn_check_cc; }; struct prev_kprobe { @@ -59,9 +62,20 @@ struct kprobe_ctlblk { }; void arch_remove_kprobe(struct kprobe *); +void kretprobe_trampoline(void); + int kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr); int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, void *data); +enum kprobe_insn { + INSN_REJECTED, + INSN_GOOD, + INSN_GOOD_NO_SLOT +}; + +enum kprobe_insn arm_kprobe_decode_insn(kprobe_opcode_t, + struct arch_specific_insn *); +void __init arm_kprobe_decode_init(void); #endif /* _ARM_KPROBES_H */ diff --git a/trunk/arch/arm/include/asm/mach/arch.h b/trunk/arch/arm/include/asm/mach/arch.h index 3281fb4b12e3..946f4d778f71 100644 --- a/trunk/arch/arm/include/asm/mach/arch.h +++ b/trunk/arch/arm/include/asm/mach/arch.h @@ -23,10 +23,6 @@ struct machine_desc { unsigned int nr_irqs; /* number of IRQs */ -#ifdef CONFIG_ZONE_DMA - unsigned long dma_zone_size; /* size of DMA-able area */ -#endif - unsigned int video_start; /* start of video RAM */ unsigned int video_end; /* end of video RAM */ diff --git a/trunk/arch/arm/include/asm/memory.h b/trunk/arch/arm/include/asm/memory.h index b8de516e600e..af44a8fb3480 100644 --- a/trunk/arch/arm/include/asm/memory.h +++ b/trunk/arch/arm/include/asm/memory.h @@ -203,6 +203,18 @@ static inline unsigned long __phys_to_virt(unsigned long x) #define PHYS_OFFSET PLAT_PHYS_OFFSET #endif +/* + * The DMA mask corresponding to the maximum bus address allocatable + * using GFP_DMA. The default here places no restriction on DMA + * allocations. This must be the smallest DMA mask in the system, + * so a successful GFP_DMA allocation will always satisfy this. + */ +#ifndef ARM_DMA_ZONE_SIZE +#define ISA_DMA_THRESHOLD (0xffffffffULL) +#else +#define ISA_DMA_THRESHOLD (PHYS_OFFSET + ARM_DMA_ZONE_SIZE - 1) +#endif + /* * PFNs are used to describe any physical page; this means * PFN 0 == physical address 0. diff --git a/trunk/arch/arm/include/asm/perf_event.h b/trunk/arch/arm/include/asm/perf_event.h index 0f8e3827a89b..c4aa4e8c6af9 100644 --- a/trunk/arch/arm/include/asm/perf_event.h +++ b/trunk/arch/arm/include/asm/perf_event.h @@ -24,8 +24,6 @@ enum arm_perf_pmu_ids { ARM_PERF_PMU_ID_V6MP, ARM_PERF_PMU_ID_CA8, ARM_PERF_PMU_ID_CA9, - ARM_PERF_PMU_ID_CA5, - ARM_PERF_PMU_ID_CA15, ARM_NUM_PMU_IDS, }; diff --git a/trunk/arch/arm/include/asm/pmu.h b/trunk/arch/arm/include/asm/pmu.h index 67c70a31a1be..7544ce6b481a 100644 --- a/trunk/arch/arm/include/asm/pmu.h +++ b/trunk/arch/arm/include/asm/pmu.h @@ -52,7 +52,7 @@ reserve_pmu(enum arm_pmu_type device); * a cookie. */ extern int -release_pmu(enum arm_pmu_type type); +release_pmu(struct platform_device *pdev); /** * init_pmu() - Initialise the PMU. diff --git a/trunk/arch/arm/include/asm/proc-fns.h b/trunk/arch/arm/include/asm/proc-fns.h index 633d1cb84d87..8ec535e11fd7 100644 --- a/trunk/arch/arm/include/asm/proc-fns.h +++ b/trunk/arch/arm/include/asm/proc-fns.h @@ -82,13 +82,13 @@ extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm); extern void cpu_set_pte_ext(pte_t *ptep, pte_t pte, unsigned int ext); extern void cpu_reset(unsigned long addr) __attribute__((noreturn)); #else -#define cpu_proc_init processor._proc_init -#define cpu_proc_fin processor._proc_fin -#define cpu_reset processor.reset -#define cpu_do_idle processor._do_idle -#define cpu_dcache_clean_area processor.dcache_clean_area -#define cpu_set_pte_ext processor.set_pte_ext -#define cpu_do_switch_mm processor.switch_mm +#define cpu_proc_init() processor._proc_init() +#define cpu_proc_fin() processor._proc_fin() +#define cpu_reset(addr) processor.reset(addr) +#define cpu_do_idle() processor._do_idle() +#define cpu_dcache_clean_area(addr,sz) processor.dcache_clean_area(addr,sz) +#define cpu_set_pte_ext(ptep,pte,ext) processor.set_pte_ext(ptep,pte,ext) +#define cpu_do_switch_mm(pgd,mm) processor.switch_mm(pgd,mm) #endif extern void cpu_resume(void); diff --git a/trunk/arch/arm/include/asm/ptrace.h b/trunk/arch/arm/include/asm/ptrace.h index 96187ff58c24..312d10877bd7 100644 --- a/trunk/arch/arm/include/asm/ptrace.h +++ b/trunk/arch/arm/include/asm/ptrace.h @@ -69,9 +69,8 @@ #define PSR_c 0x000000ff /* Control */ /* - * ARMv7 groups of PSR bits + * ARMv7 groups of APSR bits */ -#define APSR_MASK 0xf80f0000 /* N, Z, C, V, Q and GE flags */ #define PSR_ISET_MASK 0x01000010 /* ISA state (J, T) mask */ #define PSR_IT_MASK 0x0600fc00 /* If-Then execution state mask */ #define PSR_ENDIAN_MASK 0x00000200 /* Endianness state mask */ @@ -200,14 +199,6 @@ extern unsigned long profile_pc(struct pt_regs *regs); #define predicate(x) ((x) & 0xf0000000) #define PREDICATE_ALWAYS 0xe0000000 -/* - * True if instr is a 32-bit thumb instruction. This works if instr - * is the first or only half-word of a thumb instruction. It also works - * when instr holds all 32-bits of a wide thumb instruction if stored - * in the form (first_half<<16)|(second_half) - */ -#define is_wide_instruction(instr) ((unsigned)(instr) >= 0xe800) - /* * kprobe-based event tracer support */ diff --git a/trunk/arch/arm/include/asm/scatterlist.h b/trunk/arch/arm/include/asm/scatterlist.h index cefdb8f898a1..2f87870d9347 100644 --- a/trunk/arch/arm/include/asm/scatterlist.h +++ b/trunk/arch/arm/include/asm/scatterlist.h @@ -1,10 +1,6 @@ #ifndef _ASMARM_SCATTERLIST_H #define _ASMARM_SCATTERLIST_H -#ifdef CONFIG_ARM_HAS_SG_CHAIN -#define ARCH_HAS_SG_CHAIN -#endif - #include #include #include diff --git a/trunk/arch/arm/include/asm/setup.h b/trunk/arch/arm/include/asm/setup.h index 915696dd9c7c..ee2ad8ae07af 100644 --- a/trunk/arch/arm/include/asm/setup.h +++ b/trunk/arch/arm/include/asm/setup.h @@ -187,16 +187,12 @@ struct tagtable { #define __tag __used __attribute__((__section__(".taglist.init"))) #define __tagtable(tag, fn) \ -static const struct tagtable __tagtable_##fn __tag = { tag, fn } +static struct tagtable __tagtable_##fn __tag = { tag, fn } /* * Memory map description */ -#ifdef CONFIG_ARCH_EP93XX -# define NR_BANKS 16 -#else -# define NR_BANKS 8 -#endif +#define NR_BANKS 8 struct membank { phys_addr_t start; diff --git a/trunk/arch/arm/include/asm/suspend.h b/trunk/arch/arm/include/asm/suspend.h deleted file mode 100644 index b0e4e1a02318..000000000000 --- a/trunk/arch/arm/include/asm/suspend.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef __ASM_ARM_SUSPEND_H -#define __ASM_ARM_SUSPEND_H - -#include -#include - -extern void cpu_resume(void); - -/* - * Hide the first two arguments to __cpu_suspend - these are an implementation - * detail which platform code shouldn't have to know about. - */ -static inline int cpu_suspend(unsigned long arg, int (*fn)(unsigned long)) -{ - extern int __cpu_suspend(int, long, unsigned long, - int (*)(unsigned long)); - int ret = __cpu_suspend(0, PHYS_OFFSET - PAGE_OFFSET, arg, fn); - flush_tlb_all(); - return ret; -} - -#endif diff --git a/trunk/arch/arm/include/asm/tcm.h b/trunk/arch/arm/include/asm/tcm.h index 8578d726ad78..5929ef5d927a 100644 --- a/trunk/arch/arm/include/asm/tcm.h +++ b/trunk/arch/arm/include/asm/tcm.h @@ -27,7 +27,5 @@ void *tcm_alloc(size_t len); void tcm_free(void *addr, size_t len); -bool tcm_dtcm_present(void); -bool tcm_itcm_present(void); #endif diff --git a/trunk/arch/arm/include/asm/tlbflush.h b/trunk/arch/arm/include/asm/tlbflush.h index 8077145698ff..d2005de383b8 100644 --- a/trunk/arch/arm/include/asm/tlbflush.h +++ b/trunk/arch/arm/include/asm/tlbflush.h @@ -34,12 +34,16 @@ #define TLB_V6_D_ASID (1 << 17) #define TLB_V6_I_ASID (1 << 18) +#define TLB_BTB (1 << 28) + /* Unified Inner Shareable TLB operations (ARMv7 MP extensions) */ #define TLB_V7_UIS_PAGE (1 << 19) #define TLB_V7_UIS_FULL (1 << 20) #define TLB_V7_UIS_ASID (1 << 21) -#define TLB_BARRIER (1 << 28) +/* Inner Shareable BTB operation (ARMv7 MP extensions) */ +#define TLB_V7_IS_BTB (1 << 22) + #define TLB_L2CLEAN_FR (1 << 29) /* Feroceon */ #define TLB_DCLEAN (1 << 30) #define TLB_WB (1 << 31) @@ -54,7 +58,7 @@ * v4wb - ARMv4 with write buffer without I TLB flush entry instruction * v4wbi - ARMv4 with write buffer with I TLB flush entry instruction * fr - Feroceon (v4wbi with non-outer-cacheable page table walks) - * fa - Faraday (v4 with write buffer with UTLB) + * fa - Faraday (v4 with write buffer with UTLB and branch target buffer (BTB)) * v6wbi - ARMv6 with write buffer with I TLB flush entry instruction * v7wbi - identical to v6wbi */ @@ -95,7 +99,7 @@ # define v4_always_flags (-1UL) #endif -#define fa_tlb_flags (TLB_WB | TLB_DCLEAN | TLB_BARRIER | \ +#define fa_tlb_flags (TLB_WB | TLB_BTB | TLB_DCLEAN | \ TLB_V4_U_FULL | TLB_V4_U_PAGE) #ifdef CONFIG_CPU_TLB_FA @@ -162,7 +166,7 @@ # define v4wb_always_flags (-1UL) #endif -#define v6wbi_tlb_flags (TLB_WB | TLB_DCLEAN | TLB_BARRIER | \ +#define v6wbi_tlb_flags (TLB_WB | TLB_DCLEAN | TLB_BTB | \ TLB_V6_I_FULL | TLB_V6_D_FULL | \ TLB_V6_I_PAGE | TLB_V6_D_PAGE | \ TLB_V6_I_ASID | TLB_V6_D_ASID) @@ -180,9 +184,9 @@ # define v6wbi_always_flags (-1UL) #endif -#define v7wbi_tlb_flags_smp (TLB_WB | TLB_DCLEAN | TLB_BARRIER | \ +#define v7wbi_tlb_flags_smp (TLB_WB | TLB_DCLEAN | TLB_V7_IS_BTB | \ TLB_V7_UIS_FULL | TLB_V7_UIS_PAGE | TLB_V7_UIS_ASID) -#define v7wbi_tlb_flags_up (TLB_WB | TLB_DCLEAN | TLB_BARRIER | \ +#define v7wbi_tlb_flags_up (TLB_WB | TLB_DCLEAN | TLB_BTB | \ TLB_V6_U_FULL | TLB_V6_U_PAGE | TLB_V6_U_ASID) #ifdef CONFIG_CPU_TLB_V7 @@ -337,7 +341,15 @@ static inline void local_flush_tlb_all(void) if (tlb_flag(TLB_V7_UIS_FULL)) asm("mcr p15, 0, %0, c8, c3, 0" : : "r" (zero) : "cc"); - if (tlb_flag(TLB_BARRIER)) { + if (tlb_flag(TLB_BTB)) { + /* flush the branch target cache */ + asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc"); + dsb(); + isb(); + } + if (tlb_flag(TLB_V7_IS_BTB)) { + /* flush the branch target cache */ + asm("mcr p15, 0, %0, c7, c1, 6" : : "r" (zero) : "cc"); dsb(); isb(); } @@ -377,8 +389,17 @@ static inline void local_flush_tlb_mm(struct mm_struct *mm) asm("mcr p15, 0, %0, c8, c3, 2" : : "r" (asid) : "cc"); #endif - if (tlb_flag(TLB_BARRIER)) + if (tlb_flag(TLB_BTB)) { + /* flush the branch target cache */ + asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc"); + dsb(); + } + if (tlb_flag(TLB_V7_IS_BTB)) { + /* flush the branch target cache */ + asm("mcr p15, 0, %0, c7, c1, 6" : : "r" (zero) : "cc"); dsb(); + isb(); + } } static inline void @@ -418,8 +439,17 @@ local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (uaddr) : "cc"); #endif - if (tlb_flag(TLB_BARRIER)) + if (tlb_flag(TLB_BTB)) { + /* flush the branch target cache */ + asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc"); + dsb(); + } + if (tlb_flag(TLB_V7_IS_BTB)) { + /* flush the branch target cache */ + asm("mcr p15, 0, %0, c7, c1, 6" : : "r" (zero) : "cc"); dsb(); + isb(); + } } static inline void local_flush_tlb_kernel_page(unsigned long kaddr) @@ -452,7 +482,15 @@ static inline void local_flush_tlb_kernel_page(unsigned long kaddr) if (tlb_flag(TLB_V7_UIS_PAGE)) asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (kaddr) : "cc"); - if (tlb_flag(TLB_BARRIER)) { + if (tlb_flag(TLB_BTB)) { + /* flush the branch target cache */ + asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc"); + dsb(); + isb(); + } + if (tlb_flag(TLB_V7_IS_BTB)) { + /* flush the branch target cache */ + asm("mcr p15, 0, %0, c7, c1, 6" : : "r" (zero) : "cc"); dsb(); isb(); } diff --git a/trunk/arch/arm/include/asm/traps.h b/trunk/arch/arm/include/asm/traps.h index 5b29a6673625..f90756dc16dc 100644 --- a/trunk/arch/arm/include/asm/traps.h +++ b/trunk/arch/arm/include/asm/traps.h @@ -3,9 +3,6 @@ #include -struct pt_regs; -struct task_struct; - struct undef_hook { struct list_head node; u32 instr_mask; diff --git a/trunk/arch/arm/kernel/Makefile b/trunk/arch/arm/kernel/Makefile index f7887dc53c1f..a5b31af5c2b8 100644 --- a/trunk/arch/arm/kernel/Makefile +++ b/trunk/arch/arm/kernel/Makefile @@ -37,12 +37,7 @@ obj-$(CONFIG_HAVE_ARM_TWD) += smp_twd.o obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o -obj-$(CONFIG_KPROBES) += kprobes.o kprobes-common.o -ifdef CONFIG_THUMB2_KERNEL -obj-$(CONFIG_KPROBES) += kprobes-thumb.o -else -obj-$(CONFIG_KPROBES) += kprobes-arm.o -endif +obj-$(CONFIG_KPROBES) += kprobes.o kprobes-decode.o obj-$(CONFIG_ATAGS_PROC) += atags.o obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o obj-$(CONFIG_ARM_THUMBEE) += thumbee.o diff --git a/trunk/arch/arm/kernel/asm-offsets.c b/trunk/arch/arm/kernel/asm-offsets.c index 16baba2e4369..927522cfc12e 100644 --- a/trunk/arch/arm/kernel/asm-offsets.c +++ b/trunk/arch/arm/kernel/asm-offsets.c @@ -59,9 +59,6 @@ int main(void) DEFINE(TI_TP_VALUE, offsetof(struct thread_info, tp_value)); DEFINE(TI_FPSTATE, offsetof(struct thread_info, fpstate)); DEFINE(TI_VFPSTATE, offsetof(struct thread_info, vfpstate)); -#ifdef CONFIG_SMP - DEFINE(VFP_CPU, offsetof(union vfp_state, hard.cpu)); -#endif #ifdef CONFIG_ARM_THUMBEE DEFINE(TI_THUMBEE_STATE, offsetof(struct thread_info, thumbee_state)); #endif diff --git a/trunk/arch/arm/kernel/entry-armv.S b/trunk/arch/arm/kernel/entry-armv.S index a87cbf889ff4..90c62cd51ca9 100644 --- a/trunk/arch/arm/kernel/entry-armv.S +++ b/trunk/arch/arm/kernel/entry-armv.S @@ -29,53 +29,21 @@ #include /* - * Interrupt handling. + * Interrupt handling. Preserves r7, r8, r9 */ .macro irq_handler #ifdef CONFIG_MULTI_IRQ_HANDLER - ldr r1, =handle_arch_irq + ldr r5, =handle_arch_irq mov r0, sp - ldr r1, [r1] + ldr r5, [r5] adr lr, BSYM(9997f) - teq r1, #0 - movne pc, r1 + teq r5, #0 + movne pc, r5 #endif arch_irq_handler_default 9997: .endm - .macro pabt_helper - @ PABORT handler takes pt_regs in r2, fault address in r4 and psr in r5 -#ifdef MULTI_PABORT - ldr ip, .LCprocfns - mov lr, pc - ldr pc, [ip, #PROCESSOR_PABT_FUNC] -#else - bl CPU_PABORT_HANDLER -#endif - .endm - - .macro dabt_helper - - @ - @ Call the processor-specific abort handler: - @ - @ r2 - pt_regs - @ r4 - aborted context pc - @ r5 - aborted context psr - @ - @ The abort handler must return the aborted address in r0, and - @ the fault status register in r1. r9 must be preserved. - @ -#ifdef MULTI_DABORT - ldr ip, .LCprocfns - mov lr, pc - ldr pc, [ip, #PROCESSOR_DABT_FUNC] -#else - bl CPU_DABORT_HANDLER -#endif - .endm - #ifdef CONFIG_KPROBES .section .kprobes.text,"ax",%progbits #else @@ -158,74 +126,106 @@ ENDPROC(__und_invalid) SPFIX( subeq sp, sp, #4 ) stmia sp, {r1 - r12} - ldmia r0, {r3 - r5} - add r7, sp, #S_SP - 4 @ here for interlock avoidance - mov r6, #-1 @ "" "" "" "" - add r2, sp, #(S_FRAME_SIZE + \stack_hole - 4) - SPFIX( addeq r2, r2, #4 ) - str r3, [sp, #-4]! @ save the "real" r0 copied + ldmia r0, {r1 - r3} + add r5, sp, #S_SP - 4 @ here for interlock avoidance + mov r4, #-1 @ "" "" "" "" + add r0, sp, #(S_FRAME_SIZE + \stack_hole - 4) + SPFIX( addeq r0, r0, #4 ) + str r1, [sp, #-4]! @ save the "real" r0 copied @ from the exception stack - mov r3, lr + mov r1, lr @ @ We are now ready to fill in the remaining blanks on the stack: @ - @ r2 - sp_svc - @ r3 - lr_svc - @ r4 - lr_, already fixed up for correct return/restart - @ r5 - spsr_ - @ r6 - orig_r0 (see pt_regs definition in ptrace.h) + @ r0 - sp_svc + @ r1 - lr_svc + @ r2 - lr_, already fixed up for correct return/restart + @ r3 - spsr_ + @ r4 - orig_r0 (see pt_regs definition in ptrace.h) @ - stmia r7, {r2 - r6} - -#ifdef CONFIG_TRACE_IRQFLAGS - bl trace_hardirqs_off -#endif + stmia r5, {r0 - r4} .endm .align 5 __dabt_svc: svc_entry + + @ + @ get ready to re-enable interrupts if appropriate + @ + mrs r9, cpsr + tst r3, #PSR_I_BIT + biceq r9, r9, #PSR_I_BIT + + @ + @ Call the processor-specific abort handler: + @ + @ r2 - aborted context pc + @ r3 - aborted context cpsr + @ + @ The abort handler must return the aborted address in r0, and + @ the fault status register in r1. r9 must be preserved. + @ +#ifdef MULTI_DABORT + ldr r4, .LCprocfns + mov lr, pc + ldr pc, [r4, #PROCESSOR_DABT_FUNC] +#else + bl CPU_DABORT_HANDLER +#endif + + @ + @ set desired IRQ state, then call main handler + @ + debug_entry r1 + msr cpsr_c, r9 mov r2, sp - dabt_helper + bl do_DataAbort @ @ IRQs off again before pulling preserved data off the stack @ disable_irq_notrace -#ifdef CONFIG_TRACE_IRQFLAGS - tst r5, #PSR_I_BIT - bleq trace_hardirqs_on - tst r5, #PSR_I_BIT - blne trace_hardirqs_off -#endif - svc_exit r5 @ return from exception + @ + @ restore SPSR and restart the instruction + @ + ldr r2, [sp, #S_PSR] + svc_exit r2 @ return from exception UNWIND(.fnend ) ENDPROC(__dabt_svc) .align 5 __irq_svc: svc_entry - irq_handler +#ifdef CONFIG_TRACE_IRQFLAGS + bl trace_hardirqs_off +#endif #ifdef CONFIG_PREEMPT get_thread_info tsk ldr r8, [tsk, #TI_PREEMPT] @ get preempt count + add r7, r8, #1 @ increment it + str r7, [tsk, #TI_PREEMPT] +#endif + + irq_handler +#ifdef CONFIG_PREEMPT + str r8, [tsk, #TI_PREEMPT] @ restore preempt count ldr r0, [tsk, #TI_FLAGS] @ get flags teq r8, #0 @ if preempt count != 0 movne r0, #0 @ force flags to 0 tst r0, #_TIF_NEED_RESCHED blne svc_preempt #endif - + ldr r4, [sp, #S_PSR] @ irqs are already disabled #ifdef CONFIG_TRACE_IRQFLAGS - @ The parent context IRQs must have been enabled to get here in - @ the first place, so there's no point checking the PSR I bit. - bl trace_hardirqs_on + tst r4, #PSR_I_BIT + bleq trace_hardirqs_on #endif - svc_exit r5 @ return from exception + svc_exit r4 @ return from exception UNWIND(.fnend ) ENDPROC(__irq_svc) @@ -251,6 +251,7 @@ __und_svc: #else svc_entry #endif + @ @ call emulation code, which returns using r9 if it has emulated @ the instruction, or the more conventional lr if we are to treat @@ -259,16 +260,15 @@ __und_svc: @ r0 - instruction @ #ifndef CONFIG_THUMB2_KERNEL - ldr r0, [r4, #-4] + ldr r0, [r2, #-4] #else - ldrh r0, [r4, #-2] @ Thumb instruction at LR - 2 + ldrh r0, [r2, #-2] @ Thumb instruction at LR - 2 and r9, r0, #0xf800 cmp r9, #0xe800 @ 32-bit instruction if xx >= 0 - ldrhhs r9, [r4] @ bottom 16 bits + ldrhhs r9, [r2] @ bottom 16 bits orrhs r0, r9, r0, lsl #16 #endif adr r9, BSYM(1f) - mov r2, r4 bl call_fpe mov r0, sp @ struct pt_regs *regs @@ -282,35 +282,45 @@ __und_svc: @ @ restore SPSR and restart the instruction @ - ldr r5, [sp, #S_PSR] @ Get SVC cpsr -#ifdef CONFIG_TRACE_IRQFLAGS - tst r5, #PSR_I_BIT - bleq trace_hardirqs_on - tst r5, #PSR_I_BIT - blne trace_hardirqs_off -#endif - svc_exit r5 @ return from exception + ldr r2, [sp, #S_PSR] @ Get SVC cpsr + svc_exit r2 @ return from exception UNWIND(.fnend ) ENDPROC(__und_svc) .align 5 __pabt_svc: svc_entry + + @ + @ re-enable interrupts if appropriate + @ + mrs r9, cpsr + tst r3, #PSR_I_BIT + biceq r9, r9, #PSR_I_BIT + + mov r0, r2 @ pass address of aborted instruction. +#ifdef MULTI_PABORT + ldr r4, .LCprocfns + mov lr, pc + ldr pc, [r4, #PROCESSOR_PABT_FUNC] +#else + bl CPU_PABORT_HANDLER +#endif + debug_entry r1 + msr cpsr_c, r9 @ Maybe enable interrupts mov r2, sp @ regs - pabt_helper + bl do_PrefetchAbort @ call abort handler @ @ IRQs off again before pulling preserved data off the stack @ disable_irq_notrace -#ifdef CONFIG_TRACE_IRQFLAGS - tst r5, #PSR_I_BIT - bleq trace_hardirqs_on - tst r5, #PSR_I_BIT - blne trace_hardirqs_off -#endif - svc_exit r5 @ return from exception + @ + @ restore SPSR and restart the instruction + @ + ldr r2, [sp, #S_PSR] + svc_exit r2 @ return from exception UNWIND(.fnend ) ENDPROC(__pabt_svc) @@ -341,23 +351,23 @@ ENDPROC(__pabt_svc) ARM( stmib sp, {r1 - r12} ) THUMB( stmia sp, {r0 - r12} ) - ldmia r0, {r3 - r5} + ldmia r0, {r1 - r3} add r0, sp, #S_PC @ here for interlock avoidance - mov r6, #-1 @ "" "" "" "" + mov r4, #-1 @ "" "" "" "" - str r3, [sp] @ save the "real" r0 copied + str r1, [sp] @ save the "real" r0 copied @ from the exception stack @ @ We are now ready to fill in the remaining blanks on the stack: @ - @ r4 - lr_, already fixed up for correct return/restart - @ r5 - spsr_ - @ r6 - orig_r0 (see pt_regs definition in ptrace.h) + @ r2 - lr_, already fixed up for correct return/restart + @ r3 - spsr_ + @ r4 - orig_r0 (see pt_regs definition in ptrace.h) @ @ Also, separately save sp_usr and lr_usr @ - stmia r0, {r4 - r6} + stmia r0, {r2 - r4} ARM( stmdb r0, {sp, lr}^ ) THUMB( store_user_sp_lr r0, r1, S_SP - S_PC ) @@ -370,14 +380,10 @@ ENDPROC(__pabt_svc) @ Clear FP to mark the first stack frame @ zero_fp - -#ifdef CONFIG_IRQSOFF_TRACER - bl trace_hardirqs_off -#endif .endm .macro kuser_cmpxchg_check -#if !defined(CONFIG_CPU_32v6K) && !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG) +#if __LINUX_ARM_ARCH__ < 6 && !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG) #ifndef CONFIG_MMU #warning "NPTL on non MMU needs fixing" #else @@ -385,8 +391,8 @@ ENDPROC(__pabt_svc) @ if it was interrupted in a critical region. Here we @ perform a quick test inline since it should be false @ 99.9999% of the time. The rest is done out of line. - cmp r4, #TASK_SIZE - blhs kuser_cmpxchg64_fixup + cmp r2, #TASK_SIZE + blhs kuser_cmpxchg_fixup #endif #endif .endm @@ -395,9 +401,32 @@ ENDPROC(__pabt_svc) __dabt_usr: usr_entry kuser_cmpxchg_check + + @ + @ Call the processor-specific abort handler: + @ + @ r2 - aborted context pc + @ r3 - aborted context cpsr + @ + @ The abort handler must return the aborted address in r0, and + @ the fault status register in r1. + @ +#ifdef MULTI_DABORT + ldr r4, .LCprocfns + mov lr, pc + ldr pc, [r4, #PROCESSOR_DABT_FUNC] +#else + bl CPU_DABORT_HANDLER +#endif + + @ + @ IRQs on, then call the main handler + @ + debug_entry r1 + enable_irq mov r2, sp - dabt_helper - b ret_from_exception + adr lr, BSYM(ret_from_exception) + b do_DataAbort UNWIND(.fnend ) ENDPROC(__dabt_usr) @@ -405,8 +434,28 @@ ENDPROC(__dabt_usr) __irq_usr: usr_entry kuser_cmpxchg_check - irq_handler + +#ifdef CONFIG_IRQSOFF_TRACER + bl trace_hardirqs_off +#endif + get_thread_info tsk +#ifdef CONFIG_PREEMPT + ldr r8, [tsk, #TI_PREEMPT] @ get preempt count + add r7, r8, #1 @ increment it + str r7, [tsk, #TI_PREEMPT] +#endif + + irq_handler +#ifdef CONFIG_PREEMPT + ldr r0, [tsk, #TI_PREEMPT] + str r8, [tsk, #TI_PREEMPT] + teq r0, r7 + ARM( strne r0, [r0, -r0] ) + THUMB( movne r0, #0 ) + THUMB( strne r0, [r0] ) +#endif + mov why, #0 b ret_to_user_from_irq UNWIND(.fnend ) @@ -418,9 +467,6 @@ ENDPROC(__irq_usr) __und_usr: usr_entry - mov r2, r4 - mov r3, r5 - @ @ fall through to the emulation code, which returns using r9 if @ it has emulated the instruction, or the more conventional lr @@ -636,8 +682,19 @@ ENDPROC(__und_usr_unknown) .align 5 __pabt_usr: usr_entry + + mov r0, r2 @ pass address of aborted instruction. +#ifdef MULTI_PABORT + ldr r4, .LCprocfns + mov lr, pc + ldr pc, [r4, #PROCESSOR_PABT_FUNC] +#else + bl CPU_PABORT_HANDLER +#endif + debug_entry r1 + enable_irq @ Enable interrupts mov r2, sp @ regs - pabt_helper + bl do_PrefetchAbort @ call abort handler UNWIND(.fnend ) /* fall through */ /* @@ -701,12 +758,31 @@ ENDPROC(__switch_to) /* * User helpers. * + * These are segment of kernel provided user code reachable from user space + * at a fixed address in kernel memory. This is used to provide user space + * with some operations which require kernel help because of unimplemented + * native feature and/or instructions in many ARM CPUs. The idea is for + * this code to be executed directly in user mode for best efficiency but + * which is too intimate with the kernel counter part to be left to user + * libraries. In fact this code might even differ from one CPU to another + * depending on the available instruction set and restrictions like on + * SMP systems. In other words, the kernel reserves the right to change + * this code as needed without warning. Only the entry points and their + * results are guaranteed to be stable. + * * Each segment is 32-byte aligned and will be moved to the top of the high * vector page. New segments (if ever needed) must be added in front of * existing ones. This mechanism should be used only for things that are * really small and justified, and not be abused freely. * - * See Documentation/arm/kernel_user_helpers.txt for formal definitions. + * User space is expected to implement those things inline when optimizing + * for a processor that has the necessary native support, but only if such + * resulting binaries are already to be incompatible with earlier ARM + * processors due to the use of unsupported instructions other than what + * is provided here. In other words don't make binaries unable to run on + * earlier processors just for the sake of not using these kernel helpers + * if your compiled code is not going to use the new instructions for other + * purpose. */ THUMB( .arm ) @@ -723,104 +799,97 @@ ENDPROC(__switch_to) __kuser_helper_start: /* - * Due to the length of some sequences, __kuser_cmpxchg64 spans 2 regular - * kuser "slots", therefore 0xffff0f80 is not used as a valid entry point. + * Reference prototype: + * + * void __kernel_memory_barrier(void) + * + * Input: + * + * lr = return address + * + * Output: + * + * none + * + * Clobbered: + * + * none + * + * Definition and user space usage example: + * + * typedef void (__kernel_dmb_t)(void); + * #define __kernel_dmb (*(__kernel_dmb_t *)0xffff0fa0) + * + * Apply any needed memory barrier to preserve consistency with data modified + * manually and __kuser_cmpxchg usage. + * + * This could be used as follows: + * + * #define __kernel_dmb() \ + * asm volatile ( "mov r0, #0xffff0fff; mov lr, pc; sub pc, r0, #95" \ + * : : : "r0", "lr","cc" ) */ -__kuser_cmpxchg64: @ 0xffff0f60 - -#if defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG) - - /* - * Poor you. No fast solution possible... - * The kernel itself must perform the operation. - * A special ghost syscall is used for that (see traps.c). - */ - stmfd sp!, {r7, lr} - ldr r7, 1f @ it's 20 bits - swi __ARM_NR_cmpxchg64 - ldmfd sp!, {r7, pc} -1: .word __ARM_NR_cmpxchg64 - -#elif defined(CONFIG_CPU_32v6K) - - stmfd sp!, {r4, r5, r6, r7} - ldrd r4, r5, [r0] @ load old val - ldrd r6, r7, [r1] @ load new val - smp_dmb arm -1: ldrexd r0, r1, [r2] @ load current val - eors r3, r0, r4 @ compare with oldval (1) - eoreqs r3, r1, r5 @ compare with oldval (2) - strexdeq r3, r6, r7, [r2] @ store newval if eq - teqeq r3, #1 @ success? - beq 1b @ if no then retry - smp_dmb arm - rsbs r0, r3, #0 @ set returned val and C flag - ldmfd sp!, {r4, r5, r6, r7} - bx lr - -#elif !defined(CONFIG_SMP) - -#ifdef CONFIG_MMU - - /* - * The only thing that can break atomicity in this cmpxchg64 - * implementation is either an IRQ or a data abort exception - * causing another process/thread to be scheduled in the middle of - * the critical sequence. The same strategy as for cmpxchg is used. - */ - stmfd sp!, {r4, r5, r6, lr} - ldmia r0, {r4, r5} @ load old val - ldmia r1, {r6, lr} @ load new val -1: ldmia r2, {r0, r1} @ load current val - eors r3, r0, r4 @ compare with oldval (1) - eoreqs r3, r1, r5 @ compare with oldval (2) -2: stmeqia r2, {r6, lr} @ store newval if eq - rsbs r0, r3, #0 @ set return val and C flag - ldmfd sp!, {r4, r5, r6, pc} - - .text -kuser_cmpxchg64_fixup: - @ Called from kuser_cmpxchg_fixup. - @ r4 = address of interrupted insn (must be preserved). - @ sp = saved regs. r7 and r8 are clobbered. - @ 1b = first critical insn, 2b = last critical insn. - @ If r4 >= 1b and r4 <= 2b then saved pc_usr is set to 1b. - mov r7, #0xffff0fff - sub r7, r7, #(0xffff0fff - (0xffff0f60 + (1b - __kuser_cmpxchg64))) - subs r8, r4, r7 - rsbcss r8, r8, #(2b - 1b) - strcs r7, [sp, #S_PC] -#if __LINUX_ARM_ARCH__ < 6 - bcc kuser_cmpxchg32_fixup -#endif - mov pc, lr - .previous - -#else -#warning "NPTL on non MMU needs fixing" - mov r0, #-1 - adds r0, r0, #0 - usr_ret lr -#endif - -#else -#error "incoherent kernel configuration" -#endif - - /* pad to next slot */ - .rept (16 - (. - __kuser_cmpxchg64)/4) - .word 0 - .endr - - .align 5 - __kuser_memory_barrier: @ 0xffff0fa0 smp_dmb arm usr_ret lr .align 5 +/* + * Reference prototype: + * + * int __kernel_cmpxchg(int oldval, int newval, int *ptr) + * + * Input: + * + * r0 = oldval + * r1 = newval + * r2 = ptr + * lr = return address + * + * Output: + * + * r0 = returned value (zero or non-zero) + * C flag = set if r0 == 0, clear if r0 != 0 + * + * Clobbered: + * + * r3, ip, flags + * + * Definition and user space usage example: + * + * typedef int (__kernel_cmpxchg_t)(int oldval, int newval, int *ptr); + * #define __kernel_cmpxchg (*(__kernel_cmpxchg_t *)0xffff0fc0) + * + * Atomically store newval in *ptr if *ptr is equal to oldval for user space. + * Return zero if *ptr was changed or non-zero if no exchange happened. + * The C flag is also set if *ptr was changed to allow for assembly + * optimization in the calling code. + * + * Notes: + * + * - This routine already includes memory barriers as needed. + * + * For example, a user space atomic_add implementation could look like this: + * + * #define atomic_add(ptr, val) \ + * ({ register unsigned int *__ptr asm("r2") = (ptr); \ + * register unsigned int __result asm("r1"); \ + * asm volatile ( \ + * "1: @ atomic_add\n\t" \ + * "ldr r0, [r2]\n\t" \ + * "mov r3, #0xffff0fff\n\t" \ + * "add lr, pc, #4\n\t" \ + * "add r1, r0, %2\n\t" \ + * "add pc, r3, #(0xffff0fc0 - 0xffff0fff)\n\t" \ + * "bcc 1b" \ + * : "=&r" (__result) \ + * : "r" (__ptr), "rIL" (val) \ + * : "r0","r3","ip","lr","cc","memory" ); \ + * __result; }) + */ + __kuser_cmpxchg: @ 0xffff0fc0 #if defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG) @@ -856,15 +925,15 @@ __kuser_cmpxchg: @ 0xffff0fc0 usr_ret lr .text -kuser_cmpxchg32_fixup: +kuser_cmpxchg_fixup: @ Called from kuser_cmpxchg_check macro. - @ r4 = address of interrupted insn (must be preserved). + @ r2 = address of interrupted insn (must be preserved). @ sp = saved regs. r7 and r8 are clobbered. @ 1b = first critical insn, 2b = last critical insn. - @ If r4 >= 1b and r4 <= 2b then saved pc_usr is set to 1b. + @ If r2 >= 1b and r2 <= 2b then saved pc_usr is set to 1b. mov r7, #0xffff0fff sub r7, r7, #(0xffff0fff - (0xffff0fc0 + (1b - __kuser_cmpxchg))) - subs r8, r4, r7 + subs r8, r2, r7 rsbcss r8, r8, #(2b - 1b) strcs r7, [sp, #S_PC] mov pc, lr @@ -894,6 +963,39 @@ kuser_cmpxchg32_fixup: .align 5 +/* + * Reference prototype: + * + * int __kernel_get_tls(void) + * + * Input: + * + * lr = return address + * + * Output: + * + * r0 = TLS value + * + * Clobbered: + * + * none + * + * Definition and user space usage example: + * + * typedef int (__kernel_get_tls_t)(void); + * #define __kernel_get_tls (*(__kernel_get_tls_t *)0xffff0fe0) + * + * Get the TLS value as previously set via the __ARM_NR_set_tls syscall. + * + * This could be used as follows: + * + * #define __kernel_get_tls() \ + * ({ register unsigned int __val asm("r0"); \ + * asm( "mov r0, #0xffff0fff; mov lr, pc; sub pc, r0, #31" \ + * : "=r" (__val) : : "lr","cc" ); \ + * __val; }) + */ + __kuser_get_tls: @ 0xffff0fe0 ldr r0, [pc, #(16 - 8)] @ read TLS, set in kuser_get_tls_init usr_ret lr @@ -902,6 +1004,19 @@ __kuser_get_tls: @ 0xffff0fe0 .word 0 @ 0xffff0ff0 software TLS value, then .endr @ pad up to __kuser_helper_version +/* + * Reference declaration: + * + * extern unsigned int __kernel_helper_version; + * + * Definition and user space usage example: + * + * #define __kernel_helper_version (*(unsigned int *)0xffff0ffc) + * + * User space may read this to determine the curent number of helpers + * available. + */ + __kuser_helper_version: @ 0xffff0ffc .word ((__kuser_helper_end - __kuser_helper_start) >> 5) diff --git a/trunk/arch/arm/kernel/entry-header.S b/trunk/arch/arm/kernel/entry-header.S index 9a8531eadd3d..051166c2a932 100644 --- a/trunk/arch/arm/kernel/entry-header.S +++ b/trunk/arch/arm/kernel/entry-header.S @@ -121,13 +121,15 @@ .endm #else /* CONFIG_THUMB2_KERNEL */ .macro svc_exit, rpsr - ldr lr, [sp, #S_SP] @ top of the stack - ldrd r0, r1, [sp, #S_LR] @ calling lr and pc clrex @ clear the exclusive monitor - stmdb lr!, {r0, r1, \rpsr} @ calling lr and rfe context + ldr r0, [sp, #S_SP] @ top of the stack + ldr r1, [sp, #S_PC] @ return address + tst r0, #4 @ orig stack 8-byte aligned? + stmdb r0, {r1, \rpsr} @ rfe context ldmia sp, {r0 - r12} - mov sp, lr - ldr lr, [sp], #4 + ldr lr, [sp, #S_LR] + addeq sp, sp, #S_FRAME_SIZE - 8 @ aligned + addne sp, sp, #S_FRAME_SIZE - 4 @ not aligned rfeia sp! .endm @@ -163,6 +165,25 @@ .endm #endif /* !CONFIG_THUMB2_KERNEL */ + @ + @ Debug exceptions are taken as prefetch or data aborts. + @ We must disable preemption during the handler so that + @ we can access the debug registers safely. + @ + .macro debug_entry, fsr +#if defined(CONFIG_HAVE_HW_BREAKPOINT) && defined(CONFIG_PREEMPT) + ldr r4, =0x40f @ mask out fsr.fs + and r5, r4, \fsr + cmp r5, #2 @ debug exception + bne 1f + get_thread_info r10 + ldr r6, [r10, #TI_PREEMPT] @ get preempt count + add r11, r6, #1 @ increment it + str r11, [r10, #TI_PREEMPT] +1: +#endif + .endm + /* * These are the registers used in the syscall handler, and allow us to * have in theory up to 7 arguments to a function - r0 to r6. diff --git a/trunk/arch/arm/kernel/head-nommu.S b/trunk/arch/arm/kernel/head-nommu.S index d46f25968bec..6b1e0ad9ec3b 100644 --- a/trunk/arch/arm/kernel/head-nommu.S +++ b/trunk/arch/arm/kernel/head-nommu.S @@ -32,16 +32,8 @@ * numbers for r1. * */ - .arm - __HEAD ENTRY(stext) - - THUMB( adr r9, BSYM(1f) ) @ Kernel is always entered in ARM. - THUMB( bx r9 ) @ If this is a Thumb-2 kernel, - THUMB( .thumb ) @ switch to Thumb now. - THUMB(1: ) - setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode @ and irqs disabled #ifndef CONFIG_CPU_CP15 diff --git a/trunk/arch/arm/kernel/head.S b/trunk/arch/arm/kernel/head.S index 742b6108a001..278c1b0ebb2e 100644 --- a/trunk/arch/arm/kernel/head.S +++ b/trunk/arch/arm/kernel/head.S @@ -71,16 +71,8 @@ * crap here - that's what the boot loader (or in extreme, well justified * circumstances, zImage) is for. */ - .arm - __HEAD ENTRY(stext) - - THUMB( adr r9, BSYM(1f) ) @ Kernel is always entered in ARM. - THUMB( bx r9 ) @ If this is a Thumb-2 kernel, - THUMB( .thumb ) @ switch to Thumb now. - THUMB(1: ) - setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode @ and irqs disabled mrc p15, 0, r9, c0, c0 @ get processor id diff --git a/trunk/arch/arm/kernel/hw_breakpoint.c b/trunk/arch/arm/kernel/hw_breakpoint.c index a927ca1f5566..87acc25d7a3e 100644 --- a/trunk/arch/arm/kernel/hw_breakpoint.c +++ b/trunk/arch/arm/kernel/hw_breakpoint.c @@ -796,7 +796,7 @@ static void breakpoint_handler(unsigned long unknown, struct pt_regs *regs) /* * Called from either the Data Abort Handler [watchpoint] or the - * Prefetch Abort Handler [breakpoint] with interrupts disabled. + * Prefetch Abort Handler [breakpoint] with preemption disabled. */ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr, struct pt_regs *regs) @@ -804,10 +804,8 @@ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr, int ret = 0; u32 dscr; - preempt_disable(); - - if (interrupts_enabled(regs)) - local_irq_enable(); + /* We must be called with preemption disabled. */ + WARN_ON(preemptible()); /* We only handle watchpoints and hardware breakpoints. */ ARM_DBG_READ(c1, 0, dscr); @@ -826,6 +824,10 @@ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr, ret = 1; /* Unhandled fault. */ } + /* + * Re-enable preemption after it was disabled in the + * low-level exception handling code. + */ preempt_enable(); return ret; diff --git a/trunk/arch/arm/kernel/irq.c b/trunk/arch/arm/kernel/irq.c index 0f928a131af8..83bbad03fcc6 100644 --- a/trunk/arch/arm/kernel/irq.c +++ b/trunk/arch/arm/kernel/irq.c @@ -131,63 +131,54 @@ int __init arch_probe_nr_irqs(void) #ifdef CONFIG_HOTPLUG_CPU -static bool migrate_one_irq(struct irq_desc *desc) +static bool migrate_one_irq(struct irq_data *d) { - struct irq_data *d = irq_desc_get_irq_data(desc); - const struct cpumask *affinity = d->affinity; - struct irq_chip *c; + unsigned int cpu = cpumask_any_and(d->affinity, cpu_online_mask); bool ret = false; - /* - * If this is a per-CPU interrupt, or the affinity does not - * include this CPU, then we have nothing to do. - */ - if (irqd_is_per_cpu(d) || !cpumask_test_cpu(smp_processor_id(), affinity)) - return false; - - if (cpumask_any_and(affinity, cpu_online_mask) >= nr_cpu_ids) { - affinity = cpu_online_mask; + if (cpu >= nr_cpu_ids) { + cpu = cpumask_any(cpu_online_mask); ret = true; } - c = irq_data_get_irq_chip(d); - if (c->irq_set_affinity) - c->irq_set_affinity(d, affinity, true); - else - pr_debug("IRQ%u: unable to set affinity\n", d->irq); + pr_debug("IRQ%u: moving from cpu%u to cpu%u\n", d->irq, d->node, cpu); + + d->chip->irq_set_affinity(d, cpumask_of(cpu), true); return ret; } /* - * The current CPU has been marked offline. Migrate IRQs off this CPU. - * If the affinity settings do not allow other CPUs, force them onto any + * The CPU has been marked offline. Migrate IRQs off this CPU. If + * the affinity settings do not allow other CPUs, force them onto any * available CPU. - * - * Note: we must iterate over all IRQs, whether they have an attached - * action structure or not, as we need to get chained interrupts too. */ void migrate_irqs(void) { - unsigned int i; + unsigned int i, cpu = smp_processor_id(); struct irq_desc *desc; unsigned long flags; local_irq_save(flags); for_each_irq_desc(i, desc) { + struct irq_data *d = &desc->irq_data; bool affinity_broken = false; - if (!desc) - continue; - raw_spin_lock(&desc->lock); - affinity_broken = migrate_one_irq(desc); + do { + if (desc->action == NULL) + break; + + if (d->node != cpu) + break; + + affinity_broken = migrate_one_irq(d); + } while (0); raw_spin_unlock(&desc->lock); if (affinity_broken && printk_ratelimit()) - pr_warning("IRQ%u no longer affine to CPU%u\n", i, - smp_processor_id()); + pr_warning("IRQ%u no longer affine to CPU%u\n", i, cpu); } local_irq_restore(flags); diff --git a/trunk/arch/arm/kernel/kprobes-arm.c b/trunk/arch/arm/kernel/kprobes-arm.c deleted file mode 100644 index 79203ee1d039..000000000000 --- a/trunk/arch/arm/kernel/kprobes-arm.c +++ /dev/null @@ -1,999 +0,0 @@ -/* - * arch/arm/kernel/kprobes-decode.c - * - * Copyright (C) 2006, 2007 Motorola Inc. - * - * 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. - * - * 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. - */ - -/* - * We do not have hardware single-stepping on ARM, This - * effort is further complicated by the ARM not having a - * "next PC" register. Instructions that change the PC - * can't be safely single-stepped in a MP environment, so - * we have a lot of work to do: - * - * In the prepare phase: - * *) If it is an instruction that does anything - * with the CPU mode, we reject it for a kprobe. - * (This is out of laziness rather than need. The - * instructions could be simulated.) - * - * *) Otherwise, decode the instruction rewriting its - * registers to take fixed, ordered registers and - * setting a handler for it to run the instruction. - * - * In the execution phase by an instruction's handler: - * - * *) If the PC is written to by the instruction, the - * instruction must be fully simulated in software. - * - * *) Otherwise, a modified form of the instruction is - * directly executed. Its handler calls the - * instruction in insn[0]. In insn[1] is a - * "mov pc, lr" to return. - * - * Before calling, load up the reordered registers - * from the original instruction's registers. If one - * of the original input registers is the PC, compute - * and adjust the appropriate input register. - * - * After call completes, copy the output registers to - * the original instruction's original registers. - * - * We don't use a real breakpoint instruction since that - * would have us in the kernel go from SVC mode to SVC - * mode losing the link register. Instead we use an - * undefined instruction. To simplify processing, the - * undefined instruction used for kprobes must be reserved - * exclusively for kprobes use. - * - * TODO: ifdef out some instruction decoding based on architecture. - */ - -#include -#include - -#include "kprobes.h" - -#define sign_extend(x, signbit) ((x) | (0 - ((x) & (1 << (signbit))))) - -#define branch_displacement(insn) sign_extend(((insn) & 0xffffff) << 2, 25) - -#if __LINUX_ARM_ARCH__ >= 6 -#define BLX(reg) "blx "reg" \n\t" -#else -#define BLX(reg) "mov lr, pc \n\t" \ - "mov pc, "reg" \n\t" -#endif - -/* - * To avoid the complications of mimicing single-stepping on a - * processor without a Next-PC or a single-step mode, and to - * avoid having to deal with the side-effects of boosting, we - * simulate or emulate (almost) all ARM instructions. - * - * "Simulation" is where the instruction's behavior is duplicated in - * C code. "Emulation" is where the original instruction is rewritten - * and executed, often by altering its registers. - * - * By having all behavior of the kprobe'd instruction completed before - * returning from the kprobe_handler(), all locks (scheduler and - * interrupt) can safely be released. There is no need for secondary - * breakpoints, no race with MP or preemptable kernels, nor having to - * clean up resources counts at a later time impacting overall system - * performance. By rewriting the instruction, only the minimum registers - * need to be loaded and saved back optimizing performance. - * - * Calling the insnslot_*_rwflags version of a function doesn't hurt - * anything even when the CPSR flags aren't updated by the - * instruction. It's just a little slower in return for saving - * a little space by not having a duplicate function that doesn't - * update the flags. (The same optimization can be said for - * instructions that do or don't perform register writeback) - * Also, instructions can either read the flags, only write the - * flags, or read and write the flags. To save combinations - * rather than for sheer performance, flag functions just assume - * read and write of flags. - */ - -static void __kprobes simulate_bbl(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - long iaddr = (long)p->addr; - int disp = branch_displacement(insn); - - if (insn & (1 << 24)) - regs->ARM_lr = iaddr + 4; - - regs->ARM_pc = iaddr + 8 + disp; -} - -static void __kprobes simulate_blx1(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - long iaddr = (long)p->addr; - int disp = branch_displacement(insn); - - regs->ARM_lr = iaddr + 4; - regs->ARM_pc = iaddr + 8 + disp + ((insn >> 23) & 0x2); - regs->ARM_cpsr |= PSR_T_BIT; -} - -static void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - int rm = insn & 0xf; - long rmv = regs->uregs[rm]; - - if (insn & (1 << 5)) - regs->ARM_lr = (long)p->addr + 4; - - regs->ARM_pc = rmv & ~0x1; - regs->ARM_cpsr &= ~PSR_T_BIT; - if (rmv & 0x1) - regs->ARM_cpsr |= PSR_T_BIT; -} - -static void __kprobes simulate_mrs(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - int rd = (insn >> 12) & 0xf; - unsigned long mask = 0xf8ff03df; /* Mask out execution state */ - regs->uregs[rd] = regs->ARM_cpsr & mask; -} - -static void __kprobes simulate_mov_ipsp(struct kprobe *p, struct pt_regs *regs) -{ - regs->uregs[12] = regs->uregs[13]; -} - -static void __kprobes -emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - unsigned long pc = (unsigned long)p->addr + 8; - int rt = (insn >> 12) & 0xf; - int rn = (insn >> 16) & 0xf; - int rm = insn & 0xf; - - register unsigned long rtv asm("r0") = regs->uregs[rt]; - register unsigned long rt2v asm("r1") = regs->uregs[rt+1]; - register unsigned long rnv asm("r2") = (rn == 15) ? pc - : regs->uregs[rn]; - register unsigned long rmv asm("r3") = regs->uregs[rm]; - - __asm__ __volatile__ ( - BLX("%[fn]") - : "=r" (rtv), "=r" (rt2v), "=r" (rnv) - : "0" (rtv), "1" (rt2v), "2" (rnv), "r" (rmv), - [fn] "r" (p->ainsn.insn_fn) - : "lr", "memory", "cc" - ); - - regs->uregs[rt] = rtv; - regs->uregs[rt+1] = rt2v; - if (is_writeback(insn)) - regs->uregs[rn] = rnv; -} - -static void __kprobes -emulate_ldr(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - unsigned long pc = (unsigned long)p->addr + 8; - int rt = (insn >> 12) & 0xf; - int rn = (insn >> 16) & 0xf; - int rm = insn & 0xf; - - register unsigned long rtv asm("r0"); - register unsigned long rnv asm("r2") = (rn == 15) ? pc - : regs->uregs[rn]; - register unsigned long rmv asm("r3") = regs->uregs[rm]; - - __asm__ __volatile__ ( - BLX("%[fn]") - : "=r" (rtv), "=r" (rnv) - : "1" (rnv), "r" (rmv), [fn] "r" (p->ainsn.insn_fn) - : "lr", "memory", "cc" - ); - - if (rt == 15) - load_write_pc(rtv, regs); - else - regs->uregs[rt] = rtv; - - if (is_writeback(insn)) - regs->uregs[rn] = rnv; -} - -static void __kprobes -emulate_str(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - unsigned long rtpc = (unsigned long)p->addr + str_pc_offset; - unsigned long rnpc = (unsigned long)p->addr + 8; - int rt = (insn >> 12) & 0xf; - int rn = (insn >> 16) & 0xf; - int rm = insn & 0xf; - - register unsigned long rtv asm("r0") = (rt == 15) ? rtpc - : regs->uregs[rt]; - register unsigned long rnv asm("r2") = (rn == 15) ? rnpc - : regs->uregs[rn]; - register unsigned long rmv asm("r3") = regs->uregs[rm]; - - __asm__ __volatile__ ( - BLX("%[fn]") - : "=r" (rnv) - : "r" (rtv), "0" (rnv), "r" (rmv), [fn] "r" (p->ainsn.insn_fn) - : "lr", "memory", "cc" - ); - - if (is_writeback(insn)) - regs->uregs[rn] = rnv; -} - -static void __kprobes -emulate_rd12rn16rm0rs8_rwflags(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - unsigned long pc = (unsigned long)p->addr + 8; - int rd = (insn >> 12) & 0xf; - int rn = (insn >> 16) & 0xf; - int rm = insn & 0xf; - int rs = (insn >> 8) & 0xf; - - register unsigned long rdv asm("r0") = regs->uregs[rd]; - register unsigned long rnv asm("r2") = (rn == 15) ? pc - : regs->uregs[rn]; - register unsigned long rmv asm("r3") = (rm == 15) ? pc - : regs->uregs[rm]; - register unsigned long rsv asm("r1") = regs->uregs[rs]; - unsigned long cpsr = regs->ARM_cpsr; - - __asm__ __volatile__ ( - "msr cpsr_fs, %[cpsr] \n\t" - BLX("%[fn]") - "mrs %[cpsr], cpsr \n\t" - : "=r" (rdv), [cpsr] "=r" (cpsr) - : "0" (rdv), "r" (rnv), "r" (rmv), "r" (rsv), - "1" (cpsr), [fn] "r" (p->ainsn.insn_fn) - : "lr", "memory", "cc" - ); - - if (rd == 15) - alu_write_pc(rdv, regs); - else - regs->uregs[rd] = rdv; - regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); -} - -static void __kprobes -emulate_rd12rn16rm0_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - int rd = (insn >> 12) & 0xf; - int rn = (insn >> 16) & 0xf; - int rm = insn & 0xf; - - register unsigned long rdv asm("r0") = regs->uregs[rd]; - register unsigned long rnv asm("r2") = regs->uregs[rn]; - register unsigned long rmv asm("r3") = regs->uregs[rm]; - unsigned long cpsr = regs->ARM_cpsr; - - __asm__ __volatile__ ( - "msr cpsr_fs, %[cpsr] \n\t" - BLX("%[fn]") - "mrs %[cpsr], cpsr \n\t" - : "=r" (rdv), [cpsr] "=r" (cpsr) - : "0" (rdv), "r" (rnv), "r" (rmv), - "1" (cpsr), [fn] "r" (p->ainsn.insn_fn) - : "lr", "memory", "cc" - ); - - regs->uregs[rd] = rdv; - regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); -} - -static void __kprobes -emulate_rd16rn12rm0rs8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - int rd = (insn >> 16) & 0xf; - int rn = (insn >> 12) & 0xf; - int rm = insn & 0xf; - int rs = (insn >> 8) & 0xf; - - register unsigned long rdv asm("r2") = regs->uregs[rd]; - register unsigned long rnv asm("r0") = regs->uregs[rn]; - register unsigned long rmv asm("r3") = regs->uregs[rm]; - register unsigned long rsv asm("r1") = regs->uregs[rs]; - unsigned long cpsr = regs->ARM_cpsr; - - __asm__ __volatile__ ( - "msr cpsr_fs, %[cpsr] \n\t" - BLX("%[fn]") - "mrs %[cpsr], cpsr \n\t" - : "=r" (rdv), [cpsr] "=r" (cpsr) - : "0" (rdv), "r" (rnv), "r" (rmv), "r" (rsv), - "1" (cpsr), [fn] "r" (p->ainsn.insn_fn) - : "lr", "memory", "cc" - ); - - regs->uregs[rd] = rdv; - regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); -} - -static void __kprobes -emulate_rd12rm0_noflags_nopc(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - int rd = (insn >> 12) & 0xf; - int rm = insn & 0xf; - - register unsigned long rdv asm("r0") = regs->uregs[rd]; - register unsigned long rmv asm("r3") = regs->uregs[rm]; - - __asm__ __volatile__ ( - BLX("%[fn]") - : "=r" (rdv) - : "0" (rdv), "r" (rmv), [fn] "r" (p->ainsn.insn_fn) - : "lr", "memory", "cc" - ); - - regs->uregs[rd] = rdv; -} - -static void __kprobes -emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - int rdlo = (insn >> 12) & 0xf; - int rdhi = (insn >> 16) & 0xf; - int rn = insn & 0xf; - int rm = (insn >> 8) & 0xf; - - register unsigned long rdlov asm("r0") = regs->uregs[rdlo]; - register unsigned long rdhiv asm("r2") = regs->uregs[rdhi]; - register unsigned long rnv asm("r3") = regs->uregs[rn]; - register unsigned long rmv asm("r1") = regs->uregs[rm]; - unsigned long cpsr = regs->ARM_cpsr; - - __asm__ __volatile__ ( - "msr cpsr_fs, %[cpsr] \n\t" - BLX("%[fn]") - "mrs %[cpsr], cpsr \n\t" - : "=r" (rdlov), "=r" (rdhiv), [cpsr] "=r" (cpsr) - : "0" (rdlov), "1" (rdhiv), "r" (rnv), "r" (rmv), - "2" (cpsr), [fn] "r" (p->ainsn.insn_fn) - : "lr", "memory", "cc" - ); - - regs->uregs[rdlo] = rdlov; - regs->uregs[rdhi] = rdhiv; - regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); -} - -/* - * For the instruction masking and comparisons in all the "space_*" - * functions below, Do _not_ rearrange the order of tests unless - * you're very, very sure of what you are doing. For the sake of - * efficiency, the masks for some tests sometimes assume other test - * have been done prior to them so the number of patterns to test - * for an instruction set can be as broad as possible to reduce the - * number of tests needed. - */ - -static const union decode_item arm_1111_table[] = { - /* Unconditional instructions */ - - /* memory hint 1111 0100 x001 xxxx xxxx xxxx xxxx xxxx */ - /* PLDI (immediate) 1111 0100 x101 xxxx xxxx xxxx xxxx xxxx */ - /* PLDW (immediate) 1111 0101 x001 xxxx xxxx xxxx xxxx xxxx */ - /* PLD (immediate) 1111 0101 x101 xxxx xxxx xxxx xxxx xxxx */ - DECODE_SIMULATE (0xfe300000, 0xf4100000, kprobe_simulate_nop), - - /* memory hint 1111 0110 x001 xxxx xxxx xxxx xxx0 xxxx */ - /* PLDI (register) 1111 0110 x101 xxxx xxxx xxxx xxx0 xxxx */ - /* PLDW (register) 1111 0111 x001 xxxx xxxx xxxx xxx0 xxxx */ - /* PLD (register) 1111 0111 x101 xxxx xxxx xxxx xxx0 xxxx */ - DECODE_SIMULATE (0xfe300010, 0xf6100000, kprobe_simulate_nop), - - /* BLX (immediate) 1111 101x xxxx xxxx xxxx xxxx xxxx xxxx */ - DECODE_SIMULATE (0xfe000000, 0xfa000000, simulate_blx1), - - /* CPS 1111 0001 0000 xxx0 xxxx xxxx xx0x xxxx */ - /* SETEND 1111 0001 0000 0001 xxxx xxxx 0000 xxxx */ - /* SRS 1111 100x x1x0 xxxx xxxx xxxx xxxx xxxx */ - /* RFE 1111 100x x0x1 xxxx xxxx xxxx xxxx xxxx */ - - /* Coprocessor instructions... */ - /* MCRR2 1111 1100 0100 xxxx xxxx xxxx xxxx xxxx */ - /* MRRC2 1111 1100 0101 xxxx xxxx xxxx xxxx xxxx */ - /* LDC2 1111 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ - /* STC2 1111 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ - /* CDP2 1111 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ - /* MCR2 1111 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ - /* MRC2 1111 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ - - /* Other unallocated instructions... */ - DECODE_END -}; - -static const union decode_item arm_cccc_0001_0xx0____0xxx_table[] = { - /* Miscellaneous instructions */ - - /* MRS cpsr cccc 0001 0000 xxxx xxxx xxxx 0000 xxxx */ - DECODE_SIMULATEX(0x0ff000f0, 0x01000000, simulate_mrs, - REGS(0, NOPC, 0, 0, 0)), - - /* BX cccc 0001 0010 xxxx xxxx xxxx 0001 xxxx */ - DECODE_SIMULATE (0x0ff000f0, 0x01200010, simulate_blx2bx), - - /* BLX (register) cccc 0001 0010 xxxx xxxx xxxx 0011 xxxx */ - DECODE_SIMULATEX(0x0ff000f0, 0x01200030, simulate_blx2bx, - REGS(0, 0, 0, 0, NOPC)), - - /* CLZ cccc 0001 0110 xxxx xxxx xxxx 0001 xxxx */ - DECODE_EMULATEX (0x0ff000f0, 0x01600010, emulate_rd12rm0_noflags_nopc, - REGS(0, NOPC, 0, 0, NOPC)), - - /* QADD cccc 0001 0000 xxxx xxxx xxxx 0101 xxxx */ - /* QSUB cccc 0001 0010 xxxx xxxx xxxx 0101 xxxx */ - /* QDADD cccc 0001 0100 xxxx xxxx xxxx 0101 xxxx */ - /* QDSUB cccc 0001 0110 xxxx xxxx xxxx 0101 xxxx */ - DECODE_EMULATEX (0x0f9000f0, 0x01000050, emulate_rd12rn16rm0_rwflags_nopc, - REGS(NOPC, NOPC, 0, 0, NOPC)), - - /* BXJ cccc 0001 0010 xxxx xxxx xxxx 0010 xxxx */ - /* MSR cccc 0001 0x10 xxxx xxxx xxxx 0000 xxxx */ - /* MRS spsr cccc 0001 0100 xxxx xxxx xxxx 0000 xxxx */ - /* BKPT 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */ - /* SMC cccc 0001 0110 xxxx xxxx xxxx 0111 xxxx */ - /* And unallocated instructions... */ - DECODE_END -}; - -static const union decode_item arm_cccc_0001_0xx0____1xx0_table[] = { - /* Halfword multiply and multiply-accumulate */ - - /* SMLALxy cccc 0001 0100 xxxx xxxx xxxx 1xx0 xxxx */ - DECODE_EMULATEX (0x0ff00090, 0x01400080, emulate_rdlo12rdhi16rn0rm8_rwflags_nopc, - REGS(NOPC, NOPC, NOPC, 0, NOPC)), - - /* SMULWy cccc 0001 0010 xxxx xxxx xxxx 1x10 xxxx */ - DECODE_OR (0x0ff000b0, 0x012000a0), - /* SMULxy cccc 0001 0110 xxxx xxxx xxxx 1xx0 xxxx */ - DECODE_EMULATEX (0x0ff00090, 0x01600080, emulate_rd16rn12rm0rs8_rwflags_nopc, - REGS(NOPC, 0, NOPC, 0, NOPC)), - - /* SMLAxy cccc 0001 0000 xxxx xxxx xxxx 1xx0 xxxx */ - DECODE_OR (0x0ff00090, 0x01000080), - /* SMLAWy cccc 0001 0010 xxxx xxxx xxxx 1x00 xxxx */ - DECODE_EMULATEX (0x0ff000b0, 0x01200080, emulate_rd16rn12rm0rs8_rwflags_nopc, - REGS(NOPC, NOPC, NOPC, 0, NOPC)), - - DECODE_END -}; - -static const union decode_item arm_cccc_0000_____1001_table[] = { - /* Multiply and multiply-accumulate */ - - /* MUL cccc 0000 0000 xxxx xxxx xxxx 1001 xxxx */ - /* MULS cccc 0000 0001 xxxx xxxx xxxx 1001 xxxx */ - DECODE_EMULATEX (0x0fe000f0, 0x00000090, emulate_rd16rn12rm0rs8_rwflags_nopc, - REGS(NOPC, 0, NOPC, 0, NOPC)), - - /* MLA cccc 0000 0010 xxxx xxxx xxxx 1001 xxxx */ - /* MLAS cccc 0000 0011 xxxx xxxx xxxx 1001 xxxx */ - DECODE_OR (0x0fe000f0, 0x00200090), - /* MLS cccc 0000 0110 xxxx xxxx xxxx 1001 xxxx */ - DECODE_EMULATEX (0x0ff000f0, 0x00600090, emulate_rd16rn12rm0rs8_rwflags_nopc, - REGS(NOPC, NOPC, NOPC, 0, NOPC)), - - /* UMAAL cccc 0000 0100 xxxx xxxx xxxx 1001 xxxx */ - DECODE_OR (0x0ff000f0, 0x00400090), - /* UMULL cccc 0000 1000 xxxx xxxx xxxx 1001 xxxx */ - /* UMULLS cccc 0000 1001 xxxx xxxx xxxx 1001 xxxx */ - /* UMLAL cccc 0000 1010 xxxx xxxx xxxx 1001 xxxx */ - /* UMLALS cccc 0000 1011 xxxx xxxx xxxx 1001 xxxx */ - /* SMULL cccc 0000 1100 xxxx xxxx xxxx 1001 xxxx */ - /* SMULLS cccc 0000 1101 xxxx xxxx xxxx 1001 xxxx */ - /* SMLAL cccc 0000 1110 xxxx xxxx xxxx 1001 xxxx */ - /* SMLALS cccc 0000 1111 xxxx xxxx xxxx 1001 xxxx */ - DECODE_EMULATEX (0x0f8000f0, 0x00800090, emulate_rdlo12rdhi16rn0rm8_rwflags_nopc, - REGS(NOPC, NOPC, NOPC, 0, NOPC)), - - DECODE_END -}; - -static const union decode_item arm_cccc_0001_____1001_table[] = { - /* Synchronization primitives */ - - /* SMP/SWPB cccc 0001 0x00 xxxx xxxx xxxx 1001 xxxx */ - DECODE_EMULATEX (0x0fb000f0, 0x01000090, emulate_rd12rn16rm0_rwflags_nopc, - REGS(NOPC, NOPC, 0, 0, NOPC)), - - /* LDREX/STREX{,D,B,H} cccc 0001 1xxx xxxx xxxx xxxx 1001 xxxx */ - /* And unallocated instructions... */ - DECODE_END -}; - -static const union decode_item arm_cccc_000x_____1xx1_table[] = { - /* Extra load/store instructions */ - - /* STRHT cccc 0000 xx10 xxxx xxxx xxxx 1011 xxxx */ - /* ??? cccc 0000 xx10 xxxx xxxx xxxx 11x1 xxxx */ - /* LDRHT cccc 0000 xx11 xxxx xxxx xxxx 1011 xxxx */ - /* LDRSBT cccc 0000 xx11 xxxx xxxx xxxx 1101 xxxx */ - /* LDRSHT cccc 0000 xx11 xxxx xxxx xxxx 1111 xxxx */ - DECODE_REJECT (0x0f200090, 0x00200090), - - /* LDRD/STRD lr,pc,{... cccc 000x x0x0 xxxx 111x xxxx 1101 xxxx */ - DECODE_REJECT (0x0e10e0d0, 0x0000e0d0), - - /* LDRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1101 xxxx */ - /* STRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1111 xxxx */ - DECODE_EMULATEX (0x0e5000d0, 0x000000d0, emulate_ldrdstrd, - REGS(NOPCWB, NOPCX, 0, 0, NOPC)), - - /* LDRD (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1101 xxxx */ - /* STRD (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1111 xxxx */ - DECODE_EMULATEX (0x0e5000d0, 0x004000d0, emulate_ldrdstrd, - REGS(NOPCWB, NOPCX, 0, 0, 0)), - - /* STRH (register) cccc 000x x0x0 xxxx xxxx xxxx 1011 xxxx */ - DECODE_EMULATEX (0x0e5000f0, 0x000000b0, emulate_str, - REGS(NOPCWB, NOPC, 0, 0, NOPC)), - - /* LDRH (register) cccc 000x x0x1 xxxx xxxx xxxx 1011 xxxx */ - /* LDRSB (register) cccc 000x x0x1 xxxx xxxx xxxx 1101 xxxx */ - /* LDRSH (register) cccc 000x x0x1 xxxx xxxx xxxx 1111 xxxx */ - DECODE_EMULATEX (0x0e500090, 0x00100090, emulate_ldr, - REGS(NOPCWB, NOPC, 0, 0, NOPC)), - - /* STRH (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1011 xxxx */ - DECODE_EMULATEX (0x0e5000f0, 0x004000b0, emulate_str, - REGS(NOPCWB, NOPC, 0, 0, 0)), - - /* LDRH (immediate) cccc 000x x1x1 xxxx xxxx xxxx 1011 xxxx */ - /* LDRSB (immediate) cccc 000x x1x1 xxxx xxxx xxxx 1101 xxxx */ - /* LDRSH (immediate) cccc 000x x1x1 xxxx xxxx xxxx 1111 xxxx */ - DECODE_EMULATEX (0x0e500090, 0x00500090, emulate_ldr, - REGS(NOPCWB, NOPC, 0, 0, 0)), - - DECODE_END -}; - -static const union decode_item arm_cccc_000x_table[] = { - /* Data-processing (register) */ - - /* S PC, ... cccc 000x xxx1 xxxx 1111 xxxx xxxx xxxx */ - DECODE_REJECT (0x0e10f000, 0x0010f000), - - /* MOV IP, SP 1110 0001 1010 0000 1100 0000 0000 1101 */ - DECODE_SIMULATE (0xffffffff, 0xe1a0c00d, simulate_mov_ipsp), - - /* TST (register) cccc 0001 0001 xxxx xxxx xxxx xxx0 xxxx */ - /* TEQ (register) cccc 0001 0011 xxxx xxxx xxxx xxx0 xxxx */ - /* CMP (register) cccc 0001 0101 xxxx xxxx xxxx xxx0 xxxx */ - /* CMN (register) cccc 0001 0111 xxxx xxxx xxxx xxx0 xxxx */ - DECODE_EMULATEX (0x0f900010, 0x01100000, emulate_rd12rn16rm0rs8_rwflags, - REGS(ANY, 0, 0, 0, ANY)), - - /* MOV (register) cccc 0001 101x xxxx xxxx xxxx xxx0 xxxx */ - /* MVN (register) cccc 0001 111x xxxx xxxx xxxx xxx0 xxxx */ - DECODE_EMULATEX (0x0fa00010, 0x01a00000, emulate_rd12rn16rm0rs8_rwflags, - REGS(0, ANY, 0, 0, ANY)), - - /* AND (register) cccc 0000 000x xxxx xxxx xxxx xxx0 xxxx */ - /* EOR (register) cccc 0000 001x xxxx xxxx xxxx xxx0 xxxx */ - /* SUB (register) cccc 0000 010x xxxx xxxx xxxx xxx0 xxxx */ - /* RSB (register) cccc 0000 011x xxxx xxxx xxxx xxx0 xxxx */ - /* ADD (register) cccc 0000 100x xxxx xxxx xxxx xxx0 xxxx */ - /* ADC (register) cccc 0000 101x xxxx xxxx xxxx xxx0 xxxx */ - /* SBC (register) cccc 0000 110x xxxx xxxx xxxx xxx0 xxxx */ - /* RSC (register) cccc 0000 111x xxxx xxxx xxxx xxx0 xxxx */ - /* ORR (register) cccc 0001 100x xxxx xxxx xxxx xxx0 xxxx */ - /* BIC (register) cccc 0001 110x xxxx xxxx xxxx xxx0 xxxx */ - DECODE_EMULATEX (0x0e000010, 0x00000000, emulate_rd12rn16rm0rs8_rwflags, - REGS(ANY, ANY, 0, 0, ANY)), - - /* TST (reg-shift reg) cccc 0001 0001 xxxx xxxx xxxx 0xx1 xxxx */ - /* TEQ (reg-shift reg) cccc 0001 0011 xxxx xxxx xxxx 0xx1 xxxx */ - /* CMP (reg-shift reg) cccc 0001 0101 xxxx xxxx xxxx 0xx1 xxxx */ - /* CMN (reg-shift reg) cccc 0001 0111 xxxx xxxx xxxx 0xx1 xxxx */ - DECODE_EMULATEX (0x0f900090, 0x01100010, emulate_rd12rn16rm0rs8_rwflags, - REGS(ANY, 0, NOPC, 0, ANY)), - - /* MOV (reg-shift reg) cccc 0001 101x xxxx xxxx xxxx 0xx1 xxxx */ - /* MVN (reg-shift reg) cccc 0001 111x xxxx xxxx xxxx 0xx1 xxxx */ - DECODE_EMULATEX (0x0fa00090, 0x01a00010, emulate_rd12rn16rm0rs8_rwflags, - REGS(0, ANY, NOPC, 0, ANY)), - - /* AND (reg-shift reg) cccc 0000 000x xxxx xxxx xxxx 0xx1 xxxx */ - /* EOR (reg-shift reg) cccc 0000 001x xxxx xxxx xxxx 0xx1 xxxx */ - /* SUB (reg-shift reg) cccc 0000 010x xxxx xxxx xxxx 0xx1 xxxx */ - /* RSB (reg-shift reg) cccc 0000 011x xxxx xxxx xxxx 0xx1 xxxx */ - /* ADD (reg-shift reg) cccc 0000 100x xxxx xxxx xxxx 0xx1 xxxx */ - /* ADC (reg-shift reg) cccc 0000 101x xxxx xxxx xxxx 0xx1 xxxx */ - /* SBC (reg-shift reg) cccc 0000 110x xxxx xxxx xxxx 0xx1 xxxx */ - /* RSC (reg-shift reg) cccc 0000 111x xxxx xxxx xxxx 0xx1 xxxx */ - /* ORR (reg-shift reg) cccc 0001 100x xxxx xxxx xxxx 0xx1 xxxx */ - /* BIC (reg-shift reg) cccc 0001 110x xxxx xxxx xxxx 0xx1 xxxx */ - DECODE_EMULATEX (0x0e000090, 0x00000010, emulate_rd12rn16rm0rs8_rwflags, - REGS(ANY, ANY, NOPC, 0, ANY)), - - DECODE_END -}; - -static const union decode_item arm_cccc_001x_table[] = { - /* Data-processing (immediate) */ - - /* MOVW cccc 0011 0000 xxxx xxxx xxxx xxxx xxxx */ - /* MOVT cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0fb00000, 0x03000000, emulate_rd12rm0_noflags_nopc, - REGS(0, NOPC, 0, 0, 0)), - - /* YIELD cccc 0011 0010 0000 xxxx xxxx 0000 0001 */ - DECODE_OR (0x0fff00ff, 0x03200001), - /* SEV cccc 0011 0010 0000 xxxx xxxx 0000 0100 */ - DECODE_EMULATE (0x0fff00ff, 0x03200004, kprobe_emulate_none), - /* NOP cccc 0011 0010 0000 xxxx xxxx 0000 0000 */ - /* WFE cccc 0011 0010 0000 xxxx xxxx 0000 0010 */ - /* WFI cccc 0011 0010 0000 xxxx xxxx 0000 0011 */ - DECODE_SIMULATE (0x0fff00fc, 0x03200000, kprobe_simulate_nop), - /* DBG cccc 0011 0010 0000 xxxx xxxx ffff xxxx */ - /* unallocated hints cccc 0011 0010 0000 xxxx xxxx xxxx xxxx */ - /* MSR (immediate) cccc 0011 0x10 xxxx xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0x0fb00000, 0x03200000), - - /* S PC, ... cccc 001x xxx1 xxxx 1111 xxxx xxxx xxxx */ - DECODE_REJECT (0x0e10f000, 0x0210f000), - - /* TST (immediate) cccc 0011 0001 xxxx xxxx xxxx xxxx xxxx */ - /* TEQ (immediate) cccc 0011 0011 xxxx xxxx xxxx xxxx xxxx */ - /* CMP (immediate) cccc 0011 0101 xxxx xxxx xxxx xxxx xxxx */ - /* CMN (immediate) cccc 0011 0111 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0f900000, 0x03100000, emulate_rd12rn16rm0rs8_rwflags, - REGS(ANY, 0, 0, 0, 0)), - - /* MOV (immediate) cccc 0011 101x xxxx xxxx xxxx xxxx xxxx */ - /* MVN (immediate) cccc 0011 111x xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0fa00000, 0x03a00000, emulate_rd12rn16rm0rs8_rwflags, - REGS(0, ANY, 0, 0, 0)), - - /* AND (immediate) cccc 0010 000x xxxx xxxx xxxx xxxx xxxx */ - /* EOR (immediate) cccc 0010 001x xxxx xxxx xxxx xxxx xxxx */ - /* SUB (immediate) cccc 0010 010x xxxx xxxx xxxx xxxx xxxx */ - /* RSB (immediate) cccc 0010 011x xxxx xxxx xxxx xxxx xxxx */ - /* ADD (immediate) cccc 0010 100x xxxx xxxx xxxx xxxx xxxx */ - /* ADC (immediate) cccc 0010 101x xxxx xxxx xxxx xxxx xxxx */ - /* SBC (immediate) cccc 0010 110x xxxx xxxx xxxx xxxx xxxx */ - /* RSC (immediate) cccc 0010 111x xxxx xxxx xxxx xxxx xxxx */ - /* ORR (immediate) cccc 0011 100x xxxx xxxx xxxx xxxx xxxx */ - /* BIC (immediate) cccc 0011 110x xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0e000000, 0x02000000, emulate_rd12rn16rm0rs8_rwflags, - REGS(ANY, ANY, 0, 0, 0)), - - DECODE_END -}; - -static const union decode_item arm_cccc_0110_____xxx1_table[] = { - /* Media instructions */ - - /* SEL cccc 0110 1000 xxxx xxxx xxxx 1011 xxxx */ - DECODE_EMULATEX (0x0ff000f0, 0x068000b0, emulate_rd12rn16rm0_rwflags_nopc, - REGS(NOPC, NOPC, 0, 0, NOPC)), - - /* SSAT cccc 0110 101x xxxx xxxx xxxx xx01 xxxx */ - /* USAT cccc 0110 111x xxxx xxxx xxxx xx01 xxxx */ - DECODE_OR(0x0fa00030, 0x06a00010), - /* SSAT16 cccc 0110 1010 xxxx xxxx xxxx 0011 xxxx */ - /* USAT16 cccc 0110 1110 xxxx xxxx xxxx 0011 xxxx */ - DECODE_EMULATEX (0x0fb000f0, 0x06a00030, emulate_rd12rn16rm0_rwflags_nopc, - REGS(0, NOPC, 0, 0, NOPC)), - - /* REV cccc 0110 1011 xxxx xxxx xxxx 0011 xxxx */ - /* REV16 cccc 0110 1011 xxxx xxxx xxxx 1011 xxxx */ - /* RBIT cccc 0110 1111 xxxx xxxx xxxx 0011 xxxx */ - /* REVSH cccc 0110 1111 xxxx xxxx xxxx 1011 xxxx */ - DECODE_EMULATEX (0x0fb00070, 0x06b00030, emulate_rd12rm0_noflags_nopc, - REGS(0, NOPC, 0, 0, NOPC)), - - /* ??? cccc 0110 0x00 xxxx xxxx xxxx xxx1 xxxx */ - DECODE_REJECT (0x0fb00010, 0x06000010), - /* ??? cccc 0110 0xxx xxxx xxxx xxxx 1011 xxxx */ - DECODE_REJECT (0x0f8000f0, 0x060000b0), - /* ??? cccc 0110 0xxx xxxx xxxx xxxx 1101 xxxx */ - DECODE_REJECT (0x0f8000f0, 0x060000d0), - /* SADD16 cccc 0110 0001 xxxx xxxx xxxx 0001 xxxx */ - /* SADDSUBX cccc 0110 0001 xxxx xxxx xxxx 0011 xxxx */ - /* SSUBADDX cccc 0110 0001 xxxx xxxx xxxx 0101 xxxx */ - /* SSUB16 cccc 0110 0001 xxxx xxxx xxxx 0111 xxxx */ - /* SADD8 cccc 0110 0001 xxxx xxxx xxxx 1001 xxxx */ - /* SSUB8 cccc 0110 0001 xxxx xxxx xxxx 1111 xxxx */ - /* QADD16 cccc 0110 0010 xxxx xxxx xxxx 0001 xxxx */ - /* QADDSUBX cccc 0110 0010 xxxx xxxx xxxx 0011 xxxx */ - /* QSUBADDX cccc 0110 0010 xxxx xxxx xxxx 0101 xxxx */ - /* QSUB16 cccc 0110 0010 xxxx xxxx xxxx 0111 xxxx */ - /* QADD8 cccc 0110 0010 xxxx xxxx xxxx 1001 xxxx */ - /* QSUB8 cccc 0110 0010 xxxx xxxx xxxx 1111 xxxx */ - /* SHADD16 cccc 0110 0011 xxxx xxxx xxxx 0001 xxxx */ - /* SHADDSUBX cccc 0110 0011 xxxx xxxx xxxx 0011 xxxx */ - /* SHSUBADDX cccc 0110 0011 xxxx xxxx xxxx 0101 xxxx */ - /* SHSUB16 cccc 0110 0011 xxxx xxxx xxxx 0111 xxxx */ - /* SHADD8 cccc 0110 0011 xxxx xxxx xxxx 1001 xxxx */ - /* SHSUB8 cccc 0110 0011 xxxx xxxx xxxx 1111 xxxx */ - /* UADD16 cccc 0110 0101 xxxx xxxx xxxx 0001 xxxx */ - /* UADDSUBX cccc 0110 0101 xxxx xxxx xxxx 0011 xxxx */ - /* USUBADDX cccc 0110 0101 xxxx xxxx xxxx 0101 xxxx */ - /* USUB16 cccc 0110 0101 xxxx xxxx xxxx 0111 xxxx */ - /* UADD8 cccc 0110 0101 xxxx xxxx xxxx 1001 xxxx */ - /* USUB8 cccc 0110 0101 xxxx xxxx xxxx 1111 xxxx */ - /* UQADD16 cccc 0110 0110 xxxx xxxx xxxx 0001 xxxx */ - /* UQADDSUBX cccc 0110 0110 xxxx xxxx xxxx 0011 xxxx */ - /* UQSUBADDX cccc 0110 0110 xxxx xxxx xxxx 0101 xxxx */ - /* UQSUB16 cccc 0110 0110 xxxx xxxx xxxx 0111 xxxx */ - /* UQADD8 cccc 0110 0110 xxxx xxxx xxxx 1001 xxxx */ - /* UQSUB8 cccc 0110 0110 xxxx xxxx xxxx 1111 xxxx */ - /* UHADD16 cccc 0110 0111 xxxx xxxx xxxx 0001 xxxx */ - /* UHADDSUBX cccc 0110 0111 xxxx xxxx xxxx 0011 xxxx */ - /* UHSUBADDX cccc 0110 0111 xxxx xxxx xxxx 0101 xxxx */ - /* UHSUB16 cccc 0110 0111 xxxx xxxx xxxx 0111 xxxx */ - /* UHADD8 cccc 0110 0111 xxxx xxxx xxxx 1001 xxxx */ - /* UHSUB8 cccc 0110 0111 xxxx xxxx xxxx 1111 xxxx */ - DECODE_EMULATEX (0x0f800010, 0x06000010, emulate_rd12rn16rm0_rwflags_nopc, - REGS(NOPC, NOPC, 0, 0, NOPC)), - - /* PKHBT cccc 0110 1000 xxxx xxxx xxxx x001 xxxx */ - /* PKHTB cccc 0110 1000 xxxx xxxx xxxx x101 xxxx */ - DECODE_EMULATEX (0x0ff00030, 0x06800010, emulate_rd12rn16rm0_rwflags_nopc, - REGS(NOPC, NOPC, 0, 0, NOPC)), - - /* ??? cccc 0110 1001 xxxx xxxx xxxx 0111 xxxx */ - /* ??? cccc 0110 1101 xxxx xxxx xxxx 0111 xxxx */ - DECODE_REJECT (0x0fb000f0, 0x06900070), - - /* SXTB16 cccc 0110 1000 1111 xxxx xxxx 0111 xxxx */ - /* SXTB cccc 0110 1010 1111 xxxx xxxx 0111 xxxx */ - /* SXTH cccc 0110 1011 1111 xxxx xxxx 0111 xxxx */ - /* UXTB16 cccc 0110 1100 1111 xxxx xxxx 0111 xxxx */ - /* UXTB cccc 0110 1110 1111 xxxx xxxx 0111 xxxx */ - /* UXTH cccc 0110 1111 1111 xxxx xxxx 0111 xxxx */ - DECODE_EMULATEX (0x0f8f00f0, 0x068f0070, emulate_rd12rm0_noflags_nopc, - REGS(0, NOPC, 0, 0, NOPC)), - - /* SXTAB16 cccc 0110 1000 xxxx xxxx xxxx 0111 xxxx */ - /* SXTAB cccc 0110 1010 xxxx xxxx xxxx 0111 xxxx */ - /* SXTAH cccc 0110 1011 xxxx xxxx xxxx 0111 xxxx */ - /* UXTAB16 cccc 0110 1100 xxxx xxxx xxxx 0111 xxxx */ - /* UXTAB cccc 0110 1110 xxxx xxxx xxxx 0111 xxxx */ - /* UXTAH cccc 0110 1111 xxxx xxxx xxxx 0111 xxxx */ - DECODE_EMULATEX (0x0f8000f0, 0x06800070, emulate_rd12rn16rm0_rwflags_nopc, - REGS(NOPCX, NOPC, 0, 0, NOPC)), - - DECODE_END -}; - -static const union decode_item arm_cccc_0111_____xxx1_table[] = { - /* Media instructions */ - - /* UNDEFINED cccc 0111 1111 xxxx xxxx xxxx 1111 xxxx */ - DECODE_REJECT (0x0ff000f0, 0x07f000f0), - - /* SMLALD cccc 0111 0100 xxxx xxxx xxxx 00x1 xxxx */ - /* SMLSLD cccc 0111 0100 xxxx xxxx xxxx 01x1 xxxx */ - DECODE_EMULATEX (0x0ff00090, 0x07400010, emulate_rdlo12rdhi16rn0rm8_rwflags_nopc, - REGS(NOPC, NOPC, NOPC, 0, NOPC)), - - /* SMUAD cccc 0111 0000 xxxx 1111 xxxx 00x1 xxxx */ - /* SMUSD cccc 0111 0000 xxxx 1111 xxxx 01x1 xxxx */ - DECODE_OR (0x0ff0f090, 0x0700f010), - /* SMMUL cccc 0111 0101 xxxx 1111 xxxx 00x1 xxxx */ - DECODE_OR (0x0ff0f0d0, 0x0750f010), - /* USAD8 cccc 0111 1000 xxxx 1111 xxxx 0001 xxxx */ - DECODE_EMULATEX (0x0ff0f0f0, 0x0780f010, emulate_rd16rn12rm0rs8_rwflags_nopc, - REGS(NOPC, 0, NOPC, 0, NOPC)), - - /* SMLAD cccc 0111 0000 xxxx xxxx xxxx 00x1 xxxx */ - /* SMLSD cccc 0111 0000 xxxx xxxx xxxx 01x1 xxxx */ - DECODE_OR (0x0ff00090, 0x07000010), - /* SMMLA cccc 0111 0101 xxxx xxxx xxxx 00x1 xxxx */ - DECODE_OR (0x0ff000d0, 0x07500010), - /* USADA8 cccc 0111 1000 xxxx xxxx xxxx 0001 xxxx */ - DECODE_EMULATEX (0x0ff000f0, 0x07800010, emulate_rd16rn12rm0rs8_rwflags_nopc, - REGS(NOPC, NOPCX, NOPC, 0, NOPC)), - - /* SMMLS cccc 0111 0101 xxxx xxxx xxxx 11x1 xxxx */ - DECODE_EMULATEX (0x0ff000d0, 0x075000d0, emulate_rd16rn12rm0rs8_rwflags_nopc, - REGS(NOPC, NOPC, NOPC, 0, NOPC)), - - /* SBFX cccc 0111 101x xxxx xxxx xxxx x101 xxxx */ - /* UBFX cccc 0111 111x xxxx xxxx xxxx x101 xxxx */ - DECODE_EMULATEX (0x0fa00070, 0x07a00050, emulate_rd12rm0_noflags_nopc, - REGS(0, NOPC, 0, 0, NOPC)), - - /* BFC cccc 0111 110x xxxx xxxx xxxx x001 1111 */ - DECODE_EMULATEX (0x0fe0007f, 0x07c0001f, emulate_rd12rm0_noflags_nopc, - REGS(0, NOPC, 0, 0, 0)), - - /* BFI cccc 0111 110x xxxx xxxx xxxx x001 xxxx */ - DECODE_EMULATEX (0x0fe00070, 0x07c00010, emulate_rd12rm0_noflags_nopc, - REGS(0, NOPC, 0, 0, NOPCX)), - - DECODE_END -}; - -static const union decode_item arm_cccc_01xx_table[] = { - /* Load/store word and unsigned byte */ - - /* LDRB/STRB pc,[...] cccc 01xx x0xx xxxx xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0x0c40f000, 0x0440f000), - - /* STRT cccc 01x0 x010 xxxx xxxx xxxx xxxx xxxx */ - /* LDRT cccc 01x0 x011 xxxx xxxx xxxx xxxx xxxx */ - /* STRBT cccc 01x0 x110 xxxx xxxx xxxx xxxx xxxx */ - /* LDRBT cccc 01x0 x111 xxxx xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0x0d200000, 0x04200000), - - /* STR (immediate) cccc 010x x0x0 xxxx xxxx xxxx xxxx xxxx */ - /* STRB (immediate) cccc 010x x1x0 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0e100000, 0x04000000, emulate_str, - REGS(NOPCWB, ANY, 0, 0, 0)), - - /* LDR (immediate) cccc 010x x0x1 xxxx xxxx xxxx xxxx xxxx */ - /* LDRB (immediate) cccc 010x x1x1 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0e100000, 0x04100000, emulate_ldr, - REGS(NOPCWB, ANY, 0, 0, 0)), - - /* STR (register) cccc 011x x0x0 xxxx xxxx xxxx xxxx xxxx */ - /* STRB (register) cccc 011x x1x0 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0e100000, 0x06000000, emulate_str, - REGS(NOPCWB, ANY, 0, 0, NOPC)), - - /* LDR (register) cccc 011x x0x1 xxxx xxxx xxxx xxxx xxxx */ - /* LDRB (register) cccc 011x x1x1 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0e100000, 0x06100000, emulate_ldr, - REGS(NOPCWB, ANY, 0, 0, NOPC)), - - DECODE_END -}; - -static const union decode_item arm_cccc_100x_table[] = { - /* Block data transfer instructions */ - - /* LDM cccc 100x x0x1 xxxx xxxx xxxx xxxx xxxx */ - /* STM cccc 100x x0x0 xxxx xxxx xxxx xxxx xxxx */ - DECODE_CUSTOM (0x0e400000, 0x08000000, kprobe_decode_ldmstm), - - /* STM (user registers) cccc 100x x1x0 xxxx xxxx xxxx xxxx xxxx */ - /* LDM (user registers) cccc 100x x1x1 xxxx 0xxx xxxx xxxx xxxx */ - /* LDM (exception ret) cccc 100x x1x1 xxxx 1xxx xxxx xxxx xxxx */ - DECODE_END -}; - -const union decode_item kprobe_decode_arm_table[] = { - /* - * Unconditional instructions - * 1111 xxxx xxxx xxxx xxxx xxxx xxxx xxxx - */ - DECODE_TABLE (0xf0000000, 0xf0000000, arm_1111_table), - - /* - * Miscellaneous instructions - * cccc 0001 0xx0 xxxx xxxx xxxx 0xxx xxxx - */ - DECODE_TABLE (0x0f900080, 0x01000000, arm_cccc_0001_0xx0____0xxx_table), - - /* - * Halfword multiply and multiply-accumulate - * cccc 0001 0xx0 xxxx xxxx xxxx 1xx0 xxxx - */ - DECODE_TABLE (0x0f900090, 0x01000080, arm_cccc_0001_0xx0____1xx0_table), - - /* - * Multiply and multiply-accumulate - * cccc 0000 xxxx xxxx xxxx xxxx 1001 xxxx - */ - DECODE_TABLE (0x0f0000f0, 0x00000090, arm_cccc_0000_____1001_table), - - /* - * Synchronization primitives - * cccc 0001 xxxx xxxx xxxx xxxx 1001 xxxx - */ - DECODE_TABLE (0x0f0000f0, 0x01000090, arm_cccc_0001_____1001_table), - - /* - * Extra load/store instructions - * cccc 000x xxxx xxxx xxxx xxxx 1xx1 xxxx - */ - DECODE_TABLE (0x0e000090, 0x00000090, arm_cccc_000x_____1xx1_table), - - /* - * Data-processing (register) - * cccc 000x xxxx xxxx xxxx xxxx xxx0 xxxx - * Data-processing (register-shifted register) - * cccc 000x xxxx xxxx xxxx xxxx 0xx1 xxxx - */ - DECODE_TABLE (0x0e000000, 0x00000000, arm_cccc_000x_table), - - /* - * Data-processing (immediate) - * cccc 001x xxxx xxxx xxxx xxxx xxxx xxxx - */ - DECODE_TABLE (0x0e000000, 0x02000000, arm_cccc_001x_table), - - /* - * Media instructions - * cccc 011x xxxx xxxx xxxx xxxx xxx1 xxxx - */ - DECODE_TABLE (0x0f000010, 0x06000010, arm_cccc_0110_____xxx1_table), - DECODE_TABLE (0x0f000010, 0x07000010, arm_cccc_0111_____xxx1_table), - - /* - * Load/store word and unsigned byte - * cccc 01xx xxxx xxxx xxxx xxxx xxxx xxxx - */ - DECODE_TABLE (0x0c000000, 0x04000000, arm_cccc_01xx_table), - - /* - * Block data transfer instructions - * cccc 100x xxxx xxxx xxxx xxxx xxxx xxxx - */ - DECODE_TABLE (0x0e000000, 0x08000000, arm_cccc_100x_table), - - /* B cccc 1010 xxxx xxxx xxxx xxxx xxxx xxxx */ - /* BL cccc 1011 xxxx xxxx xxxx xxxx xxxx xxxx */ - DECODE_SIMULATE (0x0e000000, 0x0a000000, simulate_bbl), - - /* - * Supervisor Call, and coprocessor instructions - */ - - /* MCRR cccc 1100 0100 xxxx xxxx xxxx xxxx xxxx */ - /* MRRC cccc 1100 0101 xxxx xxxx xxxx xxxx xxxx */ - /* LDC cccc 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ - /* STC cccc 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ - /* CDP cccc 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ - /* MCR cccc 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ - /* MRC cccc 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ - /* SVC cccc 1111 xxxx xxxx xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0x0c000000, 0x0c000000), - - DECODE_END -}; - -static void __kprobes arm_singlestep(struct kprobe *p, struct pt_regs *regs) -{ - regs->ARM_pc += 4; - p->ainsn.insn_handler(p, regs); -} - -/* Return: - * INSN_REJECTED If instruction is one not allowed to kprobe, - * INSN_GOOD If instruction is supported and uses instruction slot, - * INSN_GOOD_NO_SLOT If instruction is supported but doesn't use its slot. - * - * For instructions we don't want to kprobe (INSN_REJECTED return result): - * These are generally ones that modify the processor state making - * them "hard" to simulate such as switches processor modes or - * make accesses in alternate modes. Any of these could be simulated - * if the work was put into it, but low return considering they - * should also be very rare. - */ -enum kprobe_insn __kprobes -arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) -{ - asi->insn_singlestep = arm_singlestep; - asi->insn_check_cc = kprobe_condition_checks[insn>>28]; - return kprobe_decode_insn(insn, asi, kprobe_decode_arm_table, false); -} diff --git a/trunk/arch/arm/kernel/kprobes-common.c b/trunk/arch/arm/kernel/kprobes-common.c deleted file mode 100644 index a5394fb4e4e0..000000000000 --- a/trunk/arch/arm/kernel/kprobes-common.c +++ /dev/null @@ -1,577 +0,0 @@ -/* - * arch/arm/kernel/kprobes-common.c - * - * Copyright (C) 2011 Jon Medhurst . - * - * Some contents moved here from arch/arm/include/asm/kprobes-arm.c which is - * Copyright (C) 2006, 2007 Motorola Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include - -#include "kprobes.h" - - -#ifndef find_str_pc_offset - -/* - * For STR and STM instructions, an ARM core may choose to use either - * a +8 or a +12 displacement from the current instruction's address. - * Whichever value is chosen for a given core, it must be the same for - * both instructions and may not change. This function measures it. - */ - -int str_pc_offset; - -void __init find_str_pc_offset(void) -{ - int addr, scratch, ret; - - __asm__ ( - "sub %[ret], pc, #4 \n\t" - "str pc, %[addr] \n\t" - "ldr %[scr], %[addr] \n\t" - "sub %[ret], %[scr], %[ret] \n\t" - : [ret] "=r" (ret), [scr] "=r" (scratch), [addr] "+m" (addr)); - - str_pc_offset = ret; -} - -#endif /* !find_str_pc_offset */ - - -#ifndef test_load_write_pc_interworking - -bool load_write_pc_interworks; - -void __init test_load_write_pc_interworking(void) -{ - int arch = cpu_architecture(); - BUG_ON(arch == CPU_ARCH_UNKNOWN); - load_write_pc_interworks = arch >= CPU_ARCH_ARMv5T; -} - -#endif /* !test_load_write_pc_interworking */ - - -#ifndef test_alu_write_pc_interworking - -bool alu_write_pc_interworks; - -void __init test_alu_write_pc_interworking(void) -{ - int arch = cpu_architecture(); - BUG_ON(arch == CPU_ARCH_UNKNOWN); - alu_write_pc_interworks = arch >= CPU_ARCH_ARMv7; -} - -#endif /* !test_alu_write_pc_interworking */ - - -void __init arm_kprobe_decode_init(void) -{ - find_str_pc_offset(); - test_load_write_pc_interworking(); - test_alu_write_pc_interworking(); -} - - -static unsigned long __kprobes __check_eq(unsigned long cpsr) -{ - return cpsr & PSR_Z_BIT; -} - -static unsigned long __kprobes __check_ne(unsigned long cpsr) -{ - return (~cpsr) & PSR_Z_BIT; -} - -static unsigned long __kprobes __check_cs(unsigned long cpsr) -{ - return cpsr & PSR_C_BIT; -} - -static unsigned long __kprobes __check_cc(unsigned long cpsr) -{ - return (~cpsr) & PSR_C_BIT; -} - -static unsigned long __kprobes __check_mi(unsigned long cpsr) -{ - return cpsr & PSR_N_BIT; -} - -static unsigned long __kprobes __check_pl(unsigned long cpsr) -{ - return (~cpsr) & PSR_N_BIT; -} - -static unsigned long __kprobes __check_vs(unsigned long cpsr) -{ - return cpsr & PSR_V_BIT; -} - -static unsigned long __kprobes __check_vc(unsigned long cpsr) -{ - return (~cpsr) & PSR_V_BIT; -} - -static unsigned long __kprobes __check_hi(unsigned long cpsr) -{ - cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */ - return cpsr & PSR_C_BIT; -} - -static unsigned long __kprobes __check_ls(unsigned long cpsr) -{ - cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */ - return (~cpsr) & PSR_C_BIT; -} - -static unsigned long __kprobes __check_ge(unsigned long cpsr) -{ - cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ - return (~cpsr) & PSR_N_BIT; -} - -static unsigned long __kprobes __check_lt(unsigned long cpsr) -{ - cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ - return cpsr & PSR_N_BIT; -} - -static unsigned long __kprobes __check_gt(unsigned long cpsr) -{ - unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ - temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */ - return (~temp) & PSR_N_BIT; -} - -static unsigned long __kprobes __check_le(unsigned long cpsr) -{ - unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ - temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */ - return temp & PSR_N_BIT; -} - -static unsigned long __kprobes __check_al(unsigned long cpsr) -{ - return true; -} - -kprobe_check_cc * const kprobe_condition_checks[16] = { - &__check_eq, &__check_ne, &__check_cs, &__check_cc, - &__check_mi, &__check_pl, &__check_vs, &__check_vc, - &__check_hi, &__check_ls, &__check_ge, &__check_lt, - &__check_gt, &__check_le, &__check_al, &__check_al -}; - - -void __kprobes kprobe_simulate_nop(struct kprobe *p, struct pt_regs *regs) -{ -} - -void __kprobes kprobe_emulate_none(struct kprobe *p, struct pt_regs *regs) -{ - p->ainsn.insn_fn(); -} - -static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - int rn = (insn >> 16) & 0xf; - int lbit = insn & (1 << 20); - int wbit = insn & (1 << 21); - int ubit = insn & (1 << 23); - int pbit = insn & (1 << 24); - long *addr = (long *)regs->uregs[rn]; - int reg_bit_vector; - int reg_count; - - reg_count = 0; - reg_bit_vector = insn & 0xffff; - while (reg_bit_vector) { - reg_bit_vector &= (reg_bit_vector - 1); - ++reg_count; - } - - if (!ubit) - addr -= reg_count; - addr += (!pbit == !ubit); - - reg_bit_vector = insn & 0xffff; - while (reg_bit_vector) { - int reg = __ffs(reg_bit_vector); - reg_bit_vector &= (reg_bit_vector - 1); - if (lbit) - regs->uregs[reg] = *addr++; - else - *addr++ = regs->uregs[reg]; - } - - if (wbit) { - if (!ubit) - addr -= reg_count; - addr -= (!pbit == !ubit); - regs->uregs[rn] = (long)addr; - } -} - -static void __kprobes simulate_stm1_pc(struct kprobe *p, struct pt_regs *regs) -{ - regs->ARM_pc = (long)p->addr + str_pc_offset; - simulate_ldm1stm1(p, regs); - regs->ARM_pc = (long)p->addr + 4; -} - -static void __kprobes simulate_ldm1_pc(struct kprobe *p, struct pt_regs *regs) -{ - simulate_ldm1stm1(p, regs); - load_write_pc(regs->ARM_pc, regs); -} - -static void __kprobes -emulate_generic_r0_12_noflags(struct kprobe *p, struct pt_regs *regs) -{ - register void *rregs asm("r1") = regs; - register void *rfn asm("lr") = p->ainsn.insn_fn; - - __asm__ __volatile__ ( - "stmdb sp!, {%[regs], r11} \n\t" - "ldmia %[regs], {r0-r12} \n\t" -#if __LINUX_ARM_ARCH__ >= 6 - "blx %[fn] \n\t" -#else - "str %[fn], [sp, #-4]! \n\t" - "adr lr, 1f \n\t" - "ldr pc, [sp], #4 \n\t" - "1: \n\t" -#endif - "ldr lr, [sp], #4 \n\t" /* lr = regs */ - "stmia lr, {r0-r12} \n\t" - "ldr r11, [sp], #4 \n\t" - : [regs] "=r" (rregs), [fn] "=r" (rfn) - : "0" (rregs), "1" (rfn) - : "r0", "r2", "r3", "r4", "r5", "r6", "r7", - "r8", "r9", "r10", "r12", "memory", "cc" - ); -} - -static void __kprobes -emulate_generic_r2_14_noflags(struct kprobe *p, struct pt_regs *regs) -{ - emulate_generic_r0_12_noflags(p, (struct pt_regs *)(regs->uregs+2)); -} - -static void __kprobes -emulate_ldm_r3_15(struct kprobe *p, struct pt_regs *regs) -{ - emulate_generic_r0_12_noflags(p, (struct pt_regs *)(regs->uregs+3)); - load_write_pc(regs->ARM_pc, regs); -} - -enum kprobe_insn __kprobes -kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi) -{ - kprobe_insn_handler_t *handler = 0; - unsigned reglist = insn & 0xffff; - int is_ldm = insn & 0x100000; - int rn = (insn >> 16) & 0xf; - - if (rn <= 12 && (reglist & 0xe000) == 0) { - /* Instruction only uses registers in the range R0..R12 */ - handler = emulate_generic_r0_12_noflags; - - } else if (rn >= 2 && (reglist & 0x8003) == 0) { - /* Instruction only uses registers in the range R2..R14 */ - rn -= 2; - reglist >>= 2; - handler = emulate_generic_r2_14_noflags; - - } else if (rn >= 3 && (reglist & 0x0007) == 0) { - /* Instruction only uses registers in the range R3..R15 */ - if (is_ldm && (reglist & 0x8000)) { - rn -= 3; - reglist >>= 3; - handler = emulate_ldm_r3_15; - } - } - - if (handler) { - /* We can emulate the instruction in (possibly) modified form */ - asi->insn[0] = (insn & 0xfff00000) | (rn << 16) | reglist; - asi->insn_handler = handler; - return INSN_GOOD; - } - - /* Fallback to slower simulation... */ - if (reglist & 0x8000) - handler = is_ldm ? simulate_ldm1_pc : simulate_stm1_pc; - else - handler = simulate_ldm1stm1; - asi->insn_handler = handler; - return INSN_GOOD_NO_SLOT; -} - - -/* - * Prepare an instruction slot to receive an instruction for emulating. - * This is done by placing a subroutine return after the location where the - * instruction will be placed. We also modify ARM instructions to be - * unconditional as the condition code will already be checked before any - * emulation handler is called. - */ -static kprobe_opcode_t __kprobes -prepare_emulated_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, - bool thumb) -{ -#ifdef CONFIG_THUMB2_KERNEL - if (thumb) { - u16 *thumb_insn = (u16 *)asi->insn; - thumb_insn[1] = 0x4770; /* Thumb bx lr */ - thumb_insn[2] = 0x4770; /* Thumb bx lr */ - return insn; - } - asi->insn[1] = 0xe12fff1e; /* ARM bx lr */ -#else - asi->insn[1] = 0xe1a0f00e; /* mov pc, lr */ -#endif - /* Make an ARM instruction unconditional */ - if (insn < 0xe0000000) - insn = (insn | 0xe0000000) & ~0x10000000; - return insn; -} - -/* - * Write a (probably modified) instruction into the slot previously prepared by - * prepare_emulated_insn - */ -static void __kprobes -set_emulated_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, - bool thumb) -{ -#ifdef CONFIG_THUMB2_KERNEL - if (thumb) { - u16 *ip = (u16 *)asi->insn; - if (is_wide_instruction(insn)) - *ip++ = insn >> 16; - *ip++ = insn; - return; - } -#endif - asi->insn[0] = insn; -} - -/* - * When we modify the register numbers encoded in an instruction to be emulated, - * the new values come from this define. For ARM and 32-bit Thumb instructions - * this gives... - * - * bit position 16 12 8 4 0 - * ---------------+---+---+---+---+---+ - * register r2 r0 r1 -- r3 - */ -#define INSN_NEW_BITS 0x00020103 - -/* Each nibble has same value as that at INSN_NEW_BITS bit 16 */ -#define INSN_SAMEAS16_BITS 0x22222222 - -/* - * Validate and modify each of the registers encoded in an instruction. - * - * Each nibble in regs contains a value from enum decode_reg_type. For each - * non-zero value, the corresponding nibble in pinsn is validated and modified - * according to the type. - */ -static bool __kprobes decode_regs(kprobe_opcode_t* pinsn, u32 regs) -{ - kprobe_opcode_t insn = *pinsn; - kprobe_opcode_t mask = 0xf; /* Start at least significant nibble */ - - for (; regs != 0; regs >>= 4, mask <<= 4) { - - kprobe_opcode_t new_bits = INSN_NEW_BITS; - - switch (regs & 0xf) { - - case REG_TYPE_NONE: - /* Nibble not a register, skip to next */ - continue; - - case REG_TYPE_ANY: - /* Any register is allowed */ - break; - - case REG_TYPE_SAMEAS16: - /* Replace register with same as at bit position 16 */ - new_bits = INSN_SAMEAS16_BITS; - break; - - case REG_TYPE_SP: - /* Only allow SP (R13) */ - if ((insn ^ 0xdddddddd) & mask) - goto reject; - break; - - case REG_TYPE_PC: - /* Only allow PC (R15) */ - if ((insn ^ 0xffffffff) & mask) - goto reject; - break; - - case REG_TYPE_NOSP: - /* Reject SP (R13) */ - if (((insn ^ 0xdddddddd) & mask) == 0) - goto reject; - break; - - case REG_TYPE_NOSPPC: - case REG_TYPE_NOSPPCX: - /* Reject SP and PC (R13 and R15) */ - if (((insn ^ 0xdddddddd) & 0xdddddddd & mask) == 0) - goto reject; - break; - - case REG_TYPE_NOPCWB: - if (!is_writeback(insn)) - break; /* No writeback, so any register is OK */ - /* fall through... */ - case REG_TYPE_NOPC: - case REG_TYPE_NOPCX: - /* Reject PC (R15) */ - if (((insn ^ 0xffffffff) & mask) == 0) - goto reject; - break; - } - - /* Replace value of nibble with new register number... */ - insn &= ~mask; - insn |= new_bits & mask; - } - - *pinsn = insn; - return true; - -reject: - return false; -} - -static const int decode_struct_sizes[NUM_DECODE_TYPES] = { - [DECODE_TYPE_TABLE] = sizeof(struct decode_table), - [DECODE_TYPE_CUSTOM] = sizeof(struct decode_custom), - [DECODE_TYPE_SIMULATE] = sizeof(struct decode_simulate), - [DECODE_TYPE_EMULATE] = sizeof(struct decode_emulate), - [DECODE_TYPE_OR] = sizeof(struct decode_or), - [DECODE_TYPE_REJECT] = sizeof(struct decode_reject) -}; - -/* - * kprobe_decode_insn operates on data tables in order to decode an ARM - * architecture instruction onto which a kprobe has been placed. - * - * These instruction decoding tables are a concatenation of entries each - * of which consist of one of the following structs: - * - * decode_table - * decode_custom - * decode_simulate - * decode_emulate - * decode_or - * decode_reject - * - * Each of these starts with a struct decode_header which has the following - * fields: - * - * type_regs - * mask - * value - * - * The least significant DECODE_TYPE_BITS of type_regs contains a value - * from enum decode_type, this indicates which of the decode_* structs - * the entry contains. The value DECODE_TYPE_END indicates the end of the - * table. - * - * When the table is parsed, each entry is checked in turn to see if it - * matches the instruction to be decoded using the test: - * - * (insn & mask) == value - * - * If no match is found before the end of the table is reached then decoding - * fails with INSN_REJECTED. - * - * When a match is found, decode_regs() is called to validate and modify each - * of the registers encoded in the instruction; the data it uses to do this - * is (type_regs >> DECODE_TYPE_BITS). A validation failure will cause decoding - * to fail with INSN_REJECTED. - * - * Once the instruction has passed the above tests, further processing - * depends on the type of the table entry's decode struct. - * - */ -int __kprobes -kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, - const union decode_item *table, bool thumb) -{ - const struct decode_header *h = (struct decode_header *)table; - const struct decode_header *next; - bool matched = false; - - insn = prepare_emulated_insn(insn, asi, thumb); - - for (;; h = next) { - enum decode_type type = h->type_regs.bits & DECODE_TYPE_MASK; - u32 regs = h->type_regs.bits >> DECODE_TYPE_BITS; - - if (type == DECODE_TYPE_END) - return INSN_REJECTED; - - next = (struct decode_header *) - ((uintptr_t)h + decode_struct_sizes[type]); - - if (!matched && (insn & h->mask.bits) != h->value.bits) - continue; - - if (!decode_regs(&insn, regs)) - return INSN_REJECTED; - - switch (type) { - - case DECODE_TYPE_TABLE: { - struct decode_table *d = (struct decode_table *)h; - next = (struct decode_header *)d->table.table; - break; - } - - case DECODE_TYPE_CUSTOM: { - struct decode_custom *d = (struct decode_custom *)h; - return (*d->decoder.decoder)(insn, asi); - } - - case DECODE_TYPE_SIMULATE: { - struct decode_simulate *d = (struct decode_simulate *)h; - asi->insn_handler = d->handler.handler; - return INSN_GOOD_NO_SLOT; - } - - case DECODE_TYPE_EMULATE: { - struct decode_emulate *d = (struct decode_emulate *)h; - asi->insn_handler = d->handler.handler; - set_emulated_insn(insn, asi, thumb); - return INSN_GOOD; - } - - case DECODE_TYPE_OR: - matched = true; - break; - - case DECODE_TYPE_REJECT: - default: - return INSN_REJECTED; - } - } - } diff --git a/trunk/arch/arm/kernel/kprobes-decode.c b/trunk/arch/arm/kernel/kprobes-decode.c new file mode 100644 index 000000000000..15eeff6aea0e --- /dev/null +++ b/trunk/arch/arm/kernel/kprobes-decode.c @@ -0,0 +1,1670 @@ +/* + * arch/arm/kernel/kprobes-decode.c + * + * Copyright (C) 2006, 2007 Motorola Inc. + * + * 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. + * + * 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. + */ + +/* + * We do not have hardware single-stepping on ARM, This + * effort is further complicated by the ARM not having a + * "next PC" register. Instructions that change the PC + * can't be safely single-stepped in a MP environment, so + * we have a lot of work to do: + * + * In the prepare phase: + * *) If it is an instruction that does anything + * with the CPU mode, we reject it for a kprobe. + * (This is out of laziness rather than need. The + * instructions could be simulated.) + * + * *) Otherwise, decode the instruction rewriting its + * registers to take fixed, ordered registers and + * setting a handler for it to run the instruction. + * + * In the execution phase by an instruction's handler: + * + * *) If the PC is written to by the instruction, the + * instruction must be fully simulated in software. + * + * *) Otherwise, a modified form of the instruction is + * directly executed. Its handler calls the + * instruction in insn[0]. In insn[1] is a + * "mov pc, lr" to return. + * + * Before calling, load up the reordered registers + * from the original instruction's registers. If one + * of the original input registers is the PC, compute + * and adjust the appropriate input register. + * + * After call completes, copy the output registers to + * the original instruction's original registers. + * + * We don't use a real breakpoint instruction since that + * would have us in the kernel go from SVC mode to SVC + * mode losing the link register. Instead we use an + * undefined instruction. To simplify processing, the + * undefined instruction used for kprobes must be reserved + * exclusively for kprobes use. + * + * TODO: ifdef out some instruction decoding based on architecture. + */ + +#include +#include + +#define sign_extend(x, signbit) ((x) | (0 - ((x) & (1 << (signbit))))) + +#define branch_displacement(insn) sign_extend(((insn) & 0xffffff) << 2, 25) + +#define is_r15(insn, bitpos) (((insn) & (0xf << bitpos)) == (0xf << bitpos)) + +/* + * Test if load/store instructions writeback the address register. + * if P (bit 24) == 0 or W (bit 21) == 1 + */ +#define is_writeback(insn) ((insn ^ 0x01000000) & 0x01200000) + +#define PSR_fs (PSR_f|PSR_s) + +#define KPROBE_RETURN_INSTRUCTION 0xe1a0f00e /* mov pc, lr */ + +typedef long (insn_0arg_fn_t)(void); +typedef long (insn_1arg_fn_t)(long); +typedef long (insn_2arg_fn_t)(long, long); +typedef long (insn_3arg_fn_t)(long, long, long); +typedef long (insn_4arg_fn_t)(long, long, long, long); +typedef long long (insn_llret_0arg_fn_t)(void); +typedef long long (insn_llret_3arg_fn_t)(long, long, long); +typedef long long (insn_llret_4arg_fn_t)(long, long, long, long); + +union reg_pair { + long long dr; +#ifdef __LITTLE_ENDIAN + struct { long r0, r1; }; +#else + struct { long r1, r0; }; +#endif +}; + +/* + * For STR and STM instructions, an ARM core may choose to use either + * a +8 or a +12 displacement from the current instruction's address. + * Whichever value is chosen for a given core, it must be the same for + * both instructions and may not change. This function measures it. + */ + +static int str_pc_offset; + +static void __init find_str_pc_offset(void) +{ + int addr, scratch, ret; + + __asm__ ( + "sub %[ret], pc, #4 \n\t" + "str pc, %[addr] \n\t" + "ldr %[scr], %[addr] \n\t" + "sub %[ret], %[scr], %[ret] \n\t" + : [ret] "=r" (ret), [scr] "=r" (scratch), [addr] "+m" (addr)); + + str_pc_offset = ret; +} + +/* + * The insnslot_?arg_r[w]flags() functions below are to keep the + * msr -> *fn -> mrs instruction sequences indivisible so that + * the state of the CPSR flags aren't inadvertently modified + * just before or just after the call. + */ + +static inline long __kprobes +insnslot_0arg_rflags(long cpsr, insn_0arg_fn_t *fn) +{ + register long ret asm("r0"); + + __asm__ __volatile__ ( + "msr cpsr_fs, %[cpsr] \n\t" + "mov lr, pc \n\t" + "mov pc, %[fn] \n\t" + : "=r" (ret) + : [cpsr] "r" (cpsr), [fn] "r" (fn) + : "lr", "cc" + ); + return ret; +} + +static inline long long __kprobes +insnslot_llret_0arg_rflags(long cpsr, insn_llret_0arg_fn_t *fn) +{ + register long ret0 asm("r0"); + register long ret1 asm("r1"); + union reg_pair fnr; + + __asm__ __volatile__ ( + "msr cpsr_fs, %[cpsr] \n\t" + "mov lr, pc \n\t" + "mov pc, %[fn] \n\t" + : "=r" (ret0), "=r" (ret1) + : [cpsr] "r" (cpsr), [fn] "r" (fn) + : "lr", "cc" + ); + fnr.r0 = ret0; + fnr.r1 = ret1; + return fnr.dr; +} + +static inline long __kprobes +insnslot_1arg_rflags(long r0, long cpsr, insn_1arg_fn_t *fn) +{ + register long rr0 asm("r0") = r0; + register long ret asm("r0"); + + __asm__ __volatile__ ( + "msr cpsr_fs, %[cpsr] \n\t" + "mov lr, pc \n\t" + "mov pc, %[fn] \n\t" + : "=r" (ret) + : "0" (rr0), [cpsr] "r" (cpsr), [fn] "r" (fn) + : "lr", "cc" + ); + return ret; +} + +static inline long __kprobes +insnslot_2arg_rflags(long r0, long r1, long cpsr, insn_2arg_fn_t *fn) +{ + register long rr0 asm("r0") = r0; + register long rr1 asm("r1") = r1; + register long ret asm("r0"); + + __asm__ __volatile__ ( + "msr cpsr_fs, %[cpsr] \n\t" + "mov lr, pc \n\t" + "mov pc, %[fn] \n\t" + : "=r" (ret) + : "0" (rr0), "r" (rr1), + [cpsr] "r" (cpsr), [fn] "r" (fn) + : "lr", "cc" + ); + return ret; +} + +static inline long __kprobes +insnslot_3arg_rflags(long r0, long r1, long r2, long cpsr, insn_3arg_fn_t *fn) +{ + register long rr0 asm("r0") = r0; + register long rr1 asm("r1") = r1; + register long rr2 asm("r2") = r2; + register long ret asm("r0"); + + __asm__ __volatile__ ( + "msr cpsr_fs, %[cpsr] \n\t" + "mov lr, pc \n\t" + "mov pc, %[fn] \n\t" + : "=r" (ret) + : "0" (rr0), "r" (rr1), "r" (rr2), + [cpsr] "r" (cpsr), [fn] "r" (fn) + : "lr", "cc" + ); + return ret; +} + +static inline long long __kprobes +insnslot_llret_3arg_rflags(long r0, long r1, long r2, long cpsr, + insn_llret_3arg_fn_t *fn) +{ + register long rr0 asm("r0") = r0; + register long rr1 asm("r1") = r1; + register long rr2 asm("r2") = r2; + register long ret0 asm("r0"); + register long ret1 asm("r1"); + union reg_pair fnr; + + __asm__ __volatile__ ( + "msr cpsr_fs, %[cpsr] \n\t" + "mov lr, pc \n\t" + "mov pc, %[fn] \n\t" + : "=r" (ret0), "=r" (ret1) + : "0" (rr0), "r" (rr1), "r" (rr2), + [cpsr] "r" (cpsr), [fn] "r" (fn) + : "lr", "cc" + ); + fnr.r0 = ret0; + fnr.r1 = ret1; + return fnr.dr; +} + +static inline long __kprobes +insnslot_4arg_rflags(long r0, long r1, long r2, long r3, long cpsr, + insn_4arg_fn_t *fn) +{ + register long rr0 asm("r0") = r0; + register long rr1 asm("r1") = r1; + register long rr2 asm("r2") = r2; + register long rr3 asm("r3") = r3; + register long ret asm("r0"); + + __asm__ __volatile__ ( + "msr cpsr_fs, %[cpsr] \n\t" + "mov lr, pc \n\t" + "mov pc, %[fn] \n\t" + : "=r" (ret) + : "0" (rr0), "r" (rr1), "r" (rr2), "r" (rr3), + [cpsr] "r" (cpsr), [fn] "r" (fn) + : "lr", "cc" + ); + return ret; +} + +static inline long __kprobes +insnslot_1arg_rwflags(long r0, long *cpsr, insn_1arg_fn_t *fn) +{ + register long rr0 asm("r0") = r0; + register long ret asm("r0"); + long oldcpsr = *cpsr; + long newcpsr; + + __asm__ __volatile__ ( + "msr cpsr_fs, %[oldcpsr] \n\t" + "mov lr, pc \n\t" + "mov pc, %[fn] \n\t" + "mrs %[newcpsr], cpsr \n\t" + : "=r" (ret), [newcpsr] "=r" (newcpsr) + : "0" (rr0), [oldcpsr] "r" (oldcpsr), [fn] "r" (fn) + : "lr", "cc" + ); + *cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs); + return ret; +} + +static inline long __kprobes +insnslot_2arg_rwflags(long r0, long r1, long *cpsr, insn_2arg_fn_t *fn) +{ + register long rr0 asm("r0") = r0; + register long rr1 asm("r1") = r1; + register long ret asm("r0"); + long oldcpsr = *cpsr; + long newcpsr; + + __asm__ __volatile__ ( + "msr cpsr_fs, %[oldcpsr] \n\t" + "mov lr, pc \n\t" + "mov pc, %[fn] \n\t" + "mrs %[newcpsr], cpsr \n\t" + : "=r" (ret), [newcpsr] "=r" (newcpsr) + : "0" (rr0), "r" (rr1), [oldcpsr] "r" (oldcpsr), [fn] "r" (fn) + : "lr", "cc" + ); + *cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs); + return ret; +} + +static inline long __kprobes +insnslot_3arg_rwflags(long r0, long r1, long r2, long *cpsr, + insn_3arg_fn_t *fn) +{ + register long rr0 asm("r0") = r0; + register long rr1 asm("r1") = r1; + register long rr2 asm("r2") = r2; + register long ret asm("r0"); + long oldcpsr = *cpsr; + long newcpsr; + + __asm__ __volatile__ ( + "msr cpsr_fs, %[oldcpsr] \n\t" + "mov lr, pc \n\t" + "mov pc, %[fn] \n\t" + "mrs %[newcpsr], cpsr \n\t" + : "=r" (ret), [newcpsr] "=r" (newcpsr) + : "0" (rr0), "r" (rr1), "r" (rr2), + [oldcpsr] "r" (oldcpsr), [fn] "r" (fn) + : "lr", "cc" + ); + *cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs); + return ret; +} + +static inline long __kprobes +insnslot_4arg_rwflags(long r0, long r1, long r2, long r3, long *cpsr, + insn_4arg_fn_t *fn) +{ + register long rr0 asm("r0") = r0; + register long rr1 asm("r1") = r1; + register long rr2 asm("r2") = r2; + register long rr3 asm("r3") = r3; + register long ret asm("r0"); + long oldcpsr = *cpsr; + long newcpsr; + + __asm__ __volatile__ ( + "msr cpsr_fs, %[oldcpsr] \n\t" + "mov lr, pc \n\t" + "mov pc, %[fn] \n\t" + "mrs %[newcpsr], cpsr \n\t" + : "=r" (ret), [newcpsr] "=r" (newcpsr) + : "0" (rr0), "r" (rr1), "r" (rr2), "r" (rr3), + [oldcpsr] "r" (oldcpsr), [fn] "r" (fn) + : "lr", "cc" + ); + *cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs); + return ret; +} + +static inline long long __kprobes +insnslot_llret_4arg_rwflags(long r0, long r1, long r2, long r3, long *cpsr, + insn_llret_4arg_fn_t *fn) +{ + register long rr0 asm("r0") = r0; + register long rr1 asm("r1") = r1; + register long rr2 asm("r2") = r2; + register long rr3 asm("r3") = r3; + register long ret0 asm("r0"); + register long ret1 asm("r1"); + long oldcpsr = *cpsr; + long newcpsr; + union reg_pair fnr; + + __asm__ __volatile__ ( + "msr cpsr_fs, %[oldcpsr] \n\t" + "mov lr, pc \n\t" + "mov pc, %[fn] \n\t" + "mrs %[newcpsr], cpsr \n\t" + : "=r" (ret0), "=r" (ret1), [newcpsr] "=r" (newcpsr) + : "0" (rr0), "r" (rr1), "r" (rr2), "r" (rr3), + [oldcpsr] "r" (oldcpsr), [fn] "r" (fn) + : "lr", "cc" + ); + *cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs); + fnr.r0 = ret0; + fnr.r1 = ret1; + return fnr.dr; +} + +/* + * To avoid the complications of mimicing single-stepping on a + * processor without a Next-PC or a single-step mode, and to + * avoid having to deal with the side-effects of boosting, we + * simulate or emulate (almost) all ARM instructions. + * + * "Simulation" is where the instruction's behavior is duplicated in + * C code. "Emulation" is where the original instruction is rewritten + * and executed, often by altering its registers. + * + * By having all behavior of the kprobe'd instruction completed before + * returning from the kprobe_handler(), all locks (scheduler and + * interrupt) can safely be released. There is no need for secondary + * breakpoints, no race with MP or preemptable kernels, nor having to + * clean up resources counts at a later time impacting overall system + * performance. By rewriting the instruction, only the minimum registers + * need to be loaded and saved back optimizing performance. + * + * Calling the insnslot_*_rwflags version of a function doesn't hurt + * anything even when the CPSR flags aren't updated by the + * instruction. It's just a little slower in return for saving + * a little space by not having a duplicate function that doesn't + * update the flags. (The same optimization can be said for + * instructions that do or don't perform register writeback) + * Also, instructions can either read the flags, only write the + * flags, or read and write the flags. To save combinations + * rather than for sheer performance, flag functions just assume + * read and write of flags. + */ + +static void __kprobes simulate_bbl(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + long iaddr = (long)p->addr; + int disp = branch_displacement(insn); + + if (insn & (1 << 24)) + regs->ARM_lr = iaddr + 4; + + regs->ARM_pc = iaddr + 8 + disp; +} + +static void __kprobes simulate_blx1(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + long iaddr = (long)p->addr; + int disp = branch_displacement(insn); + + regs->ARM_lr = iaddr + 4; + regs->ARM_pc = iaddr + 8 + disp + ((insn >> 23) & 0x2); + regs->ARM_cpsr |= PSR_T_BIT; +} + +static void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + int rm = insn & 0xf; + long rmv = regs->uregs[rm]; + + if (insn & (1 << 5)) + regs->ARM_lr = (long)p->addr + 4; + + regs->ARM_pc = rmv & ~0x1; + regs->ARM_cpsr &= ~PSR_T_BIT; + if (rmv & 0x1) + regs->ARM_cpsr |= PSR_T_BIT; +} + +static void __kprobes simulate_mrs(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + int rd = (insn >> 12) & 0xf; + unsigned long mask = 0xf8ff03df; /* Mask out execution state */ + regs->uregs[rd] = regs->ARM_cpsr & mask; +} + +static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + int rn = (insn >> 16) & 0xf; + int lbit = insn & (1 << 20); + int wbit = insn & (1 << 21); + int ubit = insn & (1 << 23); + int pbit = insn & (1 << 24); + long *addr = (long *)regs->uregs[rn]; + int reg_bit_vector; + int reg_count; + + reg_count = 0; + reg_bit_vector = insn & 0xffff; + while (reg_bit_vector) { + reg_bit_vector &= (reg_bit_vector - 1); + ++reg_count; + } + + if (!ubit) + addr -= reg_count; + addr += (!pbit == !ubit); + + reg_bit_vector = insn & 0xffff; + while (reg_bit_vector) { + int reg = __ffs(reg_bit_vector); + reg_bit_vector &= (reg_bit_vector - 1); + if (lbit) + regs->uregs[reg] = *addr++; + else + *addr++ = regs->uregs[reg]; + } + + if (wbit) { + if (!ubit) + addr -= reg_count; + addr -= (!pbit == !ubit); + regs->uregs[rn] = (long)addr; + } +} + +static void __kprobes simulate_stm1_pc(struct kprobe *p, struct pt_regs *regs) +{ + regs->ARM_pc = (long)p->addr + str_pc_offset; + simulate_ldm1stm1(p, regs); + regs->ARM_pc = (long)p->addr + 4; +} + +static void __kprobes simulate_mov_ipsp(struct kprobe *p, struct pt_regs *regs) +{ + regs->uregs[12] = regs->uregs[13]; +} + +static void __kprobes emulate_ldrd(struct kprobe *p, struct pt_regs *regs) +{ + insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; + kprobe_opcode_t insn = p->opcode; + long ppc = (long)p->addr + 8; + int rd = (insn >> 12) & 0xf; + int rn = (insn >> 16) & 0xf; + int rm = insn & 0xf; /* rm may be invalid, don't care. */ + long rmv = (rm == 15) ? ppc : regs->uregs[rm]; + long rnv = (rn == 15) ? ppc : regs->uregs[rn]; + + /* Not following the C calling convention here, so need asm(). */ + __asm__ __volatile__ ( + "ldr r0, %[rn] \n\t" + "ldr r1, %[rm] \n\t" + "msr cpsr_fs, %[cpsr]\n\t" + "mov lr, pc \n\t" + "mov pc, %[i_fn] \n\t" + "str r0, %[rn] \n\t" /* in case of writeback */ + "str r2, %[rd0] \n\t" + "str r3, %[rd1] \n\t" + : [rn] "+m" (rnv), + [rd0] "=m" (regs->uregs[rd]), + [rd1] "=m" (regs->uregs[rd+1]) + : [rm] "m" (rmv), + [cpsr] "r" (regs->ARM_cpsr), + [i_fn] "r" (i_fn) + : "r0", "r1", "r2", "r3", "lr", "cc" + ); + if (is_writeback(insn)) + regs->uregs[rn] = rnv; +} + +static void __kprobes emulate_strd(struct kprobe *p, struct pt_regs *regs) +{ + insn_4arg_fn_t *i_fn = (insn_4arg_fn_t *)&p->ainsn.insn[0]; + kprobe_opcode_t insn = p->opcode; + long ppc = (long)p->addr + 8; + int rd = (insn >> 12) & 0xf; + int rn = (insn >> 16) & 0xf; + int rm = insn & 0xf; + long rnv = (rn == 15) ? ppc : regs->uregs[rn]; + /* rm/rmv may be invalid, don't care. */ + long rmv = (rm == 15) ? ppc : regs->uregs[rm]; + long rnv_wb; + + rnv_wb = insnslot_4arg_rflags(rnv, rmv, regs->uregs[rd], + regs->uregs[rd+1], + regs->ARM_cpsr, i_fn); + if (is_writeback(insn)) + regs->uregs[rn] = rnv_wb; +} + +static void __kprobes emulate_ldr(struct kprobe *p, struct pt_regs *regs) +{ + insn_llret_3arg_fn_t *i_fn = (insn_llret_3arg_fn_t *)&p->ainsn.insn[0]; + kprobe_opcode_t insn = p->opcode; + long ppc = (long)p->addr + 8; + union reg_pair fnr; + int rd = (insn >> 12) & 0xf; + int rn = (insn >> 16) & 0xf; + int rm = insn & 0xf; + long rdv; + long rnv = (rn == 15) ? ppc : regs->uregs[rn]; + long rmv = (rm == 15) ? ppc : regs->uregs[rm]; + long cpsr = regs->ARM_cpsr; + + fnr.dr = insnslot_llret_3arg_rflags(rnv, 0, rmv, cpsr, i_fn); + if (rn != 15) + regs->uregs[rn] = fnr.r0; /* Save Rn in case of writeback. */ + rdv = fnr.r1; + + if (rd == 15) { +#if __LINUX_ARM_ARCH__ >= 5 + cpsr &= ~PSR_T_BIT; + if (rdv & 0x1) + cpsr |= PSR_T_BIT; + regs->ARM_cpsr = cpsr; + rdv &= ~0x1; +#else + rdv &= ~0x2; +#endif + } + regs->uregs[rd] = rdv; +} + +static void __kprobes emulate_str(struct kprobe *p, struct pt_regs *regs) +{ + insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; + kprobe_opcode_t insn = p->opcode; + long iaddr = (long)p->addr; + int rd = (insn >> 12) & 0xf; + int rn = (insn >> 16) & 0xf; + int rm = insn & 0xf; + long rdv = (rd == 15) ? iaddr + str_pc_offset : regs->uregs[rd]; + long rnv = (rn == 15) ? iaddr + 8 : regs->uregs[rn]; + long rmv = regs->uregs[rm]; /* rm/rmv may be invalid, don't care. */ + long rnv_wb; + + rnv_wb = insnslot_3arg_rflags(rnv, rdv, rmv, regs->ARM_cpsr, i_fn); + if (rn != 15) + regs->uregs[rn] = rnv_wb; /* Save Rn in case of writeback. */ +} + +static void __kprobes emulate_sat(struct kprobe *p, struct pt_regs *regs) +{ + insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; + kprobe_opcode_t insn = p->opcode; + int rd = (insn >> 12) & 0xf; + int rm = insn & 0xf; + long rmv = regs->uregs[rm]; + + /* Writes Q flag */ + regs->uregs[rd] = insnslot_1arg_rwflags(rmv, ®s->ARM_cpsr, i_fn); +} + +static void __kprobes emulate_sel(struct kprobe *p, struct pt_regs *regs) +{ + insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; + kprobe_opcode_t insn = p->opcode; + int rd = (insn >> 12) & 0xf; + int rn = (insn >> 16) & 0xf; + int rm = insn & 0xf; + long rnv = regs->uregs[rn]; + long rmv = regs->uregs[rm]; + + /* Reads GE bits */ + regs->uregs[rd] = insnslot_2arg_rflags(rnv, rmv, regs->ARM_cpsr, i_fn); +} + +static void __kprobes emulate_none(struct kprobe *p, struct pt_regs *regs) +{ + insn_0arg_fn_t *i_fn = (insn_0arg_fn_t *)&p->ainsn.insn[0]; + + insnslot_0arg_rflags(regs->ARM_cpsr, i_fn); +} + +static void __kprobes emulate_nop(struct kprobe *p, struct pt_regs *regs) +{ +} + +static void __kprobes +emulate_rd12_modify(struct kprobe *p, struct pt_regs *regs) +{ + insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; + kprobe_opcode_t insn = p->opcode; + int rd = (insn >> 12) & 0xf; + long rdv = regs->uregs[rd]; + + regs->uregs[rd] = insnslot_1arg_rflags(rdv, regs->ARM_cpsr, i_fn); +} + +static void __kprobes +emulate_rd12rn0_modify(struct kprobe *p, struct pt_regs *regs) +{ + insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; + kprobe_opcode_t insn = p->opcode; + int rd = (insn >> 12) & 0xf; + int rn = insn & 0xf; + long rdv = regs->uregs[rd]; + long rnv = regs->uregs[rn]; + + regs->uregs[rd] = insnslot_2arg_rflags(rdv, rnv, regs->ARM_cpsr, i_fn); +} + +static void __kprobes emulate_rd12rm0(struct kprobe *p, struct pt_regs *regs) +{ + insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; + kprobe_opcode_t insn = p->opcode; + int rd = (insn >> 12) & 0xf; + int rm = insn & 0xf; + long rmv = regs->uregs[rm]; + + regs->uregs[rd] = insnslot_1arg_rflags(rmv, regs->ARM_cpsr, i_fn); +} + +static void __kprobes +emulate_rd12rn16rm0_rwflags(struct kprobe *p, struct pt_regs *regs) +{ + insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; + kprobe_opcode_t insn = p->opcode; + int rd = (insn >> 12) & 0xf; + int rn = (insn >> 16) & 0xf; + int rm = insn & 0xf; + long rnv = regs->uregs[rn]; + long rmv = regs->uregs[rm]; + + regs->uregs[rd] = + insnslot_2arg_rwflags(rnv, rmv, ®s->ARM_cpsr, i_fn); +} + +static void __kprobes +emulate_rd16rn12rs8rm0_rwflags(struct kprobe *p, struct pt_regs *regs) +{ + insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; + kprobe_opcode_t insn = p->opcode; + int rd = (insn >> 16) & 0xf; + int rn = (insn >> 12) & 0xf; + int rs = (insn >> 8) & 0xf; + int rm = insn & 0xf; + long rnv = regs->uregs[rn]; + long rsv = regs->uregs[rs]; + long rmv = regs->uregs[rm]; + + regs->uregs[rd] = + insnslot_3arg_rwflags(rnv, rsv, rmv, ®s->ARM_cpsr, i_fn); +} + +static void __kprobes +emulate_rd16rs8rm0_rwflags(struct kprobe *p, struct pt_regs *regs) +{ + insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; + kprobe_opcode_t insn = p->opcode; + int rd = (insn >> 16) & 0xf; + int rs = (insn >> 8) & 0xf; + int rm = insn & 0xf; + long rsv = regs->uregs[rs]; + long rmv = regs->uregs[rm]; + + regs->uregs[rd] = + insnslot_2arg_rwflags(rsv, rmv, ®s->ARM_cpsr, i_fn); +} + +static void __kprobes +emulate_rdhi16rdlo12rs8rm0_rwflags(struct kprobe *p, struct pt_regs *regs) +{ + insn_llret_4arg_fn_t *i_fn = (insn_llret_4arg_fn_t *)&p->ainsn.insn[0]; + kprobe_opcode_t insn = p->opcode; + union reg_pair fnr; + int rdhi = (insn >> 16) & 0xf; + int rdlo = (insn >> 12) & 0xf; + int rs = (insn >> 8) & 0xf; + int rm = insn & 0xf; + long rsv = regs->uregs[rs]; + long rmv = regs->uregs[rm]; + + fnr.dr = insnslot_llret_4arg_rwflags(regs->uregs[rdhi], + regs->uregs[rdlo], rsv, rmv, + ®s->ARM_cpsr, i_fn); + regs->uregs[rdhi] = fnr.r0; + regs->uregs[rdlo] = fnr.r1; +} + +static void __kprobes +emulate_alu_imm_rflags(struct kprobe *p, struct pt_regs *regs) +{ + insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; + kprobe_opcode_t insn = p->opcode; + int rd = (insn >> 12) & 0xf; + int rn = (insn >> 16) & 0xf; + long rnv = (rn == 15) ? (long)p->addr + 8 : regs->uregs[rn]; + + regs->uregs[rd] = insnslot_1arg_rflags(rnv, regs->ARM_cpsr, i_fn); +} + +static void __kprobes +emulate_alu_imm_rwflags(struct kprobe *p, struct pt_regs *regs) +{ + insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; + kprobe_opcode_t insn = p->opcode; + int rd = (insn >> 12) & 0xf; + int rn = (insn >> 16) & 0xf; + long rnv = (rn == 15) ? (long)p->addr + 8 : regs->uregs[rn]; + + regs->uregs[rd] = insnslot_1arg_rwflags(rnv, ®s->ARM_cpsr, i_fn); +} + +static void __kprobes +emulate_alu_tests_imm(struct kprobe *p, struct pt_regs *regs) +{ + insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; + kprobe_opcode_t insn = p->opcode; + int rn = (insn >> 16) & 0xf; + long rnv = (rn == 15) ? (long)p->addr + 8 : regs->uregs[rn]; + + insnslot_1arg_rwflags(rnv, ®s->ARM_cpsr, i_fn); +} + +static void __kprobes +emulate_alu_rflags(struct kprobe *p, struct pt_regs *regs) +{ + insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; + kprobe_opcode_t insn = p->opcode; + long ppc = (long)p->addr + 8; + int rd = (insn >> 12) & 0xf; + int rn = (insn >> 16) & 0xf; /* rn/rnv/rs/rsv may be */ + int rs = (insn >> 8) & 0xf; /* invalid, don't care. */ + int rm = insn & 0xf; + long rnv = (rn == 15) ? ppc : regs->uregs[rn]; + long rmv = (rm == 15) ? ppc : regs->uregs[rm]; + long rsv = regs->uregs[rs]; + + regs->uregs[rd] = + insnslot_3arg_rflags(rnv, rmv, rsv, regs->ARM_cpsr, i_fn); +} + +static void __kprobes +emulate_alu_rwflags(struct kprobe *p, struct pt_regs *regs) +{ + insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; + kprobe_opcode_t insn = p->opcode; + long ppc = (long)p->addr + 8; + int rd = (insn >> 12) & 0xf; + int rn = (insn >> 16) & 0xf; /* rn/rnv/rs/rsv may be */ + int rs = (insn >> 8) & 0xf; /* invalid, don't care. */ + int rm = insn & 0xf; + long rnv = (rn == 15) ? ppc : regs->uregs[rn]; + long rmv = (rm == 15) ? ppc : regs->uregs[rm]; + long rsv = regs->uregs[rs]; + + regs->uregs[rd] = + insnslot_3arg_rwflags(rnv, rmv, rsv, ®s->ARM_cpsr, i_fn); +} + +static void __kprobes +emulate_alu_tests(struct kprobe *p, struct pt_regs *regs) +{ + insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; + kprobe_opcode_t insn = p->opcode; + long ppc = (long)p->addr + 8; + int rn = (insn >> 16) & 0xf; + int rs = (insn >> 8) & 0xf; /* rs/rsv may be invalid, don't care. */ + int rm = insn & 0xf; + long rnv = (rn == 15) ? ppc : regs->uregs[rn]; + long rmv = (rm == 15) ? ppc : regs->uregs[rm]; + long rsv = regs->uregs[rs]; + + insnslot_3arg_rwflags(rnv, rmv, rsv, ®s->ARM_cpsr, i_fn); +} + +static enum kprobe_insn __kprobes +prep_emulate_ldr_str(kprobe_opcode_t insn, struct arch_specific_insn *asi) +{ + int not_imm = (insn & (1 << 26)) ? (insn & (1 << 25)) + : (~insn & (1 << 22)); + + if (is_writeback(insn) && is_r15(insn, 16)) + return INSN_REJECTED; /* Writeback to PC */ + + insn &= 0xfff00fff; + insn |= 0x00001000; /* Rn = r0, Rd = r1 */ + if (not_imm) { + insn &= ~0xf; + insn |= 2; /* Rm = r2 */ + } + asi->insn[0] = insn; + asi->insn_handler = (insn & (1 << 20)) ? emulate_ldr : emulate_str; + return INSN_GOOD; +} + +static enum kprobe_insn __kprobes +prep_emulate_rd12_modify(kprobe_opcode_t insn, struct arch_specific_insn *asi) +{ + if (is_r15(insn, 12)) + return INSN_REJECTED; /* Rd is PC */ + + insn &= 0xffff0fff; /* Rd = r0 */ + asi->insn[0] = insn; + asi->insn_handler = emulate_rd12_modify; + return INSN_GOOD; +} + +static enum kprobe_insn __kprobes +prep_emulate_rd12rn0_modify(kprobe_opcode_t insn, + struct arch_specific_insn *asi) +{ + if (is_r15(insn, 12)) + return INSN_REJECTED; /* Rd is PC */ + + insn &= 0xffff0ff0; /* Rd = r0 */ + insn |= 0x00000001; /* Rn = r1 */ + asi->insn[0] = insn; + asi->insn_handler = emulate_rd12rn0_modify; + return INSN_GOOD; +} + +static enum kprobe_insn __kprobes +prep_emulate_rd12rm0(kprobe_opcode_t insn, struct arch_specific_insn *asi) +{ + if (is_r15(insn, 12)) + return INSN_REJECTED; /* Rd is PC */ + + insn &= 0xffff0ff0; /* Rd = r0, Rm = r0 */ + asi->insn[0] = insn; + asi->insn_handler = emulate_rd12rm0; + return INSN_GOOD; +} + +static enum kprobe_insn __kprobes +prep_emulate_rd12rn16rm0_wflags(kprobe_opcode_t insn, + struct arch_specific_insn *asi) +{ + if (is_r15(insn, 12)) + return INSN_REJECTED; /* Rd is PC */ + + insn &= 0xfff00ff0; /* Rd = r0, Rn = r0 */ + insn |= 0x00000001; /* Rm = r1 */ + asi->insn[0] = insn; + asi->insn_handler = emulate_rd12rn16rm0_rwflags; + return INSN_GOOD; +} + +static enum kprobe_insn __kprobes +prep_emulate_rd16rs8rm0_wflags(kprobe_opcode_t insn, + struct arch_specific_insn *asi) +{ + if (is_r15(insn, 16)) + return INSN_REJECTED; /* Rd is PC */ + + insn &= 0xfff0f0f0; /* Rd = r0, Rs = r0 */ + insn |= 0x00000001; /* Rm = r1 */ + asi->insn[0] = insn; + asi->insn_handler = emulate_rd16rs8rm0_rwflags; + return INSN_GOOD; +} + +static enum kprobe_insn __kprobes +prep_emulate_rd16rn12rs8rm0_wflags(kprobe_opcode_t insn, + struct arch_specific_insn *asi) +{ + if (is_r15(insn, 16)) + return INSN_REJECTED; /* Rd is PC */ + + insn &= 0xfff000f0; /* Rd = r0, Rn = r0 */ + insn |= 0x00000102; /* Rs = r1, Rm = r2 */ + asi->insn[0] = insn; + asi->insn_handler = emulate_rd16rn12rs8rm0_rwflags; + return INSN_GOOD; +} + +static enum kprobe_insn __kprobes +prep_emulate_rdhi16rdlo12rs8rm0_wflags(kprobe_opcode_t insn, + struct arch_specific_insn *asi) +{ + if (is_r15(insn, 16) || is_r15(insn, 12)) + return INSN_REJECTED; /* RdHi or RdLo is PC */ + + insn &= 0xfff000f0; /* RdHi = r0, RdLo = r1 */ + insn |= 0x00001203; /* Rs = r2, Rm = r3 */ + asi->insn[0] = insn; + asi->insn_handler = emulate_rdhi16rdlo12rs8rm0_rwflags; + return INSN_GOOD; +} + +/* + * For the instruction masking and comparisons in all the "space_*" + * functions below, Do _not_ rearrange the order of tests unless + * you're very, very sure of what you are doing. For the sake of + * efficiency, the masks for some tests sometimes assume other test + * have been done prior to them so the number of patterns to test + * for an instruction set can be as broad as possible to reduce the + * number of tests needed. + */ + +static enum kprobe_insn __kprobes +space_1111(kprobe_opcode_t insn, struct arch_specific_insn *asi) +{ + /* memory hint : 1111 0100 x001 xxxx xxxx xxxx xxxx xxxx : */ + /* PLDI : 1111 0100 x101 xxxx xxxx xxxx xxxx xxxx : */ + /* PLDW : 1111 0101 x001 xxxx xxxx xxxx xxxx xxxx : */ + /* PLD : 1111 0101 x101 xxxx xxxx xxxx xxxx xxxx : */ + if ((insn & 0xfe300000) == 0xf4100000) { + asi->insn_handler = emulate_nop; + return INSN_GOOD_NO_SLOT; + } + + /* BLX(1) : 1111 101x xxxx xxxx xxxx xxxx xxxx xxxx : */ + if ((insn & 0xfe000000) == 0xfa000000) { + asi->insn_handler = simulate_blx1; + return INSN_GOOD_NO_SLOT; + } + + /* CPS : 1111 0001 0000 xxx0 xxxx xxxx xx0x xxxx */ + /* SETEND: 1111 0001 0000 0001 xxxx xxxx 0000 xxxx */ + + /* SRS : 1111 100x x1x0 xxxx xxxx xxxx xxxx xxxx */ + /* RFE : 1111 100x x0x1 xxxx xxxx xxxx xxxx xxxx */ + + /* Coprocessor instructions... */ + /* MCRR2 : 1111 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd != Rn) */ + /* MRRC2 : 1111 1100 0101 xxxx xxxx xxxx xxxx xxxx : (Rd != Rn) */ + /* LDC2 : 1111 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ + /* STC2 : 1111 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ + /* CDP2 : 1111 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ + /* MCR2 : 1111 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ + /* MRC2 : 1111 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ + + return INSN_REJECTED; +} + +static enum kprobe_insn __kprobes +space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) +{ + /* cccc 0001 0xx0 xxxx xxxx xxxx xxxx xxx0 xxxx */ + if ((insn & 0x0f900010) == 0x01000000) { + + /* MRS cpsr : cccc 0001 0000 xxxx xxxx xxxx 0000 xxxx */ + if ((insn & 0x0ff000f0) == 0x01000000) { + if (is_r15(insn, 12)) + return INSN_REJECTED; /* Rd is PC */ + asi->insn_handler = simulate_mrs; + return INSN_GOOD_NO_SLOT; + } + + /* SMLALxy : cccc 0001 0100 xxxx xxxx xxxx 1xx0 xxxx */ + if ((insn & 0x0ff00090) == 0x01400080) + return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, + asi); + + /* SMULWy : cccc 0001 0010 xxxx xxxx xxxx 1x10 xxxx */ + /* SMULxy : cccc 0001 0110 xxxx xxxx xxxx 1xx0 xxxx */ + if ((insn & 0x0ff000b0) == 0x012000a0 || + (insn & 0x0ff00090) == 0x01600080) + return prep_emulate_rd16rs8rm0_wflags(insn, asi); + + /* SMLAxy : cccc 0001 0000 xxxx xxxx xxxx 1xx0 xxxx : Q */ + /* SMLAWy : cccc 0001 0010 xxxx xxxx xxxx 1x00 xxxx : Q */ + if ((insn & 0x0ff00090) == 0x01000080 || + (insn & 0x0ff000b0) == 0x01200080) + return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); + + /* BXJ : cccc 0001 0010 xxxx xxxx xxxx 0010 xxxx */ + /* MSR : cccc 0001 0x10 xxxx xxxx xxxx 0000 xxxx */ + /* MRS spsr : cccc 0001 0100 xxxx xxxx xxxx 0000 xxxx */ + + /* Other instruction encodings aren't yet defined */ + return INSN_REJECTED; + } + + /* cccc 0001 0xx0 xxxx xxxx xxxx xxxx 0xx1 xxxx */ + else if ((insn & 0x0f900090) == 0x01000010) { + + /* BLX(2) : cccc 0001 0010 xxxx xxxx xxxx 0011 xxxx */ + /* BX : cccc 0001 0010 xxxx xxxx xxxx 0001 xxxx */ + if ((insn & 0x0ff000d0) == 0x01200010) { + if ((insn & 0x0ff000ff) == 0x0120003f) + return INSN_REJECTED; /* BLX pc */ + asi->insn_handler = simulate_blx2bx; + return INSN_GOOD_NO_SLOT; + } + + /* CLZ : cccc 0001 0110 xxxx xxxx xxxx 0001 xxxx */ + if ((insn & 0x0ff000f0) == 0x01600010) + return prep_emulate_rd12rm0(insn, asi); + + /* QADD : cccc 0001 0000 xxxx xxxx xxxx 0101 xxxx :Q */ + /* QSUB : cccc 0001 0010 xxxx xxxx xxxx 0101 xxxx :Q */ + /* QDADD : cccc 0001 0100 xxxx xxxx xxxx 0101 xxxx :Q */ + /* QDSUB : cccc 0001 0110 xxxx xxxx xxxx 0101 xxxx :Q */ + if ((insn & 0x0f9000f0) == 0x01000050) + return prep_emulate_rd12rn16rm0_wflags(insn, asi); + + /* BKPT : 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */ + /* SMC : cccc 0001 0110 xxxx xxxx xxxx 0111 xxxx */ + + /* Other instruction encodings aren't yet defined */ + return INSN_REJECTED; + } + + /* cccc 0000 xxxx xxxx xxxx xxxx xxxx 1001 xxxx */ + else if ((insn & 0x0f0000f0) == 0x00000090) { + + /* MUL : cccc 0000 0000 xxxx xxxx xxxx 1001 xxxx : */ + /* MULS : cccc 0000 0001 xxxx xxxx xxxx 1001 xxxx :cc */ + /* MLA : cccc 0000 0010 xxxx xxxx xxxx 1001 xxxx : */ + /* MLAS : cccc 0000 0011 xxxx xxxx xxxx 1001 xxxx :cc */ + /* UMAAL : cccc 0000 0100 xxxx xxxx xxxx 1001 xxxx : */ + /* undef : cccc 0000 0101 xxxx xxxx xxxx 1001 xxxx : */ + /* MLS : cccc 0000 0110 xxxx xxxx xxxx 1001 xxxx : */ + /* undef : cccc 0000 0111 xxxx xxxx xxxx 1001 xxxx : */ + /* UMULL : cccc 0000 1000 xxxx xxxx xxxx 1001 xxxx : */ + /* UMULLS : cccc 0000 1001 xxxx xxxx xxxx 1001 xxxx :cc */ + /* UMLAL : cccc 0000 1010 xxxx xxxx xxxx 1001 xxxx : */ + /* UMLALS : cccc 0000 1011 xxxx xxxx xxxx 1001 xxxx :cc */ + /* SMULL : cccc 0000 1100 xxxx xxxx xxxx 1001 xxxx : */ + /* SMULLS : cccc 0000 1101 xxxx xxxx xxxx 1001 xxxx :cc */ + /* SMLAL : cccc 0000 1110 xxxx xxxx xxxx 1001 xxxx : */ + /* SMLALS : cccc 0000 1111 xxxx xxxx xxxx 1001 xxxx :cc */ + if ((insn & 0x00d00000) == 0x00500000) + return INSN_REJECTED; + else if ((insn & 0x00e00000) == 0x00000000) + return prep_emulate_rd16rs8rm0_wflags(insn, asi); + else if ((insn & 0x00a00000) == 0x00200000) + return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); + else + return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, + asi); + } + + /* cccc 000x xxxx xxxx xxxx xxxx xxxx 1xx1 xxxx */ + else if ((insn & 0x0e000090) == 0x00000090) { + + /* SWP : cccc 0001 0000 xxxx xxxx xxxx 1001 xxxx */ + /* SWPB : cccc 0001 0100 xxxx xxxx xxxx 1001 xxxx */ + /* ??? : cccc 0001 0x01 xxxx xxxx xxxx 1001 xxxx */ + /* ??? : cccc 0001 0x10 xxxx xxxx xxxx 1001 xxxx */ + /* ??? : cccc 0001 0x11 xxxx xxxx xxxx 1001 xxxx */ + /* STREX : cccc 0001 1000 xxxx xxxx xxxx 1001 xxxx */ + /* LDREX : cccc 0001 1001 xxxx xxxx xxxx 1001 xxxx */ + /* STREXD: cccc 0001 1010 xxxx xxxx xxxx 1001 xxxx */ + /* LDREXD: cccc 0001 1011 xxxx xxxx xxxx 1001 xxxx */ + /* STREXB: cccc 0001 1100 xxxx xxxx xxxx 1001 xxxx */ + /* LDREXB: cccc 0001 1101 xxxx xxxx xxxx 1001 xxxx */ + /* STREXH: cccc 0001 1110 xxxx xxxx xxxx 1001 xxxx */ + /* LDREXH: cccc 0001 1111 xxxx xxxx xxxx 1001 xxxx */ + + /* LDRD : cccc 000x xxx0 xxxx xxxx xxxx 1101 xxxx */ + /* STRD : cccc 000x xxx0 xxxx xxxx xxxx 1111 xxxx */ + /* LDRH : cccc 000x xxx1 xxxx xxxx xxxx 1011 xxxx */ + /* STRH : cccc 000x xxx0 xxxx xxxx xxxx 1011 xxxx */ + /* LDRSB : cccc 000x xxx1 xxxx xxxx xxxx 1101 xxxx */ + /* LDRSH : cccc 000x xxx1 xxxx xxxx xxxx 1111 xxxx */ + if ((insn & 0x0f0000f0) == 0x01000090) { + if ((insn & 0x0fb000f0) == 0x01000090) { + /* SWP/SWPB */ + return prep_emulate_rd12rn16rm0_wflags(insn, + asi); + } else { + /* STREX/LDREX variants and unallocaed space */ + return INSN_REJECTED; + } + + } else if ((insn & 0x0e1000d0) == 0x00000d0) { + /* STRD/LDRD */ + if ((insn & 0x0000e000) == 0x0000e000) + return INSN_REJECTED; /* Rd is LR or PC */ + if (is_writeback(insn) && is_r15(insn, 16)) + return INSN_REJECTED; /* Writeback to PC */ + + insn &= 0xfff00fff; + insn |= 0x00002000; /* Rn = r0, Rd = r2 */ + if (!(insn & (1 << 22))) { + /* Register index */ + insn &= ~0xf; + insn |= 1; /* Rm = r1 */ + } + asi->insn[0] = insn; + asi->insn_handler = + (insn & (1 << 5)) ? emulate_strd : emulate_ldrd; + return INSN_GOOD; + } + + /* LDRH/STRH/LDRSB/LDRSH */ + if (is_r15(insn, 12)) + return INSN_REJECTED; /* Rd is PC */ + return prep_emulate_ldr_str(insn, asi); + } + + /* cccc 000x xxxx xxxx xxxx xxxx xxxx xxxx xxxx */ + + /* + * ALU op with S bit and Rd == 15 : + * cccc 000x xxx1 xxxx 1111 xxxx xxxx xxxx + */ + if ((insn & 0x0e10f000) == 0x0010f000) + return INSN_REJECTED; + + /* + * "mov ip, sp" is the most common kprobe'd instruction by far. + * Check and optimize for it explicitly. + */ + if (insn == 0xe1a0c00d) { + asi->insn_handler = simulate_mov_ipsp; + return INSN_GOOD_NO_SLOT; + } + + /* + * Data processing: Immediate-shift / Register-shift + * ALU op : cccc 000x xxxx xxxx xxxx xxxx xxxx xxxx + * CPY : cccc 0001 1010 xxxx xxxx 0000 0000 xxxx + * MOV : cccc 0001 101x xxxx xxxx xxxx xxxx xxxx + * *S (bit 20) updates condition codes + * ADC/SBC/RSC reads the C flag + */ + insn &= 0xfff00ff0; /* Rn = r0, Rd = r0 */ + insn |= 0x00000001; /* Rm = r1 */ + if (insn & 0x010) { + insn &= 0xfffff0ff; /* register shift */ + insn |= 0x00000200; /* Rs = r2 */ + } + asi->insn[0] = insn; + + if ((insn & 0x0f900000) == 0x01100000) { + /* + * TST : cccc 0001 0001 xxxx xxxx xxxx xxxx xxxx + * TEQ : cccc 0001 0011 xxxx xxxx xxxx xxxx xxxx + * CMP : cccc 0001 0101 xxxx xxxx xxxx xxxx xxxx + * CMN : cccc 0001 0111 xxxx xxxx xxxx xxxx xxxx + */ + asi->insn_handler = emulate_alu_tests; + } else { + /* ALU ops which write to Rd */ + asi->insn_handler = (insn & (1 << 20)) ? /* S-bit */ + emulate_alu_rwflags : emulate_alu_rflags; + } + return INSN_GOOD; +} + +static enum kprobe_insn __kprobes +space_cccc_001x(kprobe_opcode_t insn, struct arch_specific_insn *asi) +{ + /* MOVW : cccc 0011 0000 xxxx xxxx xxxx xxxx xxxx */ + /* MOVT : cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx */ + if ((insn & 0x0fb00000) == 0x03000000) + return prep_emulate_rd12_modify(insn, asi); + + /* hints : cccc 0011 0010 0000 xxxx xxxx xxxx xxxx */ + if ((insn & 0x0fff0000) == 0x03200000) { + unsigned op2 = insn & 0x000000ff; + if (op2 == 0x01 || op2 == 0x04) { + /* YIELD : cccc 0011 0010 0000 xxxx xxxx 0000 0001 */ + /* SEV : cccc 0011 0010 0000 xxxx xxxx 0000 0100 */ + asi->insn[0] = insn; + asi->insn_handler = emulate_none; + return INSN_GOOD; + } else if (op2 <= 0x03) { + /* NOP : cccc 0011 0010 0000 xxxx xxxx 0000 0000 */ + /* WFE : cccc 0011 0010 0000 xxxx xxxx 0000 0010 */ + /* WFI : cccc 0011 0010 0000 xxxx xxxx 0000 0011 */ + /* + * We make WFE and WFI true NOPs to avoid stalls due + * to missing events whilst processing the probe. + */ + asi->insn_handler = emulate_nop; + return INSN_GOOD_NO_SLOT; + } + /* For DBG and unallocated hints it's safest to reject them */ + return INSN_REJECTED; + } + + /* + * MSR : cccc 0011 0x10 xxxx xxxx xxxx xxxx xxxx + * ALU op with S bit and Rd == 15 : + * cccc 001x xxx1 xxxx 1111 xxxx xxxx xxxx + */ + if ((insn & 0x0fb00000) == 0x03200000 || /* MSR */ + (insn & 0x0e10f000) == 0x0210f000) /* ALU s-bit, R15 */ + return INSN_REJECTED; + + /* + * Data processing: 32-bit Immediate + * ALU op : cccc 001x xxxx xxxx xxxx xxxx xxxx xxxx + * MOV : cccc 0011 101x xxxx xxxx xxxx xxxx xxxx + * *S (bit 20) updates condition codes + * ADC/SBC/RSC reads the C flag + */ + insn &= 0xfff00fff; /* Rn = r0 and Rd = r0 */ + asi->insn[0] = insn; + + if ((insn & 0x0f900000) == 0x03100000) { + /* + * TST : cccc 0011 0001 xxxx xxxx xxxx xxxx xxxx + * TEQ : cccc 0011 0011 xxxx xxxx xxxx xxxx xxxx + * CMP : cccc 0011 0101 xxxx xxxx xxxx xxxx xxxx + * CMN : cccc 0011 0111 xxxx xxxx xxxx xxxx xxxx + */ + asi->insn_handler = emulate_alu_tests_imm; + } else { + /* ALU ops which write to Rd */ + asi->insn_handler = (insn & (1 << 20)) ? /* S-bit */ + emulate_alu_imm_rwflags : emulate_alu_imm_rflags; + } + return INSN_GOOD; +} + +static enum kprobe_insn __kprobes +space_cccc_0110__1(kprobe_opcode_t insn, struct arch_specific_insn *asi) +{ + /* SEL : cccc 0110 1000 xxxx xxxx xxxx 1011 xxxx GE: !!! */ + if ((insn & 0x0ff000f0) == 0x068000b0) { + if (is_r15(insn, 12)) + return INSN_REJECTED; /* Rd is PC */ + insn &= 0xfff00ff0; /* Rd = r0, Rn = r0 */ + insn |= 0x00000001; /* Rm = r1 */ + asi->insn[0] = insn; + asi->insn_handler = emulate_sel; + return INSN_GOOD; + } + + /* SSAT : cccc 0110 101x xxxx xxxx xxxx xx01 xxxx :Q */ + /* USAT : cccc 0110 111x xxxx xxxx xxxx xx01 xxxx :Q */ + /* SSAT16 : cccc 0110 1010 xxxx xxxx xxxx 0011 xxxx :Q */ + /* USAT16 : cccc 0110 1110 xxxx xxxx xxxx 0011 xxxx :Q */ + if ((insn & 0x0fa00030) == 0x06a00010 || + (insn & 0x0fb000f0) == 0x06a00030) { + if (is_r15(insn, 12)) + return INSN_REJECTED; /* Rd is PC */ + insn &= 0xffff0ff0; /* Rd = r0, Rm = r0 */ + asi->insn[0] = insn; + asi->insn_handler = emulate_sat; + return INSN_GOOD; + } + + /* REV : cccc 0110 1011 xxxx xxxx xxxx 0011 xxxx */ + /* REV16 : cccc 0110 1011 xxxx xxxx xxxx 1011 xxxx */ + /* RBIT : cccc 0110 1111 xxxx xxxx xxxx 0011 xxxx */ + /* REVSH : cccc 0110 1111 xxxx xxxx xxxx 1011 xxxx */ + if ((insn & 0x0ff00070) == 0x06b00030 || + (insn & 0x0ff00070) == 0x06f00030) + return prep_emulate_rd12rm0(insn, asi); + + /* ??? : cccc 0110 0000 xxxx xxxx xxxx xxx1 xxxx : */ + /* SADD16 : cccc 0110 0001 xxxx xxxx xxxx 0001 xxxx :GE */ + /* SADDSUBX : cccc 0110 0001 xxxx xxxx xxxx 0011 xxxx :GE */ + /* SSUBADDX : cccc 0110 0001 xxxx xxxx xxxx 0101 xxxx :GE */ + /* SSUB16 : cccc 0110 0001 xxxx xxxx xxxx 0111 xxxx :GE */ + /* SADD8 : cccc 0110 0001 xxxx xxxx xxxx 1001 xxxx :GE */ + /* ??? : cccc 0110 0001 xxxx xxxx xxxx 1011 xxxx : */ + /* ??? : cccc 0110 0001 xxxx xxxx xxxx 1101 xxxx : */ + /* SSUB8 : cccc 0110 0001 xxxx xxxx xxxx 1111 xxxx :GE */ + /* QADD16 : cccc 0110 0010 xxxx xxxx xxxx 0001 xxxx : */ + /* QADDSUBX : cccc 0110 0010 xxxx xxxx xxxx 0011 xxxx : */ + /* QSUBADDX : cccc 0110 0010 xxxx xxxx xxxx 0101 xxxx : */ + /* QSUB16 : cccc 0110 0010 xxxx xxxx xxxx 0111 xxxx : */ + /* QADD8 : cccc 0110 0010 xxxx xxxx xxxx 1001 xxxx : */ + /* ??? : cccc 0110 0010 xxxx xxxx xxxx 1011 xxxx : */ + /* ??? : cccc 0110 0010 xxxx xxxx xxxx 1101 xxxx : */ + /* QSUB8 : cccc 0110 0010 xxxx xxxx xxxx 1111 xxxx : */ + /* SHADD16 : cccc 0110 0011 xxxx xxxx xxxx 0001 xxxx : */ + /* SHADDSUBX : cccc 0110 0011 xxxx xxxx xxxx 0011 xxxx : */ + /* SHSUBADDX : cccc 0110 0011 xxxx xxxx xxxx 0101 xxxx : */ + /* SHSUB16 : cccc 0110 0011 xxxx xxxx xxxx 0111 xxxx : */ + /* SHADD8 : cccc 0110 0011 xxxx xxxx xxxx 1001 xxxx : */ + /* ??? : cccc 0110 0011 xxxx xxxx xxxx 1011 xxxx : */ + /* ??? : cccc 0110 0011 xxxx xxxx xxxx 1101 xxxx : */ + /* SHSUB8 : cccc 0110 0011 xxxx xxxx xxxx 1111 xxxx : */ + /* ??? : cccc 0110 0100 xxxx xxxx xxxx xxx1 xxxx : */ + /* UADD16 : cccc 0110 0101 xxxx xxxx xxxx 0001 xxxx :GE */ + /* UADDSUBX : cccc 0110 0101 xxxx xxxx xxxx 0011 xxxx :GE */ + /* USUBADDX : cccc 0110 0101 xxxx xxxx xxxx 0101 xxxx :GE */ + /* USUB16 : cccc 0110 0101 xxxx xxxx xxxx 0111 xxxx :GE */ + /* UADD8 : cccc 0110 0101 xxxx xxxx xxxx 1001 xxxx :GE */ + /* ??? : cccc 0110 0101 xxxx xxxx xxxx 1011 xxxx : */ + /* ??? : cccc 0110 0101 xxxx xxxx xxxx 1101 xxxx : */ + /* USUB8 : cccc 0110 0101 xxxx xxxx xxxx 1111 xxxx :GE */ + /* UQADD16 : cccc 0110 0110 xxxx xxxx xxxx 0001 xxxx : */ + /* UQADDSUBX : cccc 0110 0110 xxxx xxxx xxxx 0011 xxxx : */ + /* UQSUBADDX : cccc 0110 0110 xxxx xxxx xxxx 0101 xxxx : */ + /* UQSUB16 : cccc 0110 0110 xxxx xxxx xxxx 0111 xxxx : */ + /* UQADD8 : cccc 0110 0110 xxxx xxxx xxxx 1001 xxxx : */ + /* ??? : cccc 0110 0110 xxxx xxxx xxxx 1011 xxxx : */ + /* ??? : cccc 0110 0110 xxxx xxxx xxxx 1101 xxxx : */ + /* UQSUB8 : cccc 0110 0110 xxxx xxxx xxxx 1111 xxxx : */ + /* UHADD16 : cccc 0110 0111 xxxx xxxx xxxx 0001 xxxx : */ + /* UHADDSUBX : cccc 0110 0111 xxxx xxxx xxxx 0011 xxxx : */ + /* UHSUBADDX : cccc 0110 0111 xxxx xxxx xxxx 0101 xxxx : */ + /* UHSUB16 : cccc 0110 0111 xxxx xxxx xxxx 0111 xxxx : */ + /* UHADD8 : cccc 0110 0111 xxxx xxxx xxxx 1001 xxxx : */ + /* ??? : cccc 0110 0111 xxxx xxxx xxxx 1011 xxxx : */ + /* ??? : cccc 0110 0111 xxxx xxxx xxxx 1101 xxxx : */ + /* UHSUB8 : cccc 0110 0111 xxxx xxxx xxxx 1111 xxxx : */ + if ((insn & 0x0f800010) == 0x06000010) { + if ((insn & 0x00300000) == 0x00000000 || + (insn & 0x000000e0) == 0x000000a0 || + (insn & 0x000000e0) == 0x000000c0) + return INSN_REJECTED; /* Unallocated space */ + return prep_emulate_rd12rn16rm0_wflags(insn, asi); + } + + /* PKHBT : cccc 0110 1000 xxxx xxxx xxxx x001 xxxx : */ + /* PKHTB : cccc 0110 1000 xxxx xxxx xxxx x101 xxxx : */ + if ((insn & 0x0ff00030) == 0x06800010) + return prep_emulate_rd12rn16rm0_wflags(insn, asi); + + /* SXTAB16 : cccc 0110 1000 xxxx xxxx xxxx 0111 xxxx : */ + /* SXTB16 : cccc 0110 1000 1111 xxxx xxxx 0111 xxxx : */ + /* ??? : cccc 0110 1001 xxxx xxxx xxxx 0111 xxxx : */ + /* SXTAB : cccc 0110 1010 xxxx xxxx xxxx 0111 xxxx : */ + /* SXTB : cccc 0110 1010 1111 xxxx xxxx 0111 xxxx : */ + /* SXTAH : cccc 0110 1011 xxxx xxxx xxxx 0111 xxxx : */ + /* SXTH : cccc 0110 1011 1111 xxxx xxxx 0111 xxxx : */ + /* UXTAB16 : cccc 0110 1100 xxxx xxxx xxxx 0111 xxxx : */ + /* UXTB16 : cccc 0110 1100 1111 xxxx xxxx 0111 xxxx : */ + /* ??? : cccc 0110 1101 xxxx xxxx xxxx 0111 xxxx : */ + /* UXTAB : cccc 0110 1110 xxxx xxxx xxxx 0111 xxxx : */ + /* UXTB : cccc 0110 1110 1111 xxxx xxxx 0111 xxxx : */ + /* UXTAH : cccc 0110 1111 xxxx xxxx xxxx 0111 xxxx : */ + /* UXTH : cccc 0110 1111 1111 xxxx xxxx 0111 xxxx : */ + if ((insn & 0x0f8000f0) == 0x06800070) { + if ((insn & 0x00300000) == 0x00100000) + return INSN_REJECTED; /* Unallocated space */ + + if ((insn & 0x000f0000) == 0x000f0000) + return prep_emulate_rd12rm0(insn, asi); + else + return prep_emulate_rd12rn16rm0_wflags(insn, asi); + } + + /* Other instruction encodings aren't yet defined */ + return INSN_REJECTED; +} + +static enum kprobe_insn __kprobes +space_cccc_0111__1(kprobe_opcode_t insn, struct arch_specific_insn *asi) +{ + /* Undef : cccc 0111 1111 xxxx xxxx xxxx 1111 xxxx */ + if ((insn & 0x0ff000f0) == 0x03f000f0) + return INSN_REJECTED; + + /* SMLALD : cccc 0111 0100 xxxx xxxx xxxx 00x1 xxxx */ + /* SMLSLD : cccc 0111 0100 xxxx xxxx xxxx 01x1 xxxx */ + if ((insn & 0x0ff00090) == 0x07400010) + return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, asi); + + /* SMLAD : cccc 0111 0000 xxxx xxxx xxxx 00x1 xxxx :Q */ + /* SMUAD : cccc 0111 0000 xxxx 1111 xxxx 00x1 xxxx :Q */ + /* SMLSD : cccc 0111 0000 xxxx xxxx xxxx 01x1 xxxx :Q */ + /* SMUSD : cccc 0111 0000 xxxx 1111 xxxx 01x1 xxxx : */ + /* SMMLA : cccc 0111 0101 xxxx xxxx xxxx 00x1 xxxx : */ + /* SMMUL : cccc 0111 0101 xxxx 1111 xxxx 00x1 xxxx : */ + /* USADA8 : cccc 0111 1000 xxxx xxxx xxxx 0001 xxxx : */ + /* USAD8 : cccc 0111 1000 xxxx 1111 xxxx 0001 xxxx : */ + if ((insn & 0x0ff00090) == 0x07000010 || + (insn & 0x0ff000d0) == 0x07500010 || + (insn & 0x0ff000f0) == 0x07800010) { + + if ((insn & 0x0000f000) == 0x0000f000) + return prep_emulate_rd16rs8rm0_wflags(insn, asi); + else + return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); + } + + /* SMMLS : cccc 0111 0101 xxxx xxxx xxxx 11x1 xxxx : */ + if ((insn & 0x0ff000d0) == 0x075000d0) + return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); + + /* SBFX : cccc 0111 101x xxxx xxxx xxxx x101 xxxx : */ + /* UBFX : cccc 0111 111x xxxx xxxx xxxx x101 xxxx : */ + if ((insn & 0x0fa00070) == 0x07a00050) + return prep_emulate_rd12rm0(insn, asi); + + /* BFI : cccc 0111 110x xxxx xxxx xxxx x001 xxxx : */ + /* BFC : cccc 0111 110x xxxx xxxx xxxx x001 1111 : */ + if ((insn & 0x0fe00070) == 0x07c00010) { + + if ((insn & 0x0000000f) == 0x0000000f) + return prep_emulate_rd12_modify(insn, asi); + else + return prep_emulate_rd12rn0_modify(insn, asi); + } + + return INSN_REJECTED; +} + +static enum kprobe_insn __kprobes +space_cccc_01xx(kprobe_opcode_t insn, struct arch_specific_insn *asi) +{ + /* LDR : cccc 01xx x0x1 xxxx xxxx xxxx xxxx xxxx */ + /* LDRB : cccc 01xx x1x1 xxxx xxxx xxxx xxxx xxxx */ + /* LDRBT : cccc 01x0 x111 xxxx xxxx xxxx xxxx xxxx */ + /* LDRT : cccc 01x0 x011 xxxx xxxx xxxx xxxx xxxx */ + /* STR : cccc 01xx x0x0 xxxx xxxx xxxx xxxx xxxx */ + /* STRB : cccc 01xx x1x0 xxxx xxxx xxxx xxxx xxxx */ + /* STRBT : cccc 01x0 x110 xxxx xxxx xxxx xxxx xxxx */ + /* STRT : cccc 01x0 x010 xxxx xxxx xxxx xxxx xxxx */ + + if ((insn & 0x00500000) == 0x00500000 && is_r15(insn, 12)) + return INSN_REJECTED; /* LDRB into PC */ + + return prep_emulate_ldr_str(insn, asi); +} + +static enum kprobe_insn __kprobes +space_cccc_100x(kprobe_opcode_t insn, struct arch_specific_insn *asi) +{ + /* LDM(2) : cccc 100x x101 xxxx 0xxx xxxx xxxx xxxx */ + /* LDM(3) : cccc 100x x1x1 xxxx 1xxx xxxx xxxx xxxx */ + if ((insn & 0x0e708000) == 0x85000000 || + (insn & 0x0e508000) == 0x85010000) + return INSN_REJECTED; + + /* LDM(1) : cccc 100x x0x1 xxxx xxxx xxxx xxxx xxxx */ + /* STM(1) : cccc 100x x0x0 xxxx xxxx xxxx xxxx xxxx */ + asi->insn_handler = ((insn & 0x108000) == 0x008000) ? /* STM & R15 */ + simulate_stm1_pc : simulate_ldm1stm1; + return INSN_GOOD_NO_SLOT; +} + +static enum kprobe_insn __kprobes +space_cccc_101x(kprobe_opcode_t insn, struct arch_specific_insn *asi) +{ + /* B : cccc 1010 xxxx xxxx xxxx xxxx xxxx xxxx */ + /* BL : cccc 1011 xxxx xxxx xxxx xxxx xxxx xxxx */ + asi->insn_handler = simulate_bbl; + return INSN_GOOD_NO_SLOT; +} + +static enum kprobe_insn __kprobes +space_cccc_11xx(kprobe_opcode_t insn, struct arch_specific_insn *asi) +{ + /* Coprocessor instructions... */ + /* MCRR : cccc 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */ + /* MRRC : cccc 1100 0101 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */ + /* LDC : cccc 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ + /* STC : cccc 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ + /* CDP : cccc 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ + /* MCR : cccc 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ + /* MRC : cccc 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ + + /* SVC : cccc 1111 xxxx xxxx xxxx xxxx xxxx xxxx */ + + return INSN_REJECTED; +} + +static unsigned long __kprobes __check_eq(unsigned long cpsr) +{ + return cpsr & PSR_Z_BIT; +} + +static unsigned long __kprobes __check_ne(unsigned long cpsr) +{ + return (~cpsr) & PSR_Z_BIT; +} + +static unsigned long __kprobes __check_cs(unsigned long cpsr) +{ + return cpsr & PSR_C_BIT; +} + +static unsigned long __kprobes __check_cc(unsigned long cpsr) +{ + return (~cpsr) & PSR_C_BIT; +} + +static unsigned long __kprobes __check_mi(unsigned long cpsr) +{ + return cpsr & PSR_N_BIT; +} + +static unsigned long __kprobes __check_pl(unsigned long cpsr) +{ + return (~cpsr) & PSR_N_BIT; +} + +static unsigned long __kprobes __check_vs(unsigned long cpsr) +{ + return cpsr & PSR_V_BIT; +} + +static unsigned long __kprobes __check_vc(unsigned long cpsr) +{ + return (~cpsr) & PSR_V_BIT; +} + +static unsigned long __kprobes __check_hi(unsigned long cpsr) +{ + cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */ + return cpsr & PSR_C_BIT; +} + +static unsigned long __kprobes __check_ls(unsigned long cpsr) +{ + cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */ + return (~cpsr) & PSR_C_BIT; +} + +static unsigned long __kprobes __check_ge(unsigned long cpsr) +{ + cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ + return (~cpsr) & PSR_N_BIT; +} + +static unsigned long __kprobes __check_lt(unsigned long cpsr) +{ + cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ + return cpsr & PSR_N_BIT; +} + +static unsigned long __kprobes __check_gt(unsigned long cpsr) +{ + unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ + temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */ + return (~temp) & PSR_N_BIT; +} + +static unsigned long __kprobes __check_le(unsigned long cpsr) +{ + unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ + temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */ + return temp & PSR_N_BIT; +} + +static unsigned long __kprobes __check_al(unsigned long cpsr) +{ + return true; +} + +static kprobe_check_cc * const condition_checks[16] = { + &__check_eq, &__check_ne, &__check_cs, &__check_cc, + &__check_mi, &__check_pl, &__check_vs, &__check_vc, + &__check_hi, &__check_ls, &__check_ge, &__check_lt, + &__check_gt, &__check_le, &__check_al, &__check_al +}; + +/* Return: + * INSN_REJECTED If instruction is one not allowed to kprobe, + * INSN_GOOD If instruction is supported and uses instruction slot, + * INSN_GOOD_NO_SLOT If instruction is supported but doesn't use its slot. + * + * For instructions we don't want to kprobe (INSN_REJECTED return result): + * These are generally ones that modify the processor state making + * them "hard" to simulate such as switches processor modes or + * make accesses in alternate modes. Any of these could be simulated + * if the work was put into it, but low return considering they + * should also be very rare. + */ +enum kprobe_insn __kprobes +arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) +{ + asi->insn_check_cc = condition_checks[insn>>28]; + asi->insn[1] = KPROBE_RETURN_INSTRUCTION; + + if ((insn & 0xf0000000) == 0xf0000000) + + return space_1111(insn, asi); + + else if ((insn & 0x0e000000) == 0x00000000) + + return space_cccc_000x(insn, asi); + + else if ((insn & 0x0e000000) == 0x02000000) + + return space_cccc_001x(insn, asi); + + else if ((insn & 0x0f000010) == 0x06000010) + + return space_cccc_0110__1(insn, asi); + + else if ((insn & 0x0f000010) == 0x07000010) + + return space_cccc_0111__1(insn, asi); + + else if ((insn & 0x0c000000) == 0x04000000) + + return space_cccc_01xx(insn, asi); + + else if ((insn & 0x0e000000) == 0x08000000) + + return space_cccc_100x(insn, asi); + + else if ((insn & 0x0e000000) == 0x0a000000) + + return space_cccc_101x(insn, asi); + + return space_cccc_11xx(insn, asi); +} + +void __init arm_kprobe_decode_init(void) +{ + find_str_pc_offset(); +} diff --git a/trunk/arch/arm/kernel/kprobes-thumb.c b/trunk/arch/arm/kernel/kprobes-thumb.c deleted file mode 100644 index 902ca59e8b11..000000000000 --- a/trunk/arch/arm/kernel/kprobes-thumb.c +++ /dev/null @@ -1,1462 +0,0 @@ -/* - * arch/arm/kernel/kprobes-thumb.c - * - * Copyright (C) 2011 Jon Medhurst . - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include - -#include "kprobes.h" - - -/* - * True if current instruction is in an IT block. - */ -#define in_it_block(cpsr) ((cpsr & 0x06000c00) != 0x00000000) - -/* - * Return the condition code to check for the currently executing instruction. - * This is in ITSTATE<7:4> which is in CPSR<15:12> but is only valid if - * in_it_block returns true. - */ -#define current_cond(cpsr) ((cpsr >> 12) & 0xf) - -/* - * Return the PC value for a probe in thumb code. - * This is the address of the probed instruction plus 4. - * We subtract one because the address will have bit zero set to indicate - * a pointer to thumb code. - */ -static inline unsigned long __kprobes thumb_probe_pc(struct kprobe *p) -{ - return (unsigned long)p->addr - 1 + 4; -} - -static void __kprobes -t32_simulate_table_branch(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - unsigned long pc = thumb_probe_pc(p); - int rn = (insn >> 16) & 0xf; - int rm = insn & 0xf; - - unsigned long rnv = (rn == 15) ? pc : regs->uregs[rn]; - unsigned long rmv = regs->uregs[rm]; - unsigned int halfwords; - - if (insn & 0x10) /* TBH */ - halfwords = ((u16 *)rnv)[rmv]; - else /* TBB */ - halfwords = ((u8 *)rnv)[rmv]; - - regs->ARM_pc = pc + 2 * halfwords; -} - -static void __kprobes -t32_simulate_mrs(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - int rd = (insn >> 8) & 0xf; - unsigned long mask = 0xf8ff03df; /* Mask out execution state */ - regs->uregs[rd] = regs->ARM_cpsr & mask; -} - -static void __kprobes -t32_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - unsigned long pc = thumb_probe_pc(p); - - long offset = insn & 0x7ff; /* imm11 */ - offset += (insn & 0x003f0000) >> 5; /* imm6 */ - offset += (insn & 0x00002000) << 4; /* J1 */ - offset += (insn & 0x00000800) << 7; /* J2 */ - offset -= (insn & 0x04000000) >> 7; /* Apply sign bit */ - - regs->ARM_pc = pc + (offset * 2); -} - -static enum kprobe_insn __kprobes -t32_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi) -{ - int cc = (insn >> 22) & 0xf; - asi->insn_check_cc = kprobe_condition_checks[cc]; - asi->insn_handler = t32_simulate_cond_branch; - return INSN_GOOD_NO_SLOT; -} - -static void __kprobes -t32_simulate_branch(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - unsigned long pc = thumb_probe_pc(p); - - long offset = insn & 0x7ff; /* imm11 */ - offset += (insn & 0x03ff0000) >> 5; /* imm10 */ - offset += (insn & 0x00002000) << 9; /* J1 */ - offset += (insn & 0x00000800) << 10; /* J2 */ - if (insn & 0x04000000) - offset -= 0x00800000; /* Apply sign bit */ - else - offset ^= 0x00600000; /* Invert J1 and J2 */ - - if (insn & (1 << 14)) { - /* BL or BLX */ - regs->ARM_lr = (unsigned long)p->addr + 4; - if (!(insn & (1 << 12))) { - /* BLX so switch to ARM mode */ - regs->ARM_cpsr &= ~PSR_T_BIT; - pc &= ~3; - } - } - - regs->ARM_pc = pc + (offset * 2); -} - -static void __kprobes -t32_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - unsigned long addr = thumb_probe_pc(p) & ~3; - int rt = (insn >> 12) & 0xf; - unsigned long rtv; - - long offset = insn & 0xfff; - if (insn & 0x00800000) - addr += offset; - else - addr -= offset; - - if (insn & 0x00400000) { - /* LDR */ - rtv = *(unsigned long *)addr; - if (rt == 15) { - bx_write_pc(rtv, regs); - return; - } - } else if (insn & 0x00200000) { - /* LDRH */ - if (insn & 0x01000000) - rtv = *(s16 *)addr; - else - rtv = *(u16 *)addr; - } else { - /* LDRB */ - if (insn & 0x01000000) - rtv = *(s8 *)addr; - else - rtv = *(u8 *)addr; - } - - regs->uregs[rt] = rtv; -} - -static enum kprobe_insn __kprobes -t32_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi) -{ - enum kprobe_insn ret = kprobe_decode_ldmstm(insn, asi); - - /* Fixup modified instruction to have halfwords in correct order...*/ - insn = asi->insn[0]; - ((u16 *)asi->insn)[0] = insn >> 16; - ((u16 *)asi->insn)[1] = insn & 0xffff; - - return ret; -} - -static void __kprobes -t32_emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - unsigned long pc = thumb_probe_pc(p) & ~3; - int rt1 = (insn >> 12) & 0xf; - int rt2 = (insn >> 8) & 0xf; - int rn = (insn >> 16) & 0xf; - - register unsigned long rt1v asm("r0") = regs->uregs[rt1]; - register unsigned long rt2v asm("r1") = regs->uregs[rt2]; - register unsigned long rnv asm("r2") = (rn == 15) ? pc - : regs->uregs[rn]; - - __asm__ __volatile__ ( - "blx %[fn]" - : "=r" (rt1v), "=r" (rt2v), "=r" (rnv) - : "0" (rt1v), "1" (rt2v), "2" (rnv), [fn] "r" (p->ainsn.insn_fn) - : "lr", "memory", "cc" - ); - - if (rn != 15) - regs->uregs[rn] = rnv; /* Writeback base register */ - regs->uregs[rt1] = rt1v; - regs->uregs[rt2] = rt2v; -} - -static void __kprobes -t32_emulate_ldrstr(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - int rt = (insn >> 12) & 0xf; - int rn = (insn >> 16) & 0xf; - int rm = insn & 0xf; - - register unsigned long rtv asm("r0") = regs->uregs[rt]; - register unsigned long rnv asm("r2") = regs->uregs[rn]; - register unsigned long rmv asm("r3") = regs->uregs[rm]; - - __asm__ __volatile__ ( - "blx %[fn]" - : "=r" (rtv), "=r" (rnv) - : "0" (rtv), "1" (rnv), "r" (rmv), [fn] "r" (p->ainsn.insn_fn) - : "lr", "memory", "cc" - ); - - regs->uregs[rn] = rnv; /* Writeback base register */ - if (rt == 15) /* Can't be true for a STR as they aren't allowed */ - bx_write_pc(rtv, regs); - else - regs->uregs[rt] = rtv; -} - -static void __kprobes -t32_emulate_rd8rn16rm0_rwflags(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - int rd = (insn >> 8) & 0xf; - int rn = (insn >> 16) & 0xf; - int rm = insn & 0xf; - - register unsigned long rdv asm("r1") = regs->uregs[rd]; - register unsigned long rnv asm("r2") = regs->uregs[rn]; - register unsigned long rmv asm("r3") = regs->uregs[rm]; - unsigned long cpsr = regs->ARM_cpsr; - - __asm__ __volatile__ ( - "msr cpsr_fs, %[cpsr] \n\t" - "blx %[fn] \n\t" - "mrs %[cpsr], cpsr \n\t" - : "=r" (rdv), [cpsr] "=r" (cpsr) - : "0" (rdv), "r" (rnv), "r" (rmv), - "1" (cpsr), [fn] "r" (p->ainsn.insn_fn) - : "lr", "memory", "cc" - ); - - regs->uregs[rd] = rdv; - regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); -} - -static void __kprobes -t32_emulate_rd8pc16_noflags(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - unsigned long pc = thumb_probe_pc(p); - int rd = (insn >> 8) & 0xf; - - register unsigned long rdv asm("r1") = regs->uregs[rd]; - register unsigned long rnv asm("r2") = pc & ~3; - - __asm__ __volatile__ ( - "blx %[fn]" - : "=r" (rdv) - : "0" (rdv), "r" (rnv), [fn] "r" (p->ainsn.insn_fn) - : "lr", "memory", "cc" - ); - - regs->uregs[rd] = rdv; -} - -static void __kprobes -t32_emulate_rd8rn16_noflags(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - int rd = (insn >> 8) & 0xf; - int rn = (insn >> 16) & 0xf; - - register unsigned long rdv asm("r1") = regs->uregs[rd]; - register unsigned long rnv asm("r2") = regs->uregs[rn]; - - __asm__ __volatile__ ( - "blx %[fn]" - : "=r" (rdv) - : "0" (rdv), "r" (rnv), [fn] "r" (p->ainsn.insn_fn) - : "lr", "memory", "cc" - ); - - regs->uregs[rd] = rdv; -} - -static void __kprobes -t32_emulate_rdlo12rdhi8rn16rm0_noflags(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - int rdlo = (insn >> 12) & 0xf; - int rdhi = (insn >> 8) & 0xf; - int rn = (insn >> 16) & 0xf; - int rm = insn & 0xf; - - register unsigned long rdlov asm("r0") = regs->uregs[rdlo]; - register unsigned long rdhiv asm("r1") = regs->uregs[rdhi]; - register unsigned long rnv asm("r2") = regs->uregs[rn]; - register unsigned long rmv asm("r3") = regs->uregs[rm]; - - __asm__ __volatile__ ( - "blx %[fn]" - : "=r" (rdlov), "=r" (rdhiv) - : "0" (rdlov), "1" (rdhiv), "r" (rnv), "r" (rmv), - [fn] "r" (p->ainsn.insn_fn) - : "lr", "memory", "cc" - ); - - regs->uregs[rdlo] = rdlov; - regs->uregs[rdhi] = rdhiv; -} - -/* These emulation encodings are functionally equivalent... */ -#define t32_emulate_rd8rn16rm0ra12_noflags \ - t32_emulate_rdlo12rdhi8rn16rm0_noflags - -static const union decode_item t32_table_1110_100x_x0xx[] = { - /* Load/store multiple instructions */ - - /* Rn is PC 1110 100x x0xx 1111 xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0xfe4f0000, 0xe80f0000), - - /* SRS 1110 1000 00x0 xxxx xxxx xxxx xxxx xxxx */ - /* RFE 1110 1000 00x1 xxxx xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0xffc00000, 0xe8000000), - /* SRS 1110 1001 10x0 xxxx xxxx xxxx xxxx xxxx */ - /* RFE 1110 1001 10x1 xxxx xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0xffc00000, 0xe9800000), - - /* STM Rn, {...pc} 1110 100x x0x0 xxxx 1xxx xxxx xxxx xxxx */ - DECODE_REJECT (0xfe508000, 0xe8008000), - /* LDM Rn, {...lr,pc} 1110 100x x0x1 xxxx 11xx xxxx xxxx xxxx */ - DECODE_REJECT (0xfe50c000, 0xe810c000), - /* LDM/STM Rn, {...sp} 1110 100x x0xx xxxx xx1x xxxx xxxx xxxx */ - DECODE_REJECT (0xfe402000, 0xe8002000), - - /* STMIA 1110 1000 10x0 xxxx xxxx xxxx xxxx xxxx */ - /* LDMIA 1110 1000 10x1 xxxx xxxx xxxx xxxx xxxx */ - /* STMDB 1110 1001 00x0 xxxx xxxx xxxx xxxx xxxx */ - /* LDMDB 1110 1001 00x1 xxxx xxxx xxxx xxxx xxxx */ - DECODE_CUSTOM (0xfe400000, 0xe8000000, t32_decode_ldmstm), - - DECODE_END -}; - -static const union decode_item t32_table_1110_100x_x1xx[] = { - /* Load/store dual, load/store exclusive, table branch */ - - /* STRD (immediate) 1110 1000 x110 xxxx xxxx xxxx xxxx xxxx */ - /* LDRD (immediate) 1110 1000 x111 xxxx xxxx xxxx xxxx xxxx */ - DECODE_OR (0xff600000, 0xe8600000), - /* STRD (immediate) 1110 1001 x1x0 xxxx xxxx xxxx xxxx xxxx */ - /* LDRD (immediate) 1110 1001 x1x1 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xff400000, 0xe9400000, t32_emulate_ldrdstrd, - REGS(NOPCWB, NOSPPC, NOSPPC, 0, 0)), - - /* TBB 1110 1000 1101 xxxx xxxx xxxx 0000 xxxx */ - /* TBH 1110 1000 1101 xxxx xxxx xxxx 0001 xxxx */ - DECODE_SIMULATEX(0xfff000e0, 0xe8d00000, t32_simulate_table_branch, - REGS(NOSP, 0, 0, 0, NOSPPC)), - - /* STREX 1110 1000 0100 xxxx xxxx xxxx xxxx xxxx */ - /* LDREX 1110 1000 0101 xxxx xxxx xxxx xxxx xxxx */ - /* STREXB 1110 1000 1100 xxxx xxxx xxxx 0100 xxxx */ - /* STREXH 1110 1000 1100 xxxx xxxx xxxx 0101 xxxx */ - /* STREXD 1110 1000 1100 xxxx xxxx xxxx 0111 xxxx */ - /* LDREXB 1110 1000 1101 xxxx xxxx xxxx 0100 xxxx */ - /* LDREXH 1110 1000 1101 xxxx xxxx xxxx 0101 xxxx */ - /* LDREXD 1110 1000 1101 xxxx xxxx xxxx 0111 xxxx */ - /* And unallocated instructions... */ - DECODE_END -}; - -static const union decode_item t32_table_1110_101x[] = { - /* Data-processing (shifted register) */ - - /* TST 1110 1010 0001 xxxx xxxx 1111 xxxx xxxx */ - /* TEQ 1110 1010 1001 xxxx xxxx 1111 xxxx xxxx */ - DECODE_EMULATEX (0xff700f00, 0xea100f00, t32_emulate_rd8rn16rm0_rwflags, - REGS(NOSPPC, 0, 0, 0, NOSPPC)), - - /* CMN 1110 1011 0001 xxxx xxxx 1111 xxxx xxxx */ - DECODE_OR (0xfff00f00, 0xeb100f00), - /* CMP 1110 1011 1011 xxxx xxxx 1111 xxxx xxxx */ - DECODE_EMULATEX (0xfff00f00, 0xebb00f00, t32_emulate_rd8rn16rm0_rwflags, - REGS(NOPC, 0, 0, 0, NOSPPC)), - - /* MOV 1110 1010 010x 1111 xxxx xxxx xxxx xxxx */ - /* MVN 1110 1010 011x 1111 xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xffcf0000, 0xea4f0000, t32_emulate_rd8rn16rm0_rwflags, - REGS(0, 0, NOSPPC, 0, NOSPPC)), - - /* ??? 1110 1010 101x xxxx xxxx xxxx xxxx xxxx */ - /* ??? 1110 1010 111x xxxx xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0xffa00000, 0xeaa00000), - /* ??? 1110 1011 001x xxxx xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0xffe00000, 0xeb200000), - /* ??? 1110 1011 100x xxxx xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0xffe00000, 0xeb800000), - /* ??? 1110 1011 111x xxxx xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0xffe00000, 0xebe00000), - - /* ADD/SUB SP, SP, Rm, LSL #0..3 */ - /* 1110 1011 x0xx 1101 x000 1101 xx00 xxxx */ - DECODE_EMULATEX (0xff4f7f30, 0xeb0d0d00, t32_emulate_rd8rn16rm0_rwflags, - REGS(SP, 0, SP, 0, NOSPPC)), - - /* ADD/SUB SP, SP, Rm, shift */ - /* 1110 1011 x0xx 1101 xxxx 1101 xxxx xxxx */ - DECODE_REJECT (0xff4f0f00, 0xeb0d0d00), - - /* ADD/SUB Rd, SP, Rm, shift */ - /* 1110 1011 x0xx 1101 xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xff4f0000, 0xeb0d0000, t32_emulate_rd8rn16rm0_rwflags, - REGS(SP, 0, NOPC, 0, NOSPPC)), - - /* AND 1110 1010 000x xxxx xxxx xxxx xxxx xxxx */ - /* BIC 1110 1010 001x xxxx xxxx xxxx xxxx xxxx */ - /* ORR 1110 1010 010x xxxx xxxx xxxx xxxx xxxx */ - /* ORN 1110 1010 011x xxxx xxxx xxxx xxxx xxxx */ - /* EOR 1110 1010 100x xxxx xxxx xxxx xxxx xxxx */ - /* PKH 1110 1010 110x xxxx xxxx xxxx xxxx xxxx */ - /* ADD 1110 1011 000x xxxx xxxx xxxx xxxx xxxx */ - /* ADC 1110 1011 010x xxxx xxxx xxxx xxxx xxxx */ - /* SBC 1110 1011 011x xxxx xxxx xxxx xxxx xxxx */ - /* SUB 1110 1011 101x xxxx xxxx xxxx xxxx xxxx */ - /* RSB 1110 1011 110x xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfe000000, 0xea000000, t32_emulate_rd8rn16rm0_rwflags, - REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)), - - DECODE_END -}; - -static const union decode_item t32_table_1111_0x0x___0[] = { - /* Data-processing (modified immediate) */ - - /* TST 1111 0x00 0001 xxxx 0xxx 1111 xxxx xxxx */ - /* TEQ 1111 0x00 1001 xxxx 0xxx 1111 xxxx xxxx */ - DECODE_EMULATEX (0xfb708f00, 0xf0100f00, t32_emulate_rd8rn16rm0_rwflags, - REGS(NOSPPC, 0, 0, 0, 0)), - - /* CMN 1111 0x01 0001 xxxx 0xxx 1111 xxxx xxxx */ - DECODE_OR (0xfbf08f00, 0xf1100f00), - /* CMP 1111 0x01 1011 xxxx 0xxx 1111 xxxx xxxx */ - DECODE_EMULATEX (0xfbf08f00, 0xf1b00f00, t32_emulate_rd8rn16rm0_rwflags, - REGS(NOPC, 0, 0, 0, 0)), - - /* MOV 1111 0x00 010x 1111 0xxx xxxx xxxx xxxx */ - /* MVN 1111 0x00 011x 1111 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfbcf8000, 0xf04f0000, t32_emulate_rd8rn16rm0_rwflags, - REGS(0, 0, NOSPPC, 0, 0)), - - /* ??? 1111 0x00 101x xxxx 0xxx xxxx xxxx xxxx */ - DECODE_REJECT (0xfbe08000, 0xf0a00000), - /* ??? 1111 0x00 110x xxxx 0xxx xxxx xxxx xxxx */ - /* ??? 1111 0x00 111x xxxx 0xxx xxxx xxxx xxxx */ - DECODE_REJECT (0xfbc08000, 0xf0c00000), - /* ??? 1111 0x01 001x xxxx 0xxx xxxx xxxx xxxx */ - DECODE_REJECT (0xfbe08000, 0xf1200000), - /* ??? 1111 0x01 100x xxxx 0xxx xxxx xxxx xxxx */ - DECODE_REJECT (0xfbe08000, 0xf1800000), - /* ??? 1111 0x01 111x xxxx 0xxx xxxx xxxx xxxx */ - DECODE_REJECT (0xfbe08000, 0xf1e00000), - - /* ADD Rd, SP, #imm 1111 0x01 000x 1101 0xxx xxxx xxxx xxxx */ - /* SUB Rd, SP, #imm 1111 0x01 101x 1101 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfb4f8000, 0xf10d0000, t32_emulate_rd8rn16rm0_rwflags, - REGS(SP, 0, NOPC, 0, 0)), - - /* AND 1111 0x00 000x xxxx 0xxx xxxx xxxx xxxx */ - /* BIC 1111 0x00 001x xxxx 0xxx xxxx xxxx xxxx */ - /* ORR 1111 0x00 010x xxxx 0xxx xxxx xxxx xxxx */ - /* ORN 1111 0x00 011x xxxx 0xxx xxxx xxxx xxxx */ - /* EOR 1111 0x00 100x xxxx 0xxx xxxx xxxx xxxx */ - /* ADD 1111 0x01 000x xxxx 0xxx xxxx xxxx xxxx */ - /* ADC 1111 0x01 010x xxxx 0xxx xxxx xxxx xxxx */ - /* SBC 1111 0x01 011x xxxx 0xxx xxxx xxxx xxxx */ - /* SUB 1111 0x01 101x xxxx 0xxx xxxx xxxx xxxx */ - /* RSB 1111 0x01 110x xxxx 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfa008000, 0xf0000000, t32_emulate_rd8rn16rm0_rwflags, - REGS(NOSPPC, 0, NOSPPC, 0, 0)), - - DECODE_END -}; - -static const union decode_item t32_table_1111_0x1x___0[] = { - /* Data-processing (plain binary immediate) */ - - /* ADDW Rd, PC, #imm 1111 0x10 0000 1111 0xxx xxxx xxxx xxxx */ - DECODE_OR (0xfbff8000, 0xf20f0000), - /* SUBW Rd, PC, #imm 1111 0x10 1010 1111 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfbff8000, 0xf2af0000, t32_emulate_rd8pc16_noflags, - REGS(PC, 0, NOSPPC, 0, 0)), - - /* ADDW SP, SP, #imm 1111 0x10 0000 1101 0xxx 1101 xxxx xxxx */ - DECODE_OR (0xfbff8f00, 0xf20d0d00), - /* SUBW SP, SP, #imm 1111 0x10 1010 1101 0xxx 1101 xxxx xxxx */ - DECODE_EMULATEX (0xfbff8f00, 0xf2ad0d00, t32_emulate_rd8rn16_noflags, - REGS(SP, 0, SP, 0, 0)), - - /* ADDW 1111 0x10 0000 xxxx 0xxx xxxx xxxx xxxx */ - DECODE_OR (0xfbf08000, 0xf2000000), - /* SUBW 1111 0x10 1010 xxxx 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfbf08000, 0xf2a00000, t32_emulate_rd8rn16_noflags, - REGS(NOPCX, 0, NOSPPC, 0, 0)), - - /* MOVW 1111 0x10 0100 xxxx 0xxx xxxx xxxx xxxx */ - /* MOVT 1111 0x10 1100 xxxx 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfb708000, 0xf2400000, t32_emulate_rd8rn16_noflags, - REGS(0, 0, NOSPPC, 0, 0)), - - /* SSAT16 1111 0x11 0010 xxxx 0000 xxxx 00xx xxxx */ - /* SSAT 1111 0x11 00x0 xxxx 0xxx xxxx xxxx xxxx */ - /* USAT16 1111 0x11 1010 xxxx 0000 xxxx 00xx xxxx */ - /* USAT 1111 0x11 10x0 xxxx 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfb508000, 0xf3000000, t32_emulate_rd8rn16rm0_rwflags, - REGS(NOSPPC, 0, NOSPPC, 0, 0)), - - /* SFBX 1111 0x11 0100 xxxx 0xxx xxxx xxxx xxxx */ - /* UFBX 1111 0x11 1100 xxxx 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfb708000, 0xf3400000, t32_emulate_rd8rn16_noflags, - REGS(NOSPPC, 0, NOSPPC, 0, 0)), - - /* BFC 1111 0x11 0110 1111 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfbff8000, 0xf36f0000, t32_emulate_rd8rn16_noflags, - REGS(0, 0, NOSPPC, 0, 0)), - - /* BFI 1111 0x11 0110 xxxx 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfbf08000, 0xf3600000, t32_emulate_rd8rn16_noflags, - REGS(NOSPPCX, 0, NOSPPC, 0, 0)), - - DECODE_END -}; - -static const union decode_item t32_table_1111_0xxx___1[] = { - /* Branches and miscellaneous control */ - - /* YIELD 1111 0011 1010 xxxx 10x0 x000 0000 0001 */ - DECODE_OR (0xfff0d7ff, 0xf3a08001), - /* SEV 1111 0011 1010 xxxx 10x0 x000 0000 0100 */ - DECODE_EMULATE (0xfff0d7ff, 0xf3a08004, kprobe_emulate_none), - /* NOP 1111 0011 1010 xxxx 10x0 x000 0000 0000 */ - /* WFE 1111 0011 1010 xxxx 10x0 x000 0000 0010 */ - /* WFI 1111 0011 1010 xxxx 10x0 x000 0000 0011 */ - DECODE_SIMULATE (0xfff0d7fc, 0xf3a08000, kprobe_simulate_nop), - - /* MRS Rd, CPSR 1111 0011 1110 xxxx 10x0 xxxx xxxx xxxx */ - DECODE_SIMULATEX(0xfff0d000, 0xf3e08000, t32_simulate_mrs, - REGS(0, 0, NOSPPC, 0, 0)), - - /* - * Unsupported instructions - * 1111 0x11 1xxx xxxx 10x0 xxxx xxxx xxxx - * - * MSR 1111 0011 100x xxxx 10x0 xxxx xxxx xxxx - * DBG hint 1111 0011 1010 xxxx 10x0 x000 1111 xxxx - * Unallocated hints 1111 0011 1010 xxxx 10x0 x000 xxxx xxxx - * CPS 1111 0011 1010 xxxx 10x0 xxxx xxxx xxxx - * CLREX/DSB/DMB/ISB 1111 0011 1011 xxxx 10x0 xxxx xxxx xxxx - * BXJ 1111 0011 1100 xxxx 10x0 xxxx xxxx xxxx - * SUBS PC,LR,# 1111 0011 1101 xxxx 10x0 xxxx xxxx xxxx - * MRS Rd, SPSR 1111 0011 1111 xxxx 10x0 xxxx xxxx xxxx - * SMC 1111 0111 1111 xxxx 1000 xxxx xxxx xxxx - * UNDEFINED 1111 0111 1111 xxxx 1010 xxxx xxxx xxxx - * ??? 1111 0111 1xxx xxxx 1010 xxxx xxxx xxxx - */ - DECODE_REJECT (0xfb80d000, 0xf3808000), - - /* Bcc 1111 0xxx xxxx xxxx 10x0 xxxx xxxx xxxx */ - DECODE_CUSTOM (0xf800d000, 0xf0008000, t32_decode_cond_branch), - - /* BLX 1111 0xxx xxxx xxxx 11x0 xxxx xxxx xxx0 */ - DECODE_OR (0xf800d001, 0xf000c000), - /* B 1111 0xxx xxxx xxxx 10x1 xxxx xxxx xxxx */ - /* BL 1111 0xxx xxxx xxxx 11x1 xxxx xxxx xxxx */ - DECODE_SIMULATE (0xf8009000, 0xf0009000, t32_simulate_branch), - - DECODE_END -}; - -static const union decode_item t32_table_1111_100x_x0x1__1111[] = { - /* Memory hints */ - - /* PLD (literal) 1111 1000 x001 1111 1111 xxxx xxxx xxxx */ - /* PLI (literal) 1111 1001 x001 1111 1111 xxxx xxxx xxxx */ - DECODE_SIMULATE (0xfe7ff000, 0xf81ff000, kprobe_simulate_nop), - - /* PLD{W} (immediate) 1111 1000 10x1 xxxx 1111 xxxx xxxx xxxx */ - DECODE_OR (0xffd0f000, 0xf890f000), - /* PLD{W} (immediate) 1111 1000 00x1 xxxx 1111 1100 xxxx xxxx */ - DECODE_OR (0xffd0ff00, 0xf810fc00), - /* PLI (immediate) 1111 1001 1001 xxxx 1111 xxxx xxxx xxxx */ - DECODE_OR (0xfff0f000, 0xf990f000), - /* PLI (immediate) 1111 1001 0001 xxxx 1111 1100 xxxx xxxx */ - DECODE_SIMULATEX(0xfff0ff00, 0xf910fc00, kprobe_simulate_nop, - REGS(NOPCX, 0, 0, 0, 0)), - - /* PLD{W} (register) 1111 1000 00x1 xxxx 1111 0000 00xx xxxx */ - DECODE_OR (0xffd0ffc0, 0xf810f000), - /* PLI (register) 1111 1001 0001 xxxx 1111 0000 00xx xxxx */ - DECODE_SIMULATEX(0xfff0ffc0, 0xf910f000, kprobe_simulate_nop, - REGS(NOPCX, 0, 0, 0, NOSPPC)), - - /* Other unallocated instructions... */ - DECODE_END -}; - -static const union decode_item t32_table_1111_100x[] = { - /* Store/Load single data item */ - - /* ??? 1111 100x x11x xxxx xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0xfe600000, 0xf8600000), - - /* ??? 1111 1001 0101 xxxx xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0xfff00000, 0xf9500000), - - /* ??? 1111 100x 0xxx xxxx xxxx 10x0 xxxx xxxx */ - DECODE_REJECT (0xfe800d00, 0xf8000800), - - /* STRBT 1111 1000 0000 xxxx xxxx 1110 xxxx xxxx */ - /* STRHT 1111 1000 0010 xxxx xxxx 1110 xxxx xxxx */ - /* STRT 1111 1000 0100 xxxx xxxx 1110 xxxx xxxx */ - /* LDRBT 1111 1000 0001 xxxx xxxx 1110 xxxx xxxx */ - /* LDRSBT 1111 1001 0001 xxxx xxxx 1110 xxxx xxxx */ - /* LDRHT 1111 1000 0011 xxxx xxxx 1110 xxxx xxxx */ - /* LDRSHT 1111 1001 0011 xxxx xxxx 1110 xxxx xxxx */ - /* LDRT 1111 1000 0101 xxxx xxxx 1110 xxxx xxxx */ - DECODE_REJECT (0xfe800f00, 0xf8000e00), - - /* STR{,B,H} Rn,[PC...] 1111 1000 xxx0 1111 xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0xff1f0000, 0xf80f0000), - - /* STR{,B,H} PC,[Rn...] 1111 1000 xxx0 xxxx 1111 xxxx xxxx xxxx */ - DECODE_REJECT (0xff10f000, 0xf800f000), - - /* LDR (literal) 1111 1000 x101 1111 xxxx xxxx xxxx xxxx */ - DECODE_SIMULATEX(0xff7f0000, 0xf85f0000, t32_simulate_ldr_literal, - REGS(PC, ANY, 0, 0, 0)), - - /* STR (immediate) 1111 1000 0100 xxxx xxxx 1xxx xxxx xxxx */ - /* LDR (immediate) 1111 1000 0101 xxxx xxxx 1xxx xxxx xxxx */ - DECODE_OR (0xffe00800, 0xf8400800), - /* STR (immediate) 1111 1000 1100 xxxx xxxx xxxx xxxx xxxx */ - /* LDR (immediate) 1111 1000 1101 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xffe00000, 0xf8c00000, t32_emulate_ldrstr, - REGS(NOPCX, ANY, 0, 0, 0)), - - /* STR (register) 1111 1000 0100 xxxx xxxx 0000 00xx xxxx */ - /* LDR (register) 1111 1000 0101 xxxx xxxx 0000 00xx xxxx */ - DECODE_EMULATEX (0xffe00fc0, 0xf8400000, t32_emulate_ldrstr, - REGS(NOPCX, ANY, 0, 0, NOSPPC)), - - /* LDRB (literal) 1111 1000 x001 1111 xxxx xxxx xxxx xxxx */ - /* LDRSB (literal) 1111 1001 x001 1111 xxxx xxxx xxxx xxxx */ - /* LDRH (literal) 1111 1000 x011 1111 xxxx xxxx xxxx xxxx */ - /* LDRSH (literal) 1111 1001 x011 1111 xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfe5f0000, 0xf81f0000, t32_simulate_ldr_literal, - REGS(PC, NOSPPCX, 0, 0, 0)), - - /* STRB (immediate) 1111 1000 0000 xxxx xxxx 1xxx xxxx xxxx */ - /* STRH (immediate) 1111 1000 0010 xxxx xxxx 1xxx xxxx xxxx */ - /* LDRB (immediate) 1111 1000 0001 xxxx xxxx 1xxx xxxx xxxx */ - /* LDRSB (immediate) 1111 1001 0001 xxxx xxxx 1xxx xxxx xxxx */ - /* LDRH (immediate) 1111 1000 0011 xxxx xxxx 1xxx xxxx xxxx */ - /* LDRSH (immediate) 1111 1001 0011 xxxx xxxx 1xxx xxxx xxxx */ - DECODE_OR (0xfec00800, 0xf8000800), - /* STRB (immediate) 1111 1000 1000 xxxx xxxx xxxx xxxx xxxx */ - /* STRH (immediate) 1111 1000 1010 xxxx xxxx xxxx xxxx xxxx */ - /* LDRB (immediate) 1111 1000 1001 xxxx xxxx xxxx xxxx xxxx */ - /* LDRSB (immediate) 1111 1001 1001 xxxx xxxx xxxx xxxx xxxx */ - /* LDRH (immediate) 1111 1000 1011 xxxx xxxx xxxx xxxx xxxx */ - /* LDRSH (immediate) 1111 1001 1011 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfec00000, 0xf8800000, t32_emulate_ldrstr, - REGS(NOPCX, NOSPPCX, 0, 0, 0)), - - /* STRB (register) 1111 1000 0000 xxxx xxxx 0000 00xx xxxx */ - /* STRH (register) 1111 1000 0010 xxxx xxxx 0000 00xx xxxx */ - /* LDRB (register) 1111 1000 0001 xxxx xxxx 0000 00xx xxxx */ - /* LDRSB (register) 1111 1001 0001 xxxx xxxx 0000 00xx xxxx */ - /* LDRH (register) 1111 1000 0011 xxxx xxxx 0000 00xx xxxx */ - /* LDRSH (register) 1111 1001 0011 xxxx xxxx 0000 00xx xxxx */ - DECODE_EMULATEX (0xfe800fc0, 0xf8000000, t32_emulate_ldrstr, - REGS(NOPCX, NOSPPCX, 0, 0, NOSPPC)), - - /* Other unallocated instructions... */ - DECODE_END -}; - -static const union decode_item t32_table_1111_1010___1111[] = { - /* Data-processing (register) */ - - /* ??? 1111 1010 011x xxxx 1111 xxxx 1xxx xxxx */ - DECODE_REJECT (0xffe0f080, 0xfa60f080), - - /* SXTH 1111 1010 0000 1111 1111 xxxx 1xxx xxxx */ - /* UXTH 1111 1010 0001 1111 1111 xxxx 1xxx xxxx */ - /* SXTB16 1111 1010 0010 1111 1111 xxxx 1xxx xxxx */ - /* UXTB16 1111 1010 0011 1111 1111 xxxx 1xxx xxxx */ - /* SXTB 1111 1010 0100 1111 1111 xxxx 1xxx xxxx */ - /* UXTB 1111 1010 0101 1111 1111 xxxx 1xxx xxxx */ - DECODE_EMULATEX (0xff8ff080, 0xfa0ff080, t32_emulate_rd8rn16rm0_rwflags, - REGS(0, 0, NOSPPC, 0, NOSPPC)), - - - /* ??? 1111 1010 1xxx xxxx 1111 xxxx 0x11 xxxx */ - DECODE_REJECT (0xff80f0b0, 0xfa80f030), - /* ??? 1111 1010 1x11 xxxx 1111 xxxx 0xxx xxxx */ - DECODE_REJECT (0xffb0f080, 0xfab0f000), - - /* SADD16 1111 1010 1001 xxxx 1111 xxxx 0000 xxxx */ - /* SASX 1111 1010 1010 xxxx 1111 xxxx 0000 xxxx */ - /* SSAX 1111 1010 1110 xxxx 1111 xxxx 0000 xxxx */ - /* SSUB16 1111 1010 1101 xxxx 1111 xxxx 0000 xxxx */ - /* SADD8 1111 1010 1000 xxxx 1111 xxxx 0000 xxxx */ - /* SSUB8 1111 1010 1100 xxxx 1111 xxxx 0000 xxxx */ - - /* QADD16 1111 1010 1001 xxxx 1111 xxxx 0001 xxxx */ - /* QASX 1111 1010 1010 xxxx 1111 xxxx 0001 xxxx */ - /* QSAX 1111 1010 1110 xxxx 1111 xxxx 0001 xxxx */ - /* QSUB16 1111 1010 1101 xxxx 1111 xxxx 0001 xxxx */ - /* QADD8 1111 1010 1000 xxxx 1111 xxxx 0001 xxxx */ - /* QSUB8 1111 1010 1100 xxxx 1111 xxxx 0001 xxxx */ - - /* SHADD16 1111 1010 1001 xxxx 1111 xxxx 0010 xxxx */ - /* SHASX 1111 1010 1010 xxxx 1111 xxxx 0010 xxxx */ - /* SHSAX 1111 1010 1110 xxxx 1111 xxxx 0010 xxxx */ - /* SHSUB16 1111 1010 1101 xxxx 1111 xxxx 0010 xxxx */ - /* SHADD8 1111 1010 1000 xxxx 1111 xxxx 0010 xxxx */ - /* SHSUB8 1111 1010 1100 xxxx 1111 xxxx 0010 xxxx */ - - /* UADD16 1111 1010 1001 xxxx 1111 xxxx 0100 xxxx */ - /* UASX 1111 1010 1010 xxxx 1111 xxxx 0100 xxxx */ - /* USAX 1111 1010 1110 xxxx 1111 xxxx 0100 xxxx */ - /* USUB16 1111 1010 1101 xxxx 1111 xxxx 0100 xxxx */ - /* UADD8 1111 1010 1000 xxxx 1111 xxxx 0100 xxxx */ - /* USUB8 1111 1010 1100 xxxx 1111 xxxx 0100 xxxx */ - - /* UQADD16 1111 1010 1001 xxxx 1111 xxxx 0101 xxxx */ - /* UQASX 1111 1010 1010 xxxx 1111 xxxx 0101 xxxx */ - /* UQSAX 1111 1010 1110 xxxx 1111 xxxx 0101 xxxx */ - /* UQSUB16 1111 1010 1101 xxxx 1111 xxxx 0101 xxxx */ - /* UQADD8 1111 1010 1000 xxxx 1111 xxxx 0101 xxxx */ - /* UQSUB8 1111 1010 1100 xxxx 1111 xxxx 0101 xxxx */ - - /* UHADD16 1111 1010 1001 xxxx 1111 xxxx 0110 xxxx */ - /* UHASX 1111 1010 1010 xxxx 1111 xxxx 0110 xxxx */ - /* UHSAX 1111 1010 1110 xxxx 1111 xxxx 0110 xxxx */ - /* UHSUB16 1111 1010 1101 xxxx 1111 xxxx 0110 xxxx */ - /* UHADD8 1111 1010 1000 xxxx 1111 xxxx 0110 xxxx */ - /* UHSUB8 1111 1010 1100 xxxx 1111 xxxx 0110 xxxx */ - DECODE_OR (0xff80f080, 0xfa80f000), - - /* SXTAH 1111 1010 0000 xxxx 1111 xxxx 1xxx xxxx */ - /* UXTAH 1111 1010 0001 xxxx 1111 xxxx 1xxx xxxx */ - /* SXTAB16 1111 1010 0010 xxxx 1111 xxxx 1xxx xxxx */ - /* UXTAB16 1111 1010 0011 xxxx 1111 xxxx 1xxx xxxx */ - /* SXTAB 1111 1010 0100 xxxx 1111 xxxx 1xxx xxxx */ - /* UXTAB 1111 1010 0101 xxxx 1111 xxxx 1xxx xxxx */ - DECODE_OR (0xff80f080, 0xfa00f080), - - /* QADD 1111 1010 1000 xxxx 1111 xxxx 1000 xxxx */ - /* QDADD 1111 1010 1000 xxxx 1111 xxxx 1001 xxxx */ - /* QSUB 1111 1010 1000 xxxx 1111 xxxx 1010 xxxx */ - /* QDSUB 1111 1010 1000 xxxx 1111 xxxx 1011 xxxx */ - DECODE_OR (0xfff0f0c0, 0xfa80f080), - - /* SEL 1111 1010 1010 xxxx 1111 xxxx 1000 xxxx */ - DECODE_OR (0xfff0f0f0, 0xfaa0f080), - - /* LSL 1111 1010 000x xxxx 1111 xxxx 0000 xxxx */ - /* LSR 1111 1010 001x xxxx 1111 xxxx 0000 xxxx */ - /* ASR 1111 1010 010x xxxx 1111 xxxx 0000 xxxx */ - /* ROR 1111 1010 011x xxxx 1111 xxxx 0000 xxxx */ - DECODE_EMULATEX (0xff80f0f0, 0xfa00f000, t32_emulate_rd8rn16rm0_rwflags, - REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)), - - /* CLZ 1111 1010 1010 xxxx 1111 xxxx 1000 xxxx */ - DECODE_OR (0xfff0f0f0, 0xfab0f080), - - /* REV 1111 1010 1001 xxxx 1111 xxxx 1000 xxxx */ - /* REV16 1111 1010 1001 xxxx 1111 xxxx 1001 xxxx */ - /* RBIT 1111 1010 1001 xxxx 1111 xxxx 1010 xxxx */ - /* REVSH 1111 1010 1001 xxxx 1111 xxxx 1011 xxxx */ - DECODE_EMULATEX (0xfff0f0c0, 0xfa90f080, t32_emulate_rd8rn16_noflags, - REGS(NOSPPC, 0, NOSPPC, 0, SAMEAS16)), - - /* Other unallocated instructions... */ - DECODE_END -}; - -static const union decode_item t32_table_1111_1011_0[] = { - /* Multiply, multiply accumulate, and absolute difference */ - - /* ??? 1111 1011 0000 xxxx 1111 xxxx 0001 xxxx */ - DECODE_REJECT (0xfff0f0f0, 0xfb00f010), - /* ??? 1111 1011 0111 xxxx 1111 xxxx 0001 xxxx */ - DECODE_REJECT (0xfff0f0f0, 0xfb70f010), - - /* SMULxy 1111 1011 0001 xxxx 1111 xxxx 00xx xxxx */ - DECODE_OR (0xfff0f0c0, 0xfb10f000), - /* MUL 1111 1011 0000 xxxx 1111 xxxx 0000 xxxx */ - /* SMUAD{X} 1111 1011 0010 xxxx 1111 xxxx 000x xxxx */ - /* SMULWy 1111 1011 0011 xxxx 1111 xxxx 000x xxxx */ - /* SMUSD{X} 1111 1011 0100 xxxx 1111 xxxx 000x xxxx */ - /* SMMUL{R} 1111 1011 0101 xxxx 1111 xxxx 000x xxxx */ - /* USAD8 1111 1011 0111 xxxx 1111 xxxx 0000 xxxx */ - DECODE_EMULATEX (0xff80f0e0, 0xfb00f000, t32_emulate_rd8rn16rm0_rwflags, - REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)), - - /* ??? 1111 1011 0111 xxxx xxxx xxxx 0001 xxxx */ - DECODE_REJECT (0xfff000f0, 0xfb700010), - - /* SMLAxy 1111 1011 0001 xxxx xxxx xxxx 00xx xxxx */ - DECODE_OR (0xfff000c0, 0xfb100000), - /* MLA 1111 1011 0000 xxxx xxxx xxxx 0000 xxxx */ - /* MLS 1111 1011 0000 xxxx xxxx xxxx 0001 xxxx */ - /* SMLAD{X} 1111 1011 0010 xxxx xxxx xxxx 000x xxxx */ - /* SMLAWy 1111 1011 0011 xxxx xxxx xxxx 000x xxxx */ - /* SMLSD{X} 1111 1011 0100 xxxx xxxx xxxx 000x xxxx */ - /* SMMLA{R} 1111 1011 0101 xxxx xxxx xxxx 000x xxxx */ - /* SMMLS{R} 1111 1011 0110 xxxx xxxx xxxx 000x xxxx */ - /* USADA8 1111 1011 0111 xxxx xxxx xxxx 0000 xxxx */ - DECODE_EMULATEX (0xff8000c0, 0xfb000000, t32_emulate_rd8rn16rm0ra12_noflags, - REGS(NOSPPC, NOSPPCX, NOSPPC, 0, NOSPPC)), - - /* Other unallocated instructions... */ - DECODE_END -}; - -static const union decode_item t32_table_1111_1011_1[] = { - /* Long multiply, long multiply accumulate, and divide */ - - /* UMAAL 1111 1011 1110 xxxx xxxx xxxx 0110 xxxx */ - DECODE_OR (0xfff000f0, 0xfbe00060), - /* SMLALxy 1111 1011 1100 xxxx xxxx xxxx 10xx xxxx */ - DECODE_OR (0xfff000c0, 0xfbc00080), - /* SMLALD{X} 1111 1011 1100 xxxx xxxx xxxx 110x xxxx */ - /* SMLSLD{X} 1111 1011 1101 xxxx xxxx xxxx 110x xxxx */ - DECODE_OR (0xffe000e0, 0xfbc000c0), - /* SMULL 1111 1011 1000 xxxx xxxx xxxx 0000 xxxx */ - /* UMULL 1111 1011 1010 xxxx xxxx xxxx 0000 xxxx */ - /* SMLAL 1111 1011 1100 xxxx xxxx xxxx 0000 xxxx */ - /* UMLAL 1111 1011 1110 xxxx xxxx xxxx 0000 xxxx */ - DECODE_EMULATEX (0xff9000f0, 0xfb800000, t32_emulate_rdlo12rdhi8rn16rm0_noflags, - REGS(NOSPPC, NOSPPC, NOSPPC, 0, NOSPPC)), - - /* SDIV 1111 1011 1001 xxxx xxxx xxxx 1111 xxxx */ - /* UDIV 1111 1011 1011 xxxx xxxx xxxx 1111 xxxx */ - /* Other unallocated instructions... */ - DECODE_END -}; - -const union decode_item kprobe_decode_thumb32_table[] = { - - /* - * Load/store multiple instructions - * 1110 100x x0xx xxxx xxxx xxxx xxxx xxxx - */ - DECODE_TABLE (0xfe400000, 0xe8000000, t32_table_1110_100x_x0xx), - - /* - * Load/store dual, load/store exclusive, table branch - * 1110 100x x1xx xxxx xxxx xxxx xxxx xxxx - */ - DECODE_TABLE (0xfe400000, 0xe8400000, t32_table_1110_100x_x1xx), - - /* - * Data-processing (shifted register) - * 1110 101x xxxx xxxx xxxx xxxx xxxx xxxx - */ - DECODE_TABLE (0xfe000000, 0xea000000, t32_table_1110_101x), - - /* - * Coprocessor instructions - * 1110 11xx xxxx xxxx xxxx xxxx xxxx xxxx - */ - DECODE_REJECT (0xfc000000, 0xec000000), - - /* - * Data-processing (modified immediate) - * 1111 0x0x xxxx xxxx 0xxx xxxx xxxx xxxx - */ - DECODE_TABLE (0xfa008000, 0xf0000000, t32_table_1111_0x0x___0), - - /* - * Data-processing (plain binary immediate) - * 1111 0x1x xxxx xxxx 0xxx xxxx xxxx xxxx - */ - DECODE_TABLE (0xfa008000, 0xf2000000, t32_table_1111_0x1x___0), - - /* - * Branches and miscellaneous control - * 1111 0xxx xxxx xxxx 1xxx xxxx xxxx xxxx - */ - DECODE_TABLE (0xf8008000, 0xf0008000, t32_table_1111_0xxx___1), - - /* - * Advanced SIMD element or structure load/store instructions - * 1111 1001 xxx0 xxxx xxxx xxxx xxxx xxxx - */ - DECODE_REJECT (0xff100000, 0xf9000000), - - /* - * Memory hints - * 1111 100x x0x1 xxxx 1111 xxxx xxxx xxxx - */ - DECODE_TABLE (0xfe50f000, 0xf810f000, t32_table_1111_100x_x0x1__1111), - - /* - * Store single data item - * 1111 1000 xxx0 xxxx xxxx xxxx xxxx xxxx - * Load single data items - * 1111 100x xxx1 xxxx xxxx xxxx xxxx xxxx - */ - DECODE_TABLE (0xfe000000, 0xf8000000, t32_table_1111_100x), - - /* - * Data-processing (register) - * 1111 1010 xxxx xxxx 1111 xxxx xxxx xxxx - */ - DECODE_TABLE (0xff00f000, 0xfa00f000, t32_table_1111_1010___1111), - - /* - * Multiply, multiply accumulate, and absolute difference - * 1111 1011 0xxx xxxx xxxx xxxx xxxx xxxx - */ - DECODE_TABLE (0xff800000, 0xfb000000, t32_table_1111_1011_0), - - /* - * Long multiply, long multiply accumulate, and divide - * 1111 1011 1xxx xxxx xxxx xxxx xxxx xxxx - */ - DECODE_TABLE (0xff800000, 0xfb800000, t32_table_1111_1011_1), - - /* - * Coprocessor instructions - * 1111 11xx xxxx xxxx xxxx xxxx xxxx xxxx - */ - DECODE_END -}; - -static void __kprobes -t16_simulate_bxblx(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - unsigned long pc = thumb_probe_pc(p); - int rm = (insn >> 3) & 0xf; - unsigned long rmv = (rm == 15) ? pc : regs->uregs[rm]; - - if (insn & (1 << 7)) /* BLX ? */ - regs->ARM_lr = (unsigned long)p->addr + 2; - - bx_write_pc(rmv, regs); -} - -static void __kprobes -t16_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - unsigned long* base = (unsigned long *)(thumb_probe_pc(p) & ~3); - long index = insn & 0xff; - int rt = (insn >> 8) & 0x7; - regs->uregs[rt] = base[index]; -} - -static void __kprobes -t16_simulate_ldrstr_sp_relative(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - unsigned long* base = (unsigned long *)regs->ARM_sp; - long index = insn & 0xff; - int rt = (insn >> 8) & 0x7; - if (insn & 0x800) /* LDR */ - regs->uregs[rt] = base[index]; - else /* STR */ - base[index] = regs->uregs[rt]; -} - -static void __kprobes -t16_simulate_reladr(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - unsigned long base = (insn & 0x800) ? regs->ARM_sp - : (thumb_probe_pc(p) & ~3); - long offset = insn & 0xff; - int rt = (insn >> 8) & 0x7; - regs->uregs[rt] = base + offset * 4; -} - -static void __kprobes -t16_simulate_add_sp_imm(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - long imm = insn & 0x7f; - if (insn & 0x80) /* SUB */ - regs->ARM_sp -= imm * 4; - else /* ADD */ - regs->ARM_sp += imm * 4; -} - -static void __kprobes -t16_simulate_cbz(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - int rn = insn & 0x7; - kprobe_opcode_t nonzero = regs->uregs[rn] ? insn : ~insn; - if (nonzero & 0x800) { - long i = insn & 0x200; - long imm5 = insn & 0xf8; - unsigned long pc = thumb_probe_pc(p); - regs->ARM_pc = pc + (i >> 3) + (imm5 >> 2); - } -} - -static void __kprobes -t16_simulate_it(struct kprobe *p, struct pt_regs *regs) -{ - /* - * The 8 IT state bits are split into two parts in CPSR: - * ITSTATE<1:0> are in CPSR<26:25> - * ITSTATE<7:2> are in CPSR<15:10> - * The new IT state is in the lower byte of insn. - */ - kprobe_opcode_t insn = p->opcode; - unsigned long cpsr = regs->ARM_cpsr; - cpsr &= ~PSR_IT_MASK; - cpsr |= (insn & 0xfc) << 8; - cpsr |= (insn & 0x03) << 25; - regs->ARM_cpsr = cpsr; -} - -static void __kprobes -t16_singlestep_it(struct kprobe *p, struct pt_regs *regs) -{ - regs->ARM_pc += 2; - t16_simulate_it(p, regs); -} - -static enum kprobe_insn __kprobes -t16_decode_it(kprobe_opcode_t insn, struct arch_specific_insn *asi) -{ - asi->insn_singlestep = t16_singlestep_it; - return INSN_GOOD_NO_SLOT; -} - -static void __kprobes -t16_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - unsigned long pc = thumb_probe_pc(p); - long offset = insn & 0x7f; - offset -= insn & 0x80; /* Apply sign bit */ - regs->ARM_pc = pc + (offset * 2); -} - -static enum kprobe_insn __kprobes -t16_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi) -{ - int cc = (insn >> 8) & 0xf; - asi->insn_check_cc = kprobe_condition_checks[cc]; - asi->insn_handler = t16_simulate_cond_branch; - return INSN_GOOD_NO_SLOT; -} - -static void __kprobes -t16_simulate_branch(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - unsigned long pc = thumb_probe_pc(p); - long offset = insn & 0x3ff; - offset -= insn & 0x400; /* Apply sign bit */ - regs->ARM_pc = pc + (offset * 2); -} - -static unsigned long __kprobes -t16_emulate_loregs(struct kprobe *p, struct pt_regs *regs) -{ - unsigned long oldcpsr = regs->ARM_cpsr; - unsigned long newcpsr; - - __asm__ __volatile__ ( - "msr cpsr_fs, %[oldcpsr] \n\t" - "ldmia %[regs], {r0-r7} \n\t" - "blx %[fn] \n\t" - "stmia %[regs], {r0-r7} \n\t" - "mrs %[newcpsr], cpsr \n\t" - : [newcpsr] "=r" (newcpsr) - : [oldcpsr] "r" (oldcpsr), [regs] "r" (regs), - [fn] "r" (p->ainsn.insn_fn) - : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", - "lr", "memory", "cc" - ); - - return (oldcpsr & ~APSR_MASK) | (newcpsr & APSR_MASK); -} - -static void __kprobes -t16_emulate_loregs_rwflags(struct kprobe *p, struct pt_regs *regs) -{ - regs->ARM_cpsr = t16_emulate_loregs(p, regs); -} - -static void __kprobes -t16_emulate_loregs_noitrwflags(struct kprobe *p, struct pt_regs *regs) -{ - unsigned long cpsr = t16_emulate_loregs(p, regs); - if (!in_it_block(cpsr)) - regs->ARM_cpsr = cpsr; -} - -static void __kprobes -t16_emulate_hiregs(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - unsigned long pc = thumb_probe_pc(p); - int rdn = (insn & 0x7) | ((insn & 0x80) >> 4); - int rm = (insn >> 3) & 0xf; - - register unsigned long rdnv asm("r1"); - register unsigned long rmv asm("r0"); - unsigned long cpsr = regs->ARM_cpsr; - - rdnv = (rdn == 15) ? pc : regs->uregs[rdn]; - rmv = (rm == 15) ? pc : regs->uregs[rm]; - - __asm__ __volatile__ ( - "msr cpsr_fs, %[cpsr] \n\t" - "blx %[fn] \n\t" - "mrs %[cpsr], cpsr \n\t" - : "=r" (rdnv), [cpsr] "=r" (cpsr) - : "0" (rdnv), "r" (rmv), "1" (cpsr), [fn] "r" (p->ainsn.insn_fn) - : "lr", "memory", "cc" - ); - - if (rdn == 15) - rdnv &= ~1; - - regs->uregs[rdn] = rdnv; - regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); -} - -static enum kprobe_insn __kprobes -t16_decode_hiregs(kprobe_opcode_t insn, struct arch_specific_insn *asi) -{ - insn &= ~0x00ff; - insn |= 0x001; /* Set Rdn = R1 and Rm = R0 */ - ((u16 *)asi->insn)[0] = insn; - asi->insn_handler = t16_emulate_hiregs; - return INSN_GOOD; -} - -static void __kprobes -t16_emulate_push(struct kprobe *p, struct pt_regs *regs) -{ - __asm__ __volatile__ ( - "ldr r9, [%[regs], #13*4] \n\t" - "ldr r8, [%[regs], #14*4] \n\t" - "ldmia %[regs], {r0-r7} \n\t" - "blx %[fn] \n\t" - "str r9, [%[regs], #13*4] \n\t" - : - : [regs] "r" (regs), [fn] "r" (p->ainsn.insn_fn) - : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", - "lr", "memory", "cc" - ); -} - -static enum kprobe_insn __kprobes -t16_decode_push(kprobe_opcode_t insn, struct arch_specific_insn *asi) -{ - /* - * To simulate a PUSH we use a Thumb-2 "STMDB R9!, {registers}" - * and call it with R9=SP and LR in the register list represented - * by R8. - */ - ((u16 *)asi->insn)[0] = 0xe929; /* 1st half STMDB R9!,{} */ - ((u16 *)asi->insn)[1] = insn & 0x1ff; /* 2nd half (register list) */ - asi->insn_handler = t16_emulate_push; - return INSN_GOOD; -} - -static void __kprobes -t16_emulate_pop_nopc(struct kprobe *p, struct pt_regs *regs) -{ - __asm__ __volatile__ ( - "ldr r9, [%[regs], #13*4] \n\t" - "ldmia %[regs], {r0-r7} \n\t" - "blx %[fn] \n\t" - "stmia %[regs], {r0-r7} \n\t" - "str r9, [%[regs], #13*4] \n\t" - : - : [regs] "r" (regs), [fn] "r" (p->ainsn.insn_fn) - : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r9", - "lr", "memory", "cc" - ); -} - -static void __kprobes -t16_emulate_pop_pc(struct kprobe *p, struct pt_regs *regs) -{ - register unsigned long pc asm("r8"); - - __asm__ __volatile__ ( - "ldr r9, [%[regs], #13*4] \n\t" - "ldmia %[regs], {r0-r7} \n\t" - "blx %[fn] \n\t" - "stmia %[regs], {r0-r7} \n\t" - "str r9, [%[regs], #13*4] \n\t" - : "=r" (pc) - : [regs] "r" (regs), [fn] "r" (p->ainsn.insn_fn) - : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r9", - "lr", "memory", "cc" - ); - - bx_write_pc(pc, regs); -} - -static enum kprobe_insn __kprobes -t16_decode_pop(kprobe_opcode_t insn, struct arch_specific_insn *asi) -{ - /* - * To simulate a POP we use a Thumb-2 "LDMDB R9!, {registers}" - * and call it with R9=SP and PC in the register list represented - * by R8. - */ - ((u16 *)asi->insn)[0] = 0xe8b9; /* 1st half LDMIA R9!,{} */ - ((u16 *)asi->insn)[1] = insn & 0x1ff; /* 2nd half (register list) */ - asi->insn_handler = insn & 0x100 ? t16_emulate_pop_pc - : t16_emulate_pop_nopc; - return INSN_GOOD; -} - -static const union decode_item t16_table_1011[] = { - /* Miscellaneous 16-bit instructions */ - - /* ADD (SP plus immediate) 1011 0000 0xxx xxxx */ - /* SUB (SP minus immediate) 1011 0000 1xxx xxxx */ - DECODE_SIMULATE (0xff00, 0xb000, t16_simulate_add_sp_imm), - - /* CBZ 1011 00x1 xxxx xxxx */ - /* CBNZ 1011 10x1 xxxx xxxx */ - DECODE_SIMULATE (0xf500, 0xb100, t16_simulate_cbz), - - /* SXTH 1011 0010 00xx xxxx */ - /* SXTB 1011 0010 01xx xxxx */ - /* UXTH 1011 0010 10xx xxxx */ - /* UXTB 1011 0010 11xx xxxx */ - /* REV 1011 1010 00xx xxxx */ - /* REV16 1011 1010 01xx xxxx */ - /* ??? 1011 1010 10xx xxxx */ - /* REVSH 1011 1010 11xx xxxx */ - DECODE_REJECT (0xffc0, 0xba80), - DECODE_EMULATE (0xf500, 0xb000, t16_emulate_loregs_rwflags), - - /* PUSH 1011 010x xxxx xxxx */ - DECODE_CUSTOM (0xfe00, 0xb400, t16_decode_push), - /* POP 1011 110x xxxx xxxx */ - DECODE_CUSTOM (0xfe00, 0xbc00, t16_decode_pop), - - /* - * If-Then, and hints - * 1011 1111 xxxx xxxx - */ - - /* YIELD 1011 1111 0001 0000 */ - DECODE_OR (0xffff, 0xbf10), - /* SEV 1011 1111 0100 0000 */ - DECODE_EMULATE (0xffff, 0xbf40, kprobe_emulate_none), - /* NOP 1011 1111 0000 0000 */ - /* WFE 1011 1111 0010 0000 */ - /* WFI 1011 1111 0011 0000 */ - DECODE_SIMULATE (0xffcf, 0xbf00, kprobe_simulate_nop), - /* Unassigned hints 1011 1111 xxxx 0000 */ - DECODE_REJECT (0xff0f, 0xbf00), - /* IT 1011 1111 xxxx xxxx */ - DECODE_CUSTOM (0xff00, 0xbf00, t16_decode_it), - - /* SETEND 1011 0110 010x xxxx */ - /* CPS 1011 0110 011x xxxx */ - /* BKPT 1011 1110 xxxx xxxx */ - /* And unallocated instructions... */ - DECODE_END -}; - -const union decode_item kprobe_decode_thumb16_table[] = { - - /* - * Shift (immediate), add, subtract, move, and compare - * 00xx xxxx xxxx xxxx - */ - - /* CMP (immediate) 0010 1xxx xxxx xxxx */ - DECODE_EMULATE (0xf800, 0x2800, t16_emulate_loregs_rwflags), - - /* ADD (register) 0001 100x xxxx xxxx */ - /* SUB (register) 0001 101x xxxx xxxx */ - /* LSL (immediate) 0000 0xxx xxxx xxxx */ - /* LSR (immediate) 0000 1xxx xxxx xxxx */ - /* ASR (immediate) 0001 0xxx xxxx xxxx */ - /* ADD (immediate, Thumb) 0001 110x xxxx xxxx */ - /* SUB (immediate, Thumb) 0001 111x xxxx xxxx */ - /* MOV (immediate) 0010 0xxx xxxx xxxx */ - /* ADD (immediate, Thumb) 0011 0xxx xxxx xxxx */ - /* SUB (immediate, Thumb) 0011 1xxx xxxx xxxx */ - DECODE_EMULATE (0xc000, 0x0000, t16_emulate_loregs_noitrwflags), - - /* - * 16-bit Thumb data-processing instructions - * 0100 00xx xxxx xxxx - */ - - /* TST (register) 0100 0010 00xx xxxx */ - DECODE_EMULATE (0xffc0, 0x4200, t16_emulate_loregs_rwflags), - /* CMP (register) 0100 0010 10xx xxxx */ - /* CMN (register) 0100 0010 11xx xxxx */ - DECODE_EMULATE (0xff80, 0x4280, t16_emulate_loregs_rwflags), - /* AND (register) 0100 0000 00xx xxxx */ - /* EOR (register) 0100 0000 01xx xxxx */ - /* LSL (register) 0100 0000 10xx xxxx */ - /* LSR (register) 0100 0000 11xx xxxx */ - /* ASR (register) 0100 0001 00xx xxxx */ - /* ADC (register) 0100 0001 01xx xxxx */ - /* SBC (register) 0100 0001 10xx xxxx */ - /* ROR (register) 0100 0001 11xx xxxx */ - /* RSB (immediate) 0100 0010 01xx xxxx */ - /* ORR (register) 0100 0011 00xx xxxx */ - /* MUL 0100 0011 00xx xxxx */ - /* BIC (register) 0100 0011 10xx xxxx */ - /* MVN (register) 0100 0011 10xx xxxx */ - DECODE_EMULATE (0xfc00, 0x4000, t16_emulate_loregs_noitrwflags), - - /* - * Special data instructions and branch and exchange - * 0100 01xx xxxx xxxx - */ - - /* BLX pc 0100 0111 1111 1xxx */ - DECODE_REJECT (0xfff8, 0x47f8), - - /* BX (register) 0100 0111 0xxx xxxx */ - /* BLX (register) 0100 0111 1xxx xxxx */ - DECODE_SIMULATE (0xff00, 0x4700, t16_simulate_bxblx), - - /* ADD pc, pc 0100 0100 1111 1111 */ - DECODE_REJECT (0xffff, 0x44ff), - - /* ADD (register) 0100 0100 xxxx xxxx */ - /* CMP (register) 0100 0101 xxxx xxxx */ - /* MOV (register) 0100 0110 xxxx xxxx */ - DECODE_CUSTOM (0xfc00, 0x4400, t16_decode_hiregs), - - /* - * Load from Literal Pool - * LDR (literal) 0100 1xxx xxxx xxxx - */ - DECODE_SIMULATE (0xf800, 0x4800, t16_simulate_ldr_literal), - - /* - * 16-bit Thumb Load/store instructions - * 0101 xxxx xxxx xxxx - * 011x xxxx xxxx xxxx - * 100x xxxx xxxx xxxx - */ - - /* STR (register) 0101 000x xxxx xxxx */ - /* STRH (register) 0101 001x xxxx xxxx */ - /* STRB (register) 0101 010x xxxx xxxx */ - /* LDRSB (register) 0101 011x xxxx xxxx */ - /* LDR (register) 0101 100x xxxx xxxx */ - /* LDRH (register) 0101 101x xxxx xxxx */ - /* LDRB (register) 0101 110x xxxx xxxx */ - /* LDRSH (register) 0101 111x xxxx xxxx */ - /* STR (immediate, Thumb) 0110 0xxx xxxx xxxx */ - /* LDR (immediate, Thumb) 0110 1xxx xxxx xxxx */ - /* STRB (immediate, Thumb) 0111 0xxx xxxx xxxx */ - /* LDRB (immediate, Thumb) 0111 1xxx xxxx xxxx */ - DECODE_EMULATE (0xc000, 0x4000, t16_emulate_loregs_rwflags), - /* STRH (immediate, Thumb) 1000 0xxx xxxx xxxx */ - /* LDRH (immediate, Thumb) 1000 1xxx xxxx xxxx */ - DECODE_EMULATE (0xf000, 0x8000, t16_emulate_loregs_rwflags), - /* STR (immediate, Thumb) 1001 0xxx xxxx xxxx */ - /* LDR (immediate, Thumb) 1001 1xxx xxxx xxxx */ - DECODE_SIMULATE (0xf000, 0x9000, t16_simulate_ldrstr_sp_relative), - - /* - * Generate PC-/SP-relative address - * ADR (literal) 1010 0xxx xxxx xxxx - * ADD (SP plus immediate) 1010 1xxx xxxx xxxx - */ - DECODE_SIMULATE (0xf000, 0xa000, t16_simulate_reladr), - - /* - * Miscellaneous 16-bit instructions - * 1011 xxxx xxxx xxxx - */ - DECODE_TABLE (0xf000, 0xb000, t16_table_1011), - - /* STM 1100 0xxx xxxx xxxx */ - /* LDM 1100 1xxx xxxx xxxx */ - DECODE_EMULATE (0xf000, 0xc000, t16_emulate_loregs_rwflags), - - /* - * Conditional branch, and Supervisor Call - */ - - /* Permanently UNDEFINED 1101 1110 xxxx xxxx */ - /* SVC 1101 1111 xxxx xxxx */ - DECODE_REJECT (0xfe00, 0xde00), - - /* Conditional branch 1101 xxxx xxxx xxxx */ - DECODE_CUSTOM (0xf000, 0xd000, t16_decode_cond_branch), - - /* - * Unconditional branch - * B 1110 0xxx xxxx xxxx - */ - DECODE_SIMULATE (0xf800, 0xe000, t16_simulate_branch), - - DECODE_END -}; - -static unsigned long __kprobes thumb_check_cc(unsigned long cpsr) -{ - if (unlikely(in_it_block(cpsr))) - return kprobe_condition_checks[current_cond(cpsr)](cpsr); - return true; -} - -static void __kprobes thumb16_singlestep(struct kprobe *p, struct pt_regs *regs) -{ - regs->ARM_pc += 2; - p->ainsn.insn_handler(p, regs); - regs->ARM_cpsr = it_advance(regs->ARM_cpsr); -} - -static void __kprobes thumb32_singlestep(struct kprobe *p, struct pt_regs *regs) -{ - regs->ARM_pc += 4; - p->ainsn.insn_handler(p, regs); - regs->ARM_cpsr = it_advance(regs->ARM_cpsr); -} - -enum kprobe_insn __kprobes -thumb16_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) -{ - asi->insn_singlestep = thumb16_singlestep; - asi->insn_check_cc = thumb_check_cc; - return kprobe_decode_insn(insn, asi, kprobe_decode_thumb16_table, true); -} - -enum kprobe_insn __kprobes -thumb32_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) -{ - asi->insn_singlestep = thumb32_singlestep; - asi->insn_check_cc = thumb_check_cc; - return kprobe_decode_insn(insn, asi, kprobe_decode_thumb32_table, true); -} diff --git a/trunk/arch/arm/kernel/kprobes.c b/trunk/arch/arm/kernel/kprobes.c index 129c1163248b..1656c87501c0 100644 --- a/trunk/arch/arm/kernel/kprobes.c +++ b/trunk/arch/arm/kernel/kprobes.c @@ -28,16 +28,14 @@ #include #include -#include "kprobes.h" - #define MIN_STACK_SIZE(addr) \ min((unsigned long)MAX_STACK_SIZE, \ (unsigned long)current_thread_info() + THREAD_START_SP - (addr)) -#define flush_insns(addr, size) \ +#define flush_insns(addr, cnt) \ flush_icache_range((unsigned long)(addr), \ (unsigned long)(addr) + \ - (size)) + sizeof(kprobe_opcode_t) * (cnt)) /* Used as a marker in ARM_pc to note when we're in a jprobe. */ #define JPROBE_MAGIC_ADDR 0xffffffff @@ -51,35 +49,16 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) kprobe_opcode_t insn; kprobe_opcode_t tmp_insn[MAX_INSN_SIZE]; unsigned long addr = (unsigned long)p->addr; - bool thumb; - kprobe_decode_insn_t *decode_insn; int is; - if (in_exception_text(addr)) + if (addr & 0x3 || in_exception_text(addr)) return -EINVAL; -#ifdef CONFIG_THUMB2_KERNEL - thumb = true; - addr &= ~1; /* Bit 0 would normally be set to indicate Thumb code */ - insn = ((u16 *)addr)[0]; - if (is_wide_instruction(insn)) { - insn <<= 16; - insn |= ((u16 *)addr)[1]; - decode_insn = thumb32_kprobe_decode_insn; - } else - decode_insn = thumb16_kprobe_decode_insn; -#else /* !CONFIG_THUMB2_KERNEL */ - thumb = false; - if (addr & 0x3) - return -EINVAL; insn = *p->addr; - decode_insn = arm_kprobe_decode_insn; -#endif - p->opcode = insn; p->ainsn.insn = tmp_insn; - switch ((*decode_insn)(insn, &p->ainsn)) { + switch (arm_kprobe_decode_insn(insn, &p->ainsn)) { case INSN_REJECTED: /* not supported */ return -EINVAL; @@ -89,10 +68,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) return -ENOMEM; for (is = 0; is < MAX_INSN_SIZE; ++is) p->ainsn.insn[is] = tmp_insn[is]; - flush_insns(p->ainsn.insn, - sizeof(p->ainsn.insn[0]) * MAX_INSN_SIZE); - p->ainsn.insn_fn = (kprobe_insn_fn_t *) - ((uintptr_t)p->ainsn.insn | thumb); + flush_insns(p->ainsn.insn, MAX_INSN_SIZE); break; case INSN_GOOD_NO_SLOT: /* instruction doesn't need insn slot */ @@ -103,88 +79,24 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) return 0; } -#ifdef CONFIG_THUMB2_KERNEL - -/* - * For a 32-bit Thumb breakpoint spanning two memory words we need to take - * special precautions to insert the breakpoint atomically, especially on SMP - * systems. This is achieved by calling this arming function using stop_machine. - */ -static int __kprobes set_t32_breakpoint(void *addr) -{ - ((u16 *)addr)[0] = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION >> 16; - ((u16 *)addr)[1] = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION & 0xffff; - flush_insns(addr, 2*sizeof(u16)); - return 0; -} - -void __kprobes arch_arm_kprobe(struct kprobe *p) -{ - uintptr_t addr = (uintptr_t)p->addr & ~1; /* Remove any Thumb flag */ - - if (!is_wide_instruction(p->opcode)) { - *(u16 *)addr = KPROBE_THUMB16_BREAKPOINT_INSTRUCTION; - flush_insns(addr, sizeof(u16)); - } else if (addr & 2) { - /* A 32-bit instruction spanning two words needs special care */ - stop_machine(set_t32_breakpoint, (void *)addr, &cpu_online_map); - } else { - /* Word aligned 32-bit instruction can be written atomically */ - u32 bkp = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION; -#ifndef __ARMEB__ /* Swap halfwords for little-endian */ - bkp = (bkp >> 16) | (bkp << 16); -#endif - *(u32 *)addr = bkp; - flush_insns(addr, sizeof(u32)); - } -} - -#else /* !CONFIG_THUMB2_KERNEL */ - void __kprobes arch_arm_kprobe(struct kprobe *p) { - kprobe_opcode_t insn = p->opcode; - kprobe_opcode_t brkp = KPROBE_ARM_BREAKPOINT_INSTRUCTION; - if (insn >= 0xe0000000) - brkp |= 0xe0000000; /* Unconditional instruction */ - else - brkp |= insn & 0xf0000000; /* Copy condition from insn */ - *p->addr = brkp; - flush_insns(p->addr, sizeof(p->addr[0])); + *p->addr = KPROBE_BREAKPOINT_INSTRUCTION; + flush_insns(p->addr, 1); } -#endif /* !CONFIG_THUMB2_KERNEL */ - /* * The actual disarming is done here on each CPU and synchronized using * stop_machine. This synchronization is necessary on SMP to avoid removing * a probe between the moment the 'Undefined Instruction' exception is raised * and the moment the exception handler reads the faulting instruction from - * memory. It is also needed to atomically set the two half-words of a 32-bit - * Thumb breakpoint. + * memory. */ int __kprobes __arch_disarm_kprobe(void *p) { struct kprobe *kp = p; -#ifdef CONFIG_THUMB2_KERNEL - u16 *addr = (u16 *)((uintptr_t)kp->addr & ~1); - kprobe_opcode_t insn = kp->opcode; - unsigned int len; - - if (is_wide_instruction(insn)) { - ((u16 *)addr)[0] = insn>>16; - ((u16 *)addr)[1] = insn; - len = 2*sizeof(u16); - } else { - ((u16 *)addr)[0] = insn; - len = sizeof(u16); - } - flush_insns(addr, len); - -#else /* !CONFIG_THUMB2_KERNEL */ *kp->addr = kp->opcode; - flush_insns(kp->addr, sizeof(kp->addr[0])); -#endif + flush_insns(kp->addr, 1); return 0; } @@ -218,24 +130,12 @@ static void __kprobes set_current_kprobe(struct kprobe *p) __get_cpu_var(current_kprobe) = p; } -static void __kprobes -singlestep_skip(struct kprobe *p, struct pt_regs *regs) +static void __kprobes singlestep(struct kprobe *p, struct pt_regs *regs, + struct kprobe_ctlblk *kcb) { -#ifdef CONFIG_THUMB2_KERNEL - regs->ARM_cpsr = it_advance(regs->ARM_cpsr); - if (is_wide_instruction(p->opcode)) - regs->ARM_pc += 4; - else - regs->ARM_pc += 2; -#else regs->ARM_pc += 4; -#endif -} - -static inline void __kprobes -singlestep(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb) -{ - p->ainsn.insn_singlestep(p, regs); + if (p->ainsn.insn_check_cc(regs->ARM_cpsr)) + p->ainsn.insn_handler(p, regs); } /* @@ -249,23 +149,11 @@ void __kprobes kprobe_handler(struct pt_regs *regs) { struct kprobe *p, *cur; struct kprobe_ctlblk *kcb; + kprobe_opcode_t *addr = (kprobe_opcode_t *)regs->ARM_pc; kcb = get_kprobe_ctlblk(); cur = kprobe_running(); - -#ifdef CONFIG_THUMB2_KERNEL - /* - * First look for a probe which was registered using an address with - * bit 0 set, this is the usual situation for pointers to Thumb code. - * If not found, fallback to looking for one with bit 0 clear. - */ - p = get_kprobe((kprobe_opcode_t *)(regs->ARM_pc | 1)); - if (!p) - p = get_kprobe((kprobe_opcode_t *)regs->ARM_pc); - -#else /* ! CONFIG_THUMB2_KERNEL */ - p = get_kprobe((kprobe_opcode_t *)regs->ARM_pc); -#endif + p = get_kprobe(addr); if (p) { if (cur) { @@ -285,8 +173,7 @@ void __kprobes kprobe_handler(struct pt_regs *regs) /* impossible cases */ BUG(); } - } else if (p->ainsn.insn_check_cc(regs->ARM_cpsr)) { - /* Probe hit and conditional execution check ok. */ + } else { set_current_kprobe(p); kcb->kprobe_status = KPROBE_HIT_ACTIVE; @@ -306,13 +193,6 @@ void __kprobes kprobe_handler(struct pt_regs *regs) } reset_current_kprobe(); } - } else { - /* - * Probe hit but conditional execution check failed, - * so just skip the instruction and continue as if - * nothing had happened. - */ - singlestep_skip(p, regs); } } else if (cur) { /* We probably hit a jprobe. Call its break handler. */ @@ -420,11 +300,7 @@ void __naked __kprobes kretprobe_trampoline(void) "bl trampoline_handler \n\t" "mov lr, r0 \n\t" "ldmia sp!, {r0 - r11} \n\t" -#ifdef CONFIG_THUMB2_KERNEL - "bx lr \n\t" -#else "mov pc, lr \n\t" -#endif : : : "memory"); } @@ -502,22 +378,11 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) struct jprobe *jp = container_of(p, struct jprobe, kp); struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); long sp_addr = regs->ARM_sp; - long cpsr; kcb->jprobe_saved_regs = *regs; memcpy(kcb->jprobes_stack, (void *)sp_addr, MIN_STACK_SIZE(sp_addr)); regs->ARM_pc = (long)jp->entry; - - cpsr = regs->ARM_cpsr | PSR_I_BIT; -#ifdef CONFIG_THUMB2_KERNEL - /* Set correct Thumb state in cpsr */ - if (regs->ARM_pc & 1) - cpsr |= PSR_T_BIT; - else - cpsr &= ~PSR_T_BIT; -#endif - regs->ARM_cpsr = cpsr; - + regs->ARM_cpsr |= PSR_I_BIT; preempt_disable(); return 1; } @@ -539,12 +404,7 @@ void __kprobes jprobe_return(void) * This is to prevent any simulated instruction from writing * over the regs when they are accessing the stack. */ -#ifdef CONFIG_THUMB2_KERNEL - "sub r0, %0, %1 \n\t" - "mov sp, r0 \n\t" -#else "sub sp, %0, %1 \n\t" -#endif "ldr r0, ="__stringify(JPROBE_MAGIC_ADDR)"\n\t" "str %0, [sp, %2] \n\t" "str r0, [sp, %3] \n\t" @@ -555,28 +415,15 @@ void __kprobes jprobe_return(void) * Return to the context saved by setjmp_pre_handler * and restored by longjmp_break_handler. */ -#ifdef CONFIG_THUMB2_KERNEL - "ldr lr, [sp, %2] \n\t" /* lr = saved sp */ - "ldrd r0, r1, [sp, %5] \n\t" /* r0,r1 = saved lr,pc */ - "ldr r2, [sp, %4] \n\t" /* r2 = saved psr */ - "stmdb lr!, {r0, r1, r2} \n\t" /* push saved lr and */ - /* rfe context */ - "ldmia sp, {r0 - r12} \n\t" - "mov sp, lr \n\t" - "ldr lr, [sp], #4 \n\t" - "rfeia sp! \n\t" -#else "ldr r0, [sp, %4] \n\t" "msr cpsr_cxsf, r0 \n\t" "ldmia sp, {r0 - pc} \n\t" -#endif : : "r" (kcb->jprobe_saved_regs.ARM_sp), "I" (sizeof(struct pt_regs) * 2), "J" (offsetof(struct pt_regs, ARM_sp)), "J" (offsetof(struct pt_regs, ARM_pc)), - "J" (offsetof(struct pt_regs, ARM_cpsr)), - "J" (offsetof(struct pt_regs, ARM_lr)) + "J" (offsetof(struct pt_regs, ARM_cpsr)) : "memory", "cc"); } @@ -613,44 +460,17 @@ int __kprobes arch_trampoline_kprobe(struct kprobe *p) return 0; } -#ifdef CONFIG_THUMB2_KERNEL - -static struct undef_hook kprobes_thumb16_break_hook = { - .instr_mask = 0xffff, - .instr_val = KPROBE_THUMB16_BREAKPOINT_INSTRUCTION, - .cpsr_mask = MODE_MASK, - .cpsr_val = SVC_MODE, - .fn = kprobe_trap_handler, -}; - -static struct undef_hook kprobes_thumb32_break_hook = { +static struct undef_hook kprobes_break_hook = { .instr_mask = 0xffffffff, - .instr_val = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION, + .instr_val = KPROBE_BREAKPOINT_INSTRUCTION, .cpsr_mask = MODE_MASK, .cpsr_val = SVC_MODE, .fn = kprobe_trap_handler, }; -#else /* !CONFIG_THUMB2_KERNEL */ - -static struct undef_hook kprobes_arm_break_hook = { - .instr_mask = 0x0fffffff, - .instr_val = KPROBE_ARM_BREAKPOINT_INSTRUCTION, - .cpsr_mask = MODE_MASK, - .cpsr_val = SVC_MODE, - .fn = kprobe_trap_handler, -}; - -#endif /* !CONFIG_THUMB2_KERNEL */ - int __init arch_init_kprobes() { arm_kprobe_decode_init(); -#ifdef CONFIG_THUMB2_KERNEL - register_undef_hook(&kprobes_thumb16_break_hook); - register_undef_hook(&kprobes_thumb32_break_hook); -#else - register_undef_hook(&kprobes_arm_break_hook); -#endif + register_undef_hook(&kprobes_break_hook); return 0; } diff --git a/trunk/arch/arm/kernel/kprobes.h b/trunk/arch/arm/kernel/kprobes.h deleted file mode 100644 index a6aeda0a6c7f..000000000000 --- a/trunk/arch/arm/kernel/kprobes.h +++ /dev/null @@ -1,420 +0,0 @@ -/* - * arch/arm/kernel/kprobes.h - * - * Copyright (C) 2011 Jon Medhurst . - * - * Some contents moved here from arch/arm/include/asm/kprobes.h which is - * Copyright (C) 2006, 2007 Motorola Inc. - * - * 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. - * - * 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. - */ - -#ifndef _ARM_KERNEL_KPROBES_H -#define _ARM_KERNEL_KPROBES_H - -/* - * These undefined instructions must be unique and - * reserved solely for kprobes' use. - */ -#define KPROBE_ARM_BREAKPOINT_INSTRUCTION 0x07f001f8 -#define KPROBE_THUMB16_BREAKPOINT_INSTRUCTION 0xde18 -#define KPROBE_THUMB32_BREAKPOINT_INSTRUCTION 0xf7f0a018 - - -enum kprobe_insn { - INSN_REJECTED, - INSN_GOOD, - INSN_GOOD_NO_SLOT -}; - -typedef enum kprobe_insn (kprobe_decode_insn_t)(kprobe_opcode_t, - struct arch_specific_insn *); - -#ifdef CONFIG_THUMB2_KERNEL - -enum kprobe_insn thumb16_kprobe_decode_insn(kprobe_opcode_t, - struct arch_specific_insn *); -enum kprobe_insn thumb32_kprobe_decode_insn(kprobe_opcode_t, - struct arch_specific_insn *); - -#else /* !CONFIG_THUMB2_KERNEL */ - -enum kprobe_insn arm_kprobe_decode_insn(kprobe_opcode_t, - struct arch_specific_insn *); -#endif - -void __init arm_kprobe_decode_init(void); - -extern kprobe_check_cc * const kprobe_condition_checks[16]; - - -#if __LINUX_ARM_ARCH__ >= 7 - -/* str_pc_offset is architecturally defined from ARMv7 onwards */ -#define str_pc_offset 8 -#define find_str_pc_offset() - -#else /* __LINUX_ARM_ARCH__ < 7 */ - -/* We need a run-time check to determine str_pc_offset */ -extern int str_pc_offset; -void __init find_str_pc_offset(void); - -#endif - - -/* - * Update ITSTATE after normal execution of an IT block instruction. - * - * The 8 IT state bits are split into two parts in CPSR: - * ITSTATE<1:0> are in CPSR<26:25> - * ITSTATE<7:2> are in CPSR<15:10> - */ -static inline unsigned long it_advance(unsigned long cpsr) - { - if ((cpsr & 0x06000400) == 0) { - /* ITSTATE<2:0> == 0 means end of IT block, so clear IT state */ - cpsr &= ~PSR_IT_MASK; - } else { - /* We need to shift left ITSTATE<4:0> */ - const unsigned long mask = 0x06001c00; /* Mask ITSTATE<4:0> */ - unsigned long it = cpsr & mask; - it <<= 1; - it |= it >> (27 - 10); /* Carry ITSTATE<2> to correct place */ - it &= mask; - cpsr &= ~mask; - cpsr |= it; - } - return cpsr; -} - -static inline void __kprobes bx_write_pc(long pcv, struct pt_regs *regs) -{ - long cpsr = regs->ARM_cpsr; - if (pcv & 0x1) { - cpsr |= PSR_T_BIT; - pcv &= ~0x1; - } else { - cpsr &= ~PSR_T_BIT; - pcv &= ~0x2; /* Avoid UNPREDICTABLE address allignment */ - } - regs->ARM_cpsr = cpsr; - regs->ARM_pc = pcv; -} - - -#if __LINUX_ARM_ARCH__ >= 6 - -/* Kernels built for >= ARMv6 should never run on <= ARMv5 hardware, so... */ -#define load_write_pc_interworks true -#define test_load_write_pc_interworking() - -#else /* __LINUX_ARM_ARCH__ < 6 */ - -/* We need run-time testing to determine if load_write_pc() should interwork. */ -extern bool load_write_pc_interworks; -void __init test_load_write_pc_interworking(void); - -#endif - -static inline void __kprobes load_write_pc(long pcv, struct pt_regs *regs) -{ - if (load_write_pc_interworks) - bx_write_pc(pcv, regs); - else - regs->ARM_pc = pcv; -} - - -#if __LINUX_ARM_ARCH__ >= 7 - -#define alu_write_pc_interworks true -#define test_alu_write_pc_interworking() - -#elif __LINUX_ARM_ARCH__ <= 5 - -/* Kernels built for <= ARMv5 should never run on >= ARMv6 hardware, so... */ -#define alu_write_pc_interworks false -#define test_alu_write_pc_interworking() - -#else /* __LINUX_ARM_ARCH__ == 6 */ - -/* We could be an ARMv6 binary on ARMv7 hardware so we need a run-time check. */ -extern bool alu_write_pc_interworks; -void __init test_alu_write_pc_interworking(void); - -#endif /* __LINUX_ARM_ARCH__ == 6 */ - -static inline void __kprobes alu_write_pc(long pcv, struct pt_regs *regs) -{ - if (alu_write_pc_interworks) - bx_write_pc(pcv, regs); - else - regs->ARM_pc = pcv; -} - - -void __kprobes kprobe_simulate_nop(struct kprobe *p, struct pt_regs *regs); -void __kprobes kprobe_emulate_none(struct kprobe *p, struct pt_regs *regs); - -enum kprobe_insn __kprobes -kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi); - -/* - * Test if load/store instructions writeback the address register. - * if P (bit 24) == 0 or W (bit 21) == 1 - */ -#define is_writeback(insn) ((insn ^ 0x01000000) & 0x01200000) - -/* - * The following definitions and macros are used to build instruction - * decoding tables for use by kprobe_decode_insn. - * - * These tables are a concatenation of entries each of which consist of one of - * the decode_* structs. All of the fields in every type of decode structure - * are of the union type decode_item, therefore the entire decode table can be - * viewed as an array of these and declared like: - * - * static const union decode_item table_name[] = {}; - * - * In order to construct each entry in the table, macros are used to - * initialise a number of sequential decode_item values in a layout which - * matches the relevant struct. E.g. DECODE_SIMULATE initialise a struct - * decode_simulate by initialising four decode_item objects like this... - * - * {.bits = _type}, - * {.bits = _mask}, - * {.bits = _value}, - * {.handler = _handler}, - * - * Initialising a specified member of the union means that the compiler - * will produce a warning if the argument is of an incorrect type. - * - * Below is a list of each of the macros used to initialise entries and a - * description of the action performed when that entry is matched to an - * instruction. A match is found when (instruction & mask) == value. - * - * DECODE_TABLE(mask, value, table) - * Instruction decoding jumps to parsing the new sub-table 'table'. - * - * DECODE_CUSTOM(mask, value, decoder) - * The custom function 'decoder' is called to the complete decoding - * of an instruction. - * - * DECODE_SIMULATE(mask, value, handler) - * Set the probes instruction handler to 'handler', this will be used - * to simulate the instruction when the probe is hit. Decoding returns - * with INSN_GOOD_NO_SLOT. - * - * DECODE_EMULATE(mask, value, handler) - * Set the probes instruction handler to 'handler', this will be used - * to emulate the instruction when the probe is hit. The modified - * instruction (see below) is placed in the probes instruction slot so it - * may be called by the emulation code. Decoding returns with INSN_GOOD. - * - * DECODE_REJECT(mask, value) - * Instruction decoding fails with INSN_REJECTED - * - * DECODE_OR(mask, value) - * This allows the mask/value test of multiple table entries to be - * logically ORed. Once an 'or' entry is matched the decoding action to - * be performed is that of the next entry which isn't an 'or'. E.g. - * - * DECODE_OR (mask1, value1) - * DECODE_OR (mask2, value2) - * DECODE_SIMULATE (mask3, value3, simulation_handler) - * - * This means that if any of the three mask/value pairs match the - * instruction being decoded, then 'simulation_handler' will be used - * for it. - * - * Both the SIMULATE and EMULATE macros have a second form which take an - * additional 'regs' argument. - * - * DECODE_SIMULATEX(mask, value, handler, regs) - * DECODE_EMULATEX (mask, value, handler, regs) - * - * These are used to specify what kind of CPU register is encoded in each of the - * least significant 5 nibbles of the instruction being decoded. The regs value - * is specified using the REGS macro, this takes any of the REG_TYPE_* values - * from enum decode_reg_type as arguments; only the '*' part of the name is - * given. E.g. - * - * REGS(0, ANY, NOPC, 0, ANY) - * - * This indicates an instruction is encoded like: - * - * bits 19..16 ignore - * bits 15..12 any register allowed here - * bits 11.. 8 any register except PC allowed here - * bits 7.. 4 ignore - * bits 3.. 0 any register allowed here - * - * This register specification is checked after a decode table entry is found to - * match an instruction (through the mask/value test). Any invalid register then - * found in the instruction will cause decoding to fail with INSN_REJECTED. In - * the above example this would happen if bits 11..8 of the instruction were - * 1111, indicating R15 or PC. - * - * As well as checking for legal combinations of registers, this data is also - * used to modify the registers encoded in the instructions so that an - * emulation routines can use it. (See decode_regs() and INSN_NEW_BITS.) - * - * Here is a real example which matches ARM instructions of the form - * "AND ,,, " - * - * DECODE_EMULATEX (0x0e000090, 0x00000010, emulate_rd12rn16rm0rs8_rwflags, - * REGS(ANY, ANY, NOPC, 0, ANY)), - * ^ ^ ^ ^ - * Rn Rd Rs Rm - * - * Decoding the instruction "AND R4, R5, R6, ASL R15" will be rejected because - * Rs == R15 - * - * Decoding the instruction "AND R4, R5, R6, ASL R7" will be accepted and the - * instruction will be modified to "AND R0, R2, R3, ASL R1" and then placed into - * the kprobes instruction slot. This can then be called later by the handler - * function emulate_rd12rn16rm0rs8_rwflags in order to simulate the instruction. - */ - -enum decode_type { - DECODE_TYPE_END, - DECODE_TYPE_TABLE, - DECODE_TYPE_CUSTOM, - DECODE_TYPE_SIMULATE, - DECODE_TYPE_EMULATE, - DECODE_TYPE_OR, - DECODE_TYPE_REJECT, - NUM_DECODE_TYPES /* Must be last enum */ -}; - -#define DECODE_TYPE_BITS 4 -#define DECODE_TYPE_MASK ((1 << DECODE_TYPE_BITS) - 1) - -enum decode_reg_type { - REG_TYPE_NONE = 0, /* Not a register, ignore */ - REG_TYPE_ANY, /* Any register allowed */ - REG_TYPE_SAMEAS16, /* Register should be same as that at bits 19..16 */ - REG_TYPE_SP, /* Register must be SP */ - REG_TYPE_PC, /* Register must be PC */ - REG_TYPE_NOSP, /* Register must not be SP */ - REG_TYPE_NOSPPC, /* Register must not be SP or PC */ - REG_TYPE_NOPC, /* Register must not be PC */ - REG_TYPE_NOPCWB, /* No PC if load/store write-back flag also set */ - - /* The following types are used when the encoding for PC indicates - * another instruction form. This distiction only matters for test - * case coverage checks. - */ - REG_TYPE_NOPCX, /* Register must not be PC */ - REG_TYPE_NOSPPCX, /* Register must not be SP or PC */ - - /* Alias to allow '0' arg to be used in REGS macro. */ - REG_TYPE_0 = REG_TYPE_NONE -}; - -#define REGS(r16, r12, r8, r4, r0) \ - ((REG_TYPE_##r16) << 16) + \ - ((REG_TYPE_##r12) << 12) + \ - ((REG_TYPE_##r8) << 8) + \ - ((REG_TYPE_##r4) << 4) + \ - (REG_TYPE_##r0) - -union decode_item { - u32 bits; - const union decode_item *table; - kprobe_insn_handler_t *handler; - kprobe_decode_insn_t *decoder; -}; - - -#define DECODE_END \ - {.bits = DECODE_TYPE_END} - - -struct decode_header { - union decode_item type_regs; - union decode_item mask; - union decode_item value; -}; - -#define DECODE_HEADER(_type, _mask, _value, _regs) \ - {.bits = (_type) | ((_regs) << DECODE_TYPE_BITS)}, \ - {.bits = (_mask)}, \ - {.bits = (_value)} - - -struct decode_table { - struct decode_header header; - union decode_item table; -}; - -#define DECODE_TABLE(_mask, _value, _table) \ - DECODE_HEADER(DECODE_TYPE_TABLE, _mask, _value, 0), \ - {.table = (_table)} - - -struct decode_custom { - struct decode_header header; - union decode_item decoder; -}; - -#define DECODE_CUSTOM(_mask, _value, _decoder) \ - DECODE_HEADER(DECODE_TYPE_CUSTOM, _mask, _value, 0), \ - {.decoder = (_decoder)} - - -struct decode_simulate { - struct decode_header header; - union decode_item handler; -}; - -#define DECODE_SIMULATEX(_mask, _value, _handler, _regs) \ - DECODE_HEADER(DECODE_TYPE_SIMULATE, _mask, _value, _regs), \ - {.handler = (_handler)} - -#define DECODE_SIMULATE(_mask, _value, _handler) \ - DECODE_SIMULATEX(_mask, _value, _handler, 0) - - -struct decode_emulate { - struct decode_header header; - union decode_item handler; -}; - -#define DECODE_EMULATEX(_mask, _value, _handler, _regs) \ - DECODE_HEADER(DECODE_TYPE_EMULATE, _mask, _value, _regs), \ - {.handler = (_handler)} - -#define DECODE_EMULATE(_mask, _value, _handler) \ - DECODE_EMULATEX(_mask, _value, _handler, 0) - - -struct decode_or { - struct decode_header header; -}; - -#define DECODE_OR(_mask, _value) \ - DECODE_HEADER(DECODE_TYPE_OR, _mask, _value, 0) - - -struct decode_reject { - struct decode_header header; -}; - -#define DECODE_REJECT(_mask, _value) \ - DECODE_HEADER(DECODE_TYPE_REJECT, _mask, _value, 0) - - -int kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, - const union decode_item *table, bool thumb16); - - -#endif /* _ARM_KERNEL_KPROBES_H */ diff --git a/trunk/arch/arm/kernel/module.c b/trunk/arch/arm/kernel/module.c index 05b377616fd5..016d6a0830a3 100644 --- a/trunk/arch/arm/kernel/module.c +++ b/trunk/arch/arm/kernel/module.c @@ -43,7 +43,25 @@ void *module_alloc(unsigned long size) GFP_KERNEL, PAGE_KERNEL_EXEC, -1, __builtin_return_address(0)); } -#endif +#else /* CONFIG_MMU */ +void *module_alloc(unsigned long size) +{ + return size == 0 ? NULL : vmalloc(size); +} +#endif /* !CONFIG_MMU */ + +void module_free(struct module *module, void *region) +{ + vfree(region); +} + +int module_frob_arch_sections(Elf_Ehdr *hdr, + Elf_Shdr *sechdrs, + char *secstrings, + struct module *mod) +{ + return 0; +} int apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, @@ -247,6 +265,15 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, return 0; } +int +apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab, + unsigned int symindex, unsigned int relsec, struct module *module) +{ + printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n", + module->name); + return -ENOEXEC; +} + struct mod_unwind_map { const Elf_Shdr *unw_sec; const Elf_Shdr *txt_sec; diff --git a/trunk/arch/arm/kernel/perf_event.c b/trunk/arch/arm/kernel/perf_event.c index 53c9c2610cbc..2b5b1421596c 100644 --- a/trunk/arch/arm/kernel/perf_event.c +++ b/trunk/arch/arm/kernel/perf_event.c @@ -435,7 +435,7 @@ armpmu_reserve_hardware(void) if (irq >= 0) free_irq(irq, NULL); } - release_pmu(ARM_PMU_DEVICE_CPU); + release_pmu(pmu_device); pmu_device = NULL; } @@ -454,7 +454,7 @@ armpmu_release_hardware(void) } armpmu->stop(); - release_pmu(ARM_PMU_DEVICE_CPU); + release_pmu(pmu_device); pmu_device = NULL; } @@ -662,12 +662,6 @@ init_hw_perf_events(void) case 0xC090: /* Cortex-A9 */ armpmu = armv7_a9_pmu_init(); break; - case 0xC050: /* Cortex-A5 */ - armpmu = armv7_a5_pmu_init(); - break; - case 0xC0F0: /* Cortex-A15 */ - armpmu = armv7_a15_pmu_init(); - break; } /* Intel CPUs [xscale]. */ } else if (0x69 == implementor) { diff --git a/trunk/arch/arm/kernel/perf_event_v6.c b/trunk/arch/arm/kernel/perf_event_v6.c index dd7f3b9f4cb3..f1e8dd94afe8 100644 --- a/trunk/arch/arm/kernel/perf_event_v6.c +++ b/trunk/arch/arm/kernel/perf_event_v6.c @@ -173,20 +173,6 @@ static const unsigned armv6_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, }, }, - [C(NODE)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - }, }; enum armv6mpcore_perf_types { @@ -324,20 +310,6 @@ static const unsigned armv6mpcore_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, }, }, - [C(NODE)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - }, }; static inline unsigned long @@ -507,7 +479,7 @@ armv6pmu_handle_irq(int irq_num, if (!armpmu_event_set_period(event, hwc, idx)) continue; - if (perf_event_overflow(event, &data, regs)) + if (perf_event_overflow(event, 0, &data, regs)) armpmu->disable(hwc, idx); } diff --git a/trunk/arch/arm/kernel/perf_event_v7.c b/trunk/arch/arm/kernel/perf_event_v7.c index 4c851834f68e..4960686afb58 100644 --- a/trunk/arch/arm/kernel/perf_event_v7.c +++ b/trunk/arch/arm/kernel/perf_event_v7.c @@ -17,23 +17,17 @@ */ #ifdef CONFIG_CPU_V7 -/* - * Common ARMv7 event types - * - * Note: An implementation may not be able to count all of these events - * but the encodings are considered to be `reserved' in the case that - * they are not available. - */ +/* Common ARMv7 event types */ enum armv7_perf_types { ARMV7_PERFCTR_PMNC_SW_INCR = 0x00, ARMV7_PERFCTR_IFETCH_MISS = 0x01, ARMV7_PERFCTR_ITLB_MISS = 0x02, - ARMV7_PERFCTR_DCACHE_REFILL = 0x03, /* L1 */ - ARMV7_PERFCTR_DCACHE_ACCESS = 0x04, /* L1 */ + ARMV7_PERFCTR_DCACHE_REFILL = 0x03, + ARMV7_PERFCTR_DCACHE_ACCESS = 0x04, ARMV7_PERFCTR_DTLB_REFILL = 0x05, ARMV7_PERFCTR_DREAD = 0x06, ARMV7_PERFCTR_DWRITE = 0x07, - ARMV7_PERFCTR_INSTR_EXECUTED = 0x08, + ARMV7_PERFCTR_EXC_TAKEN = 0x09, ARMV7_PERFCTR_EXC_EXECUTED = 0x0A, ARMV7_PERFCTR_CID_WRITE = 0x0B, @@ -45,30 +39,21 @@ enum armv7_perf_types { */ ARMV7_PERFCTR_PC_WRITE = 0x0C, ARMV7_PERFCTR_PC_IMM_BRANCH = 0x0D, - ARMV7_PERFCTR_PC_PROC_RETURN = 0x0E, ARMV7_PERFCTR_UNALIGNED_ACCESS = 0x0F, - - /* These events are defined by the PMUv2 supplement (ARM DDI 0457A). */ ARMV7_PERFCTR_PC_BRANCH_MIS_PRED = 0x10, ARMV7_PERFCTR_CLOCK_CYCLES = 0x11, - ARMV7_PERFCTR_PC_BRANCH_PRED = 0x12, - ARMV7_PERFCTR_MEM_ACCESS = 0x13, - ARMV7_PERFCTR_L1_ICACHE_ACCESS = 0x14, - ARMV7_PERFCTR_L1_DCACHE_WB = 0x15, - ARMV7_PERFCTR_L2_DCACHE_ACCESS = 0x16, - ARMV7_PERFCTR_L2_DCACHE_REFILL = 0x17, - ARMV7_PERFCTR_L2_DCACHE_WB = 0x18, - ARMV7_PERFCTR_BUS_ACCESS = 0x19, - ARMV7_PERFCTR_MEMORY_ERROR = 0x1A, - ARMV7_PERFCTR_INSTR_SPEC = 0x1B, - ARMV7_PERFCTR_TTBR_WRITE = 0x1C, - ARMV7_PERFCTR_BUS_CYCLES = 0x1D, + + ARMV7_PERFCTR_PC_BRANCH_MIS_USED = 0x12, ARMV7_PERFCTR_CPU_CYCLES = 0xFF }; /* ARMv7 Cortex-A8 specific event types */ enum armv7_a8_perf_types { + ARMV7_PERFCTR_INSTR_EXECUTED = 0x08, + + ARMV7_PERFCTR_PC_PROC_RETURN = 0x0E, + ARMV7_PERFCTR_WRITE_BUFFER_FULL = 0x40, ARMV7_PERFCTR_L2_STORE_MERGED = 0x41, ARMV7_PERFCTR_L2_STORE_BUFF = 0x42, @@ -153,39 +138,6 @@ enum armv7_a9_perf_types { ARMV7_PERFCTR_PLE_RQST_PROG = 0xA5 }; -/* ARMv7 Cortex-A5 specific event types */ -enum armv7_a5_perf_types { - ARMV7_PERFCTR_IRQ_TAKEN = 0x86, - ARMV7_PERFCTR_FIQ_TAKEN = 0x87, - - ARMV7_PERFCTR_EXT_MEM_RQST = 0xc0, - ARMV7_PERFCTR_NC_EXT_MEM_RQST = 0xc1, - ARMV7_PERFCTR_PREFETCH_LINEFILL = 0xc2, - ARMV7_PERFCTR_PREFETCH_LINEFILL_DROP = 0xc3, - ARMV7_PERFCTR_ENTER_READ_ALLOC = 0xc4, - ARMV7_PERFCTR_READ_ALLOC = 0xc5, - - ARMV7_PERFCTR_STALL_SB_FULL = 0xc9, -}; - -/* ARMv7 Cortex-A15 specific event types */ -enum armv7_a15_perf_types { - ARMV7_PERFCTR_L1_DCACHE_READ_ACCESS = 0x40, - ARMV7_PERFCTR_L1_DCACHE_WRITE_ACCESS = 0x41, - ARMV7_PERFCTR_L1_DCACHE_READ_REFILL = 0x42, - ARMV7_PERFCTR_L1_DCACHE_WRITE_REFILL = 0x43, - - ARMV7_PERFCTR_L1_DTLB_READ_REFILL = 0x4C, - ARMV7_PERFCTR_L1_DTLB_WRITE_REFILL = 0x4D, - - ARMV7_PERFCTR_L2_DCACHE_READ_ACCESS = 0x50, - ARMV7_PERFCTR_L2_DCACHE_WRITE_ACCESS = 0x51, - ARMV7_PERFCTR_L2_DCACHE_READ_REFILL = 0x52, - ARMV7_PERFCTR_L2_DCACHE_WRITE_REFILL = 0x53, - - ARMV7_PERFCTR_SPEC_PC_WRITE = 0x76, -}; - /* * Cortex-A8 HW events mapping * @@ -255,6 +207,11 @@ static const unsigned armv7_a8_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] }, }, [C(DTLB)] = { + /* + * Only ITLB misses and DTLB refills are supported. + * If users want the DTLB refills misses a raw counter + * must be used. + */ [C(OP_READ)] = { [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, [C(RESULT_MISS)] = ARMV7_PERFCTR_DTLB_REFILL, @@ -298,20 +255,6 @@ static const unsigned armv7_a8_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, }, }, - [C(NODE)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - }, }; /* @@ -380,136 +323,11 @@ static const unsigned armv7_a9_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] }, }, [C(DTLB)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = ARMV7_PERFCTR_DTLB_REFILL, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = ARMV7_PERFCTR_DTLB_REFILL, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - }, - [C(ITLB)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = ARMV7_PERFCTR_ITLB_MISS, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = ARMV7_PERFCTR_ITLB_MISS, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - }, - [C(BPU)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_WRITE, - [C(RESULT_MISS)] - = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_WRITE, - [C(RESULT_MISS)] - = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - }, - [C(NODE)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - }, -}; - -/* - * Cortex-A5 HW events mapping - */ -static const unsigned armv7_a5_perf_map[PERF_COUNT_HW_MAX] = { - [PERF_COUNT_HW_CPU_CYCLES] = ARMV7_PERFCTR_CPU_CYCLES, - [PERF_COUNT_HW_INSTRUCTIONS] = ARMV7_PERFCTR_INSTR_EXECUTED, - [PERF_COUNT_HW_CACHE_REFERENCES] = HW_OP_UNSUPPORTED, - [PERF_COUNT_HW_CACHE_MISSES] = HW_OP_UNSUPPORTED, - [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV7_PERFCTR_PC_WRITE, - [PERF_COUNT_HW_BRANCH_MISSES] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, - [PERF_COUNT_HW_BUS_CYCLES] = HW_OP_UNSUPPORTED, -}; - -static const unsigned armv7_a5_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] - [PERF_COUNT_HW_CACHE_OP_MAX] - [PERF_COUNT_HW_CACHE_RESULT_MAX] = { - [C(L1D)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] - = ARMV7_PERFCTR_DCACHE_ACCESS, - [C(RESULT_MISS)] - = ARMV7_PERFCTR_DCACHE_REFILL, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] - = ARMV7_PERFCTR_DCACHE_ACCESS, - [C(RESULT_MISS)] - = ARMV7_PERFCTR_DCACHE_REFILL, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] - = ARMV7_PERFCTR_PREFETCH_LINEFILL, - [C(RESULT_MISS)] - = ARMV7_PERFCTR_PREFETCH_LINEFILL_DROP, - }, - }, - [C(L1I)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_ICACHE_ACCESS, - [C(RESULT_MISS)] = ARMV7_PERFCTR_IFETCH_MISS, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_ICACHE_ACCESS, - [C(RESULT_MISS)] = ARMV7_PERFCTR_IFETCH_MISS, - }, /* - * The prefetch counters don't differentiate between the I - * side and the D side. + * Only ITLB misses and DTLB refills are supported. + * If users want the DTLB refills misses a raw counter + * must be used. */ - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] - = ARMV7_PERFCTR_PREFETCH_LINEFILL, - [C(RESULT_MISS)] - = ARMV7_PERFCTR_PREFETCH_LINEFILL_DROP, - }, - }, - [C(LL)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - }, - [C(DTLB)] = { [C(OP_READ)] = { [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, [C(RESULT_MISS)] = ARMV7_PERFCTR_DTLB_REFILL, @@ -539,132 +357,12 @@ static const unsigned armv7_a5_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] }, [C(BPU)] = { [C(OP_READ)] = { - [C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_BRANCH_PRED, - [C(RESULT_MISS)] - = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_BRANCH_PRED, - [C(RESULT_MISS)] - = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - }, -}; - -/* - * Cortex-A15 HW events mapping - */ -static const unsigned armv7_a15_perf_map[PERF_COUNT_HW_MAX] = { - [PERF_COUNT_HW_CPU_CYCLES] = ARMV7_PERFCTR_CPU_CYCLES, - [PERF_COUNT_HW_INSTRUCTIONS] = ARMV7_PERFCTR_INSTR_EXECUTED, - [PERF_COUNT_HW_CACHE_REFERENCES] = HW_OP_UNSUPPORTED, - [PERF_COUNT_HW_CACHE_MISSES] = HW_OP_UNSUPPORTED, - [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV7_PERFCTR_SPEC_PC_WRITE, - [PERF_COUNT_HW_BRANCH_MISSES] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, - [PERF_COUNT_HW_BUS_CYCLES] = ARMV7_PERFCTR_BUS_CYCLES, -}; - -static const unsigned armv7_a15_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] - [PERF_COUNT_HW_CACHE_OP_MAX] - [PERF_COUNT_HW_CACHE_RESULT_MAX] = { - [C(L1D)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] - = ARMV7_PERFCTR_L1_DCACHE_READ_ACCESS, - [C(RESULT_MISS)] - = ARMV7_PERFCTR_L1_DCACHE_READ_REFILL, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] - = ARMV7_PERFCTR_L1_DCACHE_WRITE_ACCESS, - [C(RESULT_MISS)] - = ARMV7_PERFCTR_L1_DCACHE_WRITE_REFILL, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - }, - [C(L1I)] = { - /* - * Not all performance counters differentiate between read - * and write accesses/misses so we're not always strictly - * correct, but it's the best we can do. Writes and reads get - * combined in these cases. - */ - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_ICACHE_ACCESS, - [C(RESULT_MISS)] = ARMV7_PERFCTR_IFETCH_MISS, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_ICACHE_ACCESS, - [C(RESULT_MISS)] = ARMV7_PERFCTR_IFETCH_MISS, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - }, - [C(LL)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] - = ARMV7_PERFCTR_L2_DCACHE_READ_ACCESS, - [C(RESULT_MISS)] - = ARMV7_PERFCTR_L2_DCACHE_READ_REFILL, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] - = ARMV7_PERFCTR_L2_DCACHE_WRITE_ACCESS, - [C(RESULT_MISS)] - = ARMV7_PERFCTR_L2_DCACHE_WRITE_REFILL, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - }, - [C(DTLB)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] - = ARMV7_PERFCTR_L1_DTLB_READ_REFILL, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] - = ARMV7_PERFCTR_L1_DTLB_WRITE_REFILL, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - }, - [C(ITLB)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = ARMV7_PERFCTR_ITLB_MISS, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = ARMV7_PERFCTR_ITLB_MISS, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - }, - [C(BPU)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_BRANCH_PRED, + [C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_WRITE, [C(RESULT_MISS)] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, }, [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_BRANCH_PRED, + [C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_WRITE, [C(RESULT_MISS)] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, }, @@ -1089,7 +787,7 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev) if (!armpmu_event_set_period(event, hwc, idx)) continue; - if (perf_event_overflow(event, &data, regs)) + if (perf_event_overflow(event, 0, &data, regs)) armpmu->disable(hwc, idx); } @@ -1207,26 +905,6 @@ static const struct arm_pmu *__init armv7_a9_pmu_init(void) armv7pmu.num_events = armv7_read_num_pmnc_events(); return &armv7pmu; } - -static const struct arm_pmu *__init armv7_a5_pmu_init(void) -{ - armv7pmu.id = ARM_PERF_PMU_ID_CA5; - armv7pmu.name = "ARMv7 Cortex-A5"; - armv7pmu.cache_map = &armv7_a5_perf_cache_map; - armv7pmu.event_map = &armv7_a5_perf_map; - armv7pmu.num_events = armv7_read_num_pmnc_events(); - return &armv7pmu; -} - -static const struct arm_pmu *__init armv7_a15_pmu_init(void) -{ - armv7pmu.id = ARM_PERF_PMU_ID_CA15; - armv7pmu.name = "ARMv7 Cortex-A15"; - armv7pmu.cache_map = &armv7_a15_perf_cache_map; - armv7pmu.event_map = &armv7_a15_perf_map; - armv7pmu.num_events = armv7_read_num_pmnc_events(); - return &armv7pmu; -} #else static const struct arm_pmu *__init armv7_a8_pmu_init(void) { @@ -1237,14 +915,4 @@ static const struct arm_pmu *__init armv7_a9_pmu_init(void) { return NULL; } - -static const struct arm_pmu *__init armv7_a5_pmu_init(void) -{ - return NULL; -} - -static const struct arm_pmu *__init armv7_a15_pmu_init(void) -{ - return NULL; -} #endif /* CONFIG_CPU_V7 */ diff --git a/trunk/arch/arm/kernel/perf_event_xscale.c b/trunk/arch/arm/kernel/perf_event_xscale.c index 3c4397491d08..39affbe4fdb2 100644 --- a/trunk/arch/arm/kernel/perf_event_xscale.c +++ b/trunk/arch/arm/kernel/perf_event_xscale.c @@ -144,20 +144,6 @@ static const unsigned xscale_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, }, }, - [C(NODE)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - }, }; #define XSCALE_PMU_ENABLE 0x001 @@ -265,7 +251,7 @@ xscale1pmu_handle_irq(int irq_num, void *dev) if (!armpmu_event_set_period(event, hwc, idx)) continue; - if (perf_event_overflow(event, &data, regs)) + if (perf_event_overflow(event, 0, &data, regs)) armpmu->disable(hwc, idx); } @@ -597,7 +583,7 @@ xscale2pmu_handle_irq(int irq_num, void *dev) if (!armpmu_event_set_period(event, hwc, idx)) continue; - if (perf_event_overflow(event, &data, regs)) + if (perf_event_overflow(event, 0, &data, regs)) armpmu->disable(hwc, idx); } diff --git a/trunk/arch/arm/kernel/pmu.c b/trunk/arch/arm/kernel/pmu.c index 2b70709376c3..2c79eec19262 100644 --- a/trunk/arch/arm/kernel/pmu.c +++ b/trunk/arch/arm/kernel/pmu.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include @@ -26,88 +25,36 @@ static volatile long pmu_lock; static struct platform_device *pmu_devices[ARM_NUM_PMU_DEVICES]; -static int __devinit pmu_register(struct platform_device *pdev, - enum arm_pmu_type type) +static int __devinit pmu_device_probe(struct platform_device *pdev) { - if (type < 0 || type >= ARM_NUM_PMU_DEVICES) { + + if (pdev->id < 0 || pdev->id >= ARM_NUM_PMU_DEVICES) { pr_warning("received registration request for unknown " - "device %d\n", type); + "device %d\n", pdev->id); return -EINVAL; } - if (pmu_devices[type]) { - pr_warning("rejecting duplicate registration of PMU device " - "type %d.", type); - return -ENOSPC; - } + if (pmu_devices[pdev->id]) + pr_warning("registering new PMU device type %d overwrites " + "previous registration!\n", pdev->id); + else + pr_info("registered new PMU device of type %d\n", + pdev->id); - pr_info("registered new PMU device of type %d\n", type); - pmu_devices[type] = pdev; + pmu_devices[pdev->id] = pdev; return 0; } -#define OF_MATCH_PMU(_name, _type) { \ - .compatible = _name, \ - .data = (void *)_type, \ -} - -#define OF_MATCH_CPU(name) OF_MATCH_PMU(name, ARM_PMU_DEVICE_CPU) - -static struct of_device_id armpmu_of_device_ids[] = { - OF_MATCH_CPU("arm,cortex-a9-pmu"), - OF_MATCH_CPU("arm,cortex-a8-pmu"), - OF_MATCH_CPU("arm,arm1136-pmu"), - OF_MATCH_CPU("arm,arm1176-pmu"), - {}, -}; - -#define PLAT_MATCH_PMU(_name, _type) { \ - .name = _name, \ - .driver_data = _type, \ -} - -#define PLAT_MATCH_CPU(_name) PLAT_MATCH_PMU(_name, ARM_PMU_DEVICE_CPU) - -static struct platform_device_id armpmu_plat_device_ids[] = { - PLAT_MATCH_CPU("arm-pmu"), - {}, -}; - -enum arm_pmu_type armpmu_device_type(struct platform_device *pdev) -{ - const struct of_device_id *of_id; - const struct platform_device_id *pdev_id; - - /* provided by of_device_id table */ - if (pdev->dev.of_node) { - of_id = of_match_device(armpmu_of_device_ids, &pdev->dev); - BUG_ON(!of_id); - return (enum arm_pmu_type)of_id->data; - } - - /* Provided by platform_device_id table */ - pdev_id = platform_get_device_id(pdev); - BUG_ON(!pdev_id); - return pdev_id->driver_data; -} - -static int __devinit armpmu_device_probe(struct platform_device *pdev) -{ - return pmu_register(pdev, armpmu_device_type(pdev)); -} - -static struct platform_driver armpmu_driver = { +static struct platform_driver pmu_driver = { .driver = { .name = "arm-pmu", - .of_match_table = armpmu_of_device_ids, }, - .probe = armpmu_device_probe, - .id_table = armpmu_plat_device_ids, + .probe = pmu_device_probe, }; static int __init register_pmu_driver(void) { - return platform_driver_register(&armpmu_driver); + return platform_driver_register(&pmu_driver); } device_initcall(register_pmu_driver); @@ -130,11 +77,11 @@ reserve_pmu(enum arm_pmu_type device) EXPORT_SYMBOL_GPL(reserve_pmu); int -release_pmu(enum arm_pmu_type device) +release_pmu(struct platform_device *pdev) { - if (WARN_ON(!pmu_devices[device])) + if (WARN_ON(pdev != pmu_devices[pdev->id])) return -EINVAL; - clear_bit_unlock(device, &pmu_lock); + clear_bit_unlock(pdev->id, &pmu_lock); return 0; } EXPORT_SYMBOL_GPL(release_pmu); diff --git a/trunk/arch/arm/kernel/ptrace.c b/trunk/arch/arm/kernel/ptrace.c index 2491f3b406bc..97260060bf26 100644 --- a/trunk/arch/arm/kernel/ptrace.c +++ b/trunk/arch/arm/kernel/ptrace.c @@ -228,12 +228,34 @@ static struct undef_hook thumb_break_hook = { .fn = break_trap, }; +static int thumb2_break_trap(struct pt_regs *regs, unsigned int instr) +{ + unsigned int instr2; + void __user *pc; + + /* Check the second half of the instruction. */ + pc = (void __user *)(instruction_pointer(regs) + 2); + + if (processor_mode(regs) == SVC_MODE) { + instr2 = *(u16 *) pc; + } else { + get_user(instr2, (u16 __user *)pc); + } + + if (instr2 == 0xa000) { + ptrace_break(current, regs); + return 0; + } else { + return 1; + } +} + static struct undef_hook thumb2_break_hook = { - .instr_mask = 0xffffffff, - .instr_val = 0xf7f0a000, + .instr_mask = 0xffff, + .instr_val = 0xf7f0, .cpsr_mask = PSR_T_BIT, .cpsr_val = PSR_T_BIT, - .fn = break_trap, + .fn = thumb2_break_trap, }; static int __init ptrace_break_init(void) @@ -374,7 +396,7 @@ static long ptrace_hbp_idx_to_num(int idx) /* * Handle hitting a HW-breakpoint. */ -static void ptrace_hbptriggered(struct perf_event *bp, +static void ptrace_hbptriggered(struct perf_event *bp, int unused, struct perf_sample_data *data, struct pt_regs *regs) { @@ -457,8 +479,7 @@ static struct perf_event *ptrace_hbp_create(struct task_struct *tsk, int type) attr.bp_type = type; attr.disabled = 1; - return register_user_hw_breakpoint(&attr, ptrace_hbptriggered, NULL, - tsk); + return register_user_hw_breakpoint(&attr, ptrace_hbptriggered, tsk); } static int ptrace_gethbpregs(struct task_struct *tsk, long num, diff --git a/trunk/arch/arm/kernel/setup.c b/trunk/arch/arm/kernel/setup.c index 70bca649e925..acbb447ac6b5 100644 --- a/trunk/arch/arm/kernel/setup.c +++ b/trunk/arch/arm/kernel/setup.c @@ -343,6 +343,54 @@ static void __init feat_v6_fixup(void) elf_hwcap &= ~HWCAP_TLS; } +static void __init setup_processor(void) +{ + struct proc_info_list *list; + + /* + * locate processor in the list of supported processor + * types. The linker builds this table for us from the + * entries in arch/arm/mm/proc-*.S + */ + list = lookup_processor_type(read_cpuid_id()); + if (!list) { + printk("CPU configuration botched (ID %08x), unable " + "to continue.\n", read_cpuid_id()); + while (1); + } + + cpu_name = list->cpu_name; + +#ifdef MULTI_CPU + processor = *list->proc; +#endif +#ifdef MULTI_TLB + cpu_tlb = *list->tlb; +#endif +#ifdef MULTI_USER + cpu_user = *list->user; +#endif +#ifdef MULTI_CACHE + cpu_cache = *list->cache; +#endif + + printk("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n", + cpu_name, read_cpuid_id(), read_cpuid_id() & 15, + proc_arch[cpu_architecture()], cr_alignment); + + sprintf(init_utsname()->machine, "%s%c", list->arch_name, ENDIANNESS); + sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS); + elf_hwcap = list->elf_hwcap; +#ifndef CONFIG_ARM_THUMB + elf_hwcap &= ~HWCAP_THUMB; +#endif + + feat_v6_fixup(); + + cacheid_init(); + cpu_proc_init(); +} + /* * cpu_init - initialise one CPU. * @@ -358,8 +406,6 @@ void cpu_init(void) BUG(); } - cpu_proc_init(); - /* * Define the placement constraint for the inline asm directive below. * In Thumb-2, msr with an immediate value is not allowed. @@ -396,54 +442,6 @@ void cpu_init(void) : "r14"); } -static void __init setup_processor(void) -{ - struct proc_info_list *list; - - /* - * locate processor in the list of supported processor - * types. The linker builds this table for us from the - * entries in arch/arm/mm/proc-*.S - */ - list = lookup_processor_type(read_cpuid_id()); - if (!list) { - printk("CPU configuration botched (ID %08x), unable " - "to continue.\n", read_cpuid_id()); - while (1); - } - - cpu_name = list->cpu_name; - -#ifdef MULTI_CPU - processor = *list->proc; -#endif -#ifdef MULTI_TLB - cpu_tlb = *list->tlb; -#endif -#ifdef MULTI_USER - cpu_user = *list->user; -#endif -#ifdef MULTI_CACHE - cpu_cache = *list->cache; -#endif - - printk("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n", - cpu_name, read_cpuid_id(), read_cpuid_id() & 15, - proc_arch[cpu_architecture()], cr_alignment); - - sprintf(init_utsname()->machine, "%s%c", list->arch_name, ENDIANNESS); - sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS); - elf_hwcap = list->elf_hwcap; -#ifndef CONFIG_ARM_THUMB - elf_hwcap &= ~HWCAP_THUMB; -#endif - - feat_v6_fixup(); - - cacheid_init(); - cpu_init(); -} - void __init dump_machine_table(void) { struct machine_desc *p; @@ -917,14 +915,9 @@ void __init setup_arch(char **cmdline_p) #endif reserve_crashkernel(); + cpu_init(); tcm_init(); -#ifdef CONFIG_ZONE_DMA - if (mdesc->dma_zone_size) { - extern unsigned long arm_dma_zone_size; - arm_dma_zone_size = mdesc->dma_zone_size; - } -#endif #ifdef CONFIG_MULTI_IRQ_HANDLER handle_arch_irq = mdesc->handle_irq; #endif @@ -986,10 +979,6 @@ static const char *hwcap_str[] = { "neon", "vfpv3", "vfpv3d16", - "tls", - "vfpv4", - "idiva", - "idivt", NULL }; diff --git a/trunk/arch/arm/kernel/sleep.S b/trunk/arch/arm/kernel/sleep.S index dc902f2c6845..6398ead9d1c0 100644 --- a/trunk/arch/arm/kernel/sleep.S +++ b/trunk/arch/arm/kernel/sleep.S @@ -10,61 +10,64 @@ /* * Save CPU state for a suspend * r1 = v:p offset - * r2 = suspend function arg0 - * r3 = suspend function + * r3 = virtual return function + * Note: sp is decremented to allocate space for CPU state on stack + * r0-r3,r9,r10,lr corrupted */ -ENTRY(__cpu_suspend) - stmfd sp!, {r4 - r11, lr} +ENTRY(cpu_suspend) + mov r9, lr #ifdef MULTI_CPU ldr r10, =processor - ldr r5, [r10, #CPU_SLEEP_SIZE] @ size of CPU sleep state + mov r2, sp @ current virtual SP + ldr r0, [r10, #CPU_SLEEP_SIZE] @ size of CPU sleep state ldr ip, [r10, #CPU_DO_RESUME] @ virtual resume function -#else - ldr r5, =cpu_suspend_size - ldr ip, =cpu_do_resume -#endif - mov r6, sp @ current virtual SP - sub sp, sp, r5 @ allocate CPU state on stack - mov r0, sp @ save pointer to CPU save block + sub sp, sp, r0 @ allocate CPU state on stack + mov r0, sp @ save pointer add ip, ip, r1 @ convert resume fn to phys - stmfd sp!, {r1, r6, ip} @ save v:p, virt SP, phys resume fn - ldr r5, =sleep_save_sp - add r6, sp, r1 @ convert SP to phys - stmfd sp!, {r2, r3} @ save suspend func arg and pointer + stmfd sp!, {r1, r2, r3, ip} @ save v:p, virt SP, retfn, phys resume fn + ldr r3, =sleep_save_sp + add r2, sp, r1 @ convert SP to phys #ifdef CONFIG_SMP ALT_SMP(mrc p15, 0, lr, c0, c0, 5) ALT_UP(mov lr, #0) and lr, lr, #15 - str r6, [r5, lr, lsl #2] @ save phys SP + str r2, [r3, lr, lsl #2] @ save phys SP #else - str r6, [r5] @ save phys SP + str r2, [r3] @ save phys SP #endif -#ifdef MULTI_CPU mov lr, pc ldr pc, [r10, #CPU_DO_SUSPEND] @ save CPU state #else + mov r2, sp @ current virtual SP + ldr r0, =cpu_suspend_size + sub sp, sp, r0 @ allocate CPU state on stack + mov r0, sp @ save pointer + stmfd sp!, {r1, r2, r3} @ save v:p, virt SP, return fn + ldr r3, =sleep_save_sp + add r2, sp, r1 @ convert SP to phys +#ifdef CONFIG_SMP + ALT_SMP(mrc p15, 0, lr, c0, c0, 5) + ALT_UP(mov lr, #0) + and lr, lr, #15 + str r2, [r3, lr, lsl #2] @ save phys SP +#else + str r2, [r3] @ save phys SP +#endif bl cpu_do_suspend #endif @ flush data cache #ifdef MULTI_CACHE ldr r10, =cpu_cache - mov lr, pc + mov lr, r9 ldr pc, [r10, #CACHE_FLUSH_KERN_ALL] #else - bl __cpuc_flush_kern_all + mov lr, r9 + b __cpuc_flush_kern_all #endif - adr lr, BSYM(cpu_suspend_abort) - ldmfd sp!, {r0, pc} @ call suspend fn -ENDPROC(__cpu_suspend) +ENDPROC(cpu_suspend) .ltorg -cpu_suspend_abort: - ldmia sp!, {r1 - r3} @ pop v:p, virt SP, phys resume fn - mov sp, r2 - ldmfd sp!, {r4 - r11, pc} -ENDPROC(cpu_suspend_abort) - /* * r0 = control register value * r1 = v:p offset (preserved by cpu_do_resume) @@ -94,9 +97,7 @@ ENDPROC(cpu_resume_turn_mmu_on) cpu_resume_after_mmu: str r5, [r2, r4, lsl #2] @ restore old mapping mcr p15, 0, r0, c1, c0, 0 @ turn on D-cache - bl cpu_init @ restore the und/abt/irq banked regs - mov r0, #0 @ return zero on success - ldmfd sp!, {r4 - r11, pc} + mov pc, lr ENDPROC(cpu_resume_after_mmu) /* @@ -119,11 +120,20 @@ ENTRY(cpu_resume) ldr r0, sleep_save_sp @ stack phys addr #endif setmode PSR_I_BIT | PSR_F_BIT | SVC_MODE, r1 @ set SVC, irqs off - @ load v:p, stack, resume fn - ARM( ldmia r0!, {r1, sp, pc} ) -THUMB( ldmia r0!, {r1, r2, r3} ) +#ifdef MULTI_CPU + @ load v:p, stack, return fn, resume fn + ARM( ldmia r0!, {r1, sp, lr, pc} ) +THUMB( ldmia r0!, {r1, r2, r3, r4} ) THUMB( mov sp, r2 ) -THUMB( bx r3 ) +THUMB( mov lr, r3 ) +THUMB( bx r4 ) +#else + @ load v:p, stack, return fn + ARM( ldmia r0!, {r1, sp, lr} ) +THUMB( ldmia r0!, {r1, r2, lr} ) +THUMB( mov sp, r2 ) + b cpu_do_resume +#endif ENDPROC(cpu_resume) sleep_save_sp: diff --git a/trunk/arch/arm/kernel/smp.c b/trunk/arch/arm/kernel/smp.c index 167e3cbe1f2f..e7f92a4321f3 100644 --- a/trunk/arch/arm/kernel/smp.c +++ b/trunk/arch/arm/kernel/smp.c @@ -365,21 +365,14 @@ void __init smp_prepare_cpus(unsigned int max_cpus) */ if (max_cpus > ncores) max_cpus = ncores; - if (ncores > 1 && max_cpus) { + + if (max_cpus > 1) { /* * Enable the local timer or broadcast device for the * boot CPU, but only if we have more than one CPU. */ percpu_timer_setup(); - /* - * Initialise the present map, which describes the set of CPUs - * actually populated at the present time. A platform should - * re-initialize the map in platform_smp_prepare_cpus() if - * present != possible (e.g. physical hotplug). - */ - init_cpu_present(&cpu_possible_map); - /* * Initialise the SCU if there are more than one CPU * and let them know where to start. diff --git a/trunk/arch/arm/kernel/smp_scu.c b/trunk/arch/arm/kernel/smp_scu.c index 79ed5e7f204a..a1e757c3439b 100644 --- a/trunk/arch/arm/kernel/smp_scu.c +++ b/trunk/arch/arm/kernel/smp_scu.c @@ -20,7 +20,6 @@ #define SCU_INVALIDATE 0x0c #define SCU_FPGA_REVISION 0x10 -#ifdef CONFIG_SMP /* * Get the number of CPU cores from the SCU configuration */ @@ -51,7 +50,6 @@ void __init scu_enable(void __iomem *scu_base) */ flush_cache_all(); } -#endif /* * Set the executing CPUs power mode as defined. This will be in diff --git a/trunk/arch/arm/kernel/swp_emulate.c b/trunk/arch/arm/kernel/swp_emulate.c index 5f452f8fde05..40ee7e5045e4 100644 --- a/trunk/arch/arm/kernel/swp_emulate.c +++ b/trunk/arch/arm/kernel/swp_emulate.c @@ -183,7 +183,7 @@ static int swp_handler(struct pt_regs *regs, unsigned int instr) unsigned int address, destreg, data, type; unsigned int res = 0; - perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->ARM_pc); + perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, 0, regs, regs->ARM_pc); if (current->pid != previous_pid) { pr_debug("\"%s\" (%ld) uses deprecated SWP{B} instruction\n", diff --git a/trunk/arch/arm/kernel/tcm.c b/trunk/arch/arm/kernel/tcm.c index 30e302d33e0a..f5cf660eefcc 100644 --- a/trunk/arch/arm/kernel/tcm.c +++ b/trunk/arch/arm/kernel/tcm.c @@ -19,8 +19,6 @@ #include "tcm.h" static struct gen_pool *tcm_pool; -static bool dtcm_present; -static bool itcm_present; /* TCM section definitions from the linker */ extern char __itcm_start, __sitcm_text, __eitcm_text; @@ -92,18 +90,6 @@ void tcm_free(void *addr, size_t len) } EXPORT_SYMBOL(tcm_free); -bool tcm_dtcm_present(void) -{ - return dtcm_present; -} -EXPORT_SYMBOL(tcm_dtcm_present); - -bool tcm_itcm_present(void) -{ - return itcm_present; -} -EXPORT_SYMBOL(tcm_itcm_present); - static int __init setup_tcm_bank(u8 type, u8 bank, u8 banks, u32 *offset) { @@ -148,10 +134,6 @@ static int __init setup_tcm_bank(u8 type, u8 bank, u8 banks, (tcm_region & 1) ? "" : "not "); } - /* Not much fun you can do with a size 0 bank */ - if (tcm_size == 0) - return 0; - /* Force move the TCM bank to where we want it, enable */ tcm_region = *offset | (tcm_region & 0x00000ffeU) | 1; @@ -183,20 +165,12 @@ void __init tcm_init(void) u32 tcm_status = read_cpuid_tcmstatus(); u8 dtcm_banks = (tcm_status >> 16) & 0x03; u8 itcm_banks = (tcm_status & 0x03); - size_t dtcm_code_sz = &__edtcm_data - &__sdtcm_data; - size_t itcm_code_sz = &__eitcm_text - &__sitcm_text; char *start; char *end; char *ram; int ret; int i; - /* Values greater than 2 for D/ITCM banks are "reserved" */ - if (dtcm_banks > 2) - dtcm_banks = 0; - if (itcm_banks > 2) - itcm_banks = 0; - /* Setup DTCM if present */ if (dtcm_banks > 0) { for (i = 0; i < dtcm_banks; i++) { @@ -204,13 +178,6 @@ void __init tcm_init(void) if (ret) return; } - /* This means you compiled more code than fits into DTCM */ - if (dtcm_code_sz > (dtcm_end - DTCM_OFFSET)) { - pr_info("CPU DTCM: %u bytes of code compiled to " - "DTCM but only %lu bytes of DTCM present\n", - dtcm_code_sz, (dtcm_end - DTCM_OFFSET)); - goto no_dtcm; - } dtcm_res.end = dtcm_end - 1; request_resource(&iomem_resource, &dtcm_res); dtcm_iomap[0].length = dtcm_end - DTCM_OFFSET; @@ -219,16 +186,12 @@ void __init tcm_init(void) start = &__sdtcm_data; end = &__edtcm_data; ram = &__dtcm_start; - memcpy(start, ram, dtcm_code_sz); - pr_debug("CPU DTCM: copied data from %p - %p\n", - start, end); - dtcm_present = true; - } else if (dtcm_code_sz) { - pr_info("CPU DTCM: %u bytes of code compiled to DTCM but no " - "DTCM banks present in CPU\n", dtcm_code_sz); + /* This means you compiled more code than fits into DTCM */ + BUG_ON((end - start) > (dtcm_end - DTCM_OFFSET)); + memcpy(start, ram, (end-start)); + pr_debug("CPU DTCM: copied data from %p - %p\n", start, end); } -no_dtcm: /* Setup ITCM if present */ if (itcm_banks > 0) { for (i = 0; i < itcm_banks; i++) { @@ -236,13 +199,6 @@ void __init tcm_init(void) if (ret) return; } - /* This means you compiled more code than fits into ITCM */ - if (itcm_code_sz > (itcm_end - ITCM_OFFSET)) { - pr_info("CPU ITCM: %u bytes of code compiled to " - "ITCM but only %lu bytes of ITCM present\n", - itcm_code_sz, (itcm_end - ITCM_OFFSET)); - return; - } itcm_res.end = itcm_end - 1; request_resource(&iomem_resource, &itcm_res); itcm_iomap[0].length = itcm_end - ITCM_OFFSET; @@ -251,13 +207,10 @@ void __init tcm_init(void) start = &__sitcm_text; end = &__eitcm_text; ram = &__itcm_start; - memcpy(start, ram, itcm_code_sz); - pr_debug("CPU ITCM: copied code from %p - %p\n", - start, end); - itcm_present = true; - } else if (itcm_code_sz) { - pr_info("CPU ITCM: %u bytes of code compiled to ITCM but no " - "ITCM banks present in CPU\n", itcm_code_sz); + /* This means you compiled more code than fits into ITCM */ + BUG_ON((end - start) > (itcm_end - ITCM_OFFSET)); + memcpy(start, ram, (end-start)); + pr_debug("CPU ITCM: copied code from %p - %p\n", start, end); } } @@ -268,6 +221,7 @@ void __init tcm_init(void) */ static int __init setup_tcm_pool(void) { + u32 tcm_status = read_cpuid_tcmstatus(); u32 dtcm_pool_start = (u32) &__edtcm_data; u32 itcm_pool_start = (u32) &__eitcm_text; int ret; @@ -282,7 +236,7 @@ static int __init setup_tcm_pool(void) pr_debug("Setting up TCM memory pool\n"); /* Add the rest of DTCM to the TCM pool */ - if (dtcm_present) { + if (tcm_status & (0x03 << 16)) { if (dtcm_pool_start < dtcm_end) { ret = gen_pool_add(tcm_pool, dtcm_pool_start, dtcm_end - dtcm_pool_start, -1); @@ -299,7 +253,7 @@ static int __init setup_tcm_pool(void) } /* Add the rest of ITCM to the TCM pool */ - if (itcm_present) { + if (tcm_status & 0x03) { if (itcm_pool_start < itcm_end) { ret = gen_pool_add(tcm_pool, itcm_pool_start, itcm_end - itcm_pool_start, -1); diff --git a/trunk/arch/arm/kernel/traps.c b/trunk/arch/arm/kernel/traps.c index 2d3436e9f71f..6807cb1e76dd 100644 --- a/trunk/arch/arm/kernel/traps.c +++ b/trunk/arch/arm/kernel/traps.c @@ -355,24 +355,9 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs) pc = (void __user *)instruction_pointer(regs); if (processor_mode(regs) == SVC_MODE) { -#ifdef CONFIG_THUMB2_KERNEL - if (thumb_mode(regs)) { - instr = ((u16 *)pc)[0]; - if (is_wide_instruction(instr)) { - instr <<= 16; - instr |= ((u16 *)pc)[1]; - } - } else -#endif - instr = *(u32 *) pc; + instr = *(u32 *) pc; } else if (thumb_mode(regs)) { get_user(instr, (u16 __user *)pc); - if (is_wide_instruction(instr)) { - unsigned int instr2; - get_user(instr2, (u16 __user *)pc+1); - instr <<= 16; - instr |= instr2; - } } else { get_user(instr, (u32 __user *)pc); } diff --git a/trunk/arch/arm/kernel/vmlinux.lds.S b/trunk/arch/arm/kernel/vmlinux.lds.S index bf977f8514f6..e5287f21badc 100644 --- a/trunk/arch/arm/kernel/vmlinux.lds.S +++ b/trunk/arch/arm/kernel/vmlinux.lds.S @@ -38,6 +38,57 @@ jiffies = jiffies_64 + 4; SECTIONS { +#ifdef CONFIG_XIP_KERNEL + . = XIP_VIRT_ADDR(CONFIG_XIP_PHYS_ADDR); +#else + . = PAGE_OFFSET + TEXT_OFFSET; +#endif + + .init : { /* Init code and data */ + _stext = .; + _sinittext = .; + HEAD_TEXT + INIT_TEXT + ARM_EXIT_KEEP(EXIT_TEXT) + _einittext = .; + ARM_CPU_DISCARD(PROC_INFO) + __arch_info_begin = .; + *(.arch.info.init) + __arch_info_end = .; + __tagtable_begin = .; + *(.taglist.init) + __tagtable_end = .; +#ifdef CONFIG_SMP_ON_UP + __smpalt_begin = .; + *(.alt.smp.init) + __smpalt_end = .; +#endif + + __pv_table_begin = .; + *(.pv_table) + __pv_table_end = .; + + INIT_SETUP(16) + + INIT_CALLS + CON_INITCALL + SECURITY_INITCALL + INIT_RAM_FS + +#ifndef CONFIG_XIP_KERNEL + __init_begin = _stext; + INIT_DATA + ARM_EXIT_KEEP(EXIT_DATA) +#endif + } + + PERCPU_SECTION(32) + +#ifndef CONFIG_XIP_KERNEL + . = ALIGN(PAGE_SIZE); + __init_end = .; +#endif + /* * unwind exit sections must be discarded before the rest of the * unwind sections get included. @@ -54,23 +105,11 @@ SECTIONS #ifndef CONFIG_MMU *(.fixup) *(__ex_table) -#endif -#ifndef CONFIG_SMP_ON_UP - *(.alt.smp.init) #endif } -#ifdef CONFIG_XIP_KERNEL - . = XIP_VIRT_ADDR(CONFIG_XIP_PHYS_ADDR); -#else - . = PAGE_OFFSET + TEXT_OFFSET; -#endif - .head.text : { - _text = .; - HEAD_TEXT - } .text : { /* Real text segment */ - _stext = .; /* Text and read-only data */ + _text = .; /* Text and read-only data */ __exception_text_start = .; *(.exception.text) __exception_text_end = .; @@ -83,6 +122,8 @@ SECTIONS *(.fixup) #endif *(.gnu.warning) + *(.rodata) + *(.rodata.*) *(.glue_7) *(.glue_7t) . = ALIGN(4); @@ -111,63 +152,10 @@ SECTIONS _etext = .; /* End of text and rodata section */ -#ifndef CONFIG_XIP_KERNEL - . = ALIGN(PAGE_SIZE); - __init_begin = .; -#endif - - INIT_TEXT_SECTION(8) - .exit.text : { - ARM_EXIT_KEEP(EXIT_TEXT) - } - .init.proc.info : { - ARM_CPU_DISCARD(PROC_INFO) - } - .init.arch.info : { - __arch_info_begin = .; - *(.arch.info.init) - __arch_info_end = .; - } - .init.tagtable : { - __tagtable_begin = .; - *(.taglist.init) - __tagtable_end = .; - } -#ifdef CONFIG_SMP_ON_UP - .init.smpalt : { - __smpalt_begin = .; - *(.alt.smp.init) - __smpalt_end = .; - } -#endif - .init.pv_table : { - __pv_table_begin = .; - *(.pv_table) - __pv_table_end = .; - } - .init.data : { -#ifndef CONFIG_XIP_KERNEL - INIT_DATA -#endif - INIT_SETUP(16) - INIT_CALLS - CON_INITCALL - SECURITY_INITCALL - INIT_RAM_FS - } -#ifndef CONFIG_XIP_KERNEL - .exit.data : { - ARM_EXIT_KEEP(EXIT_DATA) - } -#endif - - PERCPU_SECTION(32) - #ifdef CONFIG_XIP_KERNEL __data_loc = ALIGN(4); /* location in binary */ . = PAGE_OFFSET + TEXT_OFFSET; #else - __init_end = .; . = ALIGN(THREAD_SIZE); __data_loc = .; #endif @@ -282,6 +270,12 @@ SECTIONS /* Default discards */ DISCARDS + +#ifndef CONFIG_SMP_ON_UP + /DISCARD/ : { + *(.alt.smp.init) + } +#endif } /* diff --git a/trunk/arch/arm/mach-bcmring/include/mach/entry-macro.S b/trunk/arch/arm/mach-bcmring/include/mach/entry-macro.S index 94c950d783ba..7d393ca010ac 100644 --- a/trunk/arch/arm/mach-bcmring/include/mach/entry-macro.S +++ b/trunk/arch/arm/mach-bcmring/include/mach/entry-macro.S @@ -80,3 +80,7 @@ .macro arch_ret_to_user, tmp1, tmp2 .endm + + .macro irq_prio_table + .endm + diff --git a/trunk/arch/arm/mach-davinci/board-da830-evm.c b/trunk/arch/arm/mach-davinci/board-da830-evm.c index 84fd78684868..8bc3701aa05c 100644 --- a/trunk/arch/arm/mach-davinci/board-da830-evm.c +++ b/trunk/arch/arm/mach-davinci/board-da830-evm.c @@ -681,5 +681,4 @@ MACHINE_START(DAVINCI_DA830_EVM, "DaVinci DA830/OMAP-L137/AM17x EVM") .init_irq = cp_intc_init, .timer = &davinci_timer, .init_machine = da830_evm_init, - .dma_zone_size = SZ_128M, MACHINE_END diff --git a/trunk/arch/arm/mach-davinci/board-da850-evm.c b/trunk/arch/arm/mach-davinci/board-da850-evm.c index 29671ef07152..a7b41bf505f1 100644 --- a/trunk/arch/arm/mach-davinci/board-da850-evm.c +++ b/trunk/arch/arm/mach-davinci/board-da850-evm.c @@ -1261,5 +1261,4 @@ MACHINE_START(DAVINCI_DA850_EVM, "DaVinci DA850/OMAP-L138/AM18x EVM") .init_irq = cp_intc_init, .timer = &davinci_timer, .init_machine = da850_evm_init, - .dma_zone_size = SZ_128M, MACHINE_END diff --git a/trunk/arch/arm/mach-davinci/board-dm355-evm.c b/trunk/arch/arm/mach-davinci/board-dm355-evm.c index 241a6bd67408..6e7cad13352c 100644 --- a/trunk/arch/arm/mach-davinci/board-dm355-evm.c +++ b/trunk/arch/arm/mach-davinci/board-dm355-evm.c @@ -356,5 +356,4 @@ MACHINE_START(DAVINCI_DM355_EVM, "DaVinci DM355 EVM") .init_irq = davinci_irq_init, .timer = &davinci_timer, .init_machine = dm355_evm_init, - .dma_zone_size = SZ_128M, MACHINE_END diff --git a/trunk/arch/arm/mach-davinci/board-dm355-leopard.c b/trunk/arch/arm/mach-davinci/board-dm355-leopard.c index bee284ca7fd6..543f9911b281 100644 --- a/trunk/arch/arm/mach-davinci/board-dm355-leopard.c +++ b/trunk/arch/arm/mach-davinci/board-dm355-leopard.c @@ -275,5 +275,4 @@ MACHINE_START(DM355_LEOPARD, "DaVinci DM355 leopard") .init_irq = davinci_irq_init, .timer = &davinci_timer, .init_machine = dm355_leopard_init, - .dma_zone_size = SZ_128M, MACHINE_END diff --git a/trunk/arch/arm/mach-davinci/board-dm365-evm.c b/trunk/arch/arm/mach-davinci/board-dm365-evm.c index 9818f214d4f0..09a87e61ffcf 100644 --- a/trunk/arch/arm/mach-davinci/board-dm365-evm.c +++ b/trunk/arch/arm/mach-davinci/board-dm365-evm.c @@ -617,6 +617,5 @@ MACHINE_START(DAVINCI_DM365_EVM, "DaVinci DM365 EVM") .init_irq = davinci_irq_init, .timer = &davinci_timer, .init_machine = dm365_evm_init, - .dma_zone_size = SZ_128M, MACHINE_END diff --git a/trunk/arch/arm/mach-davinci/board-dm644x-evm.c b/trunk/arch/arm/mach-davinci/board-dm644x-evm.c index 95607a191e03..556bbd468db3 100644 --- a/trunk/arch/arm/mach-davinci/board-dm644x-evm.c +++ b/trunk/arch/arm/mach-davinci/board-dm644x-evm.c @@ -717,5 +717,4 @@ MACHINE_START(DAVINCI_EVM, "DaVinci DM644x EVM") .init_irq = davinci_irq_init, .timer = &davinci_timer, .init_machine = davinci_evm_init, - .dma_zone_size = SZ_128M, MACHINE_END diff --git a/trunk/arch/arm/mach-davinci/board-dm646x-evm.c b/trunk/arch/arm/mach-davinci/board-dm646x-evm.c index 6d03643b9bd1..f6ac9ba74878 100644 --- a/trunk/arch/arm/mach-davinci/board-dm646x-evm.c +++ b/trunk/arch/arm/mach-davinci/board-dm646x-evm.c @@ -802,7 +802,6 @@ MACHINE_START(DAVINCI_DM6467_EVM, "DaVinci DM646x EVM") .init_irq = davinci_irq_init, .timer = &davinci_timer, .init_machine = evm_init, - .dma_zone_size = SZ_128M, MACHINE_END MACHINE_START(DAVINCI_DM6467TEVM, "DaVinci DM6467T EVM") @@ -811,6 +810,5 @@ MACHINE_START(DAVINCI_DM6467TEVM, "DaVinci DM6467T EVM") .init_irq = davinci_irq_init, .timer = &davinci_timer, .init_machine = evm_init, - .dma_zone_size = SZ_128M, MACHINE_END diff --git a/trunk/arch/arm/mach-davinci/board-mityomapl138.c b/trunk/arch/arm/mach-davinci/board-mityomapl138.c index c278226627ad..5f5d78308873 100644 --- a/trunk/arch/arm/mach-davinci/board-mityomapl138.c +++ b/trunk/arch/arm/mach-davinci/board-mityomapl138.c @@ -571,5 +571,4 @@ MACHINE_START(MITYOMAPL138, "MityDSP-L138/MityARM-1808") .init_irq = cp_intc_init, .timer = &davinci_timer, .init_machine = mityomapl138_init, - .dma_zone_size = SZ_128M, MACHINE_END diff --git a/trunk/arch/arm/mach-davinci/board-neuros-osd2.c b/trunk/arch/arm/mach-davinci/board-neuros-osd2.c index d60a80028ba3..3e7be2de96de 100644 --- a/trunk/arch/arm/mach-davinci/board-neuros-osd2.c +++ b/trunk/arch/arm/mach-davinci/board-neuros-osd2.c @@ -277,5 +277,4 @@ MACHINE_START(NEUROS_OSD2, "Neuros OSD2") .init_irq = davinci_irq_init, .timer = &davinci_timer, .init_machine = davinci_ntosd2_init, - .dma_zone_size = SZ_128M, MACHINE_END diff --git a/trunk/arch/arm/mach-davinci/board-omapl138-hawk.c b/trunk/arch/arm/mach-davinci/board-omapl138-hawk.c index 237332a11421..67c38d0ecd10 100644 --- a/trunk/arch/arm/mach-davinci/board-omapl138-hawk.c +++ b/trunk/arch/arm/mach-davinci/board-omapl138-hawk.c @@ -343,5 +343,4 @@ MACHINE_START(OMAPL138_HAWKBOARD, "AM18x/OMAP-L138 Hawkboard") .init_irq = cp_intc_init, .timer = &davinci_timer, .init_machine = omapl138_hawk_init, - .dma_zone_size = SZ_128M, MACHINE_END diff --git a/trunk/arch/arm/mach-davinci/board-sffsdr.c b/trunk/arch/arm/mach-davinci/board-sffsdr.c index 5f4385c0a089..61ac96d8f00d 100644 --- a/trunk/arch/arm/mach-davinci/board-sffsdr.c +++ b/trunk/arch/arm/mach-davinci/board-sffsdr.c @@ -156,5 +156,4 @@ MACHINE_START(SFFSDR, "Lyrtech SFFSDR") .init_irq = davinci_irq_init, .timer = &davinci_timer, .init_machine = davinci_sffsdr_init, - .dma_zone_size = SZ_128M, MACHINE_END diff --git a/trunk/arch/arm/mach-davinci/board-tnetv107x-evm.c b/trunk/arch/arm/mach-davinci/board-tnetv107x-evm.c index 782892065682..1a656e882262 100644 --- a/trunk/arch/arm/mach-davinci/board-tnetv107x-evm.c +++ b/trunk/arch/arm/mach-davinci/board-tnetv107x-evm.c @@ -282,5 +282,4 @@ MACHINE_START(TNETV107X, "TNETV107X EVM") .init_irq = cp_intc_init, .timer = &davinci_timer, .init_machine = tnetv107x_evm_board_init, - .dma_zone_size = SZ_128M, MACHINE_END diff --git a/trunk/arch/arm/mach-davinci/include/mach/entry-macro.S b/trunk/arch/arm/mach-davinci/include/mach/entry-macro.S index e14c0dc0e12c..fbdebc7cb409 100644 --- a/trunk/arch/arm/mach-davinci/include/mach/entry-macro.S +++ b/trunk/arch/arm/mach-davinci/include/mach/entry-macro.S @@ -46,3 +46,6 @@ #endif 1002: .endm + + .macro irq_prio_table + .endm diff --git a/trunk/arch/arm/mach-davinci/include/mach/memory.h b/trunk/arch/arm/mach-davinci/include/mach/memory.h index 78731944a70c..491249ef209c 100644 --- a/trunk/arch/arm/mach-davinci/include/mach/memory.h +++ b/trunk/arch/arm/mach-davinci/include/mach/memory.h @@ -41,4 +41,11 @@ */ #define CONSISTENT_DMA_SIZE (14<<20) +/* + * Restrict DMA-able region to workaround silicon bug. The bug + * restricts buffers available for DMA to video hardware to be + * below 128M + */ +#define ARM_DMA_ZONE_SIZE SZ_128M + #endif /* __ASM_ARCH_MEMORY_H */ diff --git a/trunk/arch/arm/mach-exynos4/platsmp.c b/trunk/arch/arm/mach-exynos4/platsmp.c index b68d5bdf04cf..c5e65a02be8d 100644 --- a/trunk/arch/arm/mach-exynos4/platsmp.c +++ b/trunk/arch/arm/mach-exynos4/platsmp.c @@ -154,6 +154,14 @@ void __init smp_init_cpus(void) void __init platform_smp_prepare_cpus(unsigned int max_cpus) { + int i; + + /* + * Initialise the present map, which describes the set of CPUs + * actually populated at the present time. + */ + for (i = 0; i < max_cpus; i++) + set_cpu_present(i, true); scu_enable(scu_base_addr()); diff --git a/trunk/arch/arm/mach-exynos4/pm.c b/trunk/arch/arm/mach-exynos4/pm.c index 533c28f758ca..8755ca8dd48d 100644 --- a/trunk/arch/arm/mach-exynos4/pm.c +++ b/trunk/arch/arm/mach-exynos4/pm.c @@ -280,7 +280,7 @@ static struct sleep_save exynos4_l2cc_save[] = { SAVE_ITEM(S5P_VA_L2CC + L2X0_AUX_CTRL), }; -static int exynos4_cpu_suspend(unsigned long arg) +void exynos4_cpu_suspend(void) { unsigned long tmp; unsigned long mask = 0xFFFFFFFF; diff --git a/trunk/arch/arm/mach-exynos4/sleep.S b/trunk/arch/arm/mach-exynos4/sleep.S index 0984078f1eba..6b62425417a6 100644 --- a/trunk/arch/arm/mach-exynos4/sleep.S +++ b/trunk/arch/arm/mach-exynos4/sleep.S @@ -32,6 +32,28 @@ .text + /* + * s3c_cpu_save + * + * entry: + * r1 = v:p offset + */ + +ENTRY(s3c_cpu_save) + + stmfd sp!, { r3 - r12, lr } + ldr r3, =resume_with_mmu + bl cpu_suspend + + ldr r0, =pm_cpu_sleep + ldr r0, [ r0 ] + mov pc, r0 + +resume_with_mmu: + ldmfd sp!, { r3 - r12, pc } + + .ltorg + /* * sleep magic, to allow the bootloader to check for an valid * image to resume to. Must be the first word before the diff --git a/trunk/arch/arm/mach-footbridge/Kconfig b/trunk/arch/arm/mach-footbridge/Kconfig index dc26fff22cf0..46adca068f2c 100644 --- a/trunk/arch/arm/mach-footbridge/Kconfig +++ b/trunk/arch/arm/mach-footbridge/Kconfig @@ -5,7 +5,6 @@ menu "Footbridge Implementations" config ARCH_CATS bool "CATS" select CLKSRC_I8253 - select CLKEVT_I8253 select FOOTBRIDGE_HOST select ISA select ISA_DMA diff --git a/trunk/arch/arm/mach-footbridge/isa-timer.c b/trunk/arch/arm/mach-footbridge/isa-timer.c index c40bb415f4b5..7020f1a3feca 100644 --- a/trunk/arch/arm/mach-footbridge/isa-timer.c +++ b/trunk/arch/arm/mach-footbridge/isa-timer.c @@ -5,18 +5,64 @@ * Copyright (C) 1998 Phil Blundell */ #include -#include +#include #include #include #include +#include #include #include #include +#include #include #include "common.h" +DEFINE_RAW_SPINLOCK(i8253_lock); + +static void pit_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + unsigned long flags; + + raw_local_irq_save(flags); + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + outb_p(0x34, PIT_MODE); + outb_p(PIT_LATCH & 0xff, PIT_CH0); + outb_p(PIT_LATCH >> 8, PIT_CH0); + break; + + case CLOCK_EVT_MODE_SHUTDOWN: + case CLOCK_EVT_MODE_UNUSED: + outb_p(0x30, PIT_MODE); + outb_p(0, PIT_CH0); + outb_p(0, PIT_CH0); + break; + + case CLOCK_EVT_MODE_ONESHOT: + case CLOCK_EVT_MODE_RESUME: + break; + } + local_irq_restore(flags); +} + +static int pit_set_next_event(unsigned long delta, + struct clock_event_device *evt) +{ + return 0; +} + +static struct clock_event_device pit_ce = { + .name = "pit", + .features = CLOCK_EVT_FEAT_PERIODIC, + .set_mode = pit_set_mode, + .set_next_event = pit_set_next_event, + .shift = 32, +}; + static irqreturn_t pit_timer_interrupt(int irq, void *dev_id) { struct clock_event_device *ce = dev_id; @@ -28,15 +74,20 @@ static struct irqaction pit_timer_irq = { .name = "pit", .handler = pit_timer_interrupt, .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, - .dev_id = &i8253_clockevent, + .dev_id = &pit_ce, }; static void __init isa_timer_init(void) { + pit_ce.cpumask = cpumask_of(smp_processor_id()); + pit_ce.mult = div_sc(PIT_TICK_RATE, NSEC_PER_SEC, pit_ce.shift); + pit_ce.max_delta_ns = clockevent_delta2ns(0x7fff, &pit_ce); + pit_ce.min_delta_ns = clockevent_delta2ns(0x000f, &pit_ce); + clocksource_i8253_init(); - setup_irq(i8253_clockevent.irq, &pit_timer_irq); - clockevent_i8253_init(false); + setup_irq(pit_ce.irq, &pit_timer_irq); + clockevents_register_device(&pit_ce); } struct sys_timer isa_timer = { diff --git a/trunk/arch/arm/mach-h720x/h7201-eval.c b/trunk/arch/arm/mach-h720x/h7201-eval.c index 65f1bea958e5..629454d71c8d 100644 --- a/trunk/arch/arm/mach-h720x/h7201-eval.c +++ b/trunk/arch/arm/mach-h720x/h7201-eval.c @@ -33,5 +33,4 @@ MACHINE_START(H7201, "Hynix GMS30C7201") .map_io = h720x_map_io, .init_irq = h720x_init_irq, .timer = &h7201_timer, - .dma_zone_size = SZ_256M, MACHINE_END diff --git a/trunk/arch/arm/mach-h720x/h7202-eval.c b/trunk/arch/arm/mach-h720x/h7202-eval.c index 884584a09752..e9f46b696354 100644 --- a/trunk/arch/arm/mach-h720x/h7202-eval.c +++ b/trunk/arch/arm/mach-h720x/h7202-eval.c @@ -76,5 +76,4 @@ MACHINE_START(H7202, "Hynix HMS30C7202") .init_irq = h7202_init_irq, .timer = &h7202_timer, .init_machine = init_eval_h7202, - .dma_zone_size = SZ_256M, MACHINE_END diff --git a/trunk/arch/arm/mach-h720x/include/mach/entry-macro.S b/trunk/arch/arm/mach-h720x/include/mach/entry-macro.S index c3948e5ba4a0..6d3b917c4a18 100644 --- a/trunk/arch/arm/mach-h720x/include/mach/entry-macro.S +++ b/trunk/arch/arm/mach-h720x/include/mach/entry-macro.S @@ -57,6 +57,9 @@ tst \irqstat, #1 @ bit 0 should be set .endm + .macro irq_prio_table + .endm + #else #error hynix processor selection missmatch #endif diff --git a/trunk/arch/arm/mach-h720x/include/mach/memory.h b/trunk/arch/arm/mach-h720x/include/mach/memory.h index 96dcf50c51d3..b0b3baec9acf 100644 --- a/trunk/arch/arm/mach-h720x/include/mach/memory.h +++ b/trunk/arch/arm/mach-h720x/include/mach/memory.h @@ -8,4 +8,11 @@ #define __ASM_ARCH_MEMORY_H #define PLAT_PHYS_OFFSET UL(0x40000000) +/* + * This is the maximum DMA address that can be DMAd to. + * There should not be more than (0xd0000000 - 0xc0000000) + * bytes of RAM. + */ +#define ARM_DMA_ZONE_SIZE SZ_256M + #endif diff --git a/trunk/arch/arm/mach-ixp4xx/avila-setup.c b/trunk/arch/arm/mach-ixp4xx/avila-setup.c index ee19c1d383aa..73745ff102d5 100644 --- a/trunk/arch/arm/mach-ixp4xx/avila-setup.c +++ b/trunk/arch/arm/mach-ixp4xx/avila-setup.c @@ -169,9 +169,6 @@ MACHINE_START(AVILA, "Gateworks Avila Network Platform") .timer = &ixp4xx_timer, .boot_params = 0x0100, .init_machine = avila_init, -#if defined(CONFIG_PCI) - .dma_zone_size = SZ_64M, -#endif MACHINE_END /* @@ -187,9 +184,6 @@ MACHINE_START(LOFT, "Giant Shoulder Inc Loft board") .timer = &ixp4xx_timer, .boot_params = 0x0100, .init_machine = avila_init, -#if defined(CONFIG_PCI) - .dma_zone_size = SZ_64M, -#endif MACHINE_END #endif diff --git a/trunk/arch/arm/mach-ixp4xx/common-pci.c b/trunk/arch/arm/mach-ixp4xx/common-pci.c index e2e98bbb6413..e9a589395723 100644 --- a/trunk/arch/arm/mach-ixp4xx/common-pci.c +++ b/trunk/arch/arm/mach-ixp4xx/common-pci.c @@ -316,11 +316,6 @@ static int abort_handler(unsigned long addr, unsigned int fsr, struct pt_regs *r } -static int ixp4xx_needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size) -{ - return (dma_addr + size) >= SZ_64M; -} - /* * Setup DMA mask to 64MB on PCI devices. Ignore all other devices. */ @@ -329,7 +324,7 @@ static int ixp4xx_pci_platform_notify(struct device *dev) if(dev->bus == &pci_bus_type) { *dev->dma_mask = SZ_64M - 1; dev->coherent_dma_mask = SZ_64M - 1; - dmabounce_register_dev(dev, 2048, 4096, ixp4xx_needs_bounce); + dmabounce_register_dev(dev, 2048, 4096); } return 0; } @@ -342,6 +337,11 @@ static int ixp4xx_pci_platform_notify_remove(struct device *dev) return 0; } +int dma_needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size) +{ + return (dev->bus == &pci_bus_type ) && ((dma_addr + size) >= SZ_64M); +} + void __init ixp4xx_pci_preinit(void) { unsigned long cpuid = read_cpuid_id(); diff --git a/trunk/arch/arm/mach-ixp4xx/coyote-setup.c b/trunk/arch/arm/mach-ixp4xx/coyote-setup.c index e24564b5d935..355e3de38733 100644 --- a/trunk/arch/arm/mach-ixp4xx/coyote-setup.c +++ b/trunk/arch/arm/mach-ixp4xx/coyote-setup.c @@ -114,9 +114,6 @@ MACHINE_START(ADI_COYOTE, "ADI Engineering Coyote") .timer = &ixp4xx_timer, .boot_params = 0x0100, .init_machine = coyote_init, -#if defined(CONFIG_PCI) - .dma_zone_size = SZ_64M, -#endif MACHINE_END #endif diff --git a/trunk/arch/arm/mach-ixp4xx/dsmg600-setup.c b/trunk/arch/arm/mach-ixp4xx/dsmg600-setup.c index 03e54515e8b3..d398229cfaa5 100644 --- a/trunk/arch/arm/mach-ixp4xx/dsmg600-setup.c +++ b/trunk/arch/arm/mach-ixp4xx/dsmg600-setup.c @@ -284,7 +284,4 @@ MACHINE_START(DSMG600, "D-Link DSM-G600 RevA") .init_irq = ixp4xx_init_irq, .timer = &dsmg600_timer, .init_machine = dsmg600_init, -#if defined(CONFIG_PCI) - .dma_zone_size = SZ_64M, -#endif MACHINE_END diff --git a/trunk/arch/arm/mach-ixp4xx/fsg-setup.c b/trunk/arch/arm/mach-ixp4xx/fsg-setup.c index 23a8b3614568..727ee39ce11c 100644 --- a/trunk/arch/arm/mach-ixp4xx/fsg-setup.c +++ b/trunk/arch/arm/mach-ixp4xx/fsg-setup.c @@ -275,8 +275,5 @@ MACHINE_START(FSG, "Freecom FSG-3") .timer = &ixp4xx_timer, .boot_params = 0x0100, .init_machine = fsg_init, -#if defined(CONFIG_PCI) - .dma_zone_size = SZ_64M, -#endif MACHINE_END diff --git a/trunk/arch/arm/mach-ixp4xx/gateway7001-setup.c b/trunk/arch/arm/mach-ixp4xx/gateway7001-setup.c index d4f851bdd9a4..9dc0b4eaa65a 100644 --- a/trunk/arch/arm/mach-ixp4xx/gateway7001-setup.c +++ b/trunk/arch/arm/mach-ixp4xx/gateway7001-setup.c @@ -101,8 +101,5 @@ MACHINE_START(GATEWAY7001, "Gateway 7001 AP") .timer = &ixp4xx_timer, .boot_params = 0x0100, .init_machine = gateway7001_init, -#if defined(CONFIG_PCI) - .dma_zone_size = SZ_64M, -#endif MACHINE_END #endif diff --git a/trunk/arch/arm/mach-ixp4xx/goramo_mlr.c b/trunk/arch/arm/mach-ixp4xx/goramo_mlr.c index 5f00ad224fe0..3e8c0e33b59c 100644 --- a/trunk/arch/arm/mach-ixp4xx/goramo_mlr.c +++ b/trunk/arch/arm/mach-ixp4xx/goramo_mlr.c @@ -501,7 +501,4 @@ MACHINE_START(GORAMO_MLR, "MultiLink") .timer = &ixp4xx_timer, .boot_params = 0x0100, .init_machine = gmlr_init, -#if defined(CONFIG_PCI) - .dma_zone_size = SZ_64M, -#endif MACHINE_END diff --git a/trunk/arch/arm/mach-ixp4xx/gtwx5715-setup.c b/trunk/arch/arm/mach-ixp4xx/gtwx5715-setup.c index 3790dffd3c30..77abead36227 100644 --- a/trunk/arch/arm/mach-ixp4xx/gtwx5715-setup.c +++ b/trunk/arch/arm/mach-ixp4xx/gtwx5715-setup.c @@ -169,9 +169,6 @@ MACHINE_START(GTWX5715, "Gemtek GTWX5715 (Linksys WRV54G)") .timer = &ixp4xx_timer, .boot_params = 0x0100, .init_machine = gtwx5715_init, -#if defined(CONFIG_PCI) - .dma_zone_size = SZ_64M, -#endif MACHINE_END diff --git a/trunk/arch/arm/mach-ixp4xx/include/mach/memory.h b/trunk/arch/arm/mach-ixp4xx/include/mach/memory.h index 4caf1761f1e2..34e79404671a 100644 --- a/trunk/arch/arm/mach-ixp4xx/include/mach/memory.h +++ b/trunk/arch/arm/mach-ixp4xx/include/mach/memory.h @@ -14,4 +14,8 @@ */ #define PLAT_PHYS_OFFSET UL(0x00000000) +#ifdef CONFIG_PCI +#define ARM_DMA_ZONE_SIZE SZ_64M +#endif + #endif diff --git a/trunk/arch/arm/mach-ixp4xx/ixdp425-setup.c b/trunk/arch/arm/mach-ixp4xx/ixdp425-setup.c index 6a2927956bf6..dca4f7f9f4f7 100644 --- a/trunk/arch/arm/mach-ixp4xx/ixdp425-setup.c +++ b/trunk/arch/arm/mach-ixp4xx/ixdp425-setup.c @@ -258,9 +258,6 @@ MACHINE_START(IXDP425, "Intel IXDP425 Development Platform") .timer = &ixp4xx_timer, .boot_params = 0x0100, .init_machine = ixdp425_init, -#if defined(CONFIG_PCI) - .dma_zone_size = SZ_64M, -#endif MACHINE_END #endif @@ -272,9 +269,6 @@ MACHINE_START(IXDP465, "Intel IXDP465 Development Platform") .timer = &ixp4xx_timer, .boot_params = 0x0100, .init_machine = ixdp425_init, -#if defined(CONFIG_PCI) - .dma_zone_size = SZ_64M, -#endif MACHINE_END #endif @@ -286,9 +280,6 @@ MACHINE_START(IXCDP1100, "Intel IXCDP1100 Development Platform") .timer = &ixp4xx_timer, .boot_params = 0x0100, .init_machine = ixdp425_init, -#if defined(CONFIG_PCI) - .dma_zone_size = SZ_64M, -#endif MACHINE_END #endif @@ -300,8 +291,5 @@ MACHINE_START(KIXRP435, "Intel KIXRP435 Reference Platform") .timer = &ixp4xx_timer, .boot_params = 0x0100, .init_machine = ixdp425_init, -#if defined(CONFIG_PCI) - .dma_zone_size = SZ_64M, -#endif MACHINE_END #endif diff --git a/trunk/arch/arm/mach-ixp4xx/nas100d-setup.c b/trunk/arch/arm/mach-ixp4xx/nas100d-setup.c index afb51879d9a4..f18fee748878 100644 --- a/trunk/arch/arm/mach-ixp4xx/nas100d-setup.c +++ b/trunk/arch/arm/mach-ixp4xx/nas100d-setup.c @@ -319,7 +319,4 @@ MACHINE_START(NAS100D, "Iomega NAS 100d") .init_irq = ixp4xx_init_irq, .timer = &ixp4xx_timer, .init_machine = nas100d_init, -#if defined(CONFIG_PCI) - .dma_zone_size = SZ_64M, -#endif MACHINE_END diff --git a/trunk/arch/arm/mach-ixp4xx/nslu2-setup.c b/trunk/arch/arm/mach-ixp4xx/nslu2-setup.c index 69e40f2cf092..f79b62eb7614 100644 --- a/trunk/arch/arm/mach-ixp4xx/nslu2-setup.c +++ b/trunk/arch/arm/mach-ixp4xx/nslu2-setup.c @@ -305,7 +305,4 @@ MACHINE_START(NSLU2, "Linksys NSLU2") .init_irq = ixp4xx_init_irq, .timer = &nslu2_timer, .init_machine = nslu2_init, -#if defined(CONFIG_PCI) - .dma_zone_size = SZ_64M, -#endif MACHINE_END diff --git a/trunk/arch/arm/mach-ixp4xx/vulcan-setup.c b/trunk/arch/arm/mach-ixp4xx/vulcan-setup.c index 045336c833af..4e72cfdd3c46 100644 --- a/trunk/arch/arm/mach-ixp4xx/vulcan-setup.c +++ b/trunk/arch/arm/mach-ixp4xx/vulcan-setup.c @@ -241,7 +241,4 @@ MACHINE_START(ARCOM_VULCAN, "Arcom/Eurotech Vulcan") .timer = &ixp4xx_timer, .boot_params = 0x0100, .init_machine = vulcan_init, -#if defined(CONFIG_PCI) - .dma_zone_size = SZ_64M, -#endif MACHINE_END diff --git a/trunk/arch/arm/mach-ixp4xx/wg302v2-setup.c b/trunk/arch/arm/mach-ixp4xx/wg302v2-setup.c index 40b9fad800b8..5d148c7bc4fb 100644 --- a/trunk/arch/arm/mach-ixp4xx/wg302v2-setup.c +++ b/trunk/arch/arm/mach-ixp4xx/wg302v2-setup.c @@ -102,8 +102,5 @@ MACHINE_START(WG302V2, "Netgear WG302 v2 / WAG302 v2") .timer = &ixp4xx_timer, .boot_params = 0x0100, .init_machine = wg302v2_init, -#if defined(CONFIG_PCI) - .dma_zone_size = SZ_64M, -#endif MACHINE_END #endif diff --git a/trunk/arch/arm/mach-lpc32xx/include/mach/entry-macro.S b/trunk/arch/arm/mach-lpc32xx/include/mach/entry-macro.S index b725f6c93975..870227c96602 100644 --- a/trunk/arch/arm/mach-lpc32xx/include/mach/entry-macro.S +++ b/trunk/arch/arm/mach-lpc32xx/include/mach/entry-macro.S @@ -41,3 +41,7 @@ rsb \irqnr, \irqnr, #31 teq \irqstat, #0 .endm + + .macro irq_prio_table + .endm + diff --git a/trunk/arch/arm/mach-msm/Kconfig b/trunk/arch/arm/mach-msm/Kconfig index 888e92502e15..1516896e8d17 100644 --- a/trunk/arch/arm/mach-msm/Kconfig +++ b/trunk/arch/arm/mach-msm/Kconfig @@ -148,6 +148,22 @@ config MACH_MSM8960_RUMI3 endmenu +config MSM_IOMMU + bool "MSM IOMMU Support" + depends on ARCH_MSM8X60 || ARCH_MSM8960 + select IOMMU_API + default n + help + Support for the IOMMUs found on certain Qualcomm SOCs. + These IOMMUs allow virtualization of the address space used by most + cores within the multimedia subsystem. + + If unsure, say N here. + +config IOMMU_PGTABLES_L2 + def_bool y + depends on MSM_IOMMU && MMU && SMP && CPU_DCACHE_DISABLE=n + config MSM_DEBUG_UART int default 1 if MSM_DEBUG_UART1 @@ -189,6 +205,9 @@ config MSM_GPIOMUX config MSM_V2_TLMM bool +config IOMMU_API + bool + config MSM_SCM bool endif diff --git a/trunk/arch/arm/mach-msm/Makefile b/trunk/arch/arm/mach-msm/Makefile index b70658c5ae00..9519fd28a025 100644 --- a/trunk/arch/arm/mach-msm/Makefile +++ b/trunk/arch/arm/mach-msm/Makefile @@ -3,7 +3,7 @@ obj-y += clock.o obj-$(CONFIG_DEBUG_FS) += clock-debug.o obj-$(CONFIG_MSM_VIC) += irq-vic.o -obj-$(CONFIG_MSM_IOMMU) += devices-iommu.o +obj-$(CONFIG_MSM_IOMMU) += iommu.o iommu_dev.o devices-iommu.o obj-$(CONFIG_ARCH_MSM7X00A) += dma.o irq.o acpuclock-arm11.o obj-$(CONFIG_ARCH_MSM7X30) += dma.o diff --git a/trunk/drivers/iommu/msm_iommu.c b/trunk/arch/arm/mach-msm/iommu.c similarity index 100% rename from trunk/drivers/iommu/msm_iommu.c rename to trunk/arch/arm/mach-msm/iommu.c diff --git a/trunk/drivers/iommu/msm_iommu_dev.c b/trunk/arch/arm/mach-msm/iommu_dev.c similarity index 100% rename from trunk/drivers/iommu/msm_iommu_dev.c rename to trunk/arch/arm/mach-msm/iommu_dev.c diff --git a/trunk/arch/arm/mach-msm/platsmp.c b/trunk/arch/arm/mach-msm/platsmp.c index 315b9f365329..2034098cf015 100644 --- a/trunk/arch/arm/mach-msm/platsmp.c +++ b/trunk/arch/arm/mach-msm/platsmp.c @@ -157,4 +157,12 @@ void __init smp_init_cpus(void) void __init platform_smp_prepare_cpus(unsigned int max_cpus) { + int i; + + /* + * Initialise the present map, which describes the set of CPUs + * actually populated at the present time. + */ + for (i = 0; i < max_cpus; i++) + set_cpu_present(i, true); } diff --git a/trunk/arch/arm/mach-omap2/control.c b/trunk/arch/arm/mach-omap2/control.c index aab884fecc55..da53ba3917ca 100644 --- a/trunk/arch/arm/mach-omap2/control.c +++ b/trunk/arch/arm/mach-omap2/control.c @@ -286,15 +286,14 @@ void omap3_save_scratchpad_contents(void) scratchpad_contents.boot_config_ptr = 0x0; if (cpu_is_omap3630()) scratchpad_contents.public_restore_ptr = - virt_to_phys(omap3_restore_3630); + virt_to_phys(get_omap3630_restore_pointer()); else if (omap_rev() != OMAP3430_REV_ES3_0 && omap_rev() != OMAP3430_REV_ES3_1) scratchpad_contents.public_restore_ptr = - virt_to_phys(omap3_restore); + virt_to_phys(get_restore_pointer()); else scratchpad_contents.public_restore_ptr = - virt_to_phys(omap3_restore_es3); - + virt_to_phys(get_es3_restore_pointer()); if (omap_type() == OMAP2_DEVICE_TYPE_GP) scratchpad_contents.secure_ram_restore_ptr = 0x0; else diff --git a/trunk/arch/arm/mach-omap2/control.h b/trunk/arch/arm/mach-omap2/control.h index d4ef75d5a382..a016c8b59e00 100644 --- a/trunk/arch/arm/mach-omap2/control.h +++ b/trunk/arch/arm/mach-omap2/control.h @@ -386,9 +386,9 @@ extern void omap4_ctrl_pad_writel(u32 val, u16 offset); extern void omap3_save_scratchpad_contents(void); extern void omap3_clear_scratchpad_contents(void); -extern void omap3_restore(void); -extern void omap3_restore_es3(void); -extern void omap3_restore_3630(void); +extern u32 *get_restore_pointer(void); +extern u32 *get_es3_restore_pointer(void); +extern u32 *get_omap3630_restore_pointer(void); extern u32 omap3_arm_context[128]; extern void omap3_control_save_context(void); extern void omap3_control_restore_context(void); diff --git a/trunk/arch/arm/mach-omap2/include/mach/entry-macro.S b/trunk/arch/arm/mach-omap2/include/mach/entry-macro.S index ceb8b7e593d7..a48690b90990 100644 --- a/trunk/arch/arm/mach-omap2/include/mach/entry-macro.S +++ b/trunk/arch/arm/mach-omap2/include/mach/entry-macro.S @@ -165,3 +165,6 @@ #endif #endif /* MULTI_OMAP2 */ + + .macro irq_prio_table + .endm diff --git a/trunk/arch/arm/mach-omap2/omap-smp.c b/trunk/arch/arm/mach-omap2/omap-smp.c index ce65e9329c7b..ecfe93c4b585 100644 --- a/trunk/arch/arm/mach-omap2/omap-smp.c +++ b/trunk/arch/arm/mach-omap2/omap-smp.c @@ -125,6 +125,14 @@ void __init smp_init_cpus(void) void __init platform_smp_prepare_cpus(unsigned int max_cpus) { + int i; + + /* + * Initialise the present map, which describes the set of CPUs + * actually populated at the present time. + */ + for (i = 0; i < max_cpus; i++) + set_cpu_present(i, true); /* * Initialise the SCU and wake up the secondary core using diff --git a/trunk/arch/arm/mach-omap2/pm.h b/trunk/arch/arm/mach-omap2/pm.h index 04ee56646126..45bcfce77352 100644 --- a/trunk/arch/arm/mach-omap2/pm.h +++ b/trunk/arch/arm/mach-omap2/pm.h @@ -88,29 +88,19 @@ extern int pm_dbg_regset_init(int reg_set); #define pm_dbg_regset_init(reg_set) do {} while (0); #endif /* CONFIG_PM_DEBUG */ -/* 24xx */ extern void omap24xx_idle_loop_suspend(void); -extern unsigned int omap24xx_idle_loop_suspend_sz; extern void omap24xx_cpu_suspend(u32 dll_ctrl, void __iomem *sdrc_dlla_ctrl, void __iomem *sdrc_power); -extern unsigned int omap24xx_cpu_suspend_sz; - -/* 3xxx */ -extern void omap34xx_cpu_suspend(int save_state); - -/* omap3_do_wfi function pointer and size, for copy to SRAM */ -extern void omap3_do_wfi(void); -extern unsigned int omap3_do_wfi_sz; -/* ... and its pointer from SRAM after copy */ -extern void (*omap3_do_wfi_sram)(void); - -/* save_secure_ram_context function pointer and size, for copy to SRAM */ +extern void omap34xx_cpu_suspend(u32 *addr, int save_state); extern int save_secure_ram_context(u32 *addr); -extern unsigned int save_secure_ram_context_sz; - extern void omap3_save_scratchpad_contents(void); +extern unsigned int omap24xx_idle_loop_suspend_sz; +extern unsigned int save_secure_ram_context_sz; +extern unsigned int omap24xx_cpu_suspend_sz; +extern unsigned int omap34xx_cpu_suspend_sz; + #define PM_RTA_ERRATUM_i608 (1 << 0) #define PM_SDRC_WAKEUP_ERRATUM_i583 (1 << 1) diff --git a/trunk/arch/arm/mach-omap2/pm34xx.c b/trunk/arch/arm/mach-omap2/pm34xx.c index b77d82665abb..c155c9d1c82c 100644 --- a/trunk/arch/arm/mach-omap2/pm34xx.c +++ b/trunk/arch/arm/mach-omap2/pm34xx.c @@ -31,8 +31,6 @@ #include #include -#include - #include #include "clockdomain.h" #include "powerdomain.h" @@ -42,6 +40,8 @@ #include #include +#include + #include "cm2xxx_3xxx.h" #include "cm-regbits-34xx.h" #include "prm-regbits-34xx.h" @@ -64,6 +64,11 @@ static inline bool is_suspending(void) } #endif +/* Scratchpad offsets */ +#define OMAP343X_TABLE_ADDRESS_OFFSET 0xc4 +#define OMAP343X_TABLE_VALUE_OFFSET 0xc0 +#define OMAP343X_CONTROL_REG_VALUE_OFFSET 0xc8 + /* pm34xx errata defined in pm.h */ u16 pm34xx_errata; @@ -78,8 +83,9 @@ struct power_state { static LIST_HEAD(pwrst_list); +static void (*_omap_sram_idle)(u32 *addr, int save_state); + static int (*_omap_save_secure_sram)(u32 *addr); -void (*omap3_do_wfi_sram)(void); static struct powerdomain *mpu_pwrdm, *neon_pwrdm; static struct powerdomain *core_pwrdm, *per_pwrdm; @@ -306,25 +312,28 @@ static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id) return IRQ_HANDLED; } -static void omap34xx_save_context(u32 *save) +/* Function to restore the table entry that was modified for enabling MMU */ +static void restore_table_entry(void) { - u32 val; + void __iomem *scratchpad_address; + u32 previous_value, control_reg_value; + u32 *address; - /* Read Auxiliary Control Register */ - asm("mrc p15, 0, %0, c1, c0, 1" : "=r" (val)); - *save++ = 1; - *save++ = val; + scratchpad_address = OMAP2_L4_IO_ADDRESS(OMAP343X_SCRATCHPAD); - /* Read L2 AUX ctrl register */ - asm("mrc p15, 1, %0, c9, c0, 2" : "=r" (val)); - *save++ = 1; - *save++ = val; -} - -static int omap34xx_do_sram_idle(unsigned long save_state) -{ - omap34xx_cpu_suspend(save_state); - return 0; + /* Get address of entry that was modified */ + address = (u32 *)__raw_readl(scratchpad_address + + OMAP343X_TABLE_ADDRESS_OFFSET); + /* Get the previous value which needs to be restored */ + previous_value = __raw_readl(scratchpad_address + + OMAP343X_TABLE_VALUE_OFFSET); + address = __va(address); + *address = previous_value; + flush_tlb_all(); + control_reg_value = __raw_readl(scratchpad_address + + OMAP343X_CONTROL_REG_VALUE_OFFSET); + /* This will enable caches and prediction */ + set_cr(control_reg_value); } void omap_sram_idle(void) @@ -343,6 +352,9 @@ void omap_sram_idle(void) int core_prev_state, per_prev_state; u32 sdrc_pwr = 0; + if (!_omap_sram_idle) + return; + pwrdm_clear_all_prev_pwrst(mpu_pwrdm); pwrdm_clear_all_prev_pwrst(neon_pwrdm); pwrdm_clear_all_prev_pwrst(core_pwrdm); @@ -420,16 +432,12 @@ void omap_sram_idle(void) sdrc_pwr = sdrc_read_reg(SDRC_POWER); /* - * omap3_arm_context is the location where some ARM context - * get saved. The rest is placed on the stack, and restored - * from there before resuming. + * omap3_arm_context is the location where ARM registers + * get saved. The restore path then reads from this + * location and restores them back. */ - if (save_state) - omap34xx_save_context(omap3_arm_context); - if (save_state == 1 || save_state == 3) - cpu_suspend(save_state, omap34xx_do_sram_idle); - else - omap34xx_do_sram_idle(save_state); + _omap_sram_idle(omap3_arm_context, save_state); + cpu_init(); /* Restore normal SDRC POWER settings */ if (omap_rev() >= OMAP3430_REV_ES3_0 && @@ -437,6 +445,10 @@ void omap_sram_idle(void) core_next_state == PWRDM_POWER_OFF) sdrc_write_reg(sdrc_pwr, SDRC_POWER); + /* Restore table entry modified during MMU restoration */ + if (pwrdm_read_prev_pwrst(mpu_pwrdm) == PWRDM_POWER_OFF) + restore_table_entry(); + /* CORE */ if (core_next_state < PWRDM_POWER_ON) { core_prev_state = pwrdm_read_prev_pwrst(core_pwrdm); @@ -840,17 +852,10 @@ static int __init clkdms_setup(struct clockdomain *clkdm, void *unused) return 0; } -/* - * Push functions to SRAM - * - * The minimum set of functions is pushed to SRAM for execution: - * - omap3_do_wfi for erratum i581 WA, - * - save_secure_ram_context for security extensions. - */ void omap_push_sram_idle(void) { - omap3_do_wfi_sram = omap_sram_push(omap3_do_wfi, omap3_do_wfi_sz); - + _omap_sram_idle = omap_sram_push(omap34xx_cpu_suspend, + omap34xx_cpu_suspend_sz); if (omap_type() != OMAP2_DEVICE_TYPE_GP) _omap_save_secure_sram = omap_sram_push(save_secure_ram_context, save_secure_ram_context_sz); @@ -915,6 +920,7 @@ static int __init omap3_pm_init(void) per_clkdm = clkdm_lookup("per_clkdm"); core_clkdm = clkdm_lookup("core_clkdm"); + omap_push_sram_idle(); #ifdef CONFIG_SUSPEND suspend_set_ops(&omap_pm_ops); #endif /* CONFIG_SUSPEND */ diff --git a/trunk/arch/arm/mach-omap2/sleep34xx.S b/trunk/arch/arm/mach-omap2/sleep34xx.S index f2ea1bd1c691..63f10669571a 100644 --- a/trunk/arch/arm/mach-omap2/sleep34xx.S +++ b/trunk/arch/arm/mach-omap2/sleep34xx.S @@ -74,6 +74,46 @@ * API functions */ +/* + * The "get_*restore_pointer" functions are used to provide a + * physical restore address where the ROM code jumps while waking + * up from MPU OFF/OSWR state. + * The restore pointer is stored into the scratchpad. + */ + + .text +/* Function call to get the restore pointer for resume from OFF */ +ENTRY(get_restore_pointer) + stmfd sp!, {lr} @ save registers on stack + adr r0, restore + ldmfd sp!, {pc} @ restore regs and return +ENDPROC(get_restore_pointer) + .align +ENTRY(get_restore_pointer_sz) + .word . - get_restore_pointer + + .text +/* Function call to get the restore pointer for 3630 resume from OFF */ +ENTRY(get_omap3630_restore_pointer) + stmfd sp!, {lr} @ save registers on stack + adr r0, restore_3630 + ldmfd sp!, {pc} @ restore regs and return +ENDPROC(get_omap3630_restore_pointer) + .align +ENTRY(get_omap3630_restore_pointer_sz) + .word . - get_omap3630_restore_pointer + + .text +/* Function call to get the restore pointer for ES3 to resume from OFF */ +ENTRY(get_es3_restore_pointer) + stmfd sp!, {lr} @ save registers on stack + adr r0, restore_es3 + ldmfd sp!, {pc} @ restore regs and return +ENDPROC(get_es3_restore_pointer) + .align +ENTRY(get_es3_restore_pointer_sz) + .word . - get_es3_restore_pointer + .text /* * L2 cache needs to be toggled for stable OFF mode functionality on 3630. @@ -93,7 +133,7 @@ ENDPROC(enable_omap3630_toggle_l2_on_restore) /* Function to call rom code to save secure ram context */ .align 3 ENTRY(save_secure_ram_context) - stmfd sp!, {r4 - r11, lr} @ save registers on stack + stmfd sp!, {r1-r12, lr} @ save registers on stack adr r3, api_params @ r3 points to parameters str r0, [r3,#0x4] @ r0 has sdram address ldr r12, high_mask @@ -112,7 +152,7 @@ ENTRY(save_secure_ram_context) nop nop nop - ldmfd sp!, {r4 - r11, pc} + ldmfd sp!, {r1-r12, pc} .align sram_phy_addr_mask: .word SRAM_BASE_P @@ -139,38 +179,69 @@ ENTRY(save_secure_ram_context_sz) * * * Notes: - * - only the minimum set of functions gets copied to internal SRAM at boot - * and after wake-up from OFF mode, cf. omap_push_sram_idle. The function - * pointers in SDRAM or SRAM are called depending on the desired low power - * target state. + * - this code gets copied to internal SRAM at boot and after wake-up + * from OFF mode. The execution pointer in SRAM is _omap_sram_idle. * - when the OMAP wakes up it continues at different execution points * depending on the low power mode (non-OFF vs OFF modes), * cf. 'Resume path for xxx mode' comments. */ .align 3 ENTRY(omap34xx_cpu_suspend) - stmfd sp!, {r4 - r11, lr} @ save registers on stack + stmfd sp!, {r0-r12, lr} @ save registers on stack /* - * r0 contains information about saving context: + * r0 contains CPU context save/restore pointer in sdram + * r1 contains information about saving context: * 0 - No context lost * 1 - Only L1 and logic lost * 2 - Only L2 lost (Even L1 is retained we clean it along with L2) * 3 - Both L1 and L2 lost and logic lost */ - /* - * For OFF mode: save context and jump to WFI in SDRAM (omap3_do_wfi) - * For non-OFF modes: jump to the WFI code in SRAM (omap3_do_wfi_sram) - */ - ldr r4, omap3_do_wfi_sram_addr - ldr r5, [r4] - cmp r0, #0x0 @ If no context save required, - bxeq r5 @ jump to the WFI code in SRAM - + /* Directly jump to WFI is the context save is not required */ + cmp r1, #0x0 + beq omap3_do_wfi /* Otherwise fall through to the save context code */ save_context_wfi: + mov r8, r0 @ Store SDRAM address in r8 + mrc p15, 0, r5, c1, c0, 1 @ Read Auxiliary Control Register + mov r4, #0x1 @ Number of parameters for restore call + stmia r8!, {r4-r5} @ Push parameters for restore call + mrc p15, 1, r5, c9, c0, 2 @ Read L2 AUX ctrl register + stmia r8!, {r4-r5} @ Push parameters for restore call + + /* Check what that target sleep state is from r1 */ + cmp r1, #0x2 @ Only L2 lost, no need to save context + beq clean_caches + +l1_logic_lost: + mov r4, sp @ Store sp + mrs r5, spsr @ Store spsr + mov r6, lr @ Store lr + stmia r8!, {r4-r6} + + mrc p15, 0, r4, c1, c0, 2 @ Coprocessor access control register + mrc p15, 0, r5, c2, c0, 0 @ TTBR0 + mrc p15, 0, r6, c2, c0, 1 @ TTBR1 + mrc p15, 0, r7, c2, c0, 2 @ TTBCR + stmia r8!, {r4-r7} + + mrc p15, 0, r4, c3, c0, 0 @ Domain access Control Register + mrc p15, 0, r5, c10, c2, 0 @ PRRR + mrc p15, 0, r6, c10, c2, 1 @ NMRR + stmia r8!,{r4-r6} + + mrc p15, 0, r4, c13, c0, 1 @ Context ID + mrc p15, 0, r5, c13, c0, 2 @ User r/w thread and process ID + mrc p15, 0, r6, c12, c0, 0 @ Secure or NS vector base address + mrs r7, cpsr @ Store current cpsr + stmia r8!, {r4-r7} + + mrc p15, 0, r4, c1, c0, 0 @ save control register + stmia r8!, {r4} + +clean_caches: /* * jump out to kernel flush routine * - reuse that code is better @@ -213,32 +284,7 @@ save_context_wfi: THUMB( nop ) .arm - b omap3_do_wfi - -/* - * Local variables - */ -omap3_do_wfi_sram_addr: - .word omap3_do_wfi_sram -kernel_flush: - .word v7_flush_dcache_all - -/* =================================== - * == WFI instruction => Enter idle == - * =================================== - */ - -/* - * Do WFI instruction - * Includes the resume path for non-OFF modes - * - * This code gets copied to internal SRAM and is accessible - * from both SDRAM and SRAM: - * - executed from SRAM for non-off modes (omap3_do_wfi_sram), - * - executed from SDRAM for OFF mode (omap3_do_wfi). - */ - .align 3 -ENTRY(omap3_do_wfi) +omap3_do_wfi: ldr r4, sdrc_power @ read the SDRC_POWER register ldr r5, [r4] @ read the contents of SDRC_POWER orr r5, r5, #0x40 @ enable self refresh on idle req @@ -270,86 +316,8 @@ ENTRY(omap3_do_wfi) nop nop nop + bl wait_sdrc_ok -/* - * This function implements the erratum ID i581 WA: - * SDRC state restore before accessing the SDRAM - * - * Only used at return from non-OFF mode. For OFF - * mode the ROM code configures the SDRC and - * the DPLL before calling the restore code directly - * from DDR. - */ - -/* Make sure SDRC accesses are ok */ -wait_sdrc_ok: - -/* DPLL3 must be locked before accessing the SDRC. Maybe the HW ensures this */ - ldr r4, cm_idlest_ckgen -wait_dpll3_lock: - ldr r5, [r4] - tst r5, #1 - beq wait_dpll3_lock - - ldr r4, cm_idlest1_core -wait_sdrc_ready: - ldr r5, [r4] - tst r5, #0x2 - bne wait_sdrc_ready - /* allow DLL powerdown upon hw idle req */ - ldr r4, sdrc_power - ldr r5, [r4] - bic r5, r5, #0x40 - str r5, [r4] - -/* - * PC-relative stores lead to undefined behaviour in Thumb-2: use a r7 as a - * base instead. - * Be careful not to clobber r7 when maintaing this code. - */ - -is_dll_in_lock_mode: - /* Is dll in lock mode? */ - ldr r4, sdrc_dlla_ctrl - ldr r5, [r4] - tst r5, #0x4 - bne exit_nonoff_modes @ Return if locked - /* wait till dll locks */ - adr r7, kick_counter -wait_dll_lock_timed: - ldr r4, wait_dll_lock_counter - add r4, r4, #1 - str r4, [r7, #wait_dll_lock_counter - kick_counter] - ldr r4, sdrc_dlla_status - /* Wait 20uS for lock */ - mov r6, #8 -wait_dll_lock: - subs r6, r6, #0x1 - beq kick_dll - ldr r5, [r4] - and r5, r5, #0x4 - cmp r5, #0x4 - bne wait_dll_lock - b exit_nonoff_modes @ Return when locked - - /* disable/reenable DLL if not locked */ -kick_dll: - ldr r4, sdrc_dlla_ctrl - ldr r5, [r4] - mov r6, r5 - bic r6, #(1<<3) @ disable dll - str r6, [r4] - dsb - orr r6, r6, #(1<<3) @ enable dll - str r6, [r4] - dsb - ldr r4, kick_counter - add r4, r4, #1 - str r4, [r7] @ kick_counter - b wait_dll_lock_timed - -exit_nonoff_modes: - /* Re-enable C-bit if needed */ mrc p15, 0, r0, c1, c0, 0 tst r0, #(1 << 2) @ Check C bit enabled? orreq r0, r0, #(1 << 2) @ Enable the C bit if cleared @@ -361,32 +329,7 @@ exit_nonoff_modes: * == Exit point from non-OFF modes == * =================================== */ - ldmfd sp!, {r4 - r11, pc} @ restore regs and return - -/* - * Local variables - */ -sdrc_power: - .word SDRC_POWER_V -cm_idlest1_core: - .word CM_IDLEST1_CORE_V -cm_idlest_ckgen: - .word CM_IDLEST_CKGEN_V -sdrc_dlla_status: - .word SDRC_DLLA_STATUS_V -sdrc_dlla_ctrl: - .word SDRC_DLLA_CTRL_V - /* - * When exporting to userspace while the counters are in SRAM, - * these 2 words need to be at the end to facilitate retrival! - */ -kick_counter: - .word 0 -wait_dll_lock_counter: - .word 0 - -ENTRY(omap3_do_wfi_sz) - .word . - omap3_do_wfi + ldmfd sp!, {r0-r12, pc} @ restore regs and return /* @@ -403,17 +346,13 @@ ENTRY(omap3_do_wfi_sz) * restore_es3: applies to 34xx >= ES3.0 * restore_3630: applies to 36xx * restore: common code for 3xxx - * - * Note: when back from CORE and MPU OFF mode we are running - * from SDRAM, without MMU, without the caches and prediction. - * Also the SRAM content has been cleared. */ -ENTRY(omap3_restore_es3) +restore_es3: ldr r5, pm_prepwstst_core_p ldr r4, [r5] and r4, r4, #0x3 cmp r4, #0x0 @ Check if previous power state of CORE is OFF - bne omap3_restore @ Fall through to OMAP3 common code + bne restore adr r0, es3_sdrc_fix ldr r1, sram_base ldr r2, es3_sdrc_fix_sz @@ -425,32 +364,35 @@ copy_to_sram: bne copy_to_sram ldr r1, sram_base blx r1 - b omap3_restore @ Fall through to OMAP3 common code -ENDPROC(omap3_restore_es3) + b restore -ENTRY(omap3_restore_3630) +restore_3630: ldr r1, pm_prepwstst_core_p ldr r2, [r1] and r2, r2, #0x3 cmp r2, #0x0 @ Check if previous power state of CORE is OFF - bne omap3_restore @ Fall through to OMAP3 common code + bne restore /* Disable RTA before giving control */ ldr r1, control_mem_rta mov r2, #OMAP36XX_RTA_DISABLE str r2, [r1] -ENDPROC(omap3_restore_3630) /* Fall through to common code for the remaining logic */ -ENTRY(omap3_restore) +restore: /* - * Read the pwstctrl register to check the reason for mpu reset. - * This tells us what was lost. + * Check what was the reason for mpu reset and store the reason in r9: + * 0 - No context lost + * 1 - Only L1 and logic lost + * 2 - Only L2 lost - In this case, we wont be here + * 3 - Both L1 and L2 lost */ ldr r1, pm_pwstctrl_mpu ldr r2, [r1] and r2, r2, #0x3 cmp r2, #0x0 @ Check if target power state was OFF or RET + moveq r9, #0x3 @ MPU OFF => L1 and L2 lost + movne r9, #0x1 @ Only L1 and L2 lost => avoid L2 invalidation bne logic_l1_restore ldr r0, l2dis_3630 @@ -529,39 +471,115 @@ logic_l1_restore: orr r1, r1, #2 @ re-enable L2 cache mcr p15, 0, r1, c1, c0, 1 skipl2reen: + mov r1, #0 + /* + * Invalidate all instruction caches to PoU + * and flush branch target cache + */ + mcr p15, 0, r1, c7, c5, 0 - /* Now branch to the common CPU resume function */ - b cpu_resume -ENDPROC(omap3_restore) - - .ltorg + ldr r4, scratchpad_base + ldr r3, [r4,#0xBC] + adds r3, r3, #16 + + ldmia r3!, {r4-r6} + mov sp, r4 @ Restore sp + msr spsr_cxsf, r5 @ Restore spsr + mov lr, r6 @ Restore lr + + ldmia r3!, {r4-r7} + mcr p15, 0, r4, c1, c0, 2 @ Coprocessor access Control Register + mcr p15, 0, r5, c2, c0, 0 @ TTBR0 + mcr p15, 0, r6, c2, c0, 1 @ TTBR1 + mcr p15, 0, r7, c2, c0, 2 @ TTBCR + + ldmia r3!,{r4-r6} + mcr p15, 0, r4, c3, c0, 0 @ Domain access Control Register + mcr p15, 0, r5, c10, c2, 0 @ PRRR + mcr p15, 0, r6, c10, c2, 1 @ NMRR + + + ldmia r3!,{r4-r7} + mcr p15, 0, r4, c13, c0, 1 @ Context ID + mcr p15, 0, r5, c13, c0, 2 @ User r/w thread and process ID + mrc p15, 0, r6, c12, c0, 0 @ Secure or NS vector base address + msr cpsr, r7 @ store cpsr + + /* Enabling MMU here */ + mrc p15, 0, r7, c2, c0, 2 @ Read TTBRControl + /* Extract N (0:2) bits and decide whether to use TTBR0 or TTBR1 */ + and r7, #0x7 + cmp r7, #0x0 + beq usettbr0 +ttbr_error: + /* + * More work needs to be done to support N[0:2] value other than 0 + * So looping here so that the error can be detected + */ + b ttbr_error +usettbr0: + mrc p15, 0, r2, c2, c0, 0 + ldr r5, ttbrbit_mask + and r2, r5 + mov r4, pc + ldr r5, table_index_mask + and r4, r5 @ r4 = 31 to 20 bits of pc + /* Extract the value to be written to table entry */ + ldr r1, table_entry + /* r1 has the value to be written to table entry*/ + add r1, r1, r4 + /* Getting the address of table entry to modify */ + lsr r4, #18 + /* r2 has the location which needs to be modified */ + add r2, r4 + /* Storing previous entry of location being modified */ + ldr r5, scratchpad_base + ldr r4, [r2] + str r4, [r5, #0xC0] + /* Modify the table entry */ + str r1, [r2] + /* + * Storing address of entry being modified + * - will be restored after enabling MMU + */ + ldr r5, scratchpad_base + str r2, [r5, #0xC4] + + mov r0, #0 + mcr p15, 0, r0, c7, c5, 4 @ Flush prefetch buffer + mcr p15, 0, r0, c7, c5, 6 @ Invalidate branch predictor array + mcr p15, 0, r0, c8, c5, 0 @ Invalidate instruction TLB + mcr p15, 0, r0, c8, c6, 0 @ Invalidate data TLB + /* + * Restore control register. This enables the MMU. + * The caches and prediction are not enabled here, they + * will be enabled after restoring the MMU table entry. + */ + ldmia r3!, {r4} + /* Store previous value of control register in scratchpad */ + str r4, [r5, #0xC8] + ldr r2, cache_pred_disable_mask + and r4, r2 + mcr p15, 0, r4, c1, c0, 0 + dsb + isb + ldr r0, =restoremmu_on + bx r0 /* - * Local variables + * ============================== + * == Exit point from OFF mode == + * ============================== */ -pm_prepwstst_core_p: - .word PM_PREPWSTST_CORE_P -pm_pwstctrl_mpu: - .word PM_PWSTCTRL_MPU_P -scratchpad_base: - .word SCRATCHPAD_BASE_P -sram_base: - .word SRAM_BASE_P + 0x8000 -control_stat: - .word CONTROL_STAT -control_mem_rta: - .word CONTROL_MEM_RTA_CTRL -l2dis_3630: - .word 0 +restoremmu_on: + ldmfd sp!, {r0-r12, pc} @ restore regs and return + /* * Internal functions */ -/* - * This function implements the erratum ID i443 WA, applies to 34xx >= ES3.0 - * Copied to and run from SRAM in order to reconfigure the SDRC parameters. - */ +/* This function implements the erratum ID i443 WA, applies to 34xx >= ES3.0 */ .text .align 3 ENTRY(es3_sdrc_fix) @@ -591,9 +609,6 @@ ENTRY(es3_sdrc_fix) str r5, [r4] @ kick off refreshes bx lr -/* - * Local variables - */ .align sdrc_syscfg: .word SDRC_SYSCONFIG_P @@ -612,3 +627,128 @@ sdrc_manual_1: ENDPROC(es3_sdrc_fix) ENTRY(es3_sdrc_fix_sz) .word . - es3_sdrc_fix + +/* + * This function implements the erratum ID i581 WA: + * SDRC state restore before accessing the SDRAM + * + * Only used at return from non-OFF mode. For OFF + * mode the ROM code configures the SDRC and + * the DPLL before calling the restore code directly + * from DDR. + */ + +/* Make sure SDRC accesses are ok */ +wait_sdrc_ok: + +/* DPLL3 must be locked before accessing the SDRC. Maybe the HW ensures this */ + ldr r4, cm_idlest_ckgen +wait_dpll3_lock: + ldr r5, [r4] + tst r5, #1 + beq wait_dpll3_lock + + ldr r4, cm_idlest1_core +wait_sdrc_ready: + ldr r5, [r4] + tst r5, #0x2 + bne wait_sdrc_ready + /* allow DLL powerdown upon hw idle req */ + ldr r4, sdrc_power + ldr r5, [r4] + bic r5, r5, #0x40 + str r5, [r4] + +/* + * PC-relative stores lead to undefined behaviour in Thumb-2: use a r7 as a + * base instead. + * Be careful not to clobber r7 when maintaing this code. + */ + +is_dll_in_lock_mode: + /* Is dll in lock mode? */ + ldr r4, sdrc_dlla_ctrl + ldr r5, [r4] + tst r5, #0x4 + bxne lr @ Return if locked + /* wait till dll locks */ + adr r7, kick_counter +wait_dll_lock_timed: + ldr r4, wait_dll_lock_counter + add r4, r4, #1 + str r4, [r7, #wait_dll_lock_counter - kick_counter] + ldr r4, sdrc_dlla_status + /* Wait 20uS for lock */ + mov r6, #8 +wait_dll_lock: + subs r6, r6, #0x1 + beq kick_dll + ldr r5, [r4] + and r5, r5, #0x4 + cmp r5, #0x4 + bne wait_dll_lock + bx lr @ Return when locked + + /* disable/reenable DLL if not locked */ +kick_dll: + ldr r4, sdrc_dlla_ctrl + ldr r5, [r4] + mov r6, r5 + bic r6, #(1<<3) @ disable dll + str r6, [r4] + dsb + orr r6, r6, #(1<<3) @ enable dll + str r6, [r4] + dsb + ldr r4, kick_counter + add r4, r4, #1 + str r4, [r7] @ kick_counter + b wait_dll_lock_timed + + .align +cm_idlest1_core: + .word CM_IDLEST1_CORE_V +cm_idlest_ckgen: + .word CM_IDLEST_CKGEN_V +sdrc_dlla_status: + .word SDRC_DLLA_STATUS_V +sdrc_dlla_ctrl: + .word SDRC_DLLA_CTRL_V +pm_prepwstst_core_p: + .word PM_PREPWSTST_CORE_P +pm_pwstctrl_mpu: + .word PM_PWSTCTRL_MPU_P +scratchpad_base: + .word SCRATCHPAD_BASE_P +sram_base: + .word SRAM_BASE_P + 0x8000 +sdrc_power: + .word SDRC_POWER_V +ttbrbit_mask: + .word 0xFFFFC000 +table_index_mask: + .word 0xFFF00000 +table_entry: + .word 0x00000C02 +cache_pred_disable_mask: + .word 0xFFFFE7FB +control_stat: + .word CONTROL_STAT +control_mem_rta: + .word CONTROL_MEM_RTA_CTRL +kernel_flush: + .word v7_flush_dcache_all +l2dis_3630: + .word 0 + /* + * When exporting to userspace while the counters are in SRAM, + * these 2 words need to be at the end to facilitate retrival! + */ +kick_counter: + .word 0 +wait_dll_lock_counter: + .word 0 +ENDPROC(omap34xx_cpu_suspend) + +ENTRY(omap34xx_cpu_suspend_sz) + .word . - omap34xx_cpu_suspend diff --git a/trunk/arch/arm/mach-pnx4008/include/mach/entry-macro.S b/trunk/arch/arm/mach-pnx4008/include/mach/entry-macro.S index db7eeebf30d7..8003037578ed 100644 --- a/trunk/arch/arm/mach-pnx4008/include/mach/entry-macro.S +++ b/trunk/arch/arm/mach-pnx4008/include/mach/entry-macro.S @@ -120,3 +120,8 @@ 1003: .endm + + .macro irq_prio_table + .endm + + diff --git a/trunk/arch/arm/mach-pxa/cm-x2xx.c b/trunk/arch/arm/mach-pxa/cm-x2xx.c index bc55d07566ca..a10996782476 100644 --- a/trunk/arch/arm/mach-pxa/cm-x2xx.c +++ b/trunk/arch/arm/mach-pxa/cm-x2xx.c @@ -518,7 +518,4 @@ MACHINE_START(ARMCORE, "Compulab CM-X2XX") .init_irq = cmx2xx_init_irq, .timer = &pxa_timer, .init_machine = cmx2xx_init, -#ifdef CONFIG_PCI - .dma_zone_size = SZ_64M, -#endif MACHINE_END diff --git a/trunk/arch/arm/mach-pxa/include/mach/memory.h b/trunk/arch/arm/mach-pxa/include/mach/memory.h index d05a59727d66..07734f37f8fd 100644 --- a/trunk/arch/arm/mach-pxa/include/mach/memory.h +++ b/trunk/arch/arm/mach-pxa/include/mach/memory.h @@ -17,4 +17,8 @@ */ #define PLAT_PHYS_OFFSET UL(0xa0000000) +#if defined(CONFIG_MACH_ARMCORE) && defined(CONFIG_PCI) +#define ARM_DMA_ZONE_SIZE SZ_64M +#endif + #endif diff --git a/trunk/arch/arm/mach-pxa/include/mach/pm.h b/trunk/arch/arm/mach-pxa/include/mach/pm.h index 51558bcee999..f15afe012995 100644 --- a/trunk/arch/arm/mach-pxa/include/mach/pm.h +++ b/trunk/arch/arm/mach-pxa/include/mach/pm.h @@ -22,8 +22,8 @@ struct pxa_cpu_pm_fns { extern struct pxa_cpu_pm_fns *pxa_cpu_pm_fns; /* sleep.S */ -extern int pxa25x_finish_suspend(unsigned long); -extern int pxa27x_finish_suspend(unsigned long); +extern void pxa25x_cpu_suspend(unsigned int, long); +extern void pxa27x_cpu_suspend(unsigned int, long); extern int pxa_pm_enter(suspend_state_t state); extern int pxa_pm_prepare(void); diff --git a/trunk/arch/arm/mach-pxa/palmz72.c b/trunk/arch/arm/mach-pxa/palmz72.c index 5a5329bc33f1..65f24f0b77e8 100644 --- a/trunk/arch/arm/mach-pxa/palmz72.c +++ b/trunk/arch/arm/mach-pxa/palmz72.c @@ -33,7 +33,6 @@ #include #include -#include #include #include diff --git a/trunk/arch/arm/mach-pxa/pm.c b/trunk/arch/arm/mach-pxa/pm.c index 37178a8559b1..51e1583265b2 100644 --- a/trunk/arch/arm/mach-pxa/pm.c +++ b/trunk/arch/arm/mach-pxa/pm.c @@ -42,6 +42,7 @@ int pxa_pm_enter(suspend_state_t state) /* *** go zzz *** */ pxa_cpu_pm_fns->enter(state); + cpu_init(); if (state != PM_SUSPEND_STANDBY && pxa_cpu_pm_fns->restore) { /* after sleeping, validate the checksum */ diff --git a/trunk/arch/arm/mach-pxa/pxa25x.c b/trunk/arch/arm/mach-pxa/pxa25x.c index 9c434d21a271..fed363cec9c6 100644 --- a/trunk/arch/arm/mach-pxa/pxa25x.c +++ b/trunk/arch/arm/mach-pxa/pxa25x.c @@ -25,7 +25,6 @@ #include #include -#include #include #include #include @@ -245,7 +244,7 @@ static void pxa25x_cpu_pm_enter(suspend_state_t state) switch (state) { case PM_SUSPEND_MEM: - cpu_suspend(PWRMODE_SLEEP, pxa25x_finish_suspend); + pxa25x_cpu_suspend(PWRMODE_SLEEP, PLAT_PHYS_OFFSET - PAGE_OFFSET); break; } } diff --git a/trunk/arch/arm/mach-pxa/pxa27x.c b/trunk/arch/arm/mach-pxa/pxa27x.c index 9d2400b5f503..2fecbec58d88 100644 --- a/trunk/arch/arm/mach-pxa/pxa27x.c +++ b/trunk/arch/arm/mach-pxa/pxa27x.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -285,11 +284,6 @@ void pxa27x_cpu_pm_restore(unsigned long *sleep_save) void pxa27x_cpu_pm_enter(suspend_state_t state) { extern void pxa_cpu_standby(void); -#ifndef CONFIG_IWMMXT - u64 acc0; - - asm volatile("mra %Q0, %R0, acc0" : "=r" (acc0)); -#endif /* ensure voltage-change sequencer not initiated, which hangs */ PCFR &= ~PCFR_FVC; @@ -305,10 +299,7 @@ void pxa27x_cpu_pm_enter(suspend_state_t state) pxa_cpu_standby(); break; case PM_SUSPEND_MEM: - cpu_suspend(pwrmode, pxa27x_finish_suspend); -#ifndef CONFIG_IWMMXT - asm volatile("mar acc0, %Q0, %R0" : "=r" (acc0)); -#endif + pxa27x_cpu_suspend(pwrmode, PLAT_PHYS_OFFSET - PAGE_OFFSET); break; } } diff --git a/trunk/arch/arm/mach-pxa/pxa3xx.c b/trunk/arch/arm/mach-pxa/pxa3xx.c index ef1c56a67afc..8521d7d6f1da 100644 --- a/trunk/arch/arm/mach-pxa/pxa3xx.c +++ b/trunk/arch/arm/mach-pxa/pxa3xx.c @@ -24,7 +24,6 @@ #include #include -#include #include #include #include @@ -142,13 +141,8 @@ static void pxa3xx_cpu_pm_suspend(void) { volatile unsigned long *p = (volatile void *)0xc0000000; unsigned long saved_data = *p; -#ifndef CONFIG_IWMMXT - u64 acc0; - asm volatile("mra %Q0, %R0, acc0" : "=r" (acc0)); -#endif - - extern int pxa3xx_finish_suspend(unsigned long); + extern void pxa3xx_cpu_suspend(long); /* resuming from D2 requires the HSIO2/BOOT/TPM clocks enabled */ CKENA |= (1 << CKEN_BOOT) | (1 << CKEN_TPM); @@ -168,15 +162,11 @@ static void pxa3xx_cpu_pm_suspend(void) /* overwrite with the resume address */ *p = virt_to_phys(cpu_resume); - cpu_suspend(0, pxa3xx_finish_suspend); + pxa3xx_cpu_suspend(PLAT_PHYS_OFFSET - PAGE_OFFSET); *p = saved_data; AD3ER = 0; - -#ifndef CONFIG_IWMMXT - asm volatile("mar acc0, %Q0, %R0" : "=r" (acc0)); -#endif } static void pxa3xx_cpu_pm_enter(suspend_state_t state) diff --git a/trunk/arch/arm/mach-pxa/sleep.S b/trunk/arch/arm/mach-pxa/sleep.S index 1e544be9905d..6f5368899d84 100644 --- a/trunk/arch/arm/mach-pxa/sleep.S +++ b/trunk/arch/arm/mach-pxa/sleep.S @@ -24,9 +24,20 @@ #ifdef CONFIG_PXA3xx /* - * pxa3xx_finish_suspend() - forces CPU into sleep state (S2D3C4) + * pxa3xx_cpu_suspend() - forces CPU into sleep state (S2D3C4) + * + * r0 = v:p offset */ -ENTRY(pxa3xx_finish_suspend) +ENTRY(pxa3xx_cpu_suspend) + +#ifndef CONFIG_IWMMXT + mra r2, r3, acc0 +#endif + stmfd sp!, {r2 - r12, lr} @ save registers on stack + mov r1, r0 + ldr r3, =pxa_cpu_resume @ resume function + bl cpu_suspend + mov r0, #0x06 @ S2D3C4 mode mcr p14, 0, r0, c7, c0, 0 @ enter sleep @@ -35,18 +46,28 @@ ENTRY(pxa3xx_finish_suspend) #ifdef CONFIG_PXA27x /* - * pxa27x_finish_suspend() + * pxa27x_cpu_suspend() * * Forces CPU into sleep state. * * r0 = value for PWRMODE M field for desired sleep state + * r1 = v:p offset */ -ENTRY(pxa27x_finish_suspend) +ENTRY(pxa27x_cpu_suspend) + +#ifndef CONFIG_IWMMXT + mra r2, r3, acc0 +#endif + stmfd sp!, {r2 - r12, lr} @ save registers on stack + mov r4, r0 @ save sleep mode + ldr r3, =pxa_cpu_resume @ resume function + bl cpu_suspend + @ Put the processor to sleep @ (also workaround for sighting 28071) @ prepare value for sleep mode - mov r1, r0 @ sleep mode + mov r1, r4 @ sleep mode @ prepare pointer to physical address 0 (virtual mapping in generic.c) mov r2, #UNCACHED_PHYS_0 @@ -78,16 +99,21 @@ ENTRY(pxa27x_finish_suspend) #ifdef CONFIG_PXA25x /* - * pxa25x_finish_suspend() + * pxa25x_cpu_suspend() * * Forces CPU into sleep state. * * r0 = value for PWRMODE M field for desired sleep state + * r1 = v:p offset */ -ENTRY(pxa25x_finish_suspend) +ENTRY(pxa25x_cpu_suspend) + stmfd sp!, {r2 - r12, lr} @ save registers on stack + mov r4, r0 @ save sleep mode + ldr r3, =pxa_cpu_resume @ resume function + bl cpu_suspend @ prepare value for sleep mode - mov r1, r0 @ sleep mode + mov r1, r4 @ sleep mode @ prepare pointer to physical address 0 (virtual mapping in generic.c) mov r2, #UNCACHED_PHYS_0 @@ -169,3 +195,16 @@ pxa_cpu_do_suspend: mcr p14, 0, r1, c7, c0, 0 @ PWRMODE 20: b 20b @ loop waiting for sleep + +/* + * pxa_cpu_resume() + * + * entry point from bootloader into kernel during resume + */ + .align 5 +pxa_cpu_resume: + ldmfd sp!, {r2, r3} +#ifndef CONFIG_IWMMXT + mar acc0, r2, r3 +#endif + ldmfd sp!, {r4 - r12, pc} @ return to caller diff --git a/trunk/arch/arm/mach-pxa/zeus.c b/trunk/arch/arm/mach-pxa/zeus.c index 9b99cc164de5..00363c7ac182 100644 --- a/trunk/arch/arm/mach-pxa/zeus.c +++ b/trunk/arch/arm/mach-pxa/zeus.c @@ -31,7 +31,6 @@ #include #include -#include #include #include @@ -677,7 +676,7 @@ static struct pxa2xx_udc_mach_info zeus_udc_info = { static void zeus_power_off(void) { local_irq_disable(); - cpu_suspend(PWRMODE_DEEPSLEEP, pxa27x_finish_suspend); + pxa27x_cpu_suspend(PWRMODE_DEEPSLEEP, PLAT_PHYS_OFFSET - PAGE_OFFSET); } #else #define zeus_power_off NULL diff --git a/trunk/arch/arm/mach-realview/Kconfig b/trunk/arch/arm/mach-realview/Kconfig index dba6d0c1fc17..b9a9805e4828 100644 --- a/trunk/arch/arm/mach-realview/Kconfig +++ b/trunk/arch/arm/mach-realview/Kconfig @@ -50,7 +50,6 @@ config MACH_REALVIEW_PB1176 bool "Support RealView(R) Platform Baseboard for ARM1176JZF-S" select CPU_V6 select ARM_GIC - select HAVE_TCM help Include support for the ARM(R) RealView(R) Platform Baseboard for ARM1176JZF-S. diff --git a/trunk/arch/arm/mach-realview/include/mach/memory.h b/trunk/arch/arm/mach-realview/include/mach/memory.h index 2022e092f0ca..1759fa673eea 100644 --- a/trunk/arch/arm/mach-realview/include/mach/memory.h +++ b/trunk/arch/arm/mach-realview/include/mach/memory.h @@ -29,6 +29,10 @@ #define PLAT_PHYS_OFFSET UL(0x00000000) #endif +#ifdef CONFIG_ZONE_DMA +#define ARM_DMA_ZONE_SIZE SZ_256M +#endif + #ifdef CONFIG_SPARSEMEM /* diff --git a/trunk/arch/arm/mach-realview/platsmp.c b/trunk/arch/arm/mach-realview/platsmp.c index 4ae943bafa92..963bf0d8119a 100644 --- a/trunk/arch/arm/mach-realview/platsmp.c +++ b/trunk/arch/arm/mach-realview/platsmp.c @@ -68,6 +68,14 @@ void __init smp_init_cpus(void) void __init platform_smp_prepare_cpus(unsigned int max_cpus) { + int i; + + /* + * Initialise the present map, which describes the set of CPUs + * actually populated at the present time. + */ + for (i = 0; i < max_cpus; i++) + set_cpu_present(i, true); scu_enable(scu_base_addr()); diff --git a/trunk/arch/arm/mach-realview/realview_eb.c b/trunk/arch/arm/mach-realview/realview_eb.c index 7a4e3b18cb3e..10e75faba4c9 100644 --- a/trunk/arch/arm/mach-realview/realview_eb.c +++ b/trunk/arch/arm/mach-realview/realview_eb.c @@ -470,7 +470,4 @@ MACHINE_START(REALVIEW_EB, "ARM-RealView EB") .init_irq = gic_init_irq, .timer = &realview_eb_timer, .init_machine = realview_eb_init, -#ifdef CONFIG_ZONE_DMA - .dma_zone_size = SZ_256M, -#endif MACHINE_END diff --git a/trunk/arch/arm/mach-realview/realview_pb1176.c b/trunk/arch/arm/mach-realview/realview_pb1176.c index ad5671acb66a..eab6070f66d0 100644 --- a/trunk/arch/arm/mach-realview/realview_pb1176.c +++ b/trunk/arch/arm/mach-realview/realview_pb1176.c @@ -365,7 +365,4 @@ MACHINE_START(REALVIEW_PB1176, "ARM-RealView PB1176") .init_irq = gic_init_irq, .timer = &realview_pb1176_timer, .init_machine = realview_pb1176_init, -#ifdef CONFIG_ZONE_DMA - .dma_zone_size = SZ_256M, -#endif MACHINE_END diff --git a/trunk/arch/arm/mach-realview/realview_pb11mp.c b/trunk/arch/arm/mach-realview/realview_pb11mp.c index b43644b3685e..b2985fc7cd4e 100644 --- a/trunk/arch/arm/mach-realview/realview_pb11mp.c +++ b/trunk/arch/arm/mach-realview/realview_pb11mp.c @@ -367,7 +367,4 @@ MACHINE_START(REALVIEW_PB11MP, "ARM-RealView PB11MPCore") .init_irq = gic_init_irq, .timer = &realview_pb11mp_timer, .init_machine = realview_pb11mp_init, -#ifdef CONFIG_ZONE_DMA - .dma_zone_size = SZ_256M, -#endif MACHINE_END diff --git a/trunk/arch/arm/mach-realview/realview_pba8.c b/trunk/arch/arm/mach-realview/realview_pba8.c index 763e8f38c15d..fb6866558760 100644 --- a/trunk/arch/arm/mach-realview/realview_pba8.c +++ b/trunk/arch/arm/mach-realview/realview_pba8.c @@ -317,7 +317,4 @@ MACHINE_START(REALVIEW_PBA8, "ARM-RealView PB-A8") .init_irq = gic_init_irq, .timer = &realview_pba8_timer, .init_machine = realview_pba8_init, -#ifdef CONFIG_ZONE_DMA - .dma_zone_size = SZ_256M, -#endif MACHINE_END diff --git a/trunk/arch/arm/mach-realview/realview_pbx.c b/trunk/arch/arm/mach-realview/realview_pbx.c index 363b0ab56150..92ace2cf2b2c 100644 --- a/trunk/arch/arm/mach-realview/realview_pbx.c +++ b/trunk/arch/arm/mach-realview/realview_pbx.c @@ -400,7 +400,4 @@ MACHINE_START(REALVIEW_PBX, "ARM-RealView PBX") .init_irq = gic_init_irq, .timer = &realview_pbx_timer, .init_machine = realview_pbx_init, -#ifdef CONFIG_ZONE_DMA - .dma_zone_size = SZ_256M, -#endif MACHINE_END diff --git a/trunk/arch/arm/mach-s3c2412/pm.c b/trunk/arch/arm/mach-s3c2412/pm.c index f4077efa51fa..752b13a7b3db 100644 --- a/trunk/arch/arm/mach-s3c2412/pm.c +++ b/trunk/arch/arm/mach-s3c2412/pm.c @@ -37,10 +37,12 @@ extern void s3c2412_sleep_enter(void); -static int s3c2412_cpu_suspend(unsigned long arg) +static void s3c2412_cpu_suspend(void) { unsigned long tmp; + flush_cache_all(); + /* set our standby method to sleep */ tmp = __raw_readl(S3C2412_PWRCFG); @@ -48,8 +50,6 @@ static int s3c2412_cpu_suspend(unsigned long arg) __raw_writel(tmp, S3C2412_PWRCFG); s3c2412_sleep_enter(); - - panic("sleep resumed to originator?"); } static void s3c2412_pm_prepare(void) diff --git a/trunk/arch/arm/mach-s3c2416/pm.c b/trunk/arch/arm/mach-s3c2416/pm.c index 9ec54f1d8e75..41db2b21e213 100644 --- a/trunk/arch/arm/mach-s3c2416/pm.c +++ b/trunk/arch/arm/mach-s3c2416/pm.c @@ -24,8 +24,10 @@ extern void s3c2412_sleep_enter(void); -static int s3c2416_cpu_suspend(unsigned long arg) +static void s3c2416_cpu_suspend(void) { + flush_cache_all(); + /* enable wakeup sources regardless of battery state */ __raw_writel(S3C2443_PWRCFG_SLEEP, S3C2443_PWRCFG); @@ -33,8 +35,6 @@ static int s3c2416_cpu_suspend(unsigned long arg) __raw_writel(0x2BED, S3C2443_PWRMODE); s3c2412_sleep_enter(); - - panic("sleep resumed to originator?"); } static void s3c2416_pm_prepare(void) diff --git a/trunk/arch/arm/mach-s3c64xx/pm.c b/trunk/arch/arm/mach-s3c64xx/pm.c index 8bad64370689..bc1c470b7de6 100644 --- a/trunk/arch/arm/mach-s3c64xx/pm.c +++ b/trunk/arch/arm/mach-s3c64xx/pm.c @@ -112,7 +112,7 @@ void s3c_pm_save_core(void) * this. */ -static int s3c64xx_cpu_suspend(unsigned long arg) +static void s3c64xx_cpu_suspend(void) { unsigned long tmp; diff --git a/trunk/arch/arm/mach-s3c64xx/sleep.S b/trunk/arch/arm/mach-s3c64xx/sleep.S index 34313f9c8792..1f87732b2320 100644 --- a/trunk/arch/arm/mach-s3c64xx/sleep.S +++ b/trunk/arch/arm/mach-s3c64xx/sleep.S @@ -25,6 +25,29 @@ .text + /* s3c_cpu_save + * + * Save enough processor state to allow the restart of the pm.c + * code after resume. + * + * entry: + * r1 = v:p offset + */ + +ENTRY(s3c_cpu_save) + stmfd sp!, { r4 - r12, lr } + ldr r3, =resume_with_mmu + bl cpu_suspend + + @@ call final suspend code + ldr r0, =pm_cpu_sleep + ldr pc, [r0] + + @@ return to the caller, after the MMU is turned on. + @@ restore the last bits of the stack and return. +resume_with_mmu: + ldmfd sp!, { r4 - r12, pc } @ return, from sp from s3c_cpu_save + /* Sleep magic, the word before the resume entry point so that the * bootloader can check for a resumeable image. */ diff --git a/trunk/arch/arm/mach-s5pv210/pm.c b/trunk/arch/arm/mach-s5pv210/pm.c index 309e388a8a83..24febae3d4c0 100644 --- a/trunk/arch/arm/mach-s5pv210/pm.c +++ b/trunk/arch/arm/mach-s5pv210/pm.c @@ -88,7 +88,7 @@ static struct sleep_save s5pv210_core_save[] = { SAVE_ITEM(S3C2410_TCNTO(0)), }; -void s5pv210_cpu_suspend(unsigned long arg) +void s5pv210_cpu_suspend(void) { unsigned long tmp; diff --git a/trunk/arch/arm/mach-s5pv210/sleep.S b/trunk/arch/arm/mach-s5pv210/sleep.S index e3452ccd4b08..a3d649466fb1 100644 --- a/trunk/arch/arm/mach-s5pv210/sleep.S +++ b/trunk/arch/arm/mach-s5pv210/sleep.S @@ -32,6 +32,27 @@ .text + /* s3c_cpu_save + * + * entry: + * r1 = v:p offset + */ + +ENTRY(s3c_cpu_save) + + stmfd sp!, { r3 - r12, lr } + ldr r3, =resume_with_mmu + bl cpu_suspend + + ldr r0, =pm_cpu_sleep + ldr r0, [ r0 ] + mov pc, r0 + +resume_with_mmu: + ldmfd sp!, { r3 - r12, pc } + + .ltorg + /* sleep magic, to allow the bootloader to check for an valid * image to resume to. Must be the first word before the * s3c_cpu_resume entry. diff --git a/trunk/arch/arm/mach-sa1100/assabet.c b/trunk/arch/arm/mach-sa1100/assabet.c index 26257df19b63..5778274a8260 100644 --- a/trunk/arch/arm/mach-sa1100/assabet.c +++ b/trunk/arch/arm/mach-sa1100/assabet.c @@ -453,7 +453,4 @@ MACHINE_START(ASSABET, "Intel-Assabet") .init_irq = sa1100_init_irq, .timer = &sa1100_timer, .init_machine = assabet_init, -#ifdef CONFIG_SA1111 - .dma_zone_size = SZ_1M, -#endif MACHINE_END diff --git a/trunk/arch/arm/mach-sa1100/badge4.c b/trunk/arch/arm/mach-sa1100/badge4.c index b4311b0a4395..4f19ff868b00 100644 --- a/trunk/arch/arm/mach-sa1100/badge4.c +++ b/trunk/arch/arm/mach-sa1100/badge4.c @@ -306,7 +306,4 @@ MACHINE_START(BADGE4, "Hewlett-Packard Laboratories BadgePAD 4") .map_io = badge4_map_io, .init_irq = sa1100_init_irq, .timer = &sa1100_timer, -#ifdef CONFIG_SA1111 - .dma_zone_size = SZ_1M, -#endif MACHINE_END diff --git a/trunk/arch/arm/mach-sa1100/include/mach/memory.h b/trunk/arch/arm/mach-sa1100/include/mach/memory.h index 12d376795abc..cff31ee246b7 100644 --- a/trunk/arch/arm/mach-sa1100/include/mach/memory.h +++ b/trunk/arch/arm/mach-sa1100/include/mach/memory.h @@ -14,6 +14,10 @@ */ #define PLAT_PHYS_OFFSET UL(0xc0000000) +#ifdef CONFIG_SA1111 +#define ARM_DMA_ZONE_SIZE SZ_1M +#endif + /* * Because of the wide memory address space between physical RAM banks on the * SA1100, it's much convenient to use Linux's SparseMEM support to implement diff --git a/trunk/arch/arm/mach-sa1100/jornada720.c b/trunk/arch/arm/mach-sa1100/jornada720.c index 176c066aec7e..491ac9f20fb4 100644 --- a/trunk/arch/arm/mach-sa1100/jornada720.c +++ b/trunk/arch/arm/mach-sa1100/jornada720.c @@ -369,7 +369,4 @@ MACHINE_START(JORNADA720, "HP Jornada 720") .init_irq = sa1100_init_irq, .timer = &sa1100_timer, .init_machine = jornada720_mach_init, -#ifdef CONFIG_SA1111 - .dma_zone_size = SZ_1M, -#endif MACHINE_END diff --git a/trunk/arch/arm/mach-sa1100/pm.c b/trunk/arch/arm/mach-sa1100/pm.c index bf85b8b259d5..c4661aab22fb 100644 --- a/trunk/arch/arm/mach-sa1100/pm.c +++ b/trunk/arch/arm/mach-sa1100/pm.c @@ -29,11 +29,10 @@ #include #include -#include #include #include -extern int sa1100_finish_suspend(unsigned long); +extern void sa1100_cpu_suspend(long); #define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x #define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x] @@ -76,7 +75,9 @@ static int sa11x0_pm_enter(suspend_state_t state) PSPR = virt_to_phys(cpu_resume); /* go zzz */ - cpu_suspend(0, sa1100_finish_suspend); + sa1100_cpu_suspend(PLAT_PHYS_OFFSET - PAGE_OFFSET); + + cpu_init(); /* * Ensure not to come back here if it wasn't intended diff --git a/trunk/arch/arm/mach-sa1100/sleep.S b/trunk/arch/arm/mach-sa1100/sleep.S index e8223315b442..04f2a618d4ef 100644 --- a/trunk/arch/arm/mach-sa1100/sleep.S +++ b/trunk/arch/arm/mach-sa1100/sleep.S @@ -22,13 +22,18 @@ .text /* - * sa1100_finish_suspend() + * sa1100_cpu_suspend() * * Causes sa11x0 to enter sleep state * */ -ENTRY(sa1100_finish_suspend) +ENTRY(sa1100_cpu_suspend) + stmfd sp!, {r4 - r12, lr} @ save registers on stack + mov r1, r0 + ldr r3, =sa1100_cpu_resume @ return function + bl cpu_suspend + @ disable clock switching mcr p15, 0, r1, c15, c2, 2 @@ -134,3 +139,13 @@ sa1110_sdram_controller_fix: str r13, [r12] 20: b 20b @ loop waiting for sleep + +/* + * cpu_sa1100_resume() + * + * entry point from bootloader into kernel during resume + */ + .align 5 +sa1100_cpu_resume: + mcr p15, 0, r1, c15, c1, 2 @ enable clock switching + ldmfd sp!, {r4 - r12, pc} @ return to caller diff --git a/trunk/arch/arm/mach-shark/core.c b/trunk/arch/arm/mach-shark/core.c index ac2873c8014b..5cf7f94c1f31 100644 --- a/trunk/arch/arm/mach-shark/core.c +++ b/trunk/arch/arm/mach-shark/core.c @@ -156,5 +156,4 @@ MACHINE_START(SHARK, "Shark") .map_io = shark_map_io, .init_irq = shark_init_irq, .timer = &shark_timer, - .dma_zone_size = SZ_4M, MACHINE_END diff --git a/trunk/arch/arm/mach-shark/include/mach/entry-macro.S b/trunk/arch/arm/mach-shark/include/mach/entry-macro.S index 0bb6cc626eb7..e2853c0a3333 100644 --- a/trunk/arch/arm/mach-shark/include/mach/entry-macro.S +++ b/trunk/arch/arm/mach-shark/include/mach/entry-macro.S @@ -11,17 +11,17 @@ .endm .macro get_irqnr_preamble, base, tmp - mov \base, #0xe0000000 .endm .macro arch_ret_to_user, tmp1, tmp2 .endm .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + mov r4, #0xe0000000 mov \irqstat, #0x0C - strb \irqstat, [\base, #0x20] @outb(0x0C, 0x20) /* Poll command */ - ldrb \irqnr, [\base, #0x20] @irq = inb(0x20) & 7 + strb \irqstat, [r4, #0x20] @outb(0x0C, 0x20) /* Poll command */ + ldrb \irqnr, [r4, #0x20] @irq = inb(0x20) & 7 and \irqstat, \irqnr, #0x80 teq \irqstat, #0 beq 43f @@ -29,8 +29,8 @@ teq \irqnr, #2 bne 44f 43: mov \irqstat, #0x0C - strb \irqstat, [\base, #0xa0] @outb(0x0C, 0xA0) /* Poll command */ - ldrb \irqnr, [\base, #0xa0] @irq = (inb(0xA0) & 7) + 8 + strb \irqstat, [r4, #0xa0] @outb(0x0C, 0xA0) /* Poll command */ + ldrb \irqnr, [r4, #0xa0] @irq = (inb(0xA0) & 7) + 8 and \irqstat, \irqnr, #0x80 teq \irqstat, #0 beq 44f diff --git a/trunk/arch/arm/mach-shark/include/mach/memory.h b/trunk/arch/arm/mach-shark/include/mach/memory.h index 1cf8d6962617..4c0831f83b0c 100644 --- a/trunk/arch/arm/mach-shark/include/mach/memory.h +++ b/trunk/arch/arm/mach-shark/include/mach/memory.h @@ -17,6 +17,8 @@ */ #define PLAT_PHYS_OFFSET UL(0x08000000) +#define ARM_DMA_ZONE_SIZE SZ_4M + /* * Cache flushing area */ diff --git a/trunk/arch/arm/mach-shmobile/include/mach/sdhi-sh7372.h b/trunk/arch/arm/mach-shmobile/include/mach/sdhi-sh7372.h deleted file mode 100644 index 4a81b01f1e8f..000000000000 --- a/trunk/arch/arm/mach-shmobile/include/mach/sdhi-sh7372.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef SDHI_SH7372_H -#define SDHI_SH7372_H - -#define SDGENCNTA 0xfe40009c - -/* The countdown of SDGENCNTA is controlled by - * ZB3D2CLK which runs at 149.5MHz. - * That is 149.5ticks/us. Approximate this as 150ticks/us. - */ -static void udelay(int us) -{ - __raw_writel(us * 150, SDGENCNTA); - while(__raw_readl(SDGENCNTA)) ; -} - -static void msleep(int ms) -{ - udelay(ms * 1000); -} - -#endif diff --git a/trunk/arch/arm/mach-shmobile/include/mach/sdhi.h b/trunk/arch/arm/mach-shmobile/include/mach/sdhi.h deleted file mode 100644 index 0ec9e69f2c3b..000000000000 --- a/trunk/arch/arm/mach-shmobile/include/mach/sdhi.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef SDHI_H -#define SDHI_H - -/************************************************** - * - * CPU specific settings - * - **************************************************/ - -#ifdef CONFIG_ARCH_SH7372 -#include "mach/sdhi-sh7372.h" -#else -#error "unsupported CPU." -#endif - -#endif /* SDHI_H */ diff --git a/trunk/arch/arm/mach-shmobile/platsmp.c b/trunk/arch/arm/mach-shmobile/platsmp.c index 66f980625a33..f3888feb1c68 100644 --- a/trunk/arch/arm/mach-shmobile/platsmp.c +++ b/trunk/arch/arm/mach-shmobile/platsmp.c @@ -64,5 +64,10 @@ void __init smp_init_cpus(void) void __init platform_smp_prepare_cpus(unsigned int max_cpus) { + int i; + + for (i = 0; i < max_cpus; i++) + set_cpu_present(i, true); + shmobile_smp_prepare_cpus(); } diff --git a/trunk/arch/arm/mach-tegra/clock.c b/trunk/arch/arm/mach-tegra/clock.c index f8d41ffc0ca9..e028320ab423 100644 --- a/trunk/arch/arm/mach-tegra/clock.c +++ b/trunk/arch/arm/mach-tegra/clock.c @@ -585,7 +585,7 @@ static const struct file_operations possible_parents_fops = { static int clk_debugfs_register_one(struct clk *c) { - struct dentry *d; + struct dentry *d, *child, *child_tmp; d = debugfs_create_dir(c->name, clk_debugfs_root); if (!d) @@ -614,7 +614,10 @@ static int clk_debugfs_register_one(struct clk *c) return 0; err_out: - debugfs_remove_recursive(c->dent); + d = c->dent; + list_for_each_entry_safe(child, child_tmp, &d->d_subdirs, d_u.d_child) + debugfs_remove(child); + debugfs_remove(c->dent); return -ENOMEM; } diff --git a/trunk/arch/arm/mach-tegra/platsmp.c b/trunk/arch/arm/mach-tegra/platsmp.c index 1a594dce8fbc..b8ae3c978dee 100644 --- a/trunk/arch/arm/mach-tegra/platsmp.c +++ b/trunk/arch/arm/mach-tegra/platsmp.c @@ -129,6 +129,14 @@ void __init smp_init_cpus(void) void __init platform_smp_prepare_cpus(unsigned int max_cpus) { + int i; + + /* + * Initialise the present map, which describes the set of CPUs + * actually populated at the present time. + */ + for (i = 0; i < max_cpus; i++) + set_cpu_present(i, true); scu_enable(scu_base); } diff --git a/trunk/arch/arm/mach-ux500/clock.c b/trunk/arch/arm/mach-ux500/clock.c index 7d107be63eb4..32ce90840ee1 100644 --- a/trunk/arch/arm/mach-ux500/clock.c +++ b/trunk/arch/arm/mach-ux500/clock.c @@ -635,13 +635,16 @@ static const struct file_operations set_rate_fops = { static struct dentry *clk_debugfs_register_dir(struct clk *c, struct dentry *p_dentry) { - struct dentry *d, *clk_d; - const char *p = c->name; + struct dentry *d, *clk_d, *child, *child_tmp; + char s[255]; + char *p = s; - if (!p) - p = "BUG"; + if (c->name == NULL) + p += sprintf(p, "BUG"); + else + p += sprintf(p, "%s", c->name); - clk_d = debugfs_create_dir(p, p_dentry); + clk_d = debugfs_create_dir(s, p_dentry); if (!clk_d) return NULL; @@ -663,10 +666,24 @@ static struct dentry *clk_debugfs_register_dir(struct clk *c, return clk_d; err_out: - debugfs_remove_recursive(clk_d); + d = clk_d; + list_for_each_entry_safe(child, child_tmp, &d->d_subdirs, d_u.d_child) + debugfs_remove(child); + debugfs_remove(clk_d); return NULL; } +static void clk_debugfs_remove_dir(struct dentry *cdentry) +{ + struct dentry *d, *child, *child_tmp; + + d = cdentry; + list_for_each_entry_safe(child, child_tmp, &d->d_subdirs, d_u.d_child) + debugfs_remove(child); + debugfs_remove(cdentry); + return ; +} + static int clk_debugfs_register_one(struct clk *c) { struct clk *pa = c->parent_periph; @@ -683,7 +700,7 @@ static int clk_debugfs_register_one(struct clk *c) c->dent_bus = clk_debugfs_register_dir(c, bpa->dent_bus ? bpa->dent_bus : bpa->dent); if ((!c->dent_bus) && (c->dent)) { - debugfs_remove_recursive(c->dent); + clk_debugfs_remove_dir(c->dent); c->dent = NULL; return -ENOMEM; } diff --git a/trunk/arch/arm/mach-ux500/platsmp.c b/trunk/arch/arm/mach-ux500/platsmp.c index a33df5f4c27a..0c527fe2cebb 100644 --- a/trunk/arch/arm/mach-ux500/platsmp.c +++ b/trunk/arch/arm/mach-ux500/platsmp.c @@ -172,6 +172,14 @@ void __init smp_init_cpus(void) void __init platform_smp_prepare_cpus(unsigned int max_cpus) { + int i; + + /* + * Initialise the present map, which describes the set of CPUs + * actually populated at the present time. + */ + for (i = 0; i < max_cpus; i++) + set_cpu_present(i, true); scu_enable(scu_base_addr()); wakeup_secondary(); diff --git a/trunk/arch/arm/mach-vexpress/ct-ca9x4.c b/trunk/arch/arm/mach-vexpress/ct-ca9x4.c index bfd32f52c2db..765a71ff7f3b 100644 --- a/trunk/arch/arm/mach-vexpress/ct-ca9x4.c +++ b/trunk/arch/arm/mach-vexpress/ct-ca9x4.c @@ -229,6 +229,10 @@ static void ct_ca9x4_init_cpu_map(void) static void ct_ca9x4_smp_enable(unsigned int max_cpus) { + int i; + for (i = 0; i < max_cpus; i++) + set_cpu_present(i, true); + scu_enable(MMIO_P2V(A9_MPCORE_SCU)); } #endif diff --git a/trunk/arch/arm/mm/abort-ev4.S b/trunk/arch/arm/mm/abort-ev4.S index 54473cd4aba9..4f18f9e87bae 100644 --- a/trunk/arch/arm/mm/abort-ev4.S +++ b/trunk/arch/arm/mm/abort-ev4.S @@ -3,11 +3,14 @@ /* * Function: v4_early_abort * - * Params : r2 = pt_regs - * : r4 = aborted context pc - * : r5 = aborted context psr + * Params : r2 = address of aborted instruction + * : r3 = saved SPSR * - * Returns : r4 - r11, r13 preserved + * Returns : r0 = address of abort + * : r1 = FSR, bit 11 = write + * : r2-r8 = corrupted + * : r9 = preserved + * : sp = pointer to registers * * Purpose : obtain information about current aborted instruction. * Note: we read user space. This means we might cause a data @@ -18,8 +21,10 @@ ENTRY(v4_early_abort) mrc p15, 0, r1, c5, c0, 0 @ get FSR mrc p15, 0, r0, c6, c0, 0 @ get FAR - ldr r3, [r4] @ read aborted ARM instruction + ldr r3, [r2] @ read aborted ARM instruction bic r1, r1, #1 << 11 | 1 << 10 @ clear bits 11 and 10 of FSR tst r3, #1 << 20 @ L = 1 -> write? orreq r1, r1, #1 << 11 @ yes. - b do_DataAbort + mov pc, lr + + diff --git a/trunk/arch/arm/mm/abort-ev4t.S b/trunk/arch/arm/mm/abort-ev4t.S index 9da704e7b86e..b6282548f922 100644 --- a/trunk/arch/arm/mm/abort-ev4t.S +++ b/trunk/arch/arm/mm/abort-ev4t.S @@ -4,11 +4,14 @@ /* * Function: v4t_early_abort * - * Params : r2 = pt_regs - * : r4 = aborted context pc - * : r5 = aborted context psr + * Params : r2 = address of aborted instruction + * : r3 = saved SPSR * - * Returns : r4 - r11, r13 preserved + * Returns : r0 = address of abort + * : r1 = FSR, bit 11 = write + * : r2-r8 = corrupted + * : r9 = preserved + * : sp = pointer to registers * * Purpose : obtain information about current aborted instruction. * Note: we read user space. This means we might cause a data @@ -19,9 +22,9 @@ ENTRY(v4t_early_abort) mrc p15, 0, r1, c5, c0, 0 @ get FSR mrc p15, 0, r0, c6, c0, 0 @ get FAR - do_thumb_abort fsr=r1, pc=r4, psr=r5, tmp=r3 - ldreq r3, [r4] @ read aborted ARM instruction + do_thumb_abort + ldreq r3, [r2] @ read aborted ARM instruction bic r1, r1, #1 << 11 | 1 << 10 @ clear bits 11 and 10 of FSR tst r3, #1 << 20 @ check write orreq r1, r1, #1 << 11 - b do_DataAbort + mov pc, lr diff --git a/trunk/arch/arm/mm/abort-ev5t.S b/trunk/arch/arm/mm/abort-ev5t.S index a0908d4653a3..02251b526c0d 100644 --- a/trunk/arch/arm/mm/abort-ev5t.S +++ b/trunk/arch/arm/mm/abort-ev5t.S @@ -4,11 +4,14 @@ /* * Function: v5t_early_abort * - * Params : r2 = pt_regs - * : r4 = aborted context pc - * : r5 = aborted context psr + * Params : r2 = address of aborted instruction + * : r3 = saved SPSR * - * Returns : r4 - r11, r13 preserved + * Returns : r0 = address of abort + * : r1 = FSR, bit 11 = write + * : r2-r8 = corrupted + * : r9 = preserved + * : sp = pointer to registers * * Purpose : obtain information about current aborted instruction. * Note: we read user space. This means we might cause a data @@ -19,10 +22,10 @@ ENTRY(v5t_early_abort) mrc p15, 0, r1, c5, c0, 0 @ get FSR mrc p15, 0, r0, c6, c0, 0 @ get FAR - do_thumb_abort fsr=r1, pc=r4, psr=r5, tmp=r3 - ldreq r3, [r4] @ read aborted ARM instruction + do_thumb_abort + ldreq r3, [r2] @ read aborted ARM instruction bic r1, r1, #1 << 11 @ clear bits 11 of FSR - do_ldrd_abort tmp=ip, insn=r3 + do_ldrd_abort tst r3, #1 << 20 @ check write orreq r1, r1, #1 << 11 - b do_DataAbort + mov pc, lr diff --git a/trunk/arch/arm/mm/abort-ev5tj.S b/trunk/arch/arm/mm/abort-ev5tj.S index 4006b7a61264..bce68d601c8b 100644 --- a/trunk/arch/arm/mm/abort-ev5tj.S +++ b/trunk/arch/arm/mm/abort-ev5tj.S @@ -4,11 +4,14 @@ /* * Function: v5tj_early_abort * - * Params : r2 = pt_regs - * : r4 = aborted context pc - * : r5 = aborted context psr + * Params : r2 = address of aborted instruction + * : r3 = saved SPSR * - * Returns : r4 - r11, r13 preserved + * Returns : r0 = address of abort + * : r1 = FSR, bit 11 = write + * : r2-r8 = corrupted + * : r9 = preserved + * : sp = pointer to registers * * Purpose : obtain information about current aborted instruction. * Note: we read user space. This means we might cause a data @@ -20,11 +23,13 @@ ENTRY(v5tj_early_abort) mrc p15, 0, r1, c5, c0, 0 @ get FSR mrc p15, 0, r0, c6, c0, 0 @ get FAR bic r1, r1, #1 << 11 | 1 << 10 @ clear bits 11 and 10 of FSR - tst r5, #PSR_J_BIT @ Java? - bne do_DataAbort - do_thumb_abort fsr=r1, pc=r4, psr=r5, tmp=r3 - ldreq r3, [r4] @ read aborted ARM instruction - do_ldrd_abort tmp=ip, insn=r3 + tst r3, #PSR_J_BIT @ Java? + movne pc, lr + do_thumb_abort + ldreq r3, [r2] @ read aborted ARM instruction + do_ldrd_abort tst r3, #1 << 20 @ L = 0 -> write orreq r1, r1, #1 << 11 @ yes. - b do_DataAbort + mov pc, lr + + diff --git a/trunk/arch/arm/mm/abort-ev6.S b/trunk/arch/arm/mm/abort-ev6.S index ff1f7cc11f87..1478aa522144 100644 --- a/trunk/arch/arm/mm/abort-ev6.S +++ b/trunk/arch/arm/mm/abort-ev6.S @@ -4,11 +4,14 @@ /* * Function: v6_early_abort * - * Params : r2 = pt_regs - * : r4 = aborted context pc - * : r5 = aborted context psr + * Params : r2 = address of aborted instruction + * : r3 = saved SPSR * - * Returns : r4 - r11, r13 preserved + * Returns : r0 = address of abort + * : r1 = FSR, bit 11 = write + * : r2-r8 = corrupted + * : r9 = preserved + * : sp = pointer to registers * * Purpose : obtain information about current aborted instruction. * Note: we read user space. This means we might cause a data @@ -30,14 +33,16 @@ ENTRY(v6_early_abort) * The test below covers all the write situations, including Java bytecodes */ bic r1, r1, #1 << 11 @ clear bit 11 of FSR - tst r5, #PSR_J_BIT @ Java? - bne do_DataAbort - do_thumb_abort fsr=r1, pc=r4, psr=r5, tmp=r3 - ldreq r3, [r4] @ read aborted ARM instruction + tst r3, #PSR_J_BIT @ Java? + movne pc, lr + do_thumb_abort + ldreq r3, [r2] @ read aborted ARM instruction #ifdef CONFIG_CPU_ENDIAN_BE8 reveq r3, r3 #endif - do_ldrd_abort tmp=ip, insn=r3 + do_ldrd_abort tst r3, #1 << 20 @ L = 0 -> write orreq r1, r1, #1 << 11 @ yes. - b do_DataAbort + mov pc, lr + + diff --git a/trunk/arch/arm/mm/abort-ev7.S b/trunk/arch/arm/mm/abort-ev7.S index 703375277ba6..ec88b157d3bb 100644 --- a/trunk/arch/arm/mm/abort-ev7.S +++ b/trunk/arch/arm/mm/abort-ev7.S @@ -3,11 +3,14 @@ /* * Function: v7_early_abort * - * Params : r2 = pt_regs - * : r4 = aborted context pc - * : r5 = aborted context psr + * Params : r2 = address of aborted instruction + * : r3 = saved SPSR * - * Returns : r4 - r11, r13 preserved + * Returns : r0 = address of abort + * : r1 = FSR, bit 11 = write + * : r2-r8 = corrupted + * : r9 = preserved + * : sp = pointer to registers * * Purpose : obtain information about current aborted instruction. */ @@ -34,18 +37,18 @@ ENTRY(v7_early_abort) ldr r3, =0x40d @ On permission fault and r3, r1, r3 cmp r3, #0x0d - bne do_DataAbort + movne pc, lr mcr p15, 0, r0, c7, c8, 0 @ Retranslate FAR isb - mrc p15, 0, ip, c7, c4, 0 @ Read the PAR - and r3, ip, #0x7b @ On translation fault + mrc p15, 0, r2, c7, c4, 0 @ Read the PAR + and r3, r2, #0x7b @ On translation fault cmp r3, #0x0b - bne do_DataAbort + movne pc, lr bic r1, r1, #0xf @ Fix up FSR FS[5:0] - and ip, ip, #0x7e - orr r1, r1, ip, LSR #1 + and r2, r2, #0x7e + orr r1, r1, r2, LSR #1 #endif - b do_DataAbort + mov pc, lr ENDPROC(v7_early_abort) diff --git a/trunk/arch/arm/mm/abort-lv4t.S b/trunk/arch/arm/mm/abort-lv4t.S index f3982580c273..9fb7b0e25ea1 100644 --- a/trunk/arch/arm/mm/abort-lv4t.S +++ b/trunk/arch/arm/mm/abort-lv4t.S @@ -3,11 +3,14 @@ /* * Function: v4t_late_abort * - * Params : r2 = pt_regs - * : r4 = aborted context pc - * : r5 = aborted context psr + * Params : r2 = address of aborted instruction + * : r3 = saved SPSR * - * Returns : r4-r5, r10-r11, r13 preserved + * Returns : r0 = address of abort + * : r1 = FSR, bit 11 = write + * : r2-r8 = corrupted + * : r9 = preserved + * : sp = pointer to registers * * Purpose : obtain information about current aborted instruction. * Note: we read user space. This means we might cause a data @@ -15,7 +18,7 @@ * picture. Unfortunately, this does happen. We live with it. */ ENTRY(v4t_late_abort) - tst r5, #PSR_T_BIT @ check for thumb mode + tst r3, #PSR_T_BIT @ check for thumb mode #ifdef CONFIG_CPU_CP15_MMU mrc p15, 0, r1, c5, c0, 0 @ get FSR mrc p15, 0, r0, c6, c0, 0 @ get FAR @@ -25,7 +28,7 @@ ENTRY(v4t_late_abort) mov r1, #0 #endif bne .data_thumb_abort - ldr r8, [r4] @ read arm instruction + ldr r8, [r2] @ read arm instruction tst r8, #1 << 20 @ L = 1 -> write? orreq r1, r1, #1 << 11 @ yes. and r7, r8, #15 << 24 @@ -44,84 +47,86 @@ ENTRY(v4t_late_abort) /* 9 */ b .data_arm_ldmstm @ ldm*b rn, /* a */ b .data_unknown /* b */ b .data_unknown -/* c */ b do_DataAbort @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m -/* d */ b do_DataAbort @ ldc rd, [rn, #m] +/* c */ mov pc, lr @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m +/* d */ mov pc, lr @ ldc rd, [rn, #m] /* e */ b .data_unknown /* f */ .data_unknown: @ Part of jumptable - mov r0, r4 + mov r0, r2 mov r1, r8 - b baddataabort + mov r2, sp + bl baddataabort + b ret_from_exception .data_arm_ldmstm: tst r8, #1 << 21 @ check writeback bit - beq do_DataAbort @ no writeback -> no fixup + moveq pc, lr @ no writeback -> no fixup mov r7, #0x11 orr r7, r7, #0x1100 and r6, r8, r7 - and r9, r8, r7, lsl #1 - add r6, r6, r9, lsr #1 - and r9, r8, r7, lsl #2 - add r6, r6, r9, lsr #2 - and r9, r8, r7, lsl #3 - add r6, r6, r9, lsr #3 + and r2, r8, r7, lsl #1 + add r6, r6, r2, lsr #1 + and r2, r8, r7, lsl #2 + add r6, r6, r2, lsr #2 + and r2, r8, r7, lsl #3 + add r6, r6, r2, lsr #3 add r6, r6, r6, lsr #8 add r6, r6, r6, lsr #4 and r6, r6, #15 @ r6 = no. of registers to transfer. - and r9, r8, #15 << 16 @ Extract 'n' from instruction - ldr r7, [r2, r9, lsr #14] @ Get register 'Rn' + and r5, r8, #15 << 16 @ Extract 'n' from instruction + ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' tst r8, #1 << 23 @ Check U bit subne r7, r7, r6, lsl #2 @ Undo increment addeq r7, r7, r6, lsl #2 @ Undo decrement - str r7, [r2, r9, lsr #14] @ Put register 'Rn' - b do_DataAbort + str r7, [sp, r5, lsr #14] @ Put register 'Rn' + mov pc, lr .data_arm_lateldrhpre: tst r8, #1 << 21 @ Check writeback bit - beq do_DataAbort @ No writeback -> no fixup + moveq pc, lr @ No writeback -> no fixup .data_arm_lateldrhpost: - and r9, r8, #0x00f @ get Rm / low nibble of immediate value + and r5, r8, #0x00f @ get Rm / low nibble of immediate value tst r8, #1 << 22 @ if (immediate offset) andne r6, r8, #0xf00 @ { immediate high nibble - orrne r6, r9, r6, lsr #4 @ combine nibbles } else - ldreq r6, [r2, r9, lsl #2] @ { load Rm value } + orrne r6, r5, r6, lsr #4 @ combine nibbles } else + ldreq r6, [sp, r5, lsl #2] @ { load Rm value } .data_arm_apply_r6_and_rn: - and r9, r8, #15 << 16 @ Extract 'n' from instruction - ldr r7, [r2, r9, lsr #14] @ Get register 'Rn' + and r5, r8, #15 << 16 @ Extract 'n' from instruction + ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' tst r8, #1 << 23 @ Check U bit subne r7, r7, r6 @ Undo incrmenet addeq r7, r7, r6 @ Undo decrement - str r7, [r2, r9, lsr #14] @ Put register 'Rn' - b do_DataAbort + str r7, [sp, r5, lsr #14] @ Put register 'Rn' + mov pc, lr .data_arm_lateldrpreconst: tst r8, #1 << 21 @ check writeback bit - beq do_DataAbort @ no writeback -> no fixup + moveq pc, lr @ no writeback -> no fixup .data_arm_lateldrpostconst: - movs r6, r8, lsl #20 @ Get offset - beq do_DataAbort @ zero -> no fixup - and r9, r8, #15 << 16 @ Extract 'n' from instruction - ldr r7, [r2, r9, lsr #14] @ Get register 'Rn' + movs r2, r8, lsl #20 @ Get offset + moveq pc, lr @ zero -> no fixup + and r5, r8, #15 << 16 @ Extract 'n' from instruction + ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' tst r8, #1 << 23 @ Check U bit - subne r7, r7, r6, lsr #20 @ Undo increment - addeq r7, r7, r6, lsr #20 @ Undo decrement - str r7, [r2, r9, lsr #14] @ Put register 'Rn' - b do_DataAbort + subne r7, r7, r2, lsr #20 @ Undo increment + addeq r7, r7, r2, lsr #20 @ Undo decrement + str r7, [sp, r5, lsr #14] @ Put register 'Rn' + mov pc, lr .data_arm_lateldrprereg: tst r8, #1 << 21 @ check writeback bit - beq do_DataAbort @ no writeback -> no fixup + moveq pc, lr @ no writeback -> no fixup .data_arm_lateldrpostreg: and r7, r8, #15 @ Extract 'm' from instruction - ldr r6, [r2, r7, lsl #2] @ Get register 'Rm' - mov r9, r8, lsr #7 @ get shift count - ands r9, r9, #31 + ldr r6, [sp, r7, lsl #2] @ Get register 'Rm' + mov r5, r8, lsr #7 @ get shift count + ands r5, r5, #31 and r7, r8, #0x70 @ get shift type orreq r7, r7, #8 @ shift count = 0 add pc, pc, r7 nop - mov r6, r6, lsl r9 @ 0: LSL #!0 + mov r6, r6, lsl r5 @ 0: LSL #!0 b .data_arm_apply_r6_and_rn b .data_arm_apply_r6_and_rn @ 1: LSL #0 nop @@ -129,7 +134,7 @@ ENTRY(v4t_late_abort) nop b .data_unknown @ 3: MUL? nop - mov r6, r6, lsr r9 @ 4: LSR #!0 + mov r6, r6, lsr r5 @ 4: LSR #!0 b .data_arm_apply_r6_and_rn mov r6, r6, lsr #32 @ 5: LSR #32 b .data_arm_apply_r6_and_rn @@ -137,7 +142,7 @@ ENTRY(v4t_late_abort) nop b .data_unknown @ 7: MUL? nop - mov r6, r6, asr r9 @ 8: ASR #!0 + mov r6, r6, asr r5 @ 8: ASR #!0 b .data_arm_apply_r6_and_rn mov r6, r6, asr #32 @ 9: ASR #32 b .data_arm_apply_r6_and_rn @@ -145,7 +150,7 @@ ENTRY(v4t_late_abort) nop b .data_unknown @ B: MUL? nop - mov r6, r6, ror r9 @ C: ROR #!0 + mov r6, r6, ror r5 @ C: ROR #!0 b .data_arm_apply_r6_and_rn mov r6, r6, rrx @ D: RRX b .data_arm_apply_r6_and_rn @@ -154,7 +159,7 @@ ENTRY(v4t_late_abort) b .data_unknown @ F: MUL? .data_thumb_abort: - ldrh r8, [r4] @ read instruction + ldrh r8, [r2] @ read instruction tst r8, #1 << 11 @ L = 1 -> write? orreq r1, r1, #1 << 8 @ yes and r7, r8, #15 << 12 @@ -167,10 +172,10 @@ ENTRY(v4t_late_abort) /* 3 */ b .data_unknown /* 4 */ b .data_unknown /* 5 */ b .data_thumb_reg -/* 6 */ b do_DataAbort -/* 7 */ b do_DataAbort -/* 8 */ b do_DataAbort -/* 9 */ b do_DataAbort +/* 6 */ mov pc, lr +/* 7 */ mov pc, lr +/* 8 */ mov pc, lr +/* 9 */ mov pc, lr /* A */ b .data_unknown /* B */ b .data_thumb_pushpop /* C */ b .data_thumb_ldmstm @@ -180,41 +185,41 @@ ENTRY(v4t_late_abort) .data_thumb_reg: tst r8, #1 << 9 - beq do_DataAbort + moveq pc, lr tst r8, #1 << 10 @ If 'S' (signed) bit is set movne r1, #0 @ it must be a load instr - b do_DataAbort + mov pc, lr .data_thumb_pushpop: tst r8, #1 << 10 beq .data_unknown and r6, r8, #0x55 @ hweight8(r8) + R bit - and r9, r8, #0xaa - add r6, r6, r9, lsr #1 - and r9, r6, #0xcc + and r2, r8, #0xaa + add r6, r6, r2, lsr #1 + and r2, r6, #0xcc and r6, r6, #0x33 - add r6, r6, r9, lsr #2 + add r6, r6, r2, lsr #2 movs r7, r8, lsr #9 @ C = r8 bit 8 (R bit) adc r6, r6, r6, lsr #4 @ high + low nibble + R bit and r6, r6, #15 @ number of regs to transfer - ldr r7, [r2, #13 << 2] + ldr r7, [sp, #13 << 2] tst r8, #1 << 11 addeq r7, r7, r6, lsl #2 @ increment SP if PUSH subne r7, r7, r6, lsl #2 @ decrement SP if POP - str r7, [r2, #13 << 2] - b do_DataAbort + str r7, [sp, #13 << 2] + mov pc, lr .data_thumb_ldmstm: and r6, r8, #0x55 @ hweight8(r8) - and r9, r8, #0xaa - add r6, r6, r9, lsr #1 - and r9, r6, #0xcc + and r2, r8, #0xaa + add r6, r6, r2, lsr #1 + and r2, r6, #0xcc and r6, r6, #0x33 - add r6, r6, r9, lsr #2 + add r6, r6, r2, lsr #2 add r6, r6, r6, lsr #4 - and r9, r8, #7 << 8 - ldr r7, [r2, r9, lsr #6] + and r5, r8, #7 << 8 + ldr r7, [sp, r5, lsr #6] and r6, r6, #15 @ number of regs to transfer sub r7, r7, r6, lsl #2 @ always decrement - str r7, [r2, r9, lsr #6] - b do_DataAbort + str r7, [sp, r5, lsr #6] + mov pc, lr diff --git a/trunk/arch/arm/mm/abort-macro.S b/trunk/arch/arm/mm/abort-macro.S index 52162d59407a..d7cb1bfa51a4 100644 --- a/trunk/arch/arm/mm/abort-macro.S +++ b/trunk/arch/arm/mm/abort-macro.S @@ -9,32 +9,34 @@ * */ - .macro do_thumb_abort, fsr, pc, psr, tmp - tst \psr, #PSR_T_BIT + .macro do_thumb_abort + tst r3, #PSR_T_BIT beq not_thumb - ldrh \tmp, [\pc] @ Read aborted Thumb instruction - and \tmp, \tmp, # 0xfe00 @ Mask opcode field - cmp \tmp, # 0x5600 @ Is it ldrsb? - orreq \tmp, \tmp, #1 << 11 @ Set L-bit if yes - tst \tmp, #1 << 11 @ L = 0 -> write - orreq \psr, \psr, #1 << 11 @ yes. - b do_DataAbort + ldrh r3, [r2] @ Read aborted Thumb instruction + and r3, r3, # 0xfe00 @ Mask opcode field + cmp r3, # 0x5600 @ Is it ldrsb? + orreq r3, r3, #1 << 11 @ Set L-bit if yes + tst r3, #1 << 11 @ L = 0 -> write + orreq r1, r1, #1 << 11 @ yes. + mov pc, lr not_thumb: .endm /* - * We check for the following instruction encoding for LDRD. + * We check for the following insturction encoding for LDRD. * - * [27:25] == 000 + * [27:25] == 0 * [7:4] == 1101 * [20] == 0 */ - .macro do_ldrd_abort, tmp, insn - tst \insn, #0x0e100000 @ [27:25,20] == 0 + .macro do_ldrd_abort + tst r3, #0x0e000000 @ [27:25] == 0 bne not_ldrd - and \tmp, \insn, #0x000000f0 @ [7:4] == 1101 - cmp \tmp, #0x000000d0 - beq do_DataAbort + and r2, r3, #0x000000f0 @ [7:4] == 1101 + cmp r2, #0x000000d0 + bne not_ldrd + tst r3, #1 << 20 @ [20] == 0 + moveq pc, lr not_ldrd: .endm diff --git a/trunk/arch/arm/mm/abort-nommu.S b/trunk/arch/arm/mm/abort-nommu.S index 119cb479c2ab..625e580945b5 100644 --- a/trunk/arch/arm/mm/abort-nommu.S +++ b/trunk/arch/arm/mm/abort-nommu.S @@ -3,11 +3,11 @@ /* * Function: nommu_early_abort * - * Params : r2 = pt_regs - * : r4 = aborted context pc - * : r5 = aborted context psr + * Params : r2 = address of aborted instruction + * : r3 = saved SPSR * - * Returns : r4 - r11, r13 preserved + * Returns : r0 = 0 (abort address) + * : r1 = 0 (FSR) * * Note: There is no FSR/FAR on !CPU_CP15_MMU cores. * Just fill zero into the registers. @@ -16,5 +16,5 @@ ENTRY(nommu_early_abort) mov r0, #0 @ clear r0, r1 (no FSR/FAR) mov r1, #0 - b do_DataAbort + mov pc, lr ENDPROC(nommu_early_abort) diff --git a/trunk/arch/arm/mm/alignment.c b/trunk/arch/arm/mm/alignment.c index be7c638b648b..724ba3bce72c 100644 --- a/trunk/arch/arm/mm/alignment.c +++ b/trunk/arch/arm/mm/alignment.c @@ -727,9 +727,6 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs) int isize = 4; int thumb2_32b = 0; - if (interrupts_enabled(regs)) - local_irq_enable(); - instrptr = instruction_pointer(regs); fs = get_fs(); diff --git a/trunk/arch/arm/mm/cache-fa.S b/trunk/arch/arm/mm/cache-fa.S index 072016371093..1fa6f71470de 100644 --- a/trunk/arch/arm/mm/cache-fa.S +++ b/trunk/arch/arm/mm/cache-fa.S @@ -242,5 +242,16 @@ ENDPROC(fa_dma_unmap_area) __INITDATA - @ define struct cpu_cache_fns (see and proc-macros.S) - define_cache_functions fa + .type fa_cache_fns, #object +ENTRY(fa_cache_fns) + .long fa_flush_icache_all + .long fa_flush_kern_cache_all + .long fa_flush_user_cache_all + .long fa_flush_user_cache_range + .long fa_coherent_kern_range + .long fa_coherent_user_range + .long fa_flush_kern_dcache_area + .long fa_dma_map_area + .long fa_dma_unmap_area + .long fa_dma_flush_range + .size fa_cache_fns, . - fa_cache_fns diff --git a/trunk/arch/arm/mm/cache-v3.S b/trunk/arch/arm/mm/cache-v3.S index c2301f226100..2e2bc406a18d 100644 --- a/trunk/arch/arm/mm/cache-v3.S +++ b/trunk/arch/arm/mm/cache-v3.S @@ -129,5 +129,16 @@ ENDPROC(v3_dma_map_area) __INITDATA - @ define struct cpu_cache_fns (see and proc-macros.S) - define_cache_functions v3 + .type v3_cache_fns, #object +ENTRY(v3_cache_fns) + .long v3_flush_icache_all + .long v3_flush_kern_cache_all + .long v3_flush_user_cache_all + .long v3_flush_user_cache_range + .long v3_coherent_kern_range + .long v3_coherent_user_range + .long v3_flush_kern_dcache_area + .long v3_dma_map_area + .long v3_dma_unmap_area + .long v3_dma_flush_range + .size v3_cache_fns, . - v3_cache_fns diff --git a/trunk/arch/arm/mm/cache-v4.S b/trunk/arch/arm/mm/cache-v4.S index fd9bb7addc8d..a8fefb523f19 100644 --- a/trunk/arch/arm/mm/cache-v4.S +++ b/trunk/arch/arm/mm/cache-v4.S @@ -141,5 +141,16 @@ ENDPROC(v4_dma_map_area) __INITDATA - @ define struct cpu_cache_fns (see and proc-macros.S) - define_cache_functions v4 + .type v4_cache_fns, #object +ENTRY(v4_cache_fns) + .long v4_flush_icache_all + .long v4_flush_kern_cache_all + .long v4_flush_user_cache_all + .long v4_flush_user_cache_range + .long v4_coherent_kern_range + .long v4_coherent_user_range + .long v4_flush_kern_dcache_area + .long v4_dma_map_area + .long v4_dma_unmap_area + .long v4_dma_flush_range + .size v4_cache_fns, . - v4_cache_fns diff --git a/trunk/arch/arm/mm/cache-v4wb.S b/trunk/arch/arm/mm/cache-v4wb.S index 4f2c14151ccb..f40c69656d8d 100644 --- a/trunk/arch/arm/mm/cache-v4wb.S +++ b/trunk/arch/arm/mm/cache-v4wb.S @@ -253,5 +253,16 @@ ENDPROC(v4wb_dma_unmap_area) __INITDATA - @ define struct cpu_cache_fns (see and proc-macros.S) - define_cache_functions v4wb + .type v4wb_cache_fns, #object +ENTRY(v4wb_cache_fns) + .long v4wb_flush_icache_all + .long v4wb_flush_kern_cache_all + .long v4wb_flush_user_cache_all + .long v4wb_flush_user_cache_range + .long v4wb_coherent_kern_range + .long v4wb_coherent_user_range + .long v4wb_flush_kern_dcache_area + .long v4wb_dma_map_area + .long v4wb_dma_unmap_area + .long v4wb_dma_flush_range + .size v4wb_cache_fns, . - v4wb_cache_fns diff --git a/trunk/arch/arm/mm/cache-v4wt.S b/trunk/arch/arm/mm/cache-v4wt.S index 4d7b467631ce..a7b276dbda11 100644 --- a/trunk/arch/arm/mm/cache-v4wt.S +++ b/trunk/arch/arm/mm/cache-v4wt.S @@ -197,5 +197,16 @@ ENDPROC(v4wt_dma_map_area) __INITDATA - @ define struct cpu_cache_fns (see and proc-macros.S) - define_cache_functions v4wt + .type v4wt_cache_fns, #object +ENTRY(v4wt_cache_fns) + .long v4wt_flush_icache_all + .long v4wt_flush_kern_cache_all + .long v4wt_flush_user_cache_all + .long v4wt_flush_user_cache_range + .long v4wt_coherent_kern_range + .long v4wt_coherent_user_range + .long v4wt_flush_kern_dcache_area + .long v4wt_dma_map_area + .long v4wt_dma_unmap_area + .long v4wt_dma_flush_range + .size v4wt_cache_fns, . - v4wt_cache_fns diff --git a/trunk/arch/arm/mm/cache-v6.S b/trunk/arch/arm/mm/cache-v6.S index 74c2e5a33a4d..73b4a8b66a57 100644 --- a/trunk/arch/arm/mm/cache-v6.S +++ b/trunk/arch/arm/mm/cache-v6.S @@ -330,5 +330,16 @@ ENDPROC(v6_dma_unmap_area) __INITDATA - @ define struct cpu_cache_fns (see and proc-macros.S) - define_cache_functions v6 + .type v6_cache_fns, #object +ENTRY(v6_cache_fns) + .long v6_flush_icache_all + .long v6_flush_kern_cache_all + .long v6_flush_user_cache_all + .long v6_flush_user_cache_range + .long v6_coherent_kern_range + .long v6_coherent_user_range + .long v6_flush_kern_dcache_area + .long v6_dma_map_area + .long v6_dma_unmap_area + .long v6_dma_flush_range + .size v6_cache_fns, . - v6_cache_fns diff --git a/trunk/arch/arm/mm/cache-v7.S b/trunk/arch/arm/mm/cache-v7.S index 3b24bfa3b828..d32f02b61866 100644 --- a/trunk/arch/arm/mm/cache-v7.S +++ b/trunk/arch/arm/mm/cache-v7.S @@ -325,5 +325,16 @@ ENDPROC(v7_dma_unmap_area) __INITDATA - @ define struct cpu_cache_fns (see and proc-macros.S) - define_cache_functions v7 + .type v7_cache_fns, #object +ENTRY(v7_cache_fns) + .long v7_flush_icache_all + .long v7_flush_kern_cache_all + .long v7_flush_user_cache_all + .long v7_flush_user_cache_range + .long v7_coherent_kern_range + .long v7_coherent_user_range + .long v7_flush_kern_dcache_area + .long v7_dma_map_area + .long v7_dma_unmap_area + .long v7_dma_flush_range + .size v7_cache_fns, . - v7_cache_fns diff --git a/trunk/arch/arm/mm/copypage-v6.c b/trunk/arch/arm/mm/copypage-v6.c index 63cca0097130..bdba6c65c901 100644 --- a/trunk/arch/arm/mm/copypage-v6.c +++ b/trunk/arch/arm/mm/copypage-v6.c @@ -41,6 +41,7 @@ static void v6_copy_user_highpage_nonaliasing(struct page *to, kfrom = kmap_atomic(from, KM_USER0); kto = kmap_atomic(to, KM_USER1); copy_page(kto, kfrom); + __cpuc_flush_dcache_area(kto, PAGE_SIZE); kunmap_atomic(kto, KM_USER1); kunmap_atomic(kfrom, KM_USER0); } diff --git a/trunk/arch/arm/mm/dma-mapping.c b/trunk/arch/arm/mm/dma-mapping.c index 0a0a1e7c20d2..82a093cee09a 100644 --- a/trunk/arch/arm/mm/dma-mapping.c +++ b/trunk/arch/arm/mm/dma-mapping.c @@ -25,11 +25,9 @@ #include #include -#include "mm.h" - static u64 get_coherent_dma_mask(struct device *dev) { - u64 mask = (u64)arm_dma_limit; + u64 mask = ISA_DMA_THRESHOLD; if (dev) { mask = dev->coherent_dma_mask; @@ -43,10 +41,10 @@ static u64 get_coherent_dma_mask(struct device *dev) return 0; } - if ((~mask) & (u64)arm_dma_limit) { + if ((~mask) & ISA_DMA_THRESHOLD) { dev_warn(dev, "coherent DMA mask %#llx is smaller " "than system GFP_DMA mask %#llx\n", - mask, (u64)arm_dma_limit); + mask, (unsigned long long)ISA_DMA_THRESHOLD); return 0; } } @@ -659,33 +657,6 @@ void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, } EXPORT_SYMBOL(dma_sync_sg_for_device); -/* - * Return whether the given device DMA address mask can be supported - * properly. For example, if your device can only drive the low 24-bits - * during bus mastering, then you would pass 0x00ffffff as the mask - * to this function. - */ -int dma_supported(struct device *dev, u64 mask) -{ - if (mask < (u64)arm_dma_limit) - return 0; - return 1; -} -EXPORT_SYMBOL(dma_supported); - -int dma_set_mask(struct device *dev, u64 dma_mask) -{ - if (!dev->dma_mask || !dma_supported(dev, dma_mask)) - return -EIO; - -#ifndef CONFIG_DMABOUNCE - *dev->dma_mask = dma_mask; -#endif - - return 0; -} -EXPORT_SYMBOL(dma_set_mask); - #define PREALLOC_DMA_DEBUG_ENTRIES 4096 static int __init dma_debug_do_init(void) diff --git a/trunk/arch/arm/mm/fault.c b/trunk/arch/arm/mm/fault.c index 3b5ea68acbb8..bc0e1d88fd3b 100644 --- a/trunk/arch/arm/mm/fault.c +++ b/trunk/arch/arm/mm/fault.c @@ -94,7 +94,7 @@ void show_pte(struct mm_struct *mm, unsigned long addr) pud = pud_offset(pgd, addr); if (PTRS_PER_PUD != 1) - printk(", *pud=%08llx", (long long)pud_val(*pud)); + printk(", *pud=%08lx", pud_val(*pud)); if (pud_none(*pud)) break; @@ -285,10 +285,6 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) tsk = current; mm = tsk->mm; - /* Enable interrupts if they were enabled in the parent context. */ - if (interrupts_enabled(regs)) - local_irq_enable(); - /* * If we're in an interrupt or have no user * context, we must not take the fault.. @@ -322,11 +318,11 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) fault = __do_page_fault(mm, addr, fsr, tsk); up_read(&mm->mmap_sem); - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, addr); + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, addr); if (fault & VM_FAULT_MAJOR) - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, regs, addr); + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0, regs, addr); else if (fault & VM_FAULT_MINOR) - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, regs, addr); + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0, regs, addr); /* * Handle the "normal" case first - VM_FAULT_MAJOR / VM_FAULT_MINOR diff --git a/trunk/arch/arm/mm/init.c b/trunk/arch/arm/mm/init.c index 2fee782077c1..c19571c40a21 100644 --- a/trunk/arch/arm/mm/init.c +++ b/trunk/arch/arm/mm/init.c @@ -212,18 +212,6 @@ static void __init arm_bootmem_init(unsigned long start_pfn, } #ifdef CONFIG_ZONE_DMA - -unsigned long arm_dma_zone_size __read_mostly; -EXPORT_SYMBOL(arm_dma_zone_size); - -/* - * The DMA mask corresponding to the maximum bus address allocatable - * using GFP_DMA. The default here places no restriction on DMA - * allocations. This must be the smallest DMA mask in the system, - * so a successful GFP_DMA allocation will always satisfy this. - */ -u32 arm_dma_limit; - static void __init arm_adjust_dma_zone(unsigned long *size, unsigned long *hole, unsigned long dma_size) { @@ -279,17 +267,17 @@ static void __init arm_bootmem_free(unsigned long min, unsigned long max_low, #endif } -#ifdef CONFIG_ZONE_DMA +#ifdef ARM_DMA_ZONE_SIZE +#ifndef CONFIG_ZONE_DMA +#error ARM_DMA_ZONE_SIZE set but no DMA zone to limit allocations +#endif + /* * Adjust the sizes according to any special requirements for * this machine type. */ - if (arm_dma_zone_size) { - arm_adjust_dma_zone(zone_size, zhole_size, - arm_dma_zone_size >> PAGE_SHIFT); - arm_dma_limit = PHYS_OFFSET + arm_dma_zone_size - 1; - } else - arm_dma_limit = 0xffffffff; + arm_adjust_dma_zone(zone_size, zhole_size, + ARM_DMA_ZONE_SIZE >> PAGE_SHIFT); #endif free_area_init_node(0, zone_size, min, zhole_size); @@ -434,17 +422,6 @@ static inline int free_area(unsigned long pfn, unsigned long end, char *s) return pages; } -/* - * Poison init memory with an undefined instruction (ARM) or a branch to an - * undefined instruction (Thumb). - */ -static inline void poison_init_mem(void *s, size_t count) -{ - u32 *p = (u32 *)s; - while ((count = count - 4)) - *p++ = 0xe7fddef0; -} - static inline void free_memmap(unsigned long start_pfn, unsigned long end_pfn) { @@ -662,8 +639,8 @@ void __init mem_init(void) " pkmap : 0x%08lx - 0x%08lx (%4ld MB)\n" #endif " modules : 0x%08lx - 0x%08lx (%4ld MB)\n" - " .text : 0x%p" " - 0x%p" " (%4d kB)\n" " .init : 0x%p" " - 0x%p" " (%4d kB)\n" + " .text : 0x%p" " - 0x%p" " (%4d kB)\n" " .data : 0x%p" " - 0x%p" " (%4d kB)\n" " .bss : 0x%p" " - 0x%p" " (%4d kB)\n", @@ -685,8 +662,8 @@ void __init mem_init(void) #endif MLM(MODULES_VADDR, MODULES_END), - MLK_ROUNDUP(_text, _etext), MLK_ROUNDUP(__init_begin, __init_end), + MLK_ROUNDUP(_text, _etext), MLK_ROUNDUP(_sdata, _edata), MLK_ROUNDUP(__bss_start, __bss_stop)); @@ -727,13 +704,11 @@ void free_initmem(void) #ifdef CONFIG_HAVE_TCM extern char __tcm_start, __tcm_end; - poison_init_mem(&__tcm_start, &__tcm_end - &__tcm_start); totalram_pages += free_area(__phys_to_pfn(__pa(&__tcm_start)), __phys_to_pfn(__pa(&__tcm_end)), "TCM link"); #endif - poison_init_mem(__init_begin, __init_end - __init_begin); if (!machine_is_integrator() && !machine_is_cintegrator()) totalram_pages += free_area(__phys_to_pfn(__pa(__init_begin)), __phys_to_pfn(__pa(__init_end)), @@ -746,12 +721,10 @@ static int keep_initrd; void free_initrd_mem(unsigned long start, unsigned long end) { - if (!keep_initrd) { - poison_init_mem((void *)start, PAGE_ALIGN(end) - start); + if (!keep_initrd) totalram_pages += free_area(__phys_to_pfn(__pa(start)), __phys_to_pfn(__pa(end)), "initrd"); - } } static int __init keepinitrd_setup(char *__unused) diff --git a/trunk/arch/arm/mm/mm.h b/trunk/arch/arm/mm/mm.h index 010566799c80..5b3d7d543659 100644 --- a/trunk/arch/arm/mm/mm.h +++ b/trunk/arch/arm/mm/mm.h @@ -23,11 +23,5 @@ extern void __flush_dcache_page(struct address_space *mapping, struct page *page #endif -#ifdef CONFIG_ZONE_DMA -extern u32 arm_dma_limit; -#else -#define arm_dma_limit ((u32)~0) -#endif - void __init bootmem_init(void); void arm_mm_memblock_reserve(void); diff --git a/trunk/arch/arm/mm/pabort-legacy.S b/trunk/arch/arm/mm/pabort-legacy.S index 8bbff025269a..87970eba88ea 100644 --- a/trunk/arch/arm/mm/pabort-legacy.S +++ b/trunk/arch/arm/mm/pabort-legacy.S @@ -4,18 +4,16 @@ /* * Function: legacy_pabort * - * Params : r2 = pt_regs - * : r4 = address of aborted instruction - * : r5 = psr for parent context + * Params : r0 = address of aborted instruction * - * Returns : r4 - r11, r13 preserved + * Returns : r0 = address of abort + * : r1 = Simulated IFSR with section translation fault status * * Purpose : obtain information about current prefetch abort. */ .align 5 ENTRY(legacy_pabort) - mov r0, r4 mov r1, #5 - b do_PrefetchAbort + mov pc, lr ENDPROC(legacy_pabort) diff --git a/trunk/arch/arm/mm/pabort-v6.S b/trunk/arch/arm/mm/pabort-v6.S index 9627646ce783..06e3d1ef2115 100644 --- a/trunk/arch/arm/mm/pabort-v6.S +++ b/trunk/arch/arm/mm/pabort-v6.S @@ -4,18 +4,16 @@ /* * Function: v6_pabort * - * Params : r2 = pt_regs - * : r4 = address of aborted instruction - * : r5 = psr for parent context + * Params : r0 = address of aborted instruction * - * Returns : r4 - r11, r13 preserved + * Returns : r0 = address of abort + * : r1 = IFSR * * Purpose : obtain information about current prefetch abort. */ .align 5 ENTRY(v6_pabort) - mov r0, r4 mrc p15, 0, r1, c5, c0, 1 @ get IFSR - b do_PrefetchAbort + mov pc, lr ENDPROC(v6_pabort) diff --git a/trunk/arch/arm/mm/pabort-v7.S b/trunk/arch/arm/mm/pabort-v7.S index 875761f44f3b..a8b3b300a18d 100644 --- a/trunk/arch/arm/mm/pabort-v7.S +++ b/trunk/arch/arm/mm/pabort-v7.S @@ -2,13 +2,12 @@ #include /* - * Function: v7_pabort + * Function: v6_pabort * - * Params : r2 = pt_regs - * : r4 = address of aborted instruction - * : r5 = psr for parent context + * Params : r0 = address of aborted instruction * - * Returns : r4 - r11, r13 preserved + * Returns : r0 = address of abort + * : r1 = IFSR * * Purpose : obtain information about current prefetch abort. */ @@ -17,5 +16,5 @@ ENTRY(v7_pabort) mrc p15, 0, r0, c6, c0, 2 @ get IFAR mrc p15, 0, r1, c5, c0, 1 @ get IFSR - b do_PrefetchAbort + mov pc, lr ENDPROC(v7_pabort) diff --git a/trunk/arch/arm/mm/proc-arm1020.S b/trunk/arch/arm/mm/proc-arm1020.S index 67469665d47a..6c4e7fd6c8af 100644 --- a/trunk/arch/arm/mm/proc-arm1020.S +++ b/trunk/arch/arm/mm/proc-arm1020.S @@ -364,8 +364,17 @@ ENTRY(arm1020_dma_unmap_area) mov pc, lr ENDPROC(arm1020_dma_unmap_area) - @ define struct cpu_cache_fns (see and proc-macros.S) - define_cache_functions arm1020 +ENTRY(arm1020_cache_fns) + .long arm1020_flush_icache_all + .long arm1020_flush_kern_cache_all + .long arm1020_flush_user_cache_all + .long arm1020_flush_user_cache_range + .long arm1020_coherent_kern_range + .long arm1020_coherent_user_range + .long arm1020_flush_kern_dcache_area + .long arm1020_dma_map_area + .long arm1020_dma_unmap_area + .long arm1020_dma_flush_range .align 5 ENTRY(cpu_arm1020_dcache_clean_area) @@ -468,14 +477,38 @@ arm1020_crval: crval clear=0x0000593f, mmuset=0x00003935, ucset=0x00001930 __INITDATA - @ define struct processor (see and proc-macros.S) - define_processor_functions arm1020, dabort=v4t_early_abort, pabort=legacy_pabort +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + .type arm1020_processor_functions, #object +arm1020_processor_functions: + .word v4t_early_abort + .word legacy_pabort + .word cpu_arm1020_proc_init + .word cpu_arm1020_proc_fin + .word cpu_arm1020_reset + .word cpu_arm1020_do_idle + .word cpu_arm1020_dcache_clean_area + .word cpu_arm1020_switch_mm + .word cpu_arm1020_set_pte_ext + .word 0 + .word 0 + .word 0 + .size arm1020_processor_functions, . - arm1020_processor_functions .section ".rodata" - string cpu_arch_name, "armv5t" - string cpu_elf_name, "v5" + .type cpu_arch_name, #object +cpu_arch_name: + .asciz "armv5t" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: + .asciz "v5" + .size cpu_elf_name, . - cpu_elf_name .type cpu_arm1020_name, #object cpu_arm1020_name: diff --git a/trunk/arch/arm/mm/proc-arm1020e.S b/trunk/arch/arm/mm/proc-arm1020e.S index 4251421c0ed5..4ce947c19623 100644 --- a/trunk/arch/arm/mm/proc-arm1020e.S +++ b/trunk/arch/arm/mm/proc-arm1020e.S @@ -350,8 +350,17 @@ ENTRY(arm1020e_dma_unmap_area) mov pc, lr ENDPROC(arm1020e_dma_unmap_area) - @ define struct cpu_cache_fns (see and proc-macros.S) - define_cache_functions arm1020e +ENTRY(arm1020e_cache_fns) + .long arm1020e_flush_icache_all + .long arm1020e_flush_kern_cache_all + .long arm1020e_flush_user_cache_all + .long arm1020e_flush_user_cache_range + .long arm1020e_coherent_kern_range + .long arm1020e_coherent_user_range + .long arm1020e_flush_kern_dcache_area + .long arm1020e_dma_map_area + .long arm1020e_dma_unmap_area + .long arm1020e_dma_flush_range .align 5 ENTRY(cpu_arm1020e_dcache_clean_area) @@ -449,14 +458,43 @@ arm1020e_crval: crval clear=0x00007f3f, mmuset=0x00003935, ucset=0x00001930 __INITDATA - @ define struct processor (see and proc-macros.S) - define_processor_functions arm1020e, dabort=v4t_early_abort, pabort=legacy_pabort + +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + .type arm1020e_processor_functions, #object +arm1020e_processor_functions: + .word v4t_early_abort + .word legacy_pabort + .word cpu_arm1020e_proc_init + .word cpu_arm1020e_proc_fin + .word cpu_arm1020e_reset + .word cpu_arm1020e_do_idle + .word cpu_arm1020e_dcache_clean_area + .word cpu_arm1020e_switch_mm + .word cpu_arm1020e_set_pte_ext + .word 0 + .word 0 + .word 0 + .size arm1020e_processor_functions, . - arm1020e_processor_functions .section ".rodata" - string cpu_arch_name, "armv5te" - string cpu_elf_name, "v5" - string cpu_arm1020e_name, "ARM1020E" + .type cpu_arch_name, #object +cpu_arch_name: + .asciz "armv5te" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: + .asciz "v5" + .size cpu_elf_name, . - cpu_elf_name + + .type cpu_arm1020e_name, #object +cpu_arm1020e_name: + .asciz "ARM1020E" + .size cpu_arm1020e_name, . - cpu_arm1020e_name .align diff --git a/trunk/arch/arm/mm/proc-arm1022.S b/trunk/arch/arm/mm/proc-arm1022.S index d283cf3d06e3..c8884c5413a2 100644 --- a/trunk/arch/arm/mm/proc-arm1022.S +++ b/trunk/arch/arm/mm/proc-arm1022.S @@ -339,8 +339,17 @@ ENTRY(arm1022_dma_unmap_area) mov pc, lr ENDPROC(arm1022_dma_unmap_area) - @ define struct cpu_cache_fns (see and proc-macros.S) - define_cache_functions arm1022 +ENTRY(arm1022_cache_fns) + .long arm1022_flush_icache_all + .long arm1022_flush_kern_cache_all + .long arm1022_flush_user_cache_all + .long arm1022_flush_user_cache_range + .long arm1022_coherent_kern_range + .long arm1022_coherent_user_range + .long arm1022_flush_kern_dcache_area + .long arm1022_dma_map_area + .long arm1022_dma_unmap_area + .long arm1022_dma_flush_range .align 5 ENTRY(cpu_arm1022_dcache_clean_area) @@ -432,14 +441,43 @@ arm1022_crval: crval clear=0x00007f3f, mmuset=0x00003935, ucset=0x00001930 __INITDATA - @ define struct processor (see and proc-macros.S) - define_processor_functions arm1022, dabort=v4t_early_abort, pabort=legacy_pabort + +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + .type arm1022_processor_functions, #object +arm1022_processor_functions: + .word v4t_early_abort + .word legacy_pabort + .word cpu_arm1022_proc_init + .word cpu_arm1022_proc_fin + .word cpu_arm1022_reset + .word cpu_arm1022_do_idle + .word cpu_arm1022_dcache_clean_area + .word cpu_arm1022_switch_mm + .word cpu_arm1022_set_pte_ext + .word 0 + .word 0 + .word 0 + .size arm1022_processor_functions, . - arm1022_processor_functions .section ".rodata" - string cpu_arch_name, "armv5te" - string cpu_elf_name, "v5" - string cpu_arm1022_name, "ARM1022" + .type cpu_arch_name, #object +cpu_arch_name: + .asciz "armv5te" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: + .asciz "v5" + .size cpu_elf_name, . - cpu_elf_name + + .type cpu_arm1022_name, #object +cpu_arm1022_name: + .asciz "ARM1022" + .size cpu_arm1022_name, . - cpu_arm1022_name .align diff --git a/trunk/arch/arm/mm/proc-arm1026.S b/trunk/arch/arm/mm/proc-arm1026.S index 678a1ceafed2..413684660aad 100644 --- a/trunk/arch/arm/mm/proc-arm1026.S +++ b/trunk/arch/arm/mm/proc-arm1026.S @@ -333,8 +333,17 @@ ENTRY(arm1026_dma_unmap_area) mov pc, lr ENDPROC(arm1026_dma_unmap_area) - @ define struct cpu_cache_fns (see and proc-macros.S) - define_cache_functions arm1026 +ENTRY(arm1026_cache_fns) + .long arm1026_flush_icache_all + .long arm1026_flush_kern_cache_all + .long arm1026_flush_user_cache_all + .long arm1026_flush_user_cache_range + .long arm1026_coherent_kern_range + .long arm1026_coherent_user_range + .long arm1026_flush_kern_dcache_area + .long arm1026_dma_map_area + .long arm1026_dma_unmap_area + .long arm1026_dma_flush_range .align 5 ENTRY(cpu_arm1026_dcache_clean_area) @@ -427,15 +436,45 @@ arm1026_crval: crval clear=0x00007f3f, mmuset=0x00003935, ucset=0x00001934 __INITDATA - @ define struct processor (see and proc-macros.S) - define_processor_functions arm1026, dabort=v5t_early_abort, pabort=legacy_pabort + +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + .type arm1026_processor_functions, #object +arm1026_processor_functions: + .word v5t_early_abort + .word legacy_pabort + .word cpu_arm1026_proc_init + .word cpu_arm1026_proc_fin + .word cpu_arm1026_reset + .word cpu_arm1026_do_idle + .word cpu_arm1026_dcache_clean_area + .word cpu_arm1026_switch_mm + .word cpu_arm1026_set_pte_ext + .word 0 + .word 0 + .word 0 + .size arm1026_processor_functions, . - arm1026_processor_functions .section .rodata - string cpu_arch_name, "armv5tej" - string cpu_elf_name, "v5" + .type cpu_arch_name, #object +cpu_arch_name: + .asciz "armv5tej" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: + .asciz "v5" + .size cpu_elf_name, . - cpu_elf_name .align - string cpu_arm1026_name, "ARM1026EJ-S" + + .type cpu_arm1026_name, #object +cpu_arm1026_name: + .asciz "ARM1026EJ-S" + .size cpu_arm1026_name, . - cpu_arm1026_name + .align .section ".proc.info.init", #alloc, #execinstr diff --git a/trunk/arch/arm/mm/proc-arm6_7.S b/trunk/arch/arm/mm/proc-arm6_7.S index e5b974cddac3..5f79dc4ce3fb 100644 --- a/trunk/arch/arm/mm/proc-arm6_7.S +++ b/trunk/arch/arm/mm/proc-arm6_7.S @@ -29,19 +29,19 @@ ENTRY(cpu_arm7_dcache_clean_area) /* * Function: arm6_7_data_abort () * - * Params : r2 = pt_regs - * : r4 = aborted context pc - * : r5 = aborted context psr + * Params : r2 = address of aborted instruction + * : sp = pointer to registers * * Purpose : obtain information about current aborted instruction * - * Returns : r4-r5, r10-r11, r13 preserved + * Returns : r0 = address of abort + * : r1 = FSR */ ENTRY(cpu_arm7_data_abort) mrc p15, 0, r1, c5, c0, 0 @ get FSR mrc p15, 0, r0, c6, c0, 0 @ get FAR - ldr r8, [r4] @ read arm instruction + ldr r8, [r2] @ read arm instruction tst r8, #1 << 20 @ L = 0 -> write? orreq r1, r1, #1 << 11 @ yes. and r7, r8, #15 << 24 @@ -49,7 +49,7 @@ ENTRY(cpu_arm7_data_abort) nop /* 0 */ b .data_unknown -/* 1 */ b do_DataAbort @ swp +/* 1 */ mov pc, lr @ swp /* 2 */ b .data_unknown /* 3 */ b .data_unknown /* 4 */ b .data_arm_lateldrpostconst @ ldr rd, [rn], #m @@ -60,85 +60,87 @@ ENTRY(cpu_arm7_data_abort) /* 9 */ b .data_arm_ldmstm @ ldm*b rn, /* a */ b .data_unknown /* b */ b .data_unknown -/* c */ b do_DataAbort @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m -/* d */ b do_DataAbort @ ldc rd, [rn, #m] +/* c */ mov pc, lr @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m +/* d */ mov pc, lr @ ldc rd, [rn, #m] /* e */ b .data_unknown /* f */ .data_unknown: @ Part of jumptable - mov r0, r4 + mov r0, r2 mov r1, r8 - b baddataabort + mov r2, sp + bl baddataabort + b ret_from_exception ENTRY(cpu_arm6_data_abort) mrc p15, 0, r1, c5, c0, 0 @ get FSR mrc p15, 0, r0, c6, c0, 0 @ get FAR - ldr r8, [r4] @ read arm instruction + ldr r8, [r2] @ read arm instruction tst r8, #1 << 20 @ L = 0 -> write? orreq r1, r1, #1 << 11 @ yes. and r7, r8, #14 << 24 teq r7, #8 << 24 @ was it ldm/stm - bne do_DataAbort + movne pc, lr .data_arm_ldmstm: tst r8, #1 << 21 @ check writeback bit - beq do_DataAbort @ no writeback -> no fixup + moveq pc, lr @ no writeback -> no fixup mov r7, #0x11 orr r7, r7, #0x1100 and r6, r8, r7 - and r9, r8, r7, lsl #1 - add r6, r6, r9, lsr #1 - and r9, r8, r7, lsl #2 - add r6, r6, r9, lsr #2 - and r9, r8, r7, lsl #3 - add r6, r6, r9, lsr #3 + and r2, r8, r7, lsl #1 + add r6, r6, r2, lsr #1 + and r2, r8, r7, lsl #2 + add r6, r6, r2, lsr #2 + and r2, r8, r7, lsl #3 + add r6, r6, r2, lsr #3 add r6, r6, r6, lsr #8 add r6, r6, r6, lsr #4 and r6, r6, #15 @ r6 = no. of registers to transfer. - and r9, r8, #15 << 16 @ Extract 'n' from instruction - ldr r7, [r2, r9, lsr #14] @ Get register 'Rn' + and r5, r8, #15 << 16 @ Extract 'n' from instruction + ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' tst r8, #1 << 23 @ Check U bit subne r7, r7, r6, lsl #2 @ Undo increment addeq r7, r7, r6, lsl #2 @ Undo decrement - str r7, [r2, r9, lsr #14] @ Put register 'Rn' - b do_DataAbort + str r7, [sp, r5, lsr #14] @ Put register 'Rn' + mov pc, lr .data_arm_apply_r6_and_rn: - and r9, r8, #15 << 16 @ Extract 'n' from instruction - ldr r7, [r2, r9, lsr #14] @ Get register 'Rn' + and r5, r8, #15 << 16 @ Extract 'n' from instruction + ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' tst r8, #1 << 23 @ Check U bit subne r7, r7, r6 @ Undo incrmenet addeq r7, r7, r6 @ Undo decrement - str r7, [r2, r9, lsr #14] @ Put register 'Rn' - b do_DataAbort + str r7, [sp, r5, lsr #14] @ Put register 'Rn' + mov pc, lr .data_arm_lateldrpreconst: tst r8, #1 << 21 @ check writeback bit - beq do_DataAbort @ no writeback -> no fixup + moveq pc, lr @ no writeback -> no fixup .data_arm_lateldrpostconst: - movs r6, r8, lsl #20 @ Get offset - beq do_DataAbort @ zero -> no fixup - and r9, r8, #15 << 16 @ Extract 'n' from instruction - ldr r7, [r2, r9, lsr #14] @ Get register 'Rn' + movs r2, r8, lsl #20 @ Get offset + moveq pc, lr @ zero -> no fixup + and r5, r8, #15 << 16 @ Extract 'n' from instruction + ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' tst r8, #1 << 23 @ Check U bit - subne r7, r7, r6, lsr #20 @ Undo increment - addeq r7, r7, r6, lsr #20 @ Undo decrement - str r7, [r2, r9, lsr #14] @ Put register 'Rn' - b do_DataAbort + subne r7, r7, r2, lsr #20 @ Undo increment + addeq r7, r7, r2, lsr #20 @ Undo decrement + str r7, [sp, r5, lsr #14] @ Put register 'Rn' + mov pc, lr .data_arm_lateldrprereg: tst r8, #1 << 21 @ check writeback bit - beq do_DataAbort @ no writeback -> no fixup + moveq pc, lr @ no writeback -> no fixup .data_arm_lateldrpostreg: and r7, r8, #15 @ Extract 'm' from instruction - ldr r6, [r2, r7, lsl #2] @ Get register 'Rm' - mov r9, r8, lsr #7 @ get shift count - ands r9, r9, #31 + ldr r6, [sp, r7, lsl #2] @ Get register 'Rm' + mov r5, r8, lsr #7 @ get shift count + ands r5, r5, #31 and r7, r8, #0x70 @ get shift type orreq r7, r7, #8 @ shift count = 0 add pc, pc, r7 nop - mov r6, r6, lsl r9 @ 0: LSL #!0 + mov r6, r6, lsl r5 @ 0: LSL #!0 b .data_arm_apply_r6_and_rn b .data_arm_apply_r6_and_rn @ 1: LSL #0 nop @@ -146,7 +148,7 @@ ENTRY(cpu_arm6_data_abort) nop b .data_unknown @ 3: MUL? nop - mov r6, r6, lsr r9 @ 4: LSR #!0 + mov r6, r6, lsr r5 @ 4: LSR #!0 b .data_arm_apply_r6_and_rn mov r6, r6, lsr #32 @ 5: LSR #32 b .data_arm_apply_r6_and_rn @@ -154,7 +156,7 @@ ENTRY(cpu_arm6_data_abort) nop b .data_unknown @ 7: MUL? nop - mov r6, r6, asr r9 @ 8: ASR #!0 + mov r6, r6, asr r5 @ 8: ASR #!0 b .data_arm_apply_r6_and_rn mov r6, r6, asr #32 @ 9: ASR #32 b .data_arm_apply_r6_and_rn @@ -162,7 +164,7 @@ ENTRY(cpu_arm6_data_abort) nop b .data_unknown @ B: MUL? nop - mov r6, r6, ror r9 @ C: ROR #!0 + mov r6, r6, ror r5 @ C: ROR #!0 b .data_arm_apply_r6_and_rn mov r6, r6, rrx @ D: RRX b .data_arm_apply_r6_and_rn @@ -267,57 +269,159 @@ __arm7_setup: mov r0, #0 __INITDATA - @ define struct processor (see and proc-macros.S) - define_processor_functions arm6, dabort=cpu_arm6_data_abort, pabort=legacy_pabort - define_processor_functions arm7, dabort=cpu_arm7_data_abort, pabort=legacy_pabort +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + .type arm6_processor_functions, #object +ENTRY(arm6_processor_functions) + .word cpu_arm6_data_abort + .word legacy_pabort + .word cpu_arm6_proc_init + .word cpu_arm6_proc_fin + .word cpu_arm6_reset + .word cpu_arm6_do_idle + .word cpu_arm6_dcache_clean_area + .word cpu_arm6_switch_mm + .word cpu_arm6_set_pte_ext + .word 0 + .word 0 + .word 0 + .size arm6_processor_functions, . - arm6_processor_functions + +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + .type arm7_processor_functions, #object +ENTRY(arm7_processor_functions) + .word cpu_arm7_data_abort + .word legacy_pabort + .word cpu_arm7_proc_init + .word cpu_arm7_proc_fin + .word cpu_arm7_reset + .word cpu_arm7_do_idle + .word cpu_arm7_dcache_clean_area + .word cpu_arm7_switch_mm + .word cpu_arm7_set_pte_ext + .word 0 + .word 0 + .word 0 + .size arm7_processor_functions, . - arm7_processor_functions .section ".rodata" - string cpu_arch_name, "armv3" - string cpu_elf_name, "v3" - string cpu_arm6_name, "ARM6" - string cpu_arm610_name, "ARM610" - string cpu_arm7_name, "ARM7" - string cpu_arm710_name, "ARM710" + .type cpu_arch_name, #object +cpu_arch_name: .asciz "armv3" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: .asciz "v3" + .size cpu_elf_name, . - cpu_elf_name + + .type cpu_arm6_name, #object +cpu_arm6_name: .asciz "ARM6" + .size cpu_arm6_name, . - cpu_arm6_name + + .type cpu_arm610_name, #object +cpu_arm610_name: + .asciz "ARM610" + .size cpu_arm610_name, . - cpu_arm610_name + + .type cpu_arm7_name, #object +cpu_arm7_name: .asciz "ARM7" + .size cpu_arm7_name, . - cpu_arm7_name + + .type cpu_arm710_name, #object +cpu_arm710_name: + .asciz "ARM710" + .size cpu_arm710_name, . - cpu_arm710_name .align .section ".proc.info.init", #alloc, #execinstr -.macro arm67_proc_info name:req, cpu_val:req, cpu_mask:req, cpu_name:req, \ - cpu_mm_mmu_flags:req, cpu_flush:req, cpu_proc_funcs:req - .type __\name\()_proc_info, #object -__\name\()_proc_info: - .long \cpu_val - .long \cpu_mask - .long \cpu_mm_mmu_flags + .type __arm6_proc_info, #object +__arm6_proc_info: + .long 0x41560600 + .long 0xfffffff0 + .long 0x00000c1e + .long PMD_TYPE_SECT | \ + PMD_BIT4 | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + b __arm6_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP | HWCAP_26BIT + .long cpu_arm6_name + .long arm6_processor_functions + .long v3_tlb_fns + .long v3_user_fns + .long v3_cache_fns + .size __arm6_proc_info, . - __arm6_proc_info + + .type __arm610_proc_info, #object +__arm610_proc_info: + .long 0x41560610 + .long 0xfffffff0 + .long 0x00000c1e .long PMD_TYPE_SECT | \ PMD_BIT4 | \ PMD_SECT_AP_WRITE | \ PMD_SECT_AP_READ - b \cpu_flush + b __arm6_setup .long cpu_arch_name .long cpu_elf_name .long HWCAP_SWP | HWCAP_26BIT - .long \cpu_name - .long \cpu_proc_funcs + .long cpu_arm610_name + .long arm6_processor_functions .long v3_tlb_fns .long v3_user_fns .long v3_cache_fns - .size __\name\()_proc_info, . - __\name\()_proc_info -.endm - - arm67_proc_info arm6, 0x41560600, 0xfffffff0, cpu_arm6_name, \ - 0x00000c1e, __arm6_setup, arm6_processor_functions - arm67_proc_info arm610, 0x41560610, 0xfffffff0, cpu_arm610_name, \ - 0x00000c1e, __arm6_setup, arm6_processor_functions - arm67_proc_info arm7, 0x41007000, 0xffffff00, cpu_arm7_name, \ - 0x00000c1e, __arm7_setup, arm7_processor_functions - arm67_proc_info arm710, 0x41007100, 0xfff8ff00, cpu_arm710_name, \ - PMD_TYPE_SECT | \ + .size __arm610_proc_info, . - __arm610_proc_info + + .type __arm7_proc_info, #object +__arm7_proc_info: + .long 0x41007000 + .long 0xffffff00 + .long 0x00000c1e + .long PMD_TYPE_SECT | \ + PMD_BIT4 | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + b __arm7_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP | HWCAP_26BIT + .long cpu_arm7_name + .long arm7_processor_functions + .long v3_tlb_fns + .long v3_user_fns + .long v3_cache_fns + .size __arm7_proc_info, . - __arm7_proc_info + + .type __arm710_proc_info, #object +__arm710_proc_info: + .long 0x41007100 + .long 0xfff8ff00 + .long PMD_TYPE_SECT | \ PMD_SECT_BUFFERABLE | \ PMD_SECT_CACHEABLE | \ PMD_BIT4 | \ PMD_SECT_AP_WRITE | \ - PMD_SECT_AP_READ, \ - __arm7_setup, arm7_processor_functions + PMD_SECT_AP_READ + .long PMD_TYPE_SECT | \ + PMD_BIT4 | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + b __arm7_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP | HWCAP_26BIT + .long cpu_arm710_name + .long arm7_processor_functions + .long v3_tlb_fns + .long v3_user_fns + .long v3_cache_fns + .size __arm710_proc_info, . - __arm710_proc_info diff --git a/trunk/arch/arm/mm/proc-arm720.S b/trunk/arch/arm/mm/proc-arm720.S index 55f4e290665a..7a06e5964f59 100644 --- a/trunk/arch/arm/mm/proc-arm720.S +++ b/trunk/arch/arm/mm/proc-arm720.S @@ -169,15 +169,46 @@ arm720_crval: crval clear=0x00002f3f, mmuset=0x0000213d, ucset=0x00000130 __INITDATA - @ define struct processor (see and proc-macros.S) - define_processor_functions arm720, dabort=v4t_late_abort, pabort=legacy_pabort + +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + .type arm720_processor_functions, #object +ENTRY(arm720_processor_functions) + .word v4t_late_abort + .word legacy_pabort + .word cpu_arm720_proc_init + .word cpu_arm720_proc_fin + .word cpu_arm720_reset + .word cpu_arm720_do_idle + .word cpu_arm720_dcache_clean_area + .word cpu_arm720_switch_mm + .word cpu_arm720_set_pte_ext + .word 0 + .word 0 + .word 0 + .size arm720_processor_functions, . - arm720_processor_functions .section ".rodata" - string cpu_arch_name, "armv4t" - string cpu_elf_name, "v4" - string cpu_arm710_name, "ARM710T" - string cpu_arm720_name, "ARM720T" + .type cpu_arch_name, #object +cpu_arch_name: .asciz "armv4t" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: .asciz "v4" + .size cpu_elf_name, . - cpu_elf_name + + .type cpu_arm710_name, #object +cpu_arm710_name: + .asciz "ARM710T" + .size cpu_arm710_name, . - cpu_arm710_name + + .type cpu_arm720_name, #object +cpu_arm720_name: + .asciz "ARM720T" + .size cpu_arm720_name, . - cpu_arm720_name .align @@ -187,11 +218,10 @@ arm720_crval: .section ".proc.info.init", #alloc, #execinstr -.macro arm720_proc_info name:req, cpu_val:req, cpu_mask:req, cpu_name:req, cpu_flush:req - .type __\name\()_proc_info,#object -__\name\()_proc_info: - .long \cpu_val - .long \cpu_mask + .type __arm710_proc_info, #object +__arm710_proc_info: + .long 0x41807100 @ cpu_val + .long 0xffffff00 @ cpu_mask .long PMD_TYPE_SECT | \ PMD_SECT_BUFFERABLE | \ PMD_SECT_CACHEABLE | \ @@ -202,17 +232,38 @@ __\name\()_proc_info: PMD_BIT4 | \ PMD_SECT_AP_WRITE | \ PMD_SECT_AP_READ - b \cpu_flush @ cpu_flush + b __arm710_setup @ cpu_flush .long cpu_arch_name @ arch_name .long cpu_elf_name @ elf_name .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB @ elf_hwcap - .long \cpu_name + .long cpu_arm710_name @ name .long arm720_processor_functions .long v4_tlb_fns .long v4wt_user_fns .long v4_cache_fns - .size __\name\()_proc_info, . - __\name\()_proc_info -.endm + .size __arm710_proc_info, . - __arm710_proc_info - arm720_proc_info arm710, 0x41807100, 0xffffff00, cpu_arm710_name, __arm710_setup - arm720_proc_info arm720, 0x41807200, 0xffffff00, cpu_arm720_name, __arm720_setup + .type __arm720_proc_info, #object +__arm720_proc_info: + .long 0x41807200 @ cpu_val + .long 0xffffff00 @ cpu_mask + .long PMD_TYPE_SECT | \ + PMD_SECT_BUFFERABLE | \ + PMD_SECT_CACHEABLE | \ + PMD_BIT4 | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + .long PMD_TYPE_SECT | \ + PMD_BIT4 | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + b __arm720_setup @ cpu_flush + .long cpu_arch_name @ arch_name + .long cpu_elf_name @ elf_name + .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB @ elf_hwcap + .long cpu_arm720_name @ name + .long arm720_processor_functions + .long v4_tlb_fns + .long v4wt_user_fns + .long v4_cache_fns + .size __arm720_proc_info, . - __arm720_proc_info diff --git a/trunk/arch/arm/mm/proc-arm740.S b/trunk/arch/arm/mm/proc-arm740.S index 4506be3adda6..6f9d12effee1 100644 --- a/trunk/arch/arm/mm/proc-arm740.S +++ b/trunk/arch/arm/mm/proc-arm740.S @@ -17,8 +17,6 @@ #include #include -#include "proc-macros.S" - .text /* * cpu_arm740_proc_init() @@ -117,14 +115,42 @@ __arm740_setup: __INITDATA - @ define struct processor (see and proc-macros.S) - define_processor_functions arm740, dabort=v4t_late_abort, pabort=legacy_pabort, nommu=1 +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + .type arm740_processor_functions, #object +ENTRY(arm740_processor_functions) + .word v4t_late_abort + .word legacy_pabort + .word cpu_arm740_proc_init + .word cpu_arm740_proc_fin + .word cpu_arm740_reset + .word cpu_arm740_do_idle + .word cpu_arm740_dcache_clean_area + .word cpu_arm740_switch_mm + .word 0 @ cpu_*_set_pte + .word 0 + .word 0 + .word 0 + .size arm740_processor_functions, . - arm740_processor_functions .section ".rodata" - string cpu_arch_name, "armv4" - string cpu_elf_name, "v4" - string cpu_arm740_name, "ARM740T" + .type cpu_arch_name, #object +cpu_arch_name: + .asciz "armv4" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: + .asciz "v4" + .size cpu_elf_name, . - cpu_elf_name + + .type cpu_arm740_name, #object +cpu_arm740_name: + .ascii "ARM740T" + .size cpu_arm740_name, . - cpu_arm740_name .align @@ -144,3 +170,5 @@ __arm740_proc_info: .long 0 .long v3_cache_fns @ cache model .size __arm740_proc_info, . - __arm740_proc_info + + diff --git a/trunk/arch/arm/mm/proc-arm7tdmi.S b/trunk/arch/arm/mm/proc-arm7tdmi.S index 7e0e1fe4ed4d..537ffcb0646d 100644 --- a/trunk/arch/arm/mm/proc-arm7tdmi.S +++ b/trunk/arch/arm/mm/proc-arm7tdmi.S @@ -17,8 +17,6 @@ #include #include -#include "proc-macros.S" - .text /* * cpu_arm7tdmi_proc_init() @@ -57,57 +55,197 @@ __arm7tdmi_setup: __INITDATA - @ define struct processor (see and proc-macros.S) - define_processor_functions arm7tdmi, dabort=v4t_late_abort, pabort=legacy_pabort, nommu=1 +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + .type arm7tdmi_processor_functions, #object +ENTRY(arm7tdmi_processor_functions) + .word v4t_late_abort + .word legacy_pabort + .word cpu_arm7tdmi_proc_init + .word cpu_arm7tdmi_proc_fin + .word cpu_arm7tdmi_reset + .word cpu_arm7tdmi_do_idle + .word cpu_arm7tdmi_dcache_clean_area + .word cpu_arm7tdmi_switch_mm + .word 0 @ cpu_*_set_pte + .word 0 + .word 0 + .word 0 + .size arm7tdmi_processor_functions, . - arm7tdmi_processor_functions .section ".rodata" - string cpu_arch_name, "armv4t" - string cpu_elf_name, "v4" - string cpu_arm7tdmi_name, "ARM7TDMI" - string cpu_triscenda7_name, "Triscend-A7x" - string cpu_at91_name, "Atmel-AT91M40xxx" - string cpu_s3c3410_name, "Samsung-S3C3410" - string cpu_s3c44b0x_name, "Samsung-S3C44B0x" - string cpu_s3c4510b_name, "Samsung-S3C4510B" - string cpu_s3c4530_name, "Samsung-S3C4530" - string cpu_netarm_name, "NETARM" + .type cpu_arch_name, #object +cpu_arch_name: + .asciz "armv4t" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: + .asciz "v4" + .size cpu_elf_name, . - cpu_elf_name + + .type cpu_arm7tdmi_name, #object +cpu_arm7tdmi_name: + .asciz "ARM7TDMI" + .size cpu_arm7tdmi_name, . - cpu_arm7tdmi_name + + .type cpu_triscenda7_name, #object +cpu_triscenda7_name: + .asciz "Triscend-A7x" + .size cpu_triscenda7_name, . - cpu_triscenda7_name + + .type cpu_at91_name, #object +cpu_at91_name: + .asciz "Atmel-AT91M40xxx" + .size cpu_at91_name, . - cpu_at91_name + + .type cpu_s3c3410_name, #object +cpu_s3c3410_name: + .asciz "Samsung-S3C3410" + .size cpu_s3c3410_name, . - cpu_s3c3410_name + + .type cpu_s3c44b0x_name, #object +cpu_s3c44b0x_name: + .asciz "Samsung-S3C44B0x" + .size cpu_s3c44b0x_name, . - cpu_s3c44b0x_name + + .type cpu_s3c4510b, #object +cpu_s3c4510b_name: + .asciz "Samsung-S3C4510B" + .size cpu_s3c4510b_name, . - cpu_s3c4510b_name + + .type cpu_s3c4530_name, #object +cpu_s3c4530_name: + .asciz "Samsung-S3C4530" + .size cpu_s3c4530_name, . - cpu_s3c4530_name + + .type cpu_netarm_name, #object +cpu_netarm_name: + .asciz "NETARM" + .size cpu_netarm_name, . - cpu_netarm_name .align .section ".proc.info.init", #alloc, #execinstr -.macro arm7tdmi_proc_info name:req, cpu_val:req, cpu_mask:req, cpu_name:req, \ - extra_hwcaps=0 - .type __\name\()_proc_info, #object -__\name\()_proc_info: - .long \cpu_val - .long \cpu_mask + .type __arm7tdmi_proc_info, #object +__arm7tdmi_proc_info: + .long 0x41007700 + .long 0xfff8ff00 + .long 0 + .long 0 + b __arm7tdmi_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP | HWCAP_26BIT + .long cpu_arm7tdmi_name + .long arm7tdmi_processor_functions + .long 0 + .long 0 + .long v4_cache_fns + .size __arm7tdmi_proc_info, . - __arm7tdmi_proc_info + + .type __triscenda7_proc_info, #object +__triscenda7_proc_info: + .long 0x0001d2ff + .long 0x0001ffff + .long 0 + .long 0 + b __arm7tdmi_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP | HWCAP_THUMB | HWCAP_26BIT + .long cpu_triscenda7_name + .long arm7tdmi_processor_functions + .long 0 + .long 0 + .long v4_cache_fns + .size __triscenda7_proc_info, . - __triscenda7_proc_info + + .type __at91_proc_info, #object +__at91_proc_info: + .long 0x14000040 + .long 0xfff000e0 + .long 0 + .long 0 + b __arm7tdmi_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP | HWCAP_THUMB | HWCAP_26BIT + .long cpu_at91_name + .long arm7tdmi_processor_functions + .long 0 + .long 0 + .long v4_cache_fns + .size __at91_proc_info, . - __at91_proc_info + + .type __s3c4510b_proc_info, #object +__s3c4510b_proc_info: + .long 0x36365000 + .long 0xfffff000 + .long 0 + .long 0 + b __arm7tdmi_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP | HWCAP_THUMB | HWCAP_26BIT + .long cpu_s3c4510b_name + .long arm7tdmi_processor_functions + .long 0 + .long 0 + .long v4_cache_fns + .size __s3c4510b_proc_info, . - __s3c4510b_proc_info + + .type __s3c4530_proc_info, #object +__s3c4530_proc_info: + .long 0x4c000000 + .long 0xfff000e0 + .long 0 + .long 0 + b __arm7tdmi_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP | HWCAP_THUMB | HWCAP_26BIT + .long cpu_s3c4530_name + .long arm7tdmi_processor_functions + .long 0 + .long 0 + .long v4_cache_fns + .size __s3c4530_proc_info, . - __s3c4530_proc_info + + .type __s3c3410_proc_info, #object +__s3c3410_proc_info: + .long 0x34100000 + .long 0xffff0000 + .long 0 + .long 0 + b __arm7tdmi_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP | HWCAP_THUMB | HWCAP_26BIT + .long cpu_s3c3410_name + .long arm7tdmi_processor_functions + .long 0 + .long 0 + .long v4_cache_fns + .size __s3c3410_proc_info, . - __s3c3410_proc_info + + .type __s3c44b0x_proc_info, #object +__s3c44b0x_proc_info: + .long 0x44b00000 + .long 0xffff0000 .long 0 .long 0 b __arm7tdmi_setup .long cpu_arch_name .long cpu_elf_name - .long HWCAP_SWP | HWCAP_26BIT | ( \extra_hwcaps ) - .long \cpu_name + .long HWCAP_SWP | HWCAP_THUMB | HWCAP_26BIT + .long cpu_s3c44b0x_name .long arm7tdmi_processor_functions .long 0 .long 0 .long v4_cache_fns - .size __\name\()_proc_info, . - __\name\()_proc_info -.endm - - arm7tdmi_proc_info arm7tdmi, 0x41007700, 0xfff8ff00, \ - cpu_arm7tdmi_name - arm7tdmi_proc_info triscenda7, 0x0001d2ff, 0x0001ffff, \ - cpu_triscenda7_name, extra_hwcaps=HWCAP_THUMB - arm7tdmi_proc_info at91, 0x14000040, 0xfff000e0, \ - cpu_at91_name, extra_hwcaps=HWCAP_THUMB - arm7tdmi_proc_info s3c4510b, 0x36365000, 0xfffff000, \ - cpu_s3c4510b_name, extra_hwcaps=HWCAP_THUMB - arm7tdmi_proc_info s3c4530, 0x4c000000, 0xfff000e0, \ - cpu_s3c4530_name, extra_hwcaps=HWCAP_THUMB - arm7tdmi_proc_info s3c3410, 0x34100000, 0xffff0000, \ - cpu_s3c3410_name, extra_hwcaps=HWCAP_THUMB - arm7tdmi_proc_info s3c44b0x, 0x44b00000, 0xffff0000, \ - cpu_s3c44b0x_name, extra_hwcaps=HWCAP_THUMB + .size __s3c44b0x_proc_info, . - __s3c44b0x_proc_info diff --git a/trunk/arch/arm/mm/proc-arm920.S b/trunk/arch/arm/mm/proc-arm920.S index 92bd102e3982..bf8a1d1cccb6 100644 --- a/trunk/arch/arm/mm/proc-arm920.S +++ b/trunk/arch/arm/mm/proc-arm920.S @@ -315,8 +315,18 @@ ENTRY(arm920_dma_unmap_area) mov pc, lr ENDPROC(arm920_dma_unmap_area) - @ define struct cpu_cache_fns (see and proc-macros.S) - define_cache_functions arm920 +ENTRY(arm920_cache_fns) + .long arm920_flush_icache_all + .long arm920_flush_kern_cache_all + .long arm920_flush_user_cache_all + .long arm920_flush_user_cache_range + .long arm920_coherent_kern_range + .long arm920_coherent_user_range + .long arm920_flush_kern_dcache_area + .long arm920_dma_map_area + .long arm920_dma_unmap_area + .long arm920_dma_flush_range + #endif @@ -406,6 +416,9 @@ ENTRY(cpu_arm920_do_resume) PMD_SECT_CACHEABLE | PMD_BIT4 | PMD_SECT_AP_WRITE b cpu_resume_mmu ENDPROC(cpu_arm920_do_resume) +#else +#define cpu_arm920_do_suspend 0 +#define cpu_arm920_do_resume 0 #endif __CPUINIT @@ -437,14 +450,43 @@ arm920_crval: crval clear=0x00003f3f, mmuset=0x00003135, ucset=0x00001130 __INITDATA - @ define struct processor (see and proc-macros.S) - define_processor_functions arm920, dabort=v4t_early_abort, pabort=legacy_pabort, suspend=1 + +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + .type arm920_processor_functions, #object +arm920_processor_functions: + .word v4t_early_abort + .word legacy_pabort + .word cpu_arm920_proc_init + .word cpu_arm920_proc_fin + .word cpu_arm920_reset + .word cpu_arm920_do_idle + .word cpu_arm920_dcache_clean_area + .word cpu_arm920_switch_mm + .word cpu_arm920_set_pte_ext + .word cpu_arm920_suspend_size + .word cpu_arm920_do_suspend + .word cpu_arm920_do_resume + .size arm920_processor_functions, . - arm920_processor_functions .section ".rodata" - string cpu_arch_name, "armv4t" - string cpu_elf_name, "v4" - string cpu_arm920_name, "ARM920T" + .type cpu_arch_name, #object +cpu_arch_name: + .asciz "armv4t" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: + .asciz "v4" + .size cpu_elf_name, . - cpu_elf_name + + .type cpu_arm920_name, #object +cpu_arm920_name: + .asciz "ARM920T" + .size cpu_arm920_name, . - cpu_arm920_name .align diff --git a/trunk/arch/arm/mm/proc-arm922.S b/trunk/arch/arm/mm/proc-arm922.S index 490e18833857..95ba1fc56e4d 100644 --- a/trunk/arch/arm/mm/proc-arm922.S +++ b/trunk/arch/arm/mm/proc-arm922.S @@ -317,8 +317,18 @@ ENTRY(arm922_dma_unmap_area) mov pc, lr ENDPROC(arm922_dma_unmap_area) - @ define struct cpu_cache_fns (see and proc-macros.S) - define_cache_functions arm922 +ENTRY(arm922_cache_fns) + .long arm922_flush_icache_all + .long arm922_flush_kern_cache_all + .long arm922_flush_user_cache_all + .long arm922_flush_user_cache_range + .long arm922_coherent_kern_range + .long arm922_coherent_user_range + .long arm922_flush_kern_dcache_area + .long arm922_dma_map_area + .long arm922_dma_unmap_area + .long arm922_dma_flush_range + #endif @@ -410,14 +420,43 @@ arm922_crval: crval clear=0x00003f3f, mmuset=0x00003135, ucset=0x00001130 __INITDATA - @ define struct processor (see and proc-macros.S) - define_processor_functions arm922, dabort=v4t_early_abort, pabort=legacy_pabort + +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + .type arm922_processor_functions, #object +arm922_processor_functions: + .word v4t_early_abort + .word legacy_pabort + .word cpu_arm922_proc_init + .word cpu_arm922_proc_fin + .word cpu_arm922_reset + .word cpu_arm922_do_idle + .word cpu_arm922_dcache_clean_area + .word cpu_arm922_switch_mm + .word cpu_arm922_set_pte_ext + .word 0 + .word 0 + .word 0 + .size arm922_processor_functions, . - arm922_processor_functions .section ".rodata" - string cpu_arch_name, "armv4t" - string cpu_elf_name, "v4" - string cpu_arm922_name, "ARM922T" + .type cpu_arch_name, #object +cpu_arch_name: + .asciz "armv4t" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: + .asciz "v4" + .size cpu_elf_name, . - cpu_elf_name + + .type cpu_arm922_name, #object +cpu_arm922_name: + .asciz "ARM922T" + .size cpu_arm922_name, . - cpu_arm922_name .align diff --git a/trunk/arch/arm/mm/proc-arm925.S b/trunk/arch/arm/mm/proc-arm925.S index 51d494be057e..541e4774eea1 100644 --- a/trunk/arch/arm/mm/proc-arm925.S +++ b/trunk/arch/arm/mm/proc-arm925.S @@ -372,8 +372,17 @@ ENTRY(arm925_dma_unmap_area) mov pc, lr ENDPROC(arm925_dma_unmap_area) - @ define struct cpu_cache_fns (see and proc-macros.S) - define_cache_functions arm925 +ENTRY(arm925_cache_fns) + .long arm925_flush_icache_all + .long arm925_flush_kern_cache_all + .long arm925_flush_user_cache_all + .long arm925_flush_user_cache_range + .long arm925_coherent_kern_range + .long arm925_coherent_user_range + .long arm925_flush_kern_dcache_area + .long arm925_dma_map_area + .long arm925_dma_unmap_area + .long arm925_dma_flush_range ENTRY(cpu_arm925_dcache_clean_area) #ifndef CONFIG_CPU_DCACHE_WRITETHROUGH @@ -478,24 +487,52 @@ arm925_crval: crval clear=0x00007f3f, mmuset=0x0000313d, ucset=0x00001130 __INITDATA - @ define struct processor (see and proc-macros.S) - define_processor_functions arm925, dabort=v4t_early_abort, pabort=legacy_pabort + +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + .type arm925_processor_functions, #object +arm925_processor_functions: + .word v4t_early_abort + .word legacy_pabort + .word cpu_arm925_proc_init + .word cpu_arm925_proc_fin + .word cpu_arm925_reset + .word cpu_arm925_do_idle + .word cpu_arm925_dcache_clean_area + .word cpu_arm925_switch_mm + .word cpu_arm925_set_pte_ext + .word 0 + .word 0 + .word 0 + .size arm925_processor_functions, . - arm925_processor_functions .section ".rodata" - string cpu_arch_name, "armv4t" - string cpu_elf_name, "v4" - string cpu_arm925_name, "ARM925T" + .type cpu_arch_name, #object +cpu_arch_name: + .asciz "armv4t" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: + .asciz "v4" + .size cpu_elf_name, . - cpu_elf_name + + .type cpu_arm925_name, #object +cpu_arm925_name: + .asciz "ARM925T" + .size cpu_arm925_name, . - cpu_arm925_name .align .section ".proc.info.init", #alloc, #execinstr -.macro arm925_proc_info name:req, cpu_val:req, cpu_mask:req, cpu_name:req, cache - .type __\name\()_proc_info,#object -__\name\()_proc_info: - .long \cpu_val - .long \cpu_mask + .type __arm925_proc_info,#object +__arm925_proc_info: + .long 0x54029250 + .long 0xfffffff0 .long PMD_TYPE_SECT | \ PMD_BIT4 | \ PMD_SECT_AP_WRITE | \ @@ -513,8 +550,27 @@ __\name\()_proc_info: .long v4wbi_tlb_fns .long v4wb_user_fns .long arm925_cache_fns - .size __\name\()_proc_info, . - __\name\()_proc_info -.endm + .size __arm925_proc_info, . - __arm925_proc_info - arm925_proc_info arm925, 0x54029250, 0xfffffff0, cpu_arm925_name - arm925_proc_info arm915, 0x54029150, 0xfffffff0, cpu_arm925_name + .type __arm915_proc_info,#object +__arm915_proc_info: + .long 0x54029150 + .long 0xfffffff0 + .long PMD_TYPE_SECT | \ + PMD_BIT4 | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + .long PMD_TYPE_SECT | \ + PMD_BIT4 | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + b __arm925_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB + .long cpu_arm925_name + .long arm925_processor_functions + .long v4wbi_tlb_fns + .long v4wb_user_fns + .long arm925_cache_fns + .size __arm925_proc_info, . - __arm925_proc_info diff --git a/trunk/arch/arm/mm/proc-arm926.S b/trunk/arch/arm/mm/proc-arm926.S index 2bbcf053dffd..0ed85d930c09 100644 --- a/trunk/arch/arm/mm/proc-arm926.S +++ b/trunk/arch/arm/mm/proc-arm926.S @@ -335,8 +335,17 @@ ENTRY(arm926_dma_unmap_area) mov pc, lr ENDPROC(arm926_dma_unmap_area) - @ define struct cpu_cache_fns (see and proc-macros.S) - define_cache_functions arm926 +ENTRY(arm926_cache_fns) + .long arm926_flush_icache_all + .long arm926_flush_kern_cache_all + .long arm926_flush_user_cache_all + .long arm926_flush_user_cache_range + .long arm926_coherent_kern_range + .long arm926_coherent_user_range + .long arm926_flush_kern_dcache_area + .long arm926_dma_map_area + .long arm926_dma_unmap_area + .long arm926_dma_flush_range ENTRY(cpu_arm926_dcache_clean_area) #ifndef CONFIG_CPU_DCACHE_WRITETHROUGH @@ -421,6 +430,9 @@ ENTRY(cpu_arm926_do_resume) PMD_SECT_CACHEABLE | PMD_BIT4 | PMD_SECT_AP_WRITE b cpu_resume_mmu ENDPROC(cpu_arm926_do_resume) +#else +#define cpu_arm926_do_suspend 0 +#define cpu_arm926_do_resume 0 #endif __CPUINIT @@ -463,14 +475,42 @@ arm926_crval: __INITDATA - @ define struct processor (see and proc-macros.S) - define_processor_functions arm926, dabort=v5tj_early_abort, pabort=legacy_pabort, suspend=1 +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + .type arm926_processor_functions, #object +arm926_processor_functions: + .word v5tj_early_abort + .word legacy_pabort + .word cpu_arm926_proc_init + .word cpu_arm926_proc_fin + .word cpu_arm926_reset + .word cpu_arm926_do_idle + .word cpu_arm926_dcache_clean_area + .word cpu_arm926_switch_mm + .word cpu_arm926_set_pte_ext + .word cpu_arm926_suspend_size + .word cpu_arm926_do_suspend + .word cpu_arm926_do_resume + .size arm926_processor_functions, . - arm926_processor_functions .section ".rodata" - string cpu_arch_name, "armv5tej" - string cpu_elf_name, "v5" - string cpu_arm926_name, "ARM926EJ-S" + .type cpu_arch_name, #object +cpu_arch_name: + .asciz "armv5tej" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: + .asciz "v5" + .size cpu_elf_name, . - cpu_elf_name + + .type cpu_arm926_name, #object +cpu_arm926_name: + .asciz "ARM926EJ-S" + .size cpu_arm926_name, . - cpu_arm926_name .align diff --git a/trunk/arch/arm/mm/proc-arm940.S b/trunk/arch/arm/mm/proc-arm940.S index ac750d506153..26aea3f71c26 100644 --- a/trunk/arch/arm/mm/proc-arm940.S +++ b/trunk/arch/arm/mm/proc-arm940.S @@ -264,8 +264,17 @@ ENTRY(arm940_dma_unmap_area) mov pc, lr ENDPROC(arm940_dma_unmap_area) - @ define struct cpu_cache_fns (see and proc-macros.S) - define_cache_functions arm940 +ENTRY(arm940_cache_fns) + .long arm940_flush_icache_all + .long arm940_flush_kern_cache_all + .long arm940_flush_user_cache_all + .long arm940_flush_user_cache_range + .long arm940_coherent_kern_range + .long arm940_coherent_user_range + .long arm940_flush_kern_dcache_area + .long arm940_dma_map_area + .long arm940_dma_unmap_area + .long arm940_dma_flush_range __CPUINIT @@ -339,14 +348,42 @@ __arm940_setup: __INITDATA - @ define struct processor (see and proc-macros.S) - define_processor_functions arm940, dabort=nommu_early_abort, pabort=legacy_pabort, nommu=1 +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + .type arm940_processor_functions, #object +ENTRY(arm940_processor_functions) + .word nommu_early_abort + .word legacy_pabort + .word cpu_arm940_proc_init + .word cpu_arm940_proc_fin + .word cpu_arm940_reset + .word cpu_arm940_do_idle + .word cpu_arm940_dcache_clean_area + .word cpu_arm940_switch_mm + .word 0 @ cpu_*_set_pte + .word 0 + .word 0 + .word 0 + .size arm940_processor_functions, . - arm940_processor_functions .section ".rodata" - string cpu_arch_name, "armv4t" - string cpu_elf_name, "v4" - string cpu_arm940_name, "ARM940T" +.type cpu_arch_name, #object +cpu_arch_name: + .asciz "armv4t" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: + .asciz "v4" + .size cpu_elf_name, . - cpu_elf_name + + .type cpu_arm940_name, #object +cpu_arm940_name: + .ascii "ARM940T" + .size cpu_arm940_name, . - cpu_arm940_name .align diff --git a/trunk/arch/arm/mm/proc-arm946.S b/trunk/arch/arm/mm/proc-arm946.S index f8f7ea34bfc5..8063345406fe 100644 --- a/trunk/arch/arm/mm/proc-arm946.S +++ b/trunk/arch/arm/mm/proc-arm946.S @@ -306,8 +306,18 @@ ENTRY(arm946_dma_unmap_area) mov pc, lr ENDPROC(arm946_dma_unmap_area) - @ define struct cpu_cache_fns (see and proc-macros.S) - define_cache_functions arm946 +ENTRY(arm946_cache_fns) + .long arm946_flush_icache_all + .long arm946_flush_kern_cache_all + .long arm946_flush_user_cache_all + .long arm946_flush_user_cache_range + .long arm946_coherent_kern_range + .long arm946_coherent_user_range + .long arm946_flush_kern_dcache_area + .long arm946_dma_map_area + .long arm946_dma_unmap_area + .long arm946_dma_flush_range + ENTRY(cpu_arm946_dcache_clean_area) #ifndef CONFIG_CPU_DCACHE_WRITETHROUGH @@ -393,14 +403,43 @@ __arm946_setup: __INITDATA - @ define struct processor (see and proc-macros.S) - define_processor_functions arm946, dabort=nommu_early_abort, pabort=legacy_pabort, nommu=1 +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + .type arm946_processor_functions, #object +ENTRY(arm946_processor_functions) + .word nommu_early_abort + .word legacy_pabort + .word cpu_arm946_proc_init + .word cpu_arm946_proc_fin + .word cpu_arm946_reset + .word cpu_arm946_do_idle + + .word cpu_arm946_dcache_clean_area + .word cpu_arm946_switch_mm + .word 0 @ cpu_*_set_pte + .word 0 + .word 0 + .word 0 + .size arm946_processor_functions, . - arm946_processor_functions .section ".rodata" - string cpu_arch_name, "armv5te" - string cpu_elf_name, "v5t" - string cpu_arm946_name, "ARM946E-S" + .type cpu_arch_name, #object +cpu_arch_name: + .asciz "armv5te" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: + .asciz "v5t" + .size cpu_elf_name, . - cpu_elf_name + + .type cpu_arm946_name, #object +cpu_arm946_name: + .ascii "ARM946E-S" + .size cpu_arm946_name, . - cpu_arm946_name .align diff --git a/trunk/arch/arm/mm/proc-arm9tdmi.S b/trunk/arch/arm/mm/proc-arm9tdmi.S index 2120f9e2af7f..546b54da1005 100644 --- a/trunk/arch/arm/mm/proc-arm9tdmi.S +++ b/trunk/arch/arm/mm/proc-arm9tdmi.S @@ -17,8 +17,6 @@ #include #include -#include "proc-macros.S" - .text /* * cpu_arm9tdmi_proc_init() @@ -57,38 +55,82 @@ __arm9tdmi_setup: __INITDATA - @ define struct processor (see and proc-macros.S) - define_processor_functions arm9tdmi, dabort=nommu_early_abort, pabort=legacy_pabort, nommu=1 +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + .type arm9tdmi_processor_functions, #object +ENTRY(arm9tdmi_processor_functions) + .word nommu_early_abort + .word legacy_pabort + .word cpu_arm9tdmi_proc_init + .word cpu_arm9tdmi_proc_fin + .word cpu_arm9tdmi_reset + .word cpu_arm9tdmi_do_idle + .word cpu_arm9tdmi_dcache_clean_area + .word cpu_arm9tdmi_switch_mm + .word 0 @ cpu_*_set_pte + .word 0 + .word 0 + .word 0 + .size arm9tdmi_processor_functions, . - arm9tdmi_processor_functions .section ".rodata" - string cpu_arch_name, "armv4t" - string cpu_elf_name, "v4" - string cpu_arm9tdmi_name, "ARM9TDMI" - string cpu_p2001_name, "P2001" + .type cpu_arch_name, #object +cpu_arch_name: + .asciz "armv4t" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: + .asciz "v4" + .size cpu_elf_name, . - cpu_elf_name + + .type cpu_arm9tdmi_name, #object +cpu_arm9tdmi_name: + .asciz "ARM9TDMI" + .size cpu_arm9tdmi_name, . - cpu_arm9tdmi_name + + .type cpu_p2001_name, #object +cpu_p2001_name: + .asciz "P2001" + .size cpu_p2001_name, . - cpu_p2001_name .align .section ".proc.info.init", #alloc, #execinstr -.macro arm9tdmi_proc_info name:req, cpu_val:req, cpu_mask:req, cpu_name:req - .type __\name\()_proc_info, #object -__\name\()_proc_info: - .long \cpu_val - .long \cpu_mask + .type __arm9tdmi_proc_info, #object +__arm9tdmi_proc_info: + .long 0x41009900 + .long 0xfff8ff00 .long 0 .long 0 b __arm9tdmi_setup .long cpu_arch_name .long cpu_elf_name .long HWCAP_SWP | HWCAP_THUMB | HWCAP_26BIT - .long \cpu_name + .long cpu_arm9tdmi_name .long arm9tdmi_processor_functions .long 0 .long 0 .long v4_cache_fns - .size __\name\()_proc_info, . - __\name\()_proc_info -.endm + .size __arm9tdmi_proc_info, . - __arm9tdmi_proc_info - arm9tdmi_proc_info arm9tdmi, 0x41009900, 0xfff8ff00, cpu_arm9tdmi_name - arm9tdmi_proc_info p2001, 0x41029000, 0xffffffff, cpu_p2001_name + .type __p2001_proc_info, #object +__p2001_proc_info: + .long 0x41029000 + .long 0xffffffff + .long 0 + .long 0 + b __arm9tdmi_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP | HWCAP_THUMB | HWCAP_26BIT + .long cpu_p2001_name + .long arm9tdmi_processor_functions + .long 0 + .long 0 + .long v4_cache_fns + .size __p2001_proc_info, . - __p2001_proc_info diff --git a/trunk/arch/arm/mm/proc-fa526.S b/trunk/arch/arm/mm/proc-fa526.S index 4c7a5710472b..fc2a4ae15cf4 100644 --- a/trunk/arch/arm/mm/proc-fa526.S +++ b/trunk/arch/arm/mm/proc-fa526.S @@ -180,14 +180,42 @@ fa526_cr1_set: __INITDATA - @ define struct processor (see and proc-macros.S) - define_processor_functions fa526, dabort=v4_early_abort, pabort=legacy_pabort +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + .type fa526_processor_functions, #object +fa526_processor_functions: + .word v4_early_abort + .word legacy_pabort + .word cpu_fa526_proc_init + .word cpu_fa526_proc_fin + .word cpu_fa526_reset + .word cpu_fa526_do_idle + .word cpu_fa526_dcache_clean_area + .word cpu_fa526_switch_mm + .word cpu_fa526_set_pte_ext + .word 0 + .word 0 + .word 0 + .size fa526_processor_functions, . - fa526_processor_functions .section ".rodata" - string cpu_arch_name, "armv4" - string cpu_elf_name, "v4" - string cpu_fa526_name, "FA526" + .type cpu_arch_name, #object +cpu_arch_name: + .asciz "armv4" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: + .asciz "v4" + .size cpu_elf_name, . - cpu_elf_name + + .type cpu_fa526_name, #object +cpu_fa526_name: + .asciz "FA526" + .size cpu_fa526_name, . - cpu_fa526_name .align diff --git a/trunk/arch/arm/mm/proc-feroceon.S b/trunk/arch/arm/mm/proc-feroceon.S index 8a6c2f78c1c3..d3883eed7a4a 100644 --- a/trunk/arch/arm/mm/proc-feroceon.S +++ b/trunk/arch/arm/mm/proc-feroceon.S @@ -411,28 +411,29 @@ ENTRY(feroceon_dma_unmap_area) mov pc, lr ENDPROC(feroceon_dma_unmap_area) - @ define struct cpu_cache_fns (see and proc-macros.S) - define_cache_functions feroceon - -.macro range_alias basename - .globl feroceon_range_\basename - .type feroceon_range_\basename , %function - .equ feroceon_range_\basename , feroceon_\basename -.endm - -/* - * Most of the cache functions are unchanged for this case. - * Export suitable alias symbols for the unchanged functions: - */ - range_alias flush_icache_all - range_alias flush_user_cache_all - range_alias flush_kern_cache_all - range_alias flush_user_cache_range - range_alias coherent_kern_range - range_alias coherent_user_range - range_alias dma_unmap_area - - define_cache_functions feroceon_range +ENTRY(feroceon_cache_fns) + .long feroceon_flush_icache_all + .long feroceon_flush_kern_cache_all + .long feroceon_flush_user_cache_all + .long feroceon_flush_user_cache_range + .long feroceon_coherent_kern_range + .long feroceon_coherent_user_range + .long feroceon_flush_kern_dcache_area + .long feroceon_dma_map_area + .long feroceon_dma_unmap_area + .long feroceon_dma_flush_range + +ENTRY(feroceon_range_cache_fns) + .long feroceon_flush_icache_all + .long feroceon_flush_kern_cache_all + .long feroceon_flush_user_cache_all + .long feroceon_flush_user_cache_range + .long feroceon_coherent_kern_range + .long feroceon_coherent_user_range + .long feroceon_range_flush_kern_dcache_area + .long feroceon_range_dma_map_area + .long feroceon_dma_unmap_area + .long feroceon_range_dma_flush_range .align 5 ENTRY(cpu_feroceon_dcache_clean_area) @@ -538,27 +539,67 @@ feroceon_crval: __INITDATA - @ define struct processor (see and proc-macros.S) - define_processor_functions feroceon, dabort=v5t_early_abort, pabort=legacy_pabort +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + .type feroceon_processor_functions, #object +feroceon_processor_functions: + .word v5t_early_abort + .word legacy_pabort + .word cpu_feroceon_proc_init + .word cpu_feroceon_proc_fin + .word cpu_feroceon_reset + .word cpu_feroceon_do_idle + .word cpu_feroceon_dcache_clean_area + .word cpu_feroceon_switch_mm + .word cpu_feroceon_set_pte_ext + .word 0 + .word 0 + .word 0 + .size feroceon_processor_functions, . - feroceon_processor_functions .section ".rodata" - string cpu_arch_name, "armv5te" - string cpu_elf_name, "v5" - string cpu_feroceon_name, "Feroceon" - string cpu_88fr531_name, "Feroceon 88FR531-vd" - string cpu_88fr571_name, "Feroceon 88FR571-vd" - string cpu_88fr131_name, "Feroceon 88FR131" + .type cpu_arch_name, #object +cpu_arch_name: + .asciz "armv5te" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: + .asciz "v5" + .size cpu_elf_name, . - cpu_elf_name + + .type cpu_feroceon_name, #object +cpu_feroceon_name: + .asciz "Feroceon" + .size cpu_feroceon_name, . - cpu_feroceon_name + + .type cpu_88fr531_name, #object +cpu_88fr531_name: + .asciz "Feroceon 88FR531-vd" + .size cpu_88fr531_name, . - cpu_88fr531_name + + .type cpu_88fr571_name, #object +cpu_88fr571_name: + .asciz "Feroceon 88FR571-vd" + .size cpu_88fr571_name, . - cpu_88fr571_name + + .type cpu_88fr131_name, #object +cpu_88fr131_name: + .asciz "Feroceon 88FR131" + .size cpu_88fr131_name, . - cpu_88fr131_name .align .section ".proc.info.init", #alloc, #execinstr -.macro feroceon_proc_info name:req, cpu_val:req, cpu_mask:req, cpu_name:req, cache:req - .type __\name\()_proc_info,#object -__\name\()_proc_info: - .long \cpu_val - .long \cpu_mask +#ifdef CONFIG_CPU_FEROCEON_OLD_ID + .type __feroceon_old_id_proc_info,#object +__feroceon_old_id_proc_info: + .long 0x41009260 + .long 0xff00fff0 .long PMD_TYPE_SECT | \ PMD_SECT_BUFFERABLE | \ PMD_SECT_CACHEABLE | \ @@ -573,22 +614,85 @@ __\name\()_proc_info: .long cpu_arch_name .long cpu_elf_name .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP - .long \cpu_name + .long cpu_feroceon_name .long feroceon_processor_functions .long v4wbi_tlb_fns .long feroceon_user_fns - .long \cache - .size __\name\()_proc_info, . - __\name\()_proc_info -.endm - -#ifdef CONFIG_CPU_FEROCEON_OLD_ID - feroceon_proc_info feroceon_old_id, 0x41009260, 0xff00fff0, \ - cpu_name=cpu_feroceon_name, cache=feroceon_cache_fns + .long feroceon_cache_fns + .size __feroceon_old_id_proc_info, . - __feroceon_old_id_proc_info #endif - feroceon_proc_info 88fr531, 0x56055310, 0xfffffff0, cpu_88fr531_name, \ - cache=feroceon_cache_fns - feroceon_proc_info 88fr571, 0x56155710, 0xfffffff0, cpu_88fr571_name, \ - cache=feroceon_range_cache_fns - feroceon_proc_info 88fr131, 0x56251310, 0xfffffff0, cpu_88fr131_name, \ - cache=feroceon_range_cache_fns + .type __88fr531_proc_info,#object +__88fr531_proc_info: + .long 0x56055310 + .long 0xfffffff0 + .long PMD_TYPE_SECT | \ + PMD_SECT_BUFFERABLE | \ + PMD_SECT_CACHEABLE | \ + PMD_BIT4 | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + .long PMD_TYPE_SECT | \ + PMD_BIT4 | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + b __feroceon_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP + .long cpu_88fr531_name + .long feroceon_processor_functions + .long v4wbi_tlb_fns + .long feroceon_user_fns + .long feroceon_cache_fns + .size __88fr531_proc_info, . - __88fr531_proc_info + + .type __88fr571_proc_info,#object +__88fr571_proc_info: + .long 0x56155710 + .long 0xfffffff0 + .long PMD_TYPE_SECT | \ + PMD_SECT_BUFFERABLE | \ + PMD_SECT_CACHEABLE | \ + PMD_BIT4 | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + .long PMD_TYPE_SECT | \ + PMD_BIT4 | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + b __feroceon_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP + .long cpu_88fr571_name + .long feroceon_processor_functions + .long v4wbi_tlb_fns + .long feroceon_user_fns + .long feroceon_range_cache_fns + .size __88fr571_proc_info, . - __88fr571_proc_info + + .type __88fr131_proc_info,#object +__88fr131_proc_info: + .long 0x56251310 + .long 0xfffffff0 + .long PMD_TYPE_SECT | \ + PMD_SECT_BUFFERABLE | \ + PMD_SECT_CACHEABLE | \ + PMD_BIT4 | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + .long PMD_TYPE_SECT | \ + PMD_BIT4 | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + b __feroceon_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP + .long cpu_88fr131_name + .long feroceon_processor_functions + .long v4wbi_tlb_fns + .long feroceon_user_fns + .long feroceon_range_cache_fns + .size __88fr131_proc_info, . - __88fr131_proc_info diff --git a/trunk/arch/arm/mm/proc-macros.S b/trunk/arch/arm/mm/proc-macros.S index 307a4def8d3a..34261f9486b9 100644 --- a/trunk/arch/arm/mm/proc-macros.S +++ b/trunk/arch/arm/mm/proc-macros.S @@ -254,71 +254,3 @@ mcr p15, 0, r0, c7, c10, 1 @ clean L1 D line mcr p15, 0, ip, c7, c10, 4 @ data write barrier .endm - -.macro define_processor_functions name:req, dabort:req, pabort:req, nommu=0, suspend=0 - .type \name\()_processor_functions, #object - .align 2 -ENTRY(\name\()_processor_functions) - .word \dabort - .word \pabort - .word cpu_\name\()_proc_init - .word cpu_\name\()_proc_fin - .word cpu_\name\()_reset - .word cpu_\name\()_do_idle - .word cpu_\name\()_dcache_clean_area - .word cpu_\name\()_switch_mm - - .if \nommu - .word 0 - .else - .word cpu_\name\()_set_pte_ext - .endif - - .if \suspend - .word cpu_\name\()_suspend_size -#ifdef CONFIG_PM_SLEEP - .word cpu_\name\()_do_suspend - .word cpu_\name\()_do_resume -#else - .word 0 - .word 0 -#endif - .else - .word 0 - .word 0 - .word 0 - .endif - - .size \name\()_processor_functions, . - \name\()_processor_functions -.endm - -.macro define_cache_functions name:req - .align 2 - .type \name\()_cache_fns, #object -ENTRY(\name\()_cache_fns) - .long \name\()_flush_icache_all - .long \name\()_flush_kern_cache_all - .long \name\()_flush_user_cache_all - .long \name\()_flush_user_cache_range - .long \name\()_coherent_kern_range - .long \name\()_coherent_user_range - .long \name\()_flush_kern_dcache_area - .long \name\()_dma_map_area - .long \name\()_dma_unmap_area - .long \name\()_dma_flush_range - .size \name\()_cache_fns, . - \name\()_cache_fns -.endm - -.macro define_tlb_functions name:req, flags_up:req, flags_smp - .type \name\()_tlb_fns, #object -ENTRY(\name\()_tlb_fns) - .long \name\()_flush_user_tlb_range - .long \name\()_flush_kern_tlb_range - .ifnb \flags_smp - ALT_SMP(.long \flags_smp ) - ALT_UP(.long \flags_up ) - .else - .long \flags_up - .endif - .size \name\()_tlb_fns, . - \name\()_tlb_fns -.endm diff --git a/trunk/arch/arm/mm/proc-mohawk.S b/trunk/arch/arm/mm/proc-mohawk.S index db52b0fb14a0..9d4f2ae63370 100644 --- a/trunk/arch/arm/mm/proc-mohawk.S +++ b/trunk/arch/arm/mm/proc-mohawk.S @@ -92,17 +92,6 @@ ENTRY(cpu_mohawk_do_idle) mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt mov pc, lr -/* - * flush_icache_all() - * - * Unconditionally clean and invalidate the entire icache. - */ -ENTRY(mohawk_flush_icache_all) - mov r0, #0 - mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache - mov pc, lr -ENDPROC(mohawk_flush_icache_all) - /* * flush_user_cache_all() * @@ -299,8 +288,16 @@ ENTRY(mohawk_dma_unmap_area) mov pc, lr ENDPROC(mohawk_dma_unmap_area) - @ define struct cpu_cache_fns (see and proc-macros.S) - define_cache_functions mohawk +ENTRY(mohawk_cache_fns) + .long mohawk_flush_kern_cache_all + .long mohawk_flush_user_cache_all + .long mohawk_flush_user_cache_range + .long mohawk_coherent_kern_range + .long mohawk_coherent_user_range + .long mohawk_flush_kern_dcache_area + .long mohawk_dma_map_area + .long mohawk_dma_unmap_area + .long mohawk_dma_flush_range ENTRY(cpu_mohawk_dcache_clean_area) 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry @@ -376,14 +373,42 @@ mohawk_crval: __INITDATA - @ define struct processor (see and proc-macros.S) - define_processor_functions mohawk, dabort=v5t_early_abort, pabort=legacy_pabort +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + .type mohawk_processor_functions, #object +mohawk_processor_functions: + .word v5t_early_abort + .word legacy_pabort + .word cpu_mohawk_proc_init + .word cpu_mohawk_proc_fin + .word cpu_mohawk_reset + .word cpu_mohawk_do_idle + .word cpu_mohawk_dcache_clean_area + .word cpu_mohawk_switch_mm + .word cpu_mohawk_set_pte_ext + .word 0 + .word 0 + .word 0 + .size mohawk_processor_functions, . - mohawk_processor_functions .section ".rodata" - string cpu_arch_name, "armv5te" - string cpu_elf_name, "v5" - string cpu_mohawk_name, "Marvell 88SV331x" + .type cpu_arch_name, #object +cpu_arch_name: + .asciz "armv5te" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: + .asciz "v5" + .size cpu_elf_name, . - cpu_elf_name + + .type cpu_mohawk_name, #object +cpu_mohawk_name: + .asciz "Marvell 88SV331x" + .size cpu_mohawk_name, . - cpu_mohawk_name .align diff --git a/trunk/arch/arm/mm/proc-sa110.S b/trunk/arch/arm/mm/proc-sa110.S index d50ada26edd6..46f09ed16b98 100644 --- a/trunk/arch/arm/mm/proc-sa110.S +++ b/trunk/arch/arm/mm/proc-sa110.S @@ -187,14 +187,43 @@ sa110_crval: __INITDATA - @ define struct processor (see and proc-macros.S) - define_processor_functions sa110, dabort=v4_early_abort, pabort=legacy_pabort +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + + .type sa110_processor_functions, #object +ENTRY(sa110_processor_functions) + .word v4_early_abort + .word legacy_pabort + .word cpu_sa110_proc_init + .word cpu_sa110_proc_fin + .word cpu_sa110_reset + .word cpu_sa110_do_idle + .word cpu_sa110_dcache_clean_area + .word cpu_sa110_switch_mm + .word cpu_sa110_set_pte_ext + .word 0 + .word 0 + .word 0 + .size sa110_processor_functions, . - sa110_processor_functions .section ".rodata" - string cpu_arch_name, "armv4" - string cpu_elf_name, "v4" - string cpu_sa110_name, "StrongARM-110" + .type cpu_arch_name, #object +cpu_arch_name: + .asciz "armv4" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: + .asciz "v4" + .size cpu_elf_name, . - cpu_elf_name + + .type cpu_sa110_name, #object +cpu_sa110_name: + .asciz "StrongARM-110" + .size cpu_sa110_name, . - cpu_sa110_name .align diff --git a/trunk/arch/arm/mm/proc-sa1100.S b/trunk/arch/arm/mm/proc-sa1100.S index 07219c2ae114..184a9c997e36 100644 --- a/trunk/arch/arm/mm/proc-sa1100.S +++ b/trunk/arch/arm/mm/proc-sa1100.S @@ -34,7 +34,7 @@ */ #define DCACHELINESIZE 32 - .section .text + __INIT /* * cpu_sa1100_proc_init() @@ -45,6 +45,8 @@ ENTRY(cpu_sa1100_proc_init) mcr p15, 0, r0, c9, c0, 5 @ Allow read-buffer operations from userland mov pc, lr + .section .text + /* * cpu_sa1100_proc_fin() * @@ -198,6 +200,9 @@ ENTRY(cpu_sa1100_do_resume) PMD_SECT_CACHEABLE | PMD_SECT_AP_WRITE b cpu_resume_mmu ENDPROC(cpu_sa1100_do_resume) +#else +#define cpu_sa1100_do_suspend 0 +#define cpu_sa1100_do_resume 0 #endif __CPUINIT @@ -231,28 +236,59 @@ sa1100_crval: __INITDATA /* - * SA1100 and SA1110 share the same function calls + * Purpose : Function pointers used to access above functions - all calls + * come through these */ - @ define struct processor (see and proc-macros.S) - define_processor_functions sa1100, dabort=v4_early_abort, pabort=legacy_pabort, suspend=1 +/* + * SA1100 and SA1110 share the same function calls + */ + .type sa1100_processor_functions, #object +ENTRY(sa1100_processor_functions) + .word v4_early_abort + .word legacy_pabort + .word cpu_sa1100_proc_init + .word cpu_sa1100_proc_fin + .word cpu_sa1100_reset + .word cpu_sa1100_do_idle + .word cpu_sa1100_dcache_clean_area + .word cpu_sa1100_switch_mm + .word cpu_sa1100_set_pte_ext + .word cpu_sa1100_suspend_size + .word cpu_sa1100_do_suspend + .word cpu_sa1100_do_resume + .size sa1100_processor_functions, . - sa1100_processor_functions .section ".rodata" - string cpu_arch_name, "armv4" - string cpu_elf_name, "v4" - string cpu_sa1100_name, "StrongARM-1100" - string cpu_sa1110_name, "StrongARM-1110" + .type cpu_arch_name, #object +cpu_arch_name: + .asciz "armv4" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: + .asciz "v4" + .size cpu_elf_name, . - cpu_elf_name + + .type cpu_sa1100_name, #object +cpu_sa1100_name: + .asciz "StrongARM-1100" + .size cpu_sa1100_name, . - cpu_sa1100_name + + .type cpu_sa1110_name, #object +cpu_sa1110_name: + .asciz "StrongARM-1110" + .size cpu_sa1110_name, . - cpu_sa1110_name .align .section ".proc.info.init", #alloc, #execinstr -.macro sa1100_proc_info name:req, cpu_val:req, cpu_mask:req, cpu_name:req - .type __\name\()_proc_info,#object -__\name\()_proc_info: - .long \cpu_val - .long \cpu_mask + .type __sa1100_proc_info,#object +__sa1100_proc_info: + .long 0x4401a110 + .long 0xfffffff0 .long PMD_TYPE_SECT | \ PMD_SECT_BUFFERABLE | \ PMD_SECT_CACHEABLE | \ @@ -265,13 +301,32 @@ __\name\()_proc_info: .long cpu_arch_name .long cpu_elf_name .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT | HWCAP_FAST_MULT - .long \cpu_name + .long cpu_sa1100_name .long sa1100_processor_functions .long v4wb_tlb_fns .long v4_mc_user_fns .long v4wb_cache_fns - .size __\name\()_proc_info, . - __\name\()_proc_info -.endm + .size __sa1100_proc_info, . - __sa1100_proc_info - sa1100_proc_info sa1100, 0x4401a110, 0xfffffff0, cpu_sa1100_name - sa1100_proc_info sa1110, 0x6901b110, 0xfffffff0, cpu_sa1110_name + .type __sa1110_proc_info,#object +__sa1110_proc_info: + .long 0x6901b110 + .long 0xfffffff0 + .long PMD_TYPE_SECT | \ + PMD_SECT_BUFFERABLE | \ + PMD_SECT_CACHEABLE | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + .long PMD_TYPE_SECT | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + b __sa1100_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT | HWCAP_FAST_MULT + .long cpu_sa1110_name + .long sa1100_processor_functions + .long v4wb_tlb_fns + .long v4_mc_user_fns + .long v4wb_cache_fns + .size __sa1110_proc_info, . - __sa1110_proc_info diff --git a/trunk/arch/arm/mm/proc-v6.S b/trunk/arch/arm/mm/proc-v6.S index 219138d2f158..1d2b8451bf25 100644 --- a/trunk/arch/arm/mm/proc-v6.S +++ b/trunk/arch/arm/mm/proc-v6.S @@ -56,11 +56,6 @@ ENTRY(cpu_v6_proc_fin) */ .align 5 ENTRY(cpu_v6_reset) - mrc p15, 0, r1, c1, c0, 0 @ ctrl register - bic r1, r1, #0x1 @ ...............m - mcr p15, 0, r1, c1, c0, 0 @ disable MMU - mov r1, #0 - mcr p15, 0, r1, c7, c5, 4 @ ISB mov pc, r0 /* @@ -169,9 +164,16 @@ ENDPROC(cpu_v6_do_resume) cpu_resume_l1_flags: ALT_SMP(.long PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_FLAGS_SMP) ALT_UP(.long PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_FLAGS_UP) +#else +#define cpu_v6_do_suspend 0 +#define cpu_v6_do_resume 0 #endif - string cpu_v6_name, "ARMv6-compatible processor" + + .type cpu_v6_name, #object +cpu_v6_name: + .asciz "ARMv6-compatible processor" + .size cpu_v6_name, . - cpu_v6_name .align @@ -237,13 +239,33 @@ v6_crval: __INITDATA - @ define struct processor (see and proc-macros.S) - define_processor_functions v6, dabort=v6_early_abort, pabort=v6_pabort, suspend=1 + .type v6_processor_functions, #object +ENTRY(v6_processor_functions) + .word v6_early_abort + .word v6_pabort + .word cpu_v6_proc_init + .word cpu_v6_proc_fin + .word cpu_v6_reset + .word cpu_v6_do_idle + .word cpu_v6_dcache_clean_area + .word cpu_v6_switch_mm + .word cpu_v6_set_pte_ext + .word cpu_v6_suspend_size + .word cpu_v6_do_suspend + .word cpu_v6_do_resume + .size v6_processor_functions, . - v6_processor_functions .section ".rodata" - string cpu_arch_name, "armv6" - string cpu_elf_name, "v6" + .type cpu_arch_name, #object +cpu_arch_name: + .asciz "armv6" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: + .asciz "v6" + .size cpu_elf_name, . - cpu_elf_name .align .section ".proc.info.init", #alloc, #execinstr diff --git a/trunk/arch/arm/mm/proc-v7.S b/trunk/arch/arm/mm/proc-v7.S index a30e78542ccf..089c0b5e454f 100644 --- a/trunk/arch/arm/mm/proc-v7.S +++ b/trunk/arch/arm/mm/proc-v7.S @@ -58,16 +58,9 @@ ENDPROC(cpu_v7_proc_fin) * to what would be the reset vector. * * - loc - location to jump to for soft reset - * - * This code must be executed using a flat identity mapping with - * caches disabled. */ .align 5 ENTRY(cpu_v7_reset) - mrc p15, 0, r1, c1, c0, 0 @ ctrl register - bic r1, r1, #0x1 @ ...............m - mcr p15, 0, r1, c1, c0, 0 @ disable MMU - isb mov pc, r0 ENDPROC(cpu_v7_reset) @@ -180,7 +173,8 @@ ENTRY(cpu_v7_set_pte_ext) mov pc, lr ENDPROC(cpu_v7_set_pte_ext) - string cpu_v7_name, "ARMv7 Processor" +cpu_v7_name: + .ascii "ARMv7 Processor" .align /* @@ -263,6 +257,9 @@ ENDPROC(cpu_v7_do_resume) cpu_resume_l1_flags: ALT_SMP(.long PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_FLAGS_SMP) ALT_UP(.long PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_FLAGS_UP) +#else +#define cpu_v7_do_suspend 0 +#define cpu_v7_do_resume 0 #endif __CPUINIT @@ -282,20 +279,13 @@ cpu_resume_l1_flags: * It is assumed that: * - cache type register is implemented */ -__v7_ca5mp_setup: __v7_ca9mp_setup: - mov r10, #(1 << 0) @ TLB ops broadcasting - b 1f -__v7_ca15mp_setup: - mov r10, #0 -1: #ifdef CONFIG_SMP ALT_SMP(mrc p15, 0, r0, c1, c0, 1) ALT_UP(mov r0, #(1 << 6)) @ fake it for UP tst r0, #(1 << 6) @ SMP/nAMP mode enabled? - orreq r0, r0, #(1 << 6) @ Enable SMP/nAMP mode - orreq r0, r0, r10 @ Enable CPU-specific SMP bits - mcreq p15, 0, r0, c1, c0, 1 + orreq r0, r0, #(1 << 6) | (1 << 0) @ Enable SMP/nAMP mode and + mcreq p15, 0, r0, c1, c0, 1 @ TLB ops broadcasting #endif __v7_setup: adr r12, __v7_setup_stack @ the local stack @@ -421,69 +411,66 @@ __v7_setup_stack: __INITDATA - @ define struct processor (see and proc-macros.S) - define_processor_functions v7, dabort=v7_early_abort, pabort=v7_pabort, suspend=1 + .type v7_processor_functions, #object +ENTRY(v7_processor_functions) + .word v7_early_abort + .word v7_pabort + .word cpu_v7_proc_init + .word cpu_v7_proc_fin + .word cpu_v7_reset + .word cpu_v7_do_idle + .word cpu_v7_dcache_clean_area + .word cpu_v7_switch_mm + .word cpu_v7_set_pte_ext + .word cpu_v7_suspend_size + .word cpu_v7_do_suspend + .word cpu_v7_do_resume + .size v7_processor_functions, . - v7_processor_functions .section ".rodata" - string cpu_arch_name, "armv7" - string cpu_elf_name, "v7" + .type cpu_arch_name, #object +cpu_arch_name: + .asciz "armv7" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: + .asciz "v7" + .size cpu_elf_name, . - cpu_elf_name .align .section ".proc.info.init", #alloc, #execinstr - /* - * Standard v7 proc info content - */ -.macro __v7_proc initfunc, mm_mmuflags = 0, io_mmuflags = 0, hwcaps = 0 - ALT_SMP(.long PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | \ - PMD_FLAGS_SMP | \mm_mmuflags) - ALT_UP(.long PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | \ - PMD_FLAGS_UP | \mm_mmuflags) - .long PMD_TYPE_SECT | PMD_SECT_XN | PMD_SECT_AP_WRITE | \ - PMD_SECT_AP_READ | \io_mmuflags - W(b) \initfunc + .type __v7_ca9mp_proc_info, #object +__v7_ca9mp_proc_info: + .long 0x410fc090 @ Required ID value + .long 0xff0ffff0 @ Mask for ID + ALT_SMP(.long \ + PMD_TYPE_SECT | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ | \ + PMD_FLAGS_SMP) + ALT_UP(.long \ + PMD_TYPE_SECT | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ | \ + PMD_FLAGS_UP) + .long PMD_TYPE_SECT | \ + PMD_SECT_XN | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + W(b) __v7_ca9mp_setup .long cpu_arch_name .long cpu_elf_name - .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB | HWCAP_FAST_MULT | \ - HWCAP_EDSP | HWCAP_TLS | \hwcaps + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_TLS .long cpu_v7_name .long v7_processor_functions .long v7wbi_tlb_fns .long v6_user_fns .long v7_cache_fns -.endm - - /* - * ARM Ltd. Cortex A5 processor. - */ - .type __v7_ca5mp_proc_info, #object -__v7_ca5mp_proc_info: - .long 0x410fc050 - .long 0xff0ffff0 - __v7_proc __v7_ca5mp_setup - .size __v7_ca5mp_proc_info, . - __v7_ca5mp_proc_info - - /* - * ARM Ltd. Cortex A9 processor. - */ - .type __v7_ca9mp_proc_info, #object -__v7_ca9mp_proc_info: - .long 0x410fc090 - .long 0xff0ffff0 - __v7_proc __v7_ca9mp_setup .size __v7_ca9mp_proc_info, . - __v7_ca9mp_proc_info - /* - * ARM Ltd. Cortex A15 processor. - */ - .type __v7_ca15mp_proc_info, #object -__v7_ca15mp_proc_info: - .long 0x410fc0f0 - .long 0xff0ffff0 - __v7_proc __v7_ca15mp_setup, hwcaps = HWCAP_IDIV - .size __v7_ca15mp_proc_info, . - __v7_ca15mp_proc_info - /* * Match any ARMv7 processor core. */ @@ -491,5 +478,27 @@ __v7_ca15mp_proc_info: __v7_proc_info: .long 0x000f0000 @ Required ID value .long 0x000f0000 @ Mask for ID - __v7_proc __v7_setup + ALT_SMP(.long \ + PMD_TYPE_SECT | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ | \ + PMD_FLAGS_SMP) + ALT_UP(.long \ + PMD_TYPE_SECT | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ | \ + PMD_FLAGS_UP) + .long PMD_TYPE_SECT | \ + PMD_SECT_XN | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + W(b) __v7_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_TLS + .long cpu_v7_name + .long v7_processor_functions + .long v7wbi_tlb_fns + .long v6_user_fns + .long v7_cache_fns .size __v7_proc_info, . - __v7_proc_info diff --git a/trunk/arch/arm/mm/proc-xsc3.S b/trunk/arch/arm/mm/proc-xsc3.S index 64f1fc7edf0a..596213699f37 100644 --- a/trunk/arch/arm/mm/proc-xsc3.S +++ b/trunk/arch/arm/mm/proc-xsc3.S @@ -335,8 +335,17 @@ ENTRY(xsc3_dma_unmap_area) mov pc, lr ENDPROC(xsc3_dma_unmap_area) - @ define struct cpu_cache_fns (see and proc-macros.S) - define_cache_functions xsc3 +ENTRY(xsc3_cache_fns) + .long xsc3_flush_icache_all + .long xsc3_flush_kern_cache_all + .long xsc3_flush_user_cache_all + .long xsc3_flush_user_cache_range + .long xsc3_coherent_kern_range + .long xsc3_coherent_user_range + .long xsc3_flush_kern_dcache_area + .long xsc3_dma_map_area + .long xsc3_dma_unmap_area + .long xsc3_dma_flush_range ENTRY(cpu_xsc3_dcache_clean_area) 1: mcr p15, 0, r0, c7, c10, 1 @ clean L1 D line @@ -445,6 +454,9 @@ ENTRY(cpu_xsc3_do_resume) ldr r3, =0x542e @ section flags b cpu_resume_mmu ENDPROC(cpu_xsc3_do_resume) +#else +#define cpu_xsc3_do_suspend 0 +#define cpu_xsc3_do_resume 0 #endif __CPUINIT @@ -491,24 +503,52 @@ xsc3_crval: __INITDATA - @ define struct processor (see and proc-macros.S) - define_processor_functions xsc3, dabort=v5t_early_abort, pabort=legacy_pabort, suspend=1 +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + + .type xsc3_processor_functions, #object +ENTRY(xsc3_processor_functions) + .word v5t_early_abort + .word legacy_pabort + .word cpu_xsc3_proc_init + .word cpu_xsc3_proc_fin + .word cpu_xsc3_reset + .word cpu_xsc3_do_idle + .word cpu_xsc3_dcache_clean_area + .word cpu_xsc3_switch_mm + .word cpu_xsc3_set_pte_ext + .word cpu_xsc3_suspend_size + .word cpu_xsc3_do_suspend + .word cpu_xsc3_do_resume + .size xsc3_processor_functions, . - xsc3_processor_functions .section ".rodata" - string cpu_arch_name, "armv5te" - string cpu_elf_name, "v5" - string cpu_xsc3_name, "XScale-V3 based processor" + .type cpu_arch_name, #object +cpu_arch_name: + .asciz "armv5te" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: + .asciz "v5" + .size cpu_elf_name, . - cpu_elf_name + + .type cpu_xsc3_name, #object +cpu_xsc3_name: + .asciz "XScale-V3 based processor" + .size cpu_xsc3_name, . - cpu_xsc3_name .align .section ".proc.info.init", #alloc, #execinstr -.macro xsc3_proc_info name:req, cpu_val:req, cpu_mask:req - .type __\name\()_proc_info,#object -__\name\()_proc_info: - .long \cpu_val - .long \cpu_mask + .type __xsc3_proc_info,#object +__xsc3_proc_info: + .long 0x69056000 + .long 0xffffe000 .long PMD_TYPE_SECT | \ PMD_SECT_BUFFERABLE | \ PMD_SECT_CACHEABLE | \ @@ -526,10 +566,29 @@ __\name\()_proc_info: .long v4wbi_tlb_fns .long xsc3_mc_user_fns .long xsc3_cache_fns - .size __\name\()_proc_info, . - __\name\()_proc_info -.endm - - xsc3_proc_info xsc3, 0x69056000, 0xffffe000 + .size __xsc3_proc_info, . - __xsc3_proc_info /* Note: PXA935 changed its implementor ID from Intel to Marvell */ - xsc3_proc_info xsc3_pxa935, 0x56056000, 0xffffe000 + + .type __xsc3_pxa935_proc_info,#object +__xsc3_pxa935_proc_info: + .long 0x56056000 + .long 0xffffe000 + .long PMD_TYPE_SECT | \ + PMD_SECT_BUFFERABLE | \ + PMD_SECT_CACHEABLE | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + .long PMD_TYPE_SECT | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + b __xsc3_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP + .long cpu_xsc3_name + .long xsc3_processor_functions + .long v4wbi_tlb_fns + .long xsc3_mc_user_fns + .long xsc3_cache_fns + .size __xsc3_pxa935_proc_info, . - __xsc3_pxa935_proc_info diff --git a/trunk/arch/arm/mm/proc-xscale.S b/trunk/arch/arm/mm/proc-xscale.S index fbc06e55b87a..42af97664c9d 100644 --- a/trunk/arch/arm/mm/proc-xscale.S +++ b/trunk/arch/arm/mm/proc-xscale.S @@ -390,12 +390,12 @@ ENDPROC(xscale_dma_map_area) * - size - size of region * - dir - DMA direction */ -ENTRY(xscale_80200_A0_A1_dma_map_area) +ENTRY(xscale_dma_a0_map_area) add r1, r1, r0 teq r2, #DMA_TO_DEVICE beq xscale_dma_clean_range b xscale_dma_flush_range -ENDPROC(xscale_80200_A0_A1_dma_map_area) +ENDPROC(xscale_dma_a0_map_area) /* * dma_unmap_area(start, size, dir) @@ -407,8 +407,17 @@ ENTRY(xscale_dma_unmap_area) mov pc, lr ENDPROC(xscale_dma_unmap_area) - @ define struct cpu_cache_fns (see and proc-macros.S) - define_cache_functions xscale +ENTRY(xscale_cache_fns) + .long xscale_flush_icache_all + .long xscale_flush_kern_cache_all + .long xscale_flush_user_cache_all + .long xscale_flush_user_cache_range + .long xscale_coherent_kern_range + .long xscale_coherent_user_range + .long xscale_flush_kern_dcache_area + .long xscale_dma_map_area + .long xscale_dma_unmap_area + .long xscale_dma_flush_range /* * On stepping A0/A1 of the 80200, invalidating D-cache by line doesn't @@ -423,28 +432,16 @@ ENDPROC(xscale_dma_unmap_area) * revision January 22, 2003, available at: * http://www.intel.com/design/iio/specupdt/273415.htm */ -.macro a0_alias basename - .globl xscale_80200_A0_A1_\basename - .type xscale_80200_A0_A1_\basename , %function - .equ xscale_80200_A0_A1_\basename , xscale_\basename -.endm - -/* - * Most of the cache functions are unchanged for these processor revisions. - * Export suitable alias symbols for the unchanged functions: - */ - a0_alias flush_icache_all - a0_alias flush_user_cache_all - a0_alias flush_kern_cache_all - a0_alias flush_user_cache_range - a0_alias coherent_kern_range - a0_alias coherent_user_range - a0_alias flush_kern_dcache_area - a0_alias dma_flush_range - a0_alias dma_unmap_area - - @ define struct cpu_cache_fns (see and proc-macros.S) - define_cache_functions xscale_80200_A0_A1 +ENTRY(xscale_80200_A0_A1_cache_fns) + .long xscale_flush_kern_cache_all + .long xscale_flush_user_cache_all + .long xscale_flush_user_cache_range + .long xscale_coherent_kern_range + .long xscale_coherent_user_range + .long xscale_flush_kern_dcache_area + .long xscale_dma_a0_map_area + .long xscale_dma_unmap_area + .long xscale_dma_flush_range ENTRY(cpu_xscale_dcache_clean_area) 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry @@ -554,6 +551,9 @@ ENTRY(cpu_xscale_do_resume) PMD_SECT_CACHEABLE | PMD_SECT_AP_WRITE b cpu_resume_mmu ENDPROC(cpu_xscale_do_resume) +#else +#define cpu_xscale_do_suspend 0 +#define cpu_xscale_do_resume 0 #endif __CPUINIT @@ -587,74 +587,432 @@ xscale_crval: __INITDATA - @ define struct processor (see and proc-macros.S) - define_processor_functions xscale, dabort=v5t_early_abort, pabort=legacy_pabort, suspend=1 +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + + .type xscale_processor_functions, #object +ENTRY(xscale_processor_functions) + .word v5t_early_abort + .word legacy_pabort + .word cpu_xscale_proc_init + .word cpu_xscale_proc_fin + .word cpu_xscale_reset + .word cpu_xscale_do_idle + .word cpu_xscale_dcache_clean_area + .word cpu_xscale_switch_mm + .word cpu_xscale_set_pte_ext + .word cpu_xscale_suspend_size + .word cpu_xscale_do_suspend + .word cpu_xscale_do_resume + .size xscale_processor_functions, . - xscale_processor_functions .section ".rodata" - string cpu_arch_name, "armv5te" - string cpu_elf_name, "v5" - - string cpu_80200_A0_A1_name, "XScale-80200 A0/A1" - string cpu_80200_name, "XScale-80200" - string cpu_80219_name, "XScale-80219" - string cpu_8032x_name, "XScale-IOP8032x Family" - string cpu_8033x_name, "XScale-IOP8033x Family" - string cpu_pxa250_name, "XScale-PXA250" - string cpu_pxa210_name, "XScale-PXA210" - string cpu_ixp42x_name, "XScale-IXP42x Family" - string cpu_ixp43x_name, "XScale-IXP43x Family" - string cpu_ixp46x_name, "XScale-IXP46x Family" - string cpu_ixp2400_name, "XScale-IXP2400" - string cpu_ixp2800_name, "XScale-IXP2800" - string cpu_pxa255_name, "XScale-PXA255" - string cpu_pxa270_name, "XScale-PXA270" + .type cpu_arch_name, #object +cpu_arch_name: + .asciz "armv5te" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: + .asciz "v5" + .size cpu_elf_name, . - cpu_elf_name + + .type cpu_80200_A0_A1_name, #object +cpu_80200_A0_A1_name: + .asciz "XScale-80200 A0/A1" + .size cpu_80200_A0_A1_name, . - cpu_80200_A0_A1_name + + .type cpu_80200_name, #object +cpu_80200_name: + .asciz "XScale-80200" + .size cpu_80200_name, . - cpu_80200_name + + .type cpu_80219_name, #object +cpu_80219_name: + .asciz "XScale-80219" + .size cpu_80219_name, . - cpu_80219_name + + .type cpu_8032x_name, #object +cpu_8032x_name: + .asciz "XScale-IOP8032x Family" + .size cpu_8032x_name, . - cpu_8032x_name + + .type cpu_8033x_name, #object +cpu_8033x_name: + .asciz "XScale-IOP8033x Family" + .size cpu_8033x_name, . - cpu_8033x_name + + .type cpu_pxa250_name, #object +cpu_pxa250_name: + .asciz "XScale-PXA250" + .size cpu_pxa250_name, . - cpu_pxa250_name + + .type cpu_pxa210_name, #object +cpu_pxa210_name: + .asciz "XScale-PXA210" + .size cpu_pxa210_name, . - cpu_pxa210_name + + .type cpu_ixp42x_name, #object +cpu_ixp42x_name: + .asciz "XScale-IXP42x Family" + .size cpu_ixp42x_name, . - cpu_ixp42x_name + + .type cpu_ixp43x_name, #object +cpu_ixp43x_name: + .asciz "XScale-IXP43x Family" + .size cpu_ixp43x_name, . - cpu_ixp43x_name + + .type cpu_ixp46x_name, #object +cpu_ixp46x_name: + .asciz "XScale-IXP46x Family" + .size cpu_ixp46x_name, . - cpu_ixp46x_name + + .type cpu_ixp2400_name, #object +cpu_ixp2400_name: + .asciz "XScale-IXP2400" + .size cpu_ixp2400_name, . - cpu_ixp2400_name + + .type cpu_ixp2800_name, #object +cpu_ixp2800_name: + .asciz "XScale-IXP2800" + .size cpu_ixp2800_name, . - cpu_ixp2800_name + + .type cpu_pxa255_name, #object +cpu_pxa255_name: + .asciz "XScale-PXA255" + .size cpu_pxa255_name, . - cpu_pxa255_name + + .type cpu_pxa270_name, #object +cpu_pxa270_name: + .asciz "XScale-PXA270" + .size cpu_pxa270_name, . - cpu_pxa270_name .align .section ".proc.info.init", #alloc, #execinstr -.macro xscale_proc_info name:req, cpu_val:req, cpu_mask:req, cpu_name:req, cache - .type __\name\()_proc_info,#object -__\name\()_proc_info: - .long \cpu_val - .long \cpu_mask - .long PMD_TYPE_SECT | \ + .type __80200_A0_A1_proc_info,#object +__80200_A0_A1_proc_info: + .long 0x69052000 + .long 0xfffffffe + .long PMD_TYPE_SECT | \ + PMD_SECT_BUFFERABLE | \ + PMD_SECT_CACHEABLE | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + .long PMD_TYPE_SECT | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + b __xscale_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP + .long cpu_80200_name + .long xscale_processor_functions + .long v4wbi_tlb_fns + .long xscale_mc_user_fns + .long xscale_80200_A0_A1_cache_fns + .size __80200_A0_A1_proc_info, . - __80200_A0_A1_proc_info + + .type __80200_proc_info,#object +__80200_proc_info: + .long 0x69052000 + .long 0xfffffff0 + .long PMD_TYPE_SECT | \ PMD_SECT_BUFFERABLE | \ PMD_SECT_CACHEABLE | \ PMD_SECT_AP_WRITE | \ PMD_SECT_AP_READ - .long PMD_TYPE_SECT | \ + .long PMD_TYPE_SECT | \ PMD_SECT_AP_WRITE | \ PMD_SECT_AP_READ b __xscale_setup .long cpu_arch_name .long cpu_elf_name .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP - .long \cpu_name + .long cpu_80200_name .long xscale_processor_functions .long v4wbi_tlb_fns .long xscale_mc_user_fns - .ifb \cache - .long xscale_cache_fns - .else - .long \cache - .endif - .size __\name\()_proc_info, . - __\name\()_proc_info -.endm - - xscale_proc_info 80200_A0_A1, 0x69052000, 0xfffffffe, cpu_80200_name, \ - cache=xscale_80200_A0_A1_cache_fns - xscale_proc_info 80200, 0x69052000, 0xfffffff0, cpu_80200_name - xscale_proc_info 80219, 0x69052e20, 0xffffffe0, cpu_80219_name - xscale_proc_info 8032x, 0x69052420, 0xfffff7e0, cpu_8032x_name - xscale_proc_info 8033x, 0x69054010, 0xfffffd30, cpu_8033x_name - xscale_proc_info pxa250, 0x69052100, 0xfffff7f0, cpu_pxa250_name - xscale_proc_info pxa210, 0x69052120, 0xfffff3f0, cpu_pxa210_name - xscale_proc_info ixp2400, 0x69054190, 0xfffffff0, cpu_ixp2400_name - xscale_proc_info ixp2800, 0x690541a0, 0xfffffff0, cpu_ixp2800_name - xscale_proc_info ixp42x, 0x690541c0, 0xffffffc0, cpu_ixp42x_name - xscale_proc_info ixp43x, 0x69054040, 0xfffffff0, cpu_ixp43x_name - xscale_proc_info ixp46x, 0x69054200, 0xffffff00, cpu_ixp46x_name - xscale_proc_info pxa255, 0x69052d00, 0xfffffff0, cpu_pxa255_name - xscale_proc_info pxa270, 0x69054110, 0xfffffff0, cpu_pxa270_name + .long xscale_cache_fns + .size __80200_proc_info, . - __80200_proc_info + + .type __80219_proc_info,#object +__80219_proc_info: + .long 0x69052e20 + .long 0xffffffe0 + .long PMD_TYPE_SECT | \ + PMD_SECT_BUFFERABLE | \ + PMD_SECT_CACHEABLE | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + .long PMD_TYPE_SECT | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + b __xscale_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP + .long cpu_80219_name + .long xscale_processor_functions + .long v4wbi_tlb_fns + .long xscale_mc_user_fns + .long xscale_cache_fns + .size __80219_proc_info, . - __80219_proc_info + + .type __8032x_proc_info,#object +__8032x_proc_info: + .long 0x69052420 + .long 0xfffff7e0 + .long PMD_TYPE_SECT | \ + PMD_SECT_BUFFERABLE | \ + PMD_SECT_CACHEABLE | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + .long PMD_TYPE_SECT | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + b __xscale_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP + .long cpu_8032x_name + .long xscale_processor_functions + .long v4wbi_tlb_fns + .long xscale_mc_user_fns + .long xscale_cache_fns + .size __8032x_proc_info, . - __8032x_proc_info + + .type __8033x_proc_info,#object +__8033x_proc_info: + .long 0x69054010 + .long 0xfffffd30 + .long PMD_TYPE_SECT | \ + PMD_SECT_BUFFERABLE | \ + PMD_SECT_CACHEABLE | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + .long PMD_TYPE_SECT | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + b __xscale_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP + .long cpu_8033x_name + .long xscale_processor_functions + .long v4wbi_tlb_fns + .long xscale_mc_user_fns + .long xscale_cache_fns + .size __8033x_proc_info, . - __8033x_proc_info + + .type __pxa250_proc_info,#object +__pxa250_proc_info: + .long 0x69052100 + .long 0xfffff7f0 + .long PMD_TYPE_SECT | \ + PMD_SECT_BUFFERABLE | \ + PMD_SECT_CACHEABLE | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + .long PMD_TYPE_SECT | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + b __xscale_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP + .long cpu_pxa250_name + .long xscale_processor_functions + .long v4wbi_tlb_fns + .long xscale_mc_user_fns + .long xscale_cache_fns + .size __pxa250_proc_info, . - __pxa250_proc_info + + .type __pxa210_proc_info,#object +__pxa210_proc_info: + .long 0x69052120 + .long 0xfffff3f0 + .long PMD_TYPE_SECT | \ + PMD_SECT_BUFFERABLE | \ + PMD_SECT_CACHEABLE | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + .long PMD_TYPE_SECT | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + b __xscale_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP + .long cpu_pxa210_name + .long xscale_processor_functions + .long v4wbi_tlb_fns + .long xscale_mc_user_fns + .long xscale_cache_fns + .size __pxa210_proc_info, . - __pxa210_proc_info + + .type __ixp2400_proc_info, #object +__ixp2400_proc_info: + .long 0x69054190 + .long 0xfffffff0 + .long PMD_TYPE_SECT | \ + PMD_SECT_BUFFERABLE | \ + PMD_SECT_CACHEABLE | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + .long PMD_TYPE_SECT | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + b __xscale_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP + .long cpu_ixp2400_name + .long xscale_processor_functions + .long v4wbi_tlb_fns + .long xscale_mc_user_fns + .long xscale_cache_fns + .size __ixp2400_proc_info, . - __ixp2400_proc_info + + .type __ixp2800_proc_info, #object +__ixp2800_proc_info: + .long 0x690541a0 + .long 0xfffffff0 + .long PMD_TYPE_SECT | \ + PMD_SECT_BUFFERABLE | \ + PMD_SECT_CACHEABLE | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + .long PMD_TYPE_SECT | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + b __xscale_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP + .long cpu_ixp2800_name + .long xscale_processor_functions + .long v4wbi_tlb_fns + .long xscale_mc_user_fns + .long xscale_cache_fns + .size __ixp2800_proc_info, . - __ixp2800_proc_info + + .type __ixp42x_proc_info, #object +__ixp42x_proc_info: + .long 0x690541c0 + .long 0xffffffc0 + .long PMD_TYPE_SECT | \ + PMD_SECT_BUFFERABLE | \ + PMD_SECT_CACHEABLE | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + .long PMD_TYPE_SECT | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + b __xscale_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP + .long cpu_ixp42x_name + .long xscale_processor_functions + .long v4wbi_tlb_fns + .long xscale_mc_user_fns + .long xscale_cache_fns + .size __ixp42x_proc_info, . - __ixp42x_proc_info + + .type __ixp43x_proc_info, #object +__ixp43x_proc_info: + .long 0x69054040 + .long 0xfffffff0 + .long PMD_TYPE_SECT | \ + PMD_SECT_BUFFERABLE | \ + PMD_SECT_CACHEABLE | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + .long PMD_TYPE_SECT | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + b __xscale_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP + .long cpu_ixp43x_name + .long xscale_processor_functions + .long v4wbi_tlb_fns + .long xscale_mc_user_fns + .long xscale_cache_fns + .size __ixp43x_proc_info, . - __ixp43x_proc_info + + .type __ixp46x_proc_info, #object +__ixp46x_proc_info: + .long 0x69054200 + .long 0xffffff00 + .long PMD_TYPE_SECT | \ + PMD_SECT_BUFFERABLE | \ + PMD_SECT_CACHEABLE | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + .long PMD_TYPE_SECT | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + b __xscale_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP + .long cpu_ixp46x_name + .long xscale_processor_functions + .long v4wbi_tlb_fns + .long xscale_mc_user_fns + .long xscale_cache_fns + .size __ixp46x_proc_info, . - __ixp46x_proc_info + + .type __pxa255_proc_info,#object +__pxa255_proc_info: + .long 0x69052d00 + .long 0xfffffff0 + .long PMD_TYPE_SECT | \ + PMD_SECT_BUFFERABLE | \ + PMD_SECT_CACHEABLE | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + .long PMD_TYPE_SECT | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + b __xscale_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP + .long cpu_pxa255_name + .long xscale_processor_functions + .long v4wbi_tlb_fns + .long xscale_mc_user_fns + .long xscale_cache_fns + .size __pxa255_proc_info, . - __pxa255_proc_info + + .type __pxa270_proc_info,#object +__pxa270_proc_info: + .long 0x69054110 + .long 0xfffffff0 + .long PMD_TYPE_SECT | \ + PMD_SECT_BUFFERABLE | \ + PMD_SECT_CACHEABLE | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + .long PMD_TYPE_SECT | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + b __xscale_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP + .long cpu_pxa270_name + .long xscale_processor_functions + .long v4wbi_tlb_fns + .long xscale_mc_user_fns + .long xscale_cache_fns + .size __pxa270_proc_info, . - __pxa270_proc_info + diff --git a/trunk/arch/arm/mm/tlb-fa.S b/trunk/arch/arm/mm/tlb-fa.S index d3ddcf9a76ca..9694f1f6f485 100644 --- a/trunk/arch/arm/mm/tlb-fa.S +++ b/trunk/arch/arm/mm/tlb-fa.S @@ -46,6 +46,7 @@ ENTRY(fa_flush_user_tlb_range) add r0, r0, #PAGE_SZ cmp r0, r1 blo 1b + mcr p15, 0, r3, c7, c5, 6 @ invalidate BTB mcr p15, 0, r3, c7, c10, 4 @ data write barrier mov pc, lr @@ -59,11 +60,16 @@ ENTRY(fa_flush_kern_tlb_range) add r0, r0, #PAGE_SZ cmp r0, r1 blo 1b + mcr p15, 0, r3, c7, c5, 6 @ invalidate BTB mcr p15, 0, r3, c7, c10, 4 @ data write barrier - mcr p15, 0, r3, c7, c5, 4 @ prefetch flush (isb) + mcr p15, 0, r3, c7, c5, 4 @ prefetch flush mov pc, lr __INITDATA - /* define struct cpu_tlb_fns (see and proc-macros.S) */ - define_tlb_functions fa, fa_tlb_flags + .type fa_tlb_fns, #object +ENTRY(fa_tlb_fns) + .long fa_flush_user_tlb_range + .long fa_flush_kern_tlb_range + .long fa_tlb_flags + .size fa_tlb_fns, . - fa_tlb_fns diff --git a/trunk/arch/arm/mm/tlb-v3.S b/trunk/arch/arm/mm/tlb-v3.S index d253995ec4ca..c10786ec8e0a 100644 --- a/trunk/arch/arm/mm/tlb-v3.S +++ b/trunk/arch/arm/mm/tlb-v3.S @@ -44,5 +44,9 @@ ENTRY(v3_flush_kern_tlb_range) __INITDATA - /* define struct cpu_tlb_fns (see and proc-macros.S) */ - define_tlb_functions v3, v3_tlb_flags + .type v3_tlb_fns, #object +ENTRY(v3_tlb_fns) + .long v3_flush_user_tlb_range + .long v3_flush_kern_tlb_range + .long v3_tlb_flags + .size v3_tlb_fns, . - v3_tlb_fns diff --git a/trunk/arch/arm/mm/tlb-v4.S b/trunk/arch/arm/mm/tlb-v4.S index 17a025ade573..d6c94457c2b9 100644 --- a/trunk/arch/arm/mm/tlb-v4.S +++ b/trunk/arch/arm/mm/tlb-v4.S @@ -57,5 +57,9 @@ ENTRY(v4_flush_user_tlb_range) __INITDATA - /* define struct cpu_tlb_fns (see and proc-macros.S) */ - define_tlb_functions v4, v4_tlb_flags + .type v4_tlb_fns, #object +ENTRY(v4_tlb_fns) + .long v4_flush_user_tlb_range + .long v4_flush_kern_tlb_range + .long v4_tlb_flags + .size v4_tlb_fns, . - v4_tlb_fns diff --git a/trunk/arch/arm/mm/tlb-v4wb.S b/trunk/arch/arm/mm/tlb-v4wb.S index c04598fa4d4a..cb829ca7845d 100644 --- a/trunk/arch/arm/mm/tlb-v4wb.S +++ b/trunk/arch/arm/mm/tlb-v4wb.S @@ -69,5 +69,9 @@ ENTRY(v4wb_flush_kern_tlb_range) __INITDATA - /* define struct cpu_tlb_fns (see and proc-macros.S) */ - define_tlb_functions v4wb, v4wb_tlb_flags + .type v4wb_tlb_fns, #object +ENTRY(v4wb_tlb_fns) + .long v4wb_flush_user_tlb_range + .long v4wb_flush_kern_tlb_range + .long v4wb_tlb_flags + .size v4wb_tlb_fns, . - v4wb_tlb_fns diff --git a/trunk/arch/arm/mm/tlb-v4wbi.S b/trunk/arch/arm/mm/tlb-v4wbi.S index 1f6062b6c1c1..60cfc4a25dd5 100644 --- a/trunk/arch/arm/mm/tlb-v4wbi.S +++ b/trunk/arch/arm/mm/tlb-v4wbi.S @@ -60,5 +60,9 @@ ENTRY(v4wbi_flush_kern_tlb_range) __INITDATA - /* define struct cpu_tlb_fns (see and proc-macros.S) */ - define_tlb_functions v4wbi, v4wbi_tlb_flags + .type v4wbi_tlb_fns, #object +ENTRY(v4wbi_tlb_fns) + .long v4wbi_flush_user_tlb_range + .long v4wbi_flush_kern_tlb_range + .long v4wbi_tlb_flags + .size v4wbi_tlb_fns, . - v4wbi_tlb_fns diff --git a/trunk/arch/arm/mm/tlb-v6.S b/trunk/arch/arm/mm/tlb-v6.S index eca07f550a0b..73d7d89b04c4 100644 --- a/trunk/arch/arm/mm/tlb-v6.S +++ b/trunk/arch/arm/mm/tlb-v6.S @@ -54,6 +54,7 @@ ENTRY(v6wbi_flush_user_tlb_range) add r0, r0, #PAGE_SZ cmp r0, r1 blo 1b + mcr p15, 0, ip, c7, c5, 6 @ flush BTAC/BTB mcr p15, 0, ip, c7, c10, 4 @ data synchronization barrier mov pc, lr @@ -82,11 +83,16 @@ ENTRY(v6wbi_flush_kern_tlb_range) add r0, r0, #PAGE_SZ cmp r0, r1 blo 1b + mcr p15, 0, r2, c7, c5, 6 @ flush BTAC/BTB mcr p15, 0, r2, c7, c10, 4 @ data synchronization barrier - mcr p15, 0, r2, c7, c5, 4 @ prefetch flush (isb) + mcr p15, 0, r2, c7, c5, 4 @ prefetch flush mov pc, lr __INIT - /* define struct cpu_tlb_fns (see and proc-macros.S) */ - define_tlb_functions v6wbi, v6wbi_tlb_flags + .type v6wbi_tlb_fns, #object +ENTRY(v6wbi_tlb_fns) + .long v6wbi_flush_user_tlb_range + .long v6wbi_flush_kern_tlb_range + .long v6wbi_tlb_flags + .size v6wbi_tlb_fns, . - v6wbi_tlb_fns diff --git a/trunk/arch/arm/mm/tlb-v7.S b/trunk/arch/arm/mm/tlb-v7.S index 845f461f8ec1..53cd5b454673 100644 --- a/trunk/arch/arm/mm/tlb-v7.S +++ b/trunk/arch/arm/mm/tlb-v7.S @@ -48,6 +48,9 @@ ENTRY(v7wbi_flush_user_tlb_range) add r0, r0, #PAGE_SZ cmp r0, r1 blo 1b + mov ip, #0 + ALT_SMP(mcr p15, 0, ip, c7, c1, 6) @ flush BTAC/BTB Inner Shareable + ALT_UP(mcr p15, 0, ip, c7, c5, 6) @ flush BTAC/BTB dsb mov pc, lr ENDPROC(v7wbi_flush_user_tlb_range) @@ -72,6 +75,9 @@ ENTRY(v7wbi_flush_kern_tlb_range) add r0, r0, #PAGE_SZ cmp r0, r1 blo 1b + mov r2, #0 + ALT_SMP(mcr p15, 0, r2, c7, c1, 6) @ flush BTAC/BTB Inner Shareable + ALT_UP(mcr p15, 0, r2, c7, c5, 6) @ flush BTAC/BTB dsb isb mov pc, lr @@ -79,5 +85,10 @@ ENDPROC(v7wbi_flush_kern_tlb_range) __INIT - /* define struct cpu_tlb_fns (see and proc-macros.S) */ - define_tlb_functions v7wbi, v7wbi_tlb_flags_up, flags_smp=v7wbi_tlb_flags_smp + .type v7wbi_tlb_fns, #object +ENTRY(v7wbi_tlb_fns) + .long v7wbi_flush_user_tlb_range + .long v7wbi_flush_kern_tlb_range + ALT_SMP(.long v7wbi_tlb_flags_smp) + ALT_UP(.long v7wbi_tlb_flags_up) + .size v7wbi_tlb_fns, . - v7wbi_tlb_fns diff --git a/trunk/arch/arm/plat-mxc/include/mach/entry-macro.S b/trunk/arch/arm/plat-mxc/include/mach/entry-macro.S index 066d464d322d..2e49e71b1b98 100644 --- a/trunk/arch/arm/plat-mxc/include/mach/entry-macro.S +++ b/trunk/arch/arm/plat-mxc/include/mach/entry-macro.S @@ -78,3 +78,7 @@ movs \irqnr, \irqnr #endif .endm + + @ irq priority table (not used) + .macro irq_prio_table + .endm diff --git a/trunk/arch/arm/plat-omap/clock.c b/trunk/arch/arm/plat-omap/clock.c index 964704f40bbe..c9122dd6ee8d 100644 --- a/trunk/arch/arm/plat-omap/clock.c +++ b/trunk/arch/arm/plat-omap/clock.c @@ -480,10 +480,13 @@ static struct dentry *clk_debugfs_root; static int clk_debugfs_register_one(struct clk *c) { int err; - struct dentry *d; + struct dentry *d, *child, *child_tmp; struct clk *pa = c->parent; + char s[255]; + char *p = s; - d = debugfs_create_dir(c->name, pa ? pa->dent : clk_debugfs_root); + p += sprintf(p, "%s", c->name); + d = debugfs_create_dir(s, pa ? pa->dent : clk_debugfs_root); if (!d) return -ENOMEM; c->dent = d; @@ -506,7 +509,10 @@ static int clk_debugfs_register_one(struct clk *c) return 0; err_out: - debugfs_remove_recursive(c->dent); + d = c->dent; + list_for_each_entry_safe(child, child_tmp, &d->d_subdirs, d_u.d_child) + debugfs_remove(child); + debugfs_remove(c->dent); return err; } diff --git a/trunk/arch/arm/plat-omap/sram.c b/trunk/arch/arm/plat-omap/sram.c index 363c91e44efb..6af3d0b1f8d0 100644 --- a/trunk/arch/arm/plat-omap/sram.c +++ b/trunk/arch/arm/plat-omap/sram.c @@ -394,15 +394,20 @@ void omap3_sram_restore_context(void) } #endif /* CONFIG_PM */ -#endif /* CONFIG_ARCH_OMAP3 */ - +static int __init omap34xx_sram_init(void) +{ + _omap3_sram_configure_core_dpll = + omap_sram_push(omap3_sram_configure_core_dpll, + omap3_sram_configure_core_dpll_sz); + omap_push_sram_idle(); + return 0; +} +#else static inline int omap34xx_sram_init(void) { -#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM) - omap3_sram_restore_context(); -#endif return 0; } +#endif int __init omap_sram_init(void) { diff --git a/trunk/arch/arm/plat-s3c24xx/sleep.S b/trunk/arch/arm/plat-s3c24xx/sleep.S index c56612569b40..fd7032f84ae7 100644 --- a/trunk/arch/arm/plat-s3c24xx/sleep.S +++ b/trunk/arch/arm/plat-s3c24xx/sleep.S @@ -41,6 +41,31 @@ .text + /* s3c_cpu_save + * + * entry: + * r1 = v:p offset + */ + +ENTRY(s3c_cpu_save) + stmfd sp!, { r4 - r12, lr } + ldr r3, =resume_with_mmu + bl cpu_suspend + + @@ jump to final code to send system to sleep + ldr r0, =pm_cpu_sleep + @@ldr pc, [ r0 ] + ldr r0, [ r0 ] + mov pc, r0 + + @@ return to the caller, after having the MMU + @@ turned on, this restores the last bits from the + @@ stack +resume_with_mmu: + ldmfd sp!, { r4 - r12, pc } + + .ltorg + /* sleep magic, to allow the bootloader to check for an valid * image to resume to. Must be the first word before the * s3c_cpu_resume entry. diff --git a/trunk/arch/arm/plat-samsung/clock.c b/trunk/arch/arm/plat-samsung/clock.c index 0c9f95d98561..772892826ffc 100644 --- a/trunk/arch/arm/plat-samsung/clock.c +++ b/trunk/arch/arm/plat-samsung/clock.c @@ -458,7 +458,7 @@ static struct dentry *clk_debugfs_root; static int clk_debugfs_register_one(struct clk *c) { int err; - struct dentry *d; + struct dentry *d, *child, *child_tmp; struct clk *pa = c->parent; char s[255]; char *p = s; @@ -488,7 +488,10 @@ static int clk_debugfs_register_one(struct clk *c) return 0; err_out: - debugfs_remove_recursive(c->dent); + d = c->dent; + list_for_each_entry_safe(child, child_tmp, &d->d_subdirs, d_u.d_child) + debugfs_remove(child); + debugfs_remove(c->dent); return err; } diff --git a/trunk/arch/arm/plat-samsung/include/plat/pm.h b/trunk/arch/arm/plat-samsung/include/plat/pm.h index f6749916d194..7fb6f6be8c81 100644 --- a/trunk/arch/arm/plat-samsung/include/plat/pm.h +++ b/trunk/arch/arm/plat-samsung/include/plat/pm.h @@ -42,7 +42,7 @@ extern unsigned long s3c_irqwake_eintallow; /* per-cpu sleep functions */ extern void (*pm_cpu_prep)(void); -extern int (*pm_cpu_sleep)(unsigned long); +extern void (*pm_cpu_sleep)(void); /* Flags for PM Control */ @@ -52,9 +52,10 @@ extern unsigned char pm_uart_udivslot; /* true to save UART UDIVSLOT */ /* from sleep.S */ +extern int s3c_cpu_save(unsigned long *saveblk, long); extern void s3c_cpu_resume(void); -extern int s3c2410_cpu_suspend(unsigned long); +extern void s3c2410_cpu_suspend(void); /* sleep save info */ diff --git a/trunk/arch/arm/plat-samsung/pm.c b/trunk/arch/arm/plat-samsung/pm.c index 5fa1742d019b..5c0a440d6e16 100644 --- a/trunk/arch/arm/plat-samsung/pm.c +++ b/trunk/arch/arm/plat-samsung/pm.c @@ -20,7 +20,6 @@ #include #include -#include #include #include @@ -232,7 +231,7 @@ static void __maybe_unused s3c_pm_show_resume_irqs(int start, void (*pm_cpu_prep)(void); -int (*pm_cpu_sleep)(unsigned long); +void (*pm_cpu_sleep)(void); #define any_allowed(mask, allow) (((mask) & (allow)) != (allow)) @@ -295,11 +294,15 @@ static int s3c_pm_enter(suspend_state_t state) s3c_pm_arch_stop_clocks(); - /* this will also act as our return point from when + /* s3c_cpu_save will also act as our return point from when * we resume as it saves its own register state and restores it * during the resume. */ - cpu_suspend(0, pm_cpu_sleep); + s3c_cpu_save(0, PLAT_PHYS_OFFSET - PAGE_OFFSET); + + /* restore the cpu state using the kernel's cpu init code. */ + + cpu_init(); /* restore the system state */ diff --git a/trunk/arch/arm/plat-spear/clock.c b/trunk/arch/arm/plat-spear/clock.c index 67dd00381ea6..6fa474cb398e 100644 --- a/trunk/arch/arm/plat-spear/clock.c +++ b/trunk/arch/arm/plat-spear/clock.c @@ -916,7 +916,7 @@ static struct dentry *clk_debugfs_root; static int clk_debugfs_register_one(struct clk *c) { int err; - struct dentry *d; + struct dentry *d, *child; struct clk *pa = c->pclk; char s[255]; char *p = s; @@ -951,7 +951,10 @@ static int clk_debugfs_register_one(struct clk *c) return 0; err_out: - debugfs_remove_recursive(c->dent); + d = c->dent; + list_for_each_entry(child, &d->d_subdirs, d_u.d_child) + debugfs_remove(child); + debugfs_remove(c->dent); return err; } diff --git a/trunk/arch/arm/vfp/vfphw.S b/trunk/arch/arm/vfp/vfphw.S index 2d30c7f6edd3..9897dcfc16d6 100644 --- a/trunk/arch/arm/vfp/vfphw.S +++ b/trunk/arch/arm/vfp/vfphw.S @@ -77,27 +77,27 @@ ENTRY(vfp_support_entry) bne look_for_VFP_exceptions @ VFP is already enabled DBGSTR1 "enable %x", r10 - ldr r3, vfp_current_hw_state_address + ldr r3, last_VFP_context_address orr r1, r1, #FPEXC_EN @ user FPEXC has the enable bit set - ldr r4, [r3, r11, lsl #2] @ vfp_current_hw_state pointer + ldr r4, [r3, r11, lsl #2] @ last_VFP_context pointer bic r5, r1, #FPEXC_EX @ make sure exceptions are disabled - cmp r4, r10 @ this thread owns the hw context? -#ifndef CONFIG_SMP - @ For UP, checking that this thread owns the hw context is - @ sufficient to determine that the hardware state is valid. - beq vfp_hw_state_valid - - @ On UP, we lazily save the VFP context. As a different - @ thread wants ownership of the VFP hardware, save the old - @ state if there was a previous (valid) owner. + cmp r4, r10 + beq check_for_exception @ we are returning to the same + @ process, so the registers are + @ still there. In this case, we do + @ not want to drop a pending exception. VFPFMXR FPEXC, r5 @ enable VFP, disable any pending @ exceptions, so we can get at the @ rest of it +#ifndef CONFIG_SMP + @ Save out the current registers to the old thread state + @ No need for SMP since this is not done lazily + DBGSTR1 "save old state %p", r4 - cmp r4, #0 @ if the vfp_current_hw_state is NULL - beq vfp_reload_hw @ then the hw state needs reloading + cmp r4, #0 + beq no_old_VFP_process VFPFSTMIA r4, r5 @ save the working registers VFPFMRX r5, FPSCR @ current status #ifndef CONFIG_CPU_FEROCEON @@ -110,35 +110,13 @@ ENTRY(vfp_support_entry) 1: #endif stmia r4, {r1, r5, r6, r8} @ save FPEXC, FPSCR, FPINST, FPINST2 -vfp_reload_hw: - -#else - @ For SMP, if this thread does not own the hw context, then we - @ need to reload it. No need to save the old state as on SMP, - @ we always save the state when we switch away from a thread. - bne vfp_reload_hw - - @ This thread has ownership of the current hardware context. - @ However, it may have been migrated to another CPU, in which - @ case the saved state is newer than the hardware context. - @ Check this by looking at the CPU number which the state was - @ last loaded onto. - ldr ip, [r10, #VFP_CPU] - teq ip, r11 - beq vfp_hw_state_valid - -vfp_reload_hw: - @ We're loading this threads state into the VFP hardware. Update - @ the CPU number which contains the most up to date VFP context. - str r11, [r10, #VFP_CPU] - - VFPFMXR FPEXC, r5 @ enable VFP, disable any pending - @ exceptions, so we can get at the - @ rest of it + @ and point r4 at the word at the + @ start of the register dump #endif +no_old_VFP_process: DBGSTR1 "load state %p", r10 - str r10, [r3, r11, lsl #2] @ update the vfp_current_hw_state pointer + str r10, [r3, r11, lsl #2] @ update the last_VFP_context pointer @ Load the saved state back into the VFP VFPFLDMIA r10, r5 @ reload the working registers while @ FPEXC is in a safe state @@ -154,8 +132,7 @@ vfp_reload_hw: #endif VFPFMXR FPSCR, r5 @ restore status -@ The context stored in the VFP hardware is up to date with this thread -vfp_hw_state_valid: +check_for_exception: tst r1, #FPEXC_EX bne process_exception @ might as well handle the pending @ exception before retrying branch @@ -230,8 +207,8 @@ ENTRY(vfp_save_state) ENDPROC(vfp_save_state) .align -vfp_current_hw_state_address: - .word vfp_current_hw_state +last_VFP_context_address: + .word last_VFP_context .macro tbl_branch, base, tmp, shift #ifdef CONFIG_THUMB2_KERNEL diff --git a/trunk/arch/arm/vfp/vfpmodule.c b/trunk/arch/arm/vfp/vfpmodule.c index 79bcb4316930..f25e7ec89416 100644 --- a/trunk/arch/arm/vfp/vfpmodule.c +++ b/trunk/arch/arm/vfp/vfpmodule.c @@ -33,6 +33,7 @@ void vfp_support_entry(void); void vfp_null_entry(void); void (*vfp_vector)(void) = vfp_null_entry; +union vfp_state *last_VFP_context[NR_CPUS]; /* * Dual-use variable. @@ -41,46 +42,6 @@ void (*vfp_vector)(void) = vfp_null_entry; */ unsigned int VFP_arch; -/* - * The pointer to the vfpstate structure of the thread which currently - * owns the context held in the VFP hardware, or NULL if the hardware - * context is invalid. - * - * For UP, this is sufficient to tell which thread owns the VFP context. - * However, for SMP, we also need to check the CPU number stored in the - * saved state too to catch migrations. - */ -union vfp_state *vfp_current_hw_state[NR_CPUS]; - -/* - * Is 'thread's most up to date state stored in this CPUs hardware? - * Must be called from non-preemptible context. - */ -static bool vfp_state_in_hw(unsigned int cpu, struct thread_info *thread) -{ -#ifdef CONFIG_SMP - if (thread->vfpstate.hard.cpu != cpu) - return false; -#endif - return vfp_current_hw_state[cpu] == &thread->vfpstate; -} - -/* - * Force a reload of the VFP context from the thread structure. We do - * this by ensuring that access to the VFP hardware is disabled, and - * clear last_VFP_context. Must be called from non-preemptible context. - */ -static void vfp_force_reload(unsigned int cpu, struct thread_info *thread) -{ - if (vfp_state_in_hw(cpu, thread)) { - fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN); - vfp_current_hw_state[cpu] = NULL; - } -#ifdef CONFIG_SMP - thread->vfpstate.hard.cpu = NR_CPUS; -#endif -} - /* * Per-thread VFP initialization. */ @@ -89,27 +50,21 @@ static void vfp_thread_flush(struct thread_info *thread) union vfp_state *vfp = &thread->vfpstate; unsigned int cpu; + memset(vfp, 0, sizeof(union vfp_state)); + + vfp->hard.fpexc = FPEXC_EN; + vfp->hard.fpscr = FPSCR_ROUND_NEAREST; + /* * Disable VFP to ensure we initialize it first. We must ensure - * that the modification of vfp_current_hw_state[] and hardware - * disable are done for the same CPU and without preemption. - * - * Do this first to ensure that preemption won't overwrite our - * state saving should access to the VFP be enabled at this point. + * that the modification of last_VFP_context[] and hardware disable + * are done for the same CPU and without preemption. */ cpu = get_cpu(); - if (vfp_current_hw_state[cpu] == vfp) - vfp_current_hw_state[cpu] = NULL; + if (last_VFP_context[cpu] == vfp) + last_VFP_context[cpu] = NULL; fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN); put_cpu(); - - memset(vfp, 0, sizeof(union vfp_state)); - - vfp->hard.fpexc = FPEXC_EN; - vfp->hard.fpscr = FPSCR_ROUND_NEAREST; -#ifdef CONFIG_SMP - vfp->hard.cpu = NR_CPUS; -#endif } static void vfp_thread_exit(struct thread_info *thread) @@ -118,8 +73,8 @@ static void vfp_thread_exit(struct thread_info *thread) union vfp_state *vfp = &thread->vfpstate; unsigned int cpu = get_cpu(); - if (vfp_current_hw_state[cpu] == vfp) - vfp_current_hw_state[cpu] = NULL; + if (last_VFP_context[cpu] == vfp) + last_VFP_context[cpu] = NULL; put_cpu(); } @@ -129,9 +84,6 @@ static void vfp_thread_copy(struct thread_info *thread) vfp_sync_hwstate(parent); thread->vfpstate = parent->vfpstate; -#ifdef CONFIG_SMP - thread->vfpstate.hard.cpu = NR_CPUS; -#endif } /* @@ -177,8 +129,17 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v) * case the thread migrates to a different CPU. The * restoring is done lazily. */ - if ((fpexc & FPEXC_EN) && vfp_current_hw_state[cpu]) - vfp_save_state(vfp_current_hw_state[cpu], fpexc); + if ((fpexc & FPEXC_EN) && last_VFP_context[cpu]) { + vfp_save_state(last_VFP_context[cpu], fpexc); + last_VFP_context[cpu]->hard.cpu = cpu; + } + /* + * Thread migration, just force the reloading of the + * state on the new CPU in case the VFP registers + * contain stale data. + */ + if (thread->vfpstate.hard.cpu != cpu) + last_VFP_context[cpu] = NULL; #endif /* @@ -454,7 +415,7 @@ static int vfp_pm_suspend(void) } /* clear any information we had about last context state */ - memset(vfp_current_hw_state, 0, sizeof(vfp_current_hw_state)); + memset(last_VFP_context, 0, sizeof(last_VFP_context)); return 0; } @@ -482,15 +443,15 @@ static void vfp_pm_init(void) static inline void vfp_pm_init(void) { } #endif /* CONFIG_PM */ -/* - * Ensure that the VFP state stored in 'thread->vfpstate' is up to date - * with the hardware state. - */ void vfp_sync_hwstate(struct thread_info *thread) { unsigned int cpu = get_cpu(); - if (vfp_state_in_hw(cpu, thread)) { + /* + * If the thread we're interested in is the current owner of the + * hardware VFP state, then we need to save its state. + */ + if (last_VFP_context[cpu] == &thread->vfpstate) { u32 fpexc = fmrx(FPEXC); /* @@ -504,13 +465,36 @@ void vfp_sync_hwstate(struct thread_info *thread) put_cpu(); } -/* Ensure that the thread reloads the hardware VFP state on the next use. */ void vfp_flush_hwstate(struct thread_info *thread) { unsigned int cpu = get_cpu(); - vfp_force_reload(cpu, thread); + /* + * If the thread we're interested in is the current owner of the + * hardware VFP state, then we need to save its state. + */ + if (last_VFP_context[cpu] == &thread->vfpstate) { + u32 fpexc = fmrx(FPEXC); + fmxr(FPEXC, fpexc & ~FPEXC_EN); + + /* + * Set the context to NULL to force a reload the next time + * the thread uses the VFP. + */ + last_VFP_context[cpu] = NULL; + } + +#ifdef CONFIG_SMP + /* + * For SMP we still have to take care of the case where the thread + * migrates to another CPU and then back to the original CPU on which + * the last VFP user is still the same thread. Mark the thread VFP + * state as belonging to a non-existent CPU so that the saved one will + * be reloaded in the above case. + */ + thread->vfpstate.hard.cpu = NR_CPUS; +#endif put_cpu(); } @@ -529,7 +513,8 @@ static int vfp_hotplug(struct notifier_block *b, unsigned long action, void *hcpu) { if (action == CPU_DYING || action == CPU_DYING_FROZEN) { - vfp_force_reload((long)hcpu, current_thread_info()); + unsigned int cpu = (long)hcpu; + last_VFP_context[cpu] = NULL; } else if (action == CPU_STARTING || action == CPU_STARTING_FROZEN) vfp_enable(NULL); return NOTIFY_OK; @@ -597,6 +582,7 @@ static int __init vfp_init(void) elf_hwcap |= HWCAP_VFPv3D16; } #endif +#ifdef CONFIG_NEON /* * Check for the presence of the Advanced SIMD * load/store instructions, integer and single @@ -604,13 +590,10 @@ static int __init vfp_init(void) * for NEON if the hardware has the MVFR registers. */ if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) { -#ifdef CONFIG_NEON if ((fmrx(MVFR1) & 0x000fff00) == 0x00011100) elf_hwcap |= HWCAP_NEON; -#endif - if ((fmrx(MVFR1) & 0xf0000000) == 0x10000000) - elf_hwcap |= HWCAP_VFPv4; } +#endif } return 0; } diff --git a/trunk/arch/avr32/include/asm/delay.h b/trunk/arch/avr32/include/asm/delay.h index 9670e127b7b2..a0ed9a9839a5 100644 --- a/trunk/arch/avr32/include/asm/delay.h +++ b/trunk/arch/avr32/include/asm/delay.h @@ -1 +1,26 @@ -#include +#ifndef __ASM_AVR32_DELAY_H +#define __ASM_AVR32_DELAY_H + +/* + * Copyright (C) 1993 Linus Torvalds + * + * Delay routines calling functions in arch/avr32/lib/delay.c + */ + +extern void __bad_udelay(void); +extern void __bad_ndelay(void); + +extern void __udelay(unsigned long usecs); +extern void __ndelay(unsigned long nsecs); +extern void __const_udelay(unsigned long xloops); +extern void __delay(unsigned long loops); + +#define udelay(n) (__builtin_constant_p(n) ? \ + ((n) > 20000 ? __bad_udelay() : __const_udelay((n) * 0x10c6ul)) : \ + __udelay(n)) + +#define ndelay(n) (__builtin_constant_p(n) ? \ + ((n) > 20000 ? __bad_ndelay() : __const_udelay((n) * 5ul)) : \ + __ndelay(n)) + +#endif /* __ASM_AVR32_DELAY_H */ diff --git a/trunk/arch/avr32/kernel/module.c b/trunk/arch/avr32/kernel/module.c index 596f7305d93f..a727f54d64d6 100644 --- a/trunk/arch/avr32/kernel/module.c +++ b/trunk/arch/avr32/kernel/module.c @@ -19,6 +19,13 @@ #include #include +void *module_alloc(unsigned long size) +{ + if (size == 0) + return NULL; + return vmalloc(size); +} + void module_free(struct module *mod, void *module_region) { vfree(mod->arch.syminfo); @@ -292,6 +299,15 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab, return ret; } +int apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, + unsigned int symindex, unsigned int relindex, + struct module *module) +{ + printk(KERN_ERR "module %s: REL relocations are not supported\n", + module->name); + return -ENOEXEC; +} + int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, struct module *module) { @@ -300,3 +316,7 @@ int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, return 0; } + +void module_arch_cleanup(struct module *module) +{ +} diff --git a/trunk/arch/blackfin/Kconfig b/trunk/arch/blackfin/Kconfig index c7476295de80..d619b17c4413 100644 --- a/trunk/arch/blackfin/Kconfig +++ b/trunk/arch/blackfin/Kconfig @@ -953,16 +953,6 @@ config BFIN_GPTIMERS To compile this driver as a module, choose M here: the module will be called gptimers. -config HAVE_PWM - tristate "Enable PWM API support" - depends on BFIN_GPTIMERS - help - Enable support for the Pulse Width Modulation framework (as - found in linux/pwm.h). - - To compile this driver as a module, choose M here: the module - will be called pwm. - choice prompt "Uncached DMA region" default DMA_UNCACHED_1M diff --git a/trunk/arch/blackfin/configs/BF561-EZKIT_defconfig b/trunk/arch/blackfin/configs/BF561-EZKIT_defconfig index d7ff2aee3fbc..1c0a82a10591 100644 --- a/trunk/arch/blackfin/configs/BF561-EZKIT_defconfig +++ b/trunk/arch/blackfin/configs/BF561-EZKIT_defconfig @@ -58,13 +58,13 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_MTD=y CONFIG_MTD_PARTITIONS=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y +CONFIG_MTD_CHAR=m CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y -CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_CFI=m +CONFIG_MTD_CFI_AMDSTD=m CONFIG_MTD_RAM=y CONFIG_MTD_ROM=m -CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP=m CONFIG_BLK_DEV_RAM=y CONFIG_NETDEVICES=y CONFIG_NET_ETHERNET=y diff --git a/trunk/arch/blackfin/include/asm/Kbuild b/trunk/arch/blackfin/include/asm/Kbuild index 7a075eaf6041..9e7c5379d3ff 100644 --- a/trunk/arch/blackfin/include/asm/Kbuild +++ b/trunk/arch/blackfin/include/asm/Kbuild @@ -1,48 +1,5 @@ include include/asm-generic/Kbuild.asm -generic-y += auxvec.h -generic-y += bitsperlong.h -generic-y += bugs.h -generic-y += cputime.h -generic-y += current.h -generic-y += device.h -generic-y += div64.h -generic-y += emergency-restart.h -generic-y += errno.h -generic-y += fb.h -generic-y += futex.h -generic-y += hw_irq.h -generic-y += ioctl.h -generic-y += ipcbuf.h -generic-y += irq_regs.h -generic-y += kdebug.h -generic-y += kmap_types.h -generic-y += local64.h -generic-y += local.h -generic-y += mman.h -generic-y += msgbuf.h -generic-y += param.h -generic-y += percpu.h -generic-y += pgalloc.h -generic-y += resource.h -generic-y += scatterlist.h -generic-y += sembuf.h -generic-y += serial.h -generic-y += setup.h -generic-y += shmbuf.h -generic-y += shmparam.h -generic-y += socket.h -generic-y += sockios.h -generic-y += statfs.h -generic-y += termbits.h -generic-y += termios.h -generic-y += topology.h -generic-y += types.h -generic-y += ucontext.h -generic-y += unaligned.h -generic-y += user.h -generic-y += xor.h - header-y += bfin_sport.h header-y += cachectl.h header-y += fixed_code.h diff --git a/trunk/arch/blackfin/include/asm/atomic.h b/trunk/arch/blackfin/include/asm/atomic.h index 4c707dbe1ff9..e48508957160 100644 --- a/trunk/arch/blackfin/include/asm/atomic.h +++ b/trunk/arch/blackfin/include/asm/atomic.h @@ -1,8 +1,8 @@ /* - * Copyright 2004-2009 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ + * Copyright 2004-2009 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ #ifndef __ARCH_BLACKFIN_ATOMIC__ #define __ARCH_BLACKFIN_ATOMIC__ @@ -76,6 +76,11 @@ static inline void atomic_set_mask(int mask, atomic_t *v) __raw_atomic_set_asm(&v->counter, mask); } +static inline int atomic_test_mask(int mask, atomic_t *v) +{ + return __raw_atomic_test_asm(&v->counter, mask); +} + /* Atomic operations are already serializing */ #define smp_mb__before_atomic_dec() barrier() #define smp_mb__after_atomic_dec() barrier() diff --git a/trunk/arch/blackfin/include/asm/auxvec.h b/trunk/arch/blackfin/include/asm/auxvec.h new file mode 100644 index 000000000000..41fa68b71287 --- /dev/null +++ b/trunk/arch/blackfin/include/asm/auxvec.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/bitsperlong.h b/trunk/arch/blackfin/include/asm/bitsperlong.h new file mode 100644 index 000000000000..6dc0bb0c13b2 --- /dev/null +++ b/trunk/arch/blackfin/include/asm/bitsperlong.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/blackfin.h b/trunk/arch/blackfin/include/asm/blackfin.h index 0928700b6bc4..eb7c1441d8f9 100644 --- a/trunk/arch/blackfin/include/asm/blackfin.h +++ b/trunk/arch/blackfin/include/asm/blackfin.h @@ -1,9 +1,9 @@ /* * Common header file for Blackfin family of processors. * - * Copyright 2004-2009 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. + * Copyright 2004-2009 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. */ #ifndef _BLACKFIN_H_ diff --git a/trunk/arch/blackfin/include/asm/bugs.h b/trunk/arch/blackfin/include/asm/bugs.h new file mode 100644 index 000000000000..61791e1ad9f5 --- /dev/null +++ b/trunk/arch/blackfin/include/asm/bugs.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/cputime.h b/trunk/arch/blackfin/include/asm/cputime.h new file mode 100644 index 000000000000..6d68ad7e0ea3 --- /dev/null +++ b/trunk/arch/blackfin/include/asm/cputime.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/current.h b/trunk/arch/blackfin/include/asm/current.h new file mode 100644 index 000000000000..4c51401b5537 --- /dev/null +++ b/trunk/arch/blackfin/include/asm/current.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/device.h b/trunk/arch/blackfin/include/asm/device.h new file mode 100644 index 000000000000..f0a4c256403b --- /dev/null +++ b/trunk/arch/blackfin/include/asm/device.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/div64.h b/trunk/arch/blackfin/include/asm/div64.h new file mode 100644 index 000000000000..6cd978cefb28 --- /dev/null +++ b/trunk/arch/blackfin/include/asm/div64.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/dpmc.h b/trunk/arch/blackfin/include/asm/dpmc.h index c4ec959dad78..edf2a2ad5183 100644 --- a/trunk/arch/blackfin/include/asm/dpmc.h +++ b/trunk/arch/blackfin/include/asm/dpmc.h @@ -117,6 +117,7 @@ #ifndef __ASSEMBLY__ void sleep_mode(u32 sic_iwr0, u32 sic_iwr1, u32 sic_iwr2); +void hibernate_mode(u32 sic_iwr0, u32 sic_iwr1, u32 sic_iwr2); void sleep_deeper(u32 sic_iwr0, u32 sic_iwr1, u32 sic_iwr2); void do_hibernate(int wakeup); void set_dram_srfs(void); @@ -133,6 +134,32 @@ struct bfin_dpmc_platform_data { unsigned short vr_settling_time; /* in us */ }; +#else + +#define PM_PUSH(x) \ + R0 = [P0 + (x - SRAM_BASE_ADDRESS)];\ + [--SP] = R0;\ + +#define PM_POP(x) \ + R0 = [SP++];\ + [P0 + (x - SRAM_BASE_ADDRESS)] = R0;\ + +#define PM_SYS_PUSH(x) \ + R0 = [P0 + (x - PLL_CTL)];\ + [--SP] = R0;\ + +#define PM_SYS_POP(x) \ + R0 = [SP++];\ + [P0 + (x - PLL_CTL)] = R0;\ + +#define PM_SYS_PUSH16(x) \ + R0 = w[P0 + (x - PLL_CTL)];\ + [--SP] = R0;\ + +#define PM_SYS_POP16(x) \ + R0 = [SP++];\ + w[P0 + (x - PLL_CTL)] = R0;\ + #endif #endif /*_BLACKFIN_DPMC_H_*/ diff --git a/trunk/arch/blackfin/include/asm/emergency-restart.h b/trunk/arch/blackfin/include/asm/emergency-restart.h new file mode 100644 index 000000000000..3711bd9d50bd --- /dev/null +++ b/trunk/arch/blackfin/include/asm/emergency-restart.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/errno.h b/trunk/arch/blackfin/include/asm/errno.h new file mode 100644 index 000000000000..4c82b503d92f --- /dev/null +++ b/trunk/arch/blackfin/include/asm/errno.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/fb.h b/trunk/arch/blackfin/include/asm/fb.h new file mode 100644 index 000000000000..3a4988e8df45 --- /dev/null +++ b/trunk/arch/blackfin/include/asm/fb.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/futex.h b/trunk/arch/blackfin/include/asm/futex.h new file mode 100644 index 000000000000..0b745828f42b --- /dev/null +++ b/trunk/arch/blackfin/include/asm/futex.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/gpio.h b/trunk/arch/blackfin/include/asm/gpio.h index 5a25856381ff..1ef8417f5d27 100644 --- a/trunk/arch/blackfin/include/asm/gpio.h +++ b/trunk/arch/blackfin/include/asm/gpio.h @@ -16,13 +16,58 @@ #include +#define GPIO_0 0 +#define GPIO_1 1 +#define GPIO_2 2 +#define GPIO_3 3 +#define GPIO_4 4 +#define GPIO_5 5 +#define GPIO_6 6 +#define GPIO_7 7 +#define GPIO_8 8 +#define GPIO_9 9 +#define GPIO_10 10 +#define GPIO_11 11 +#define GPIO_12 12 +#define GPIO_13 13 +#define GPIO_14 14 +#define GPIO_15 15 +#define GPIO_16 16 +#define GPIO_17 17 +#define GPIO_18 18 +#define GPIO_19 19 +#define GPIO_20 20 +#define GPIO_21 21 +#define GPIO_22 22 +#define GPIO_23 23 +#define GPIO_24 24 +#define GPIO_25 25 +#define GPIO_26 26 +#define GPIO_27 27 +#define GPIO_28 28 +#define GPIO_29 29 +#define GPIO_30 30 +#define GPIO_31 31 +#define GPIO_32 32 +#define GPIO_33 33 +#define GPIO_34 34 +#define GPIO_35 35 +#define GPIO_36 36 +#define GPIO_37 37 +#define GPIO_38 38 +#define GPIO_39 39 +#define GPIO_40 40 +#define GPIO_41 41 +#define GPIO_42 42 +#define GPIO_43 43 +#define GPIO_44 44 +#define GPIO_45 45 +#define GPIO_46 46 +#define GPIO_47 47 + #define PERIPHERAL_USAGE 1 #define GPIO_USAGE 0 -#ifndef BFIN_GPIO_PINT -# define BFIN_GPIO_PINT 0 -#endif - #ifndef __ASSEMBLY__ #include @@ -44,7 +89,7 @@ * MODIFICATION HISTORY : **************************************************************/ -#if !BFIN_GPIO_PINT +#ifndef CONFIG_BF54x void set_gpio_dir(unsigned, unsigned short); void set_gpio_inen(unsigned, unsigned short); void set_gpio_polar(unsigned, unsigned short); @@ -119,10 +164,6 @@ struct gpio_port_t { #ifdef BFIN_SPECIAL_GPIO_BANKS void bfin_special_gpio_free(unsigned gpio); int bfin_special_gpio_request(unsigned gpio, const char *label); -# ifdef CONFIG_PM -void bfin_special_gpio_pm_hibernate_restore(void); -void bfin_special_gpio_pm_hibernate_suspend(void); -# endif #endif #ifdef CONFIG_PM @@ -141,7 +182,7 @@ static inline void bfin_pm_standby_restore(void) void bfin_gpio_pm_hibernate_restore(void); void bfin_gpio_pm_hibernate_suspend(void); -# if !BFIN_GPIO_PINT +#ifndef CONFIG_BF54x int gpio_pm_wakeup_ctrl(unsigned gpio, unsigned ctrl); struct gpio_port_s { @@ -158,9 +199,8 @@ struct gpio_port_s { unsigned short reserved; unsigned short mux; }; -# endif +#endif /*CONFIG_BF54x*/ #endif /*CONFIG_PM*/ - /*********************************************************** * * FUNCTIONS: Blackfin GPIO Driver diff --git a/trunk/arch/blackfin/include/asm/gptimers.h b/trunk/arch/blackfin/include/asm/gptimers.h index 38bddcb190c8..38657dac1235 100644 --- a/trunk/arch/blackfin/include/asm/gptimers.h +++ b/trunk/arch/blackfin/include/asm/gptimers.h @@ -193,16 +193,6 @@ uint16_t get_enabled_gptimers(void); uint32_t get_gptimer_status(unsigned int group); void set_gptimer_status(unsigned int group, uint32_t value); -static inline void enable_gptimer(unsigned int timer_id) -{ - enable_gptimers(1 << timer_id); -} - -static inline void disable_gptimer(unsigned int timer_id) -{ - disable_gptimers(1 << timer_id); -} - /* * All Blackfin system MMRs are padded to 32bits even if the register * itself is only 16bits. So use a helper macro to streamline this. @@ -219,15 +209,6 @@ struct bfin_gptimer_regs { u32 width; }; -/* - * bfin group timer registers layout - */ -struct bfin_gptimer_group_regs { - __BFP(enable); - __BFP(disable); - u32 status; -}; - #undef __BFP #endif diff --git a/trunk/arch/blackfin/include/asm/hw_irq.h b/trunk/arch/blackfin/include/asm/hw_irq.h new file mode 100644 index 000000000000..1f5ef7da0045 --- /dev/null +++ b/trunk/arch/blackfin/include/asm/hw_irq.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/ioctl.h b/trunk/arch/blackfin/include/asm/ioctl.h new file mode 100644 index 000000000000..b279fe06dfe5 --- /dev/null +++ b/trunk/arch/blackfin/include/asm/ioctl.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/ipcbuf.h b/trunk/arch/blackfin/include/asm/ipcbuf.h new file mode 100644 index 000000000000..84c7e51cb6d0 --- /dev/null +++ b/trunk/arch/blackfin/include/asm/ipcbuf.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/irq_regs.h b/trunk/arch/blackfin/include/asm/irq_regs.h new file mode 100644 index 000000000000..3dd9c0b70270 --- /dev/null +++ b/trunk/arch/blackfin/include/asm/irq_regs.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/irqflags.h b/trunk/arch/blackfin/include/asm/irqflags.h index 43eb4749de3d..b4bbb75a9e15 100644 --- a/trunk/arch/blackfin/include/asm/irqflags.h +++ b/trunk/arch/blackfin/include/asm/irqflags.h @@ -18,12 +18,12 @@ extern unsigned long bfin_irq_flags; #endif -static inline notrace void bfin_sti(unsigned long flags) +static inline void bfin_sti(unsigned long flags) { asm volatile("sti %0;" : : "d" (flags)); } -static inline notrace unsigned long bfin_cli(void) +static inline unsigned long bfin_cli(void) { unsigned long flags; asm volatile("cli %0;" : "=d" (flags)); @@ -40,22 +40,22 @@ static inline notrace unsigned long bfin_cli(void) /* * Hard, untraced CPU interrupt flag manipulation and access. */ -static inline notrace void __hard_local_irq_disable(void) +static inline void __hard_local_irq_disable(void) { bfin_cli(); } -static inline notrace void __hard_local_irq_enable(void) +static inline void __hard_local_irq_enable(void) { bfin_sti(bfin_irq_flags); } -static inline notrace unsigned long hard_local_save_flags(void) +static inline unsigned long hard_local_save_flags(void) { return bfin_read_IMASK(); } -static inline notrace unsigned long __hard_local_irq_save(void) +static inline unsigned long __hard_local_irq_save(void) { unsigned long flags; flags = bfin_cli(); @@ -65,18 +65,18 @@ static inline notrace unsigned long __hard_local_irq_save(void) return flags; } -static inline notrace int hard_irqs_disabled_flags(unsigned long flags) +static inline int hard_irqs_disabled_flags(unsigned long flags) { return (flags & ~0x3f) == 0; } -static inline notrace int hard_irqs_disabled(void) +static inline int hard_irqs_disabled(void) { unsigned long flags = hard_local_save_flags(); return hard_irqs_disabled_flags(flags); } -static inline notrace void __hard_local_irq_restore(unsigned long flags) +static inline void __hard_local_irq_restore(unsigned long flags) { if (!hard_irqs_disabled_flags(flags)) __hard_local_irq_enable(); @@ -113,31 +113,31 @@ void ipipe_check_context(struct ipipe_domain *ipd); /* * Interrupt pipe interface to linux/irqflags.h. */ -static inline notrace void arch_local_irq_disable(void) +static inline void arch_local_irq_disable(void) { __check_irqop_context(); __ipipe_stall_root(); barrier(); } -static inline notrace void arch_local_irq_enable(void) +static inline void arch_local_irq_enable(void) { barrier(); __check_irqop_context(); __ipipe_unstall_root(); } -static inline notrace unsigned long arch_local_save_flags(void) +static inline unsigned long arch_local_save_flags(void) { return __ipipe_test_root() ? bfin_no_irqs : bfin_irq_flags; } -static inline notrace int arch_irqs_disabled_flags(unsigned long flags) +static inline int arch_irqs_disabled_flags(unsigned long flags) { return flags == bfin_no_irqs; } -static inline notrace unsigned long arch_local_irq_save(void) +static inline unsigned long arch_local_irq_save(void) { unsigned long flags; @@ -148,13 +148,13 @@ static inline notrace unsigned long arch_local_irq_save(void) return flags; } -static inline notrace void arch_local_irq_restore(unsigned long flags) +static inline void arch_local_irq_restore(unsigned long flags) { __check_irqop_context(); __ipipe_restore_root(flags == bfin_no_irqs); } -static inline notrace unsigned long arch_mangle_irq_bits(int virt, unsigned long real) +static inline unsigned long arch_mangle_irq_bits(int virt, unsigned long real) { /* * Merge virtual and real interrupt mask bits into a single @@ -163,7 +163,7 @@ static inline notrace unsigned long arch_mangle_irq_bits(int virt, unsigned long return (real & ~(1 << 31)) | ((virt != 0) << 31); } -static inline notrace int arch_demangle_irq_bits(unsigned long *x) +static inline int arch_demangle_irq_bits(unsigned long *x) { int virt = (*x & (1 << 31)) != 0; *x &= ~(1L << 31); @@ -174,7 +174,7 @@ static inline notrace int arch_demangle_irq_bits(unsigned long *x) * Interface to various arch routines that may be traced. */ #ifdef CONFIG_IPIPE_TRACE_IRQSOFF -static inline notrace void hard_local_irq_disable(void) +static inline void hard_local_irq_disable(void) { if (!hard_irqs_disabled()) { __hard_local_irq_disable(); @@ -182,7 +182,7 @@ static inline notrace void hard_local_irq_disable(void) } } -static inline notrace void hard_local_irq_enable(void) +static inline void hard_local_irq_enable(void) { if (hard_irqs_disabled()) { ipipe_trace_end(0x80000000); @@ -190,7 +190,7 @@ static inline notrace void hard_local_irq_enable(void) } } -static inline notrace unsigned long hard_local_irq_save(void) +static inline unsigned long hard_local_irq_save(void) { unsigned long flags = hard_local_save_flags(); if (!hard_irqs_disabled_flags(flags)) { @@ -200,7 +200,7 @@ static inline notrace unsigned long hard_local_irq_save(void) return flags; } -static inline notrace void hard_local_irq_restore(unsigned long flags) +static inline void hard_local_irq_restore(unsigned long flags) { if (!hard_irqs_disabled_flags(flags)) { ipipe_trace_end(0x80000001); diff --git a/trunk/arch/blackfin/include/asm/kdebug.h b/trunk/arch/blackfin/include/asm/kdebug.h new file mode 100644 index 000000000000..6ece1b037665 --- /dev/null +++ b/trunk/arch/blackfin/include/asm/kdebug.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/kmap_types.h b/trunk/arch/blackfin/include/asm/kmap_types.h new file mode 100644 index 000000000000..3575c64af42a --- /dev/null +++ b/trunk/arch/blackfin/include/asm/kmap_types.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/local.h b/trunk/arch/blackfin/include/asm/local.h new file mode 100644 index 000000000000..c11c530f74d0 --- /dev/null +++ b/trunk/arch/blackfin/include/asm/local.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/local64.h b/trunk/arch/blackfin/include/asm/local64.h new file mode 100644 index 000000000000..36c93b5cc239 --- /dev/null +++ b/trunk/arch/blackfin/include/asm/local64.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/mman.h b/trunk/arch/blackfin/include/asm/mman.h new file mode 100644 index 000000000000..8eebf89f5ab1 --- /dev/null +++ b/trunk/arch/blackfin/include/asm/mman.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/module.h b/trunk/arch/blackfin/include/asm/module.h index ed5689b82c9f..4282b169ead9 100644 --- a/trunk/arch/blackfin/include/asm/module.h +++ b/trunk/arch/blackfin/include/asm/module.h @@ -1,8 +1,8 @@ /* - * Copyright 2004-2008 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ + * Copyright 2004-2008 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ #ifndef _ASM_BFIN_MODULE_H #define _ASM_BFIN_MODULE_H diff --git a/trunk/arch/blackfin/include/asm/msgbuf.h b/trunk/arch/blackfin/include/asm/msgbuf.h new file mode 100644 index 000000000000..809134c644a6 --- /dev/null +++ b/trunk/arch/blackfin/include/asm/msgbuf.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/mutex.h b/trunk/arch/blackfin/include/asm/mutex.h index ff6101aa2c71..f726e3a80ad0 100644 --- a/trunk/arch/blackfin/include/asm/mutex.h +++ b/trunk/arch/blackfin/include/asm/mutex.h @@ -1 +1,76 @@ -#include +/* + * Pull in the generic implementation for the mutex fastpath. + * + * TODO: implement optimized primitives instead, or leave the generic + * implementation in place, or pick the atomic_xchg() based generic + * implementation. (see asm-generic/mutex-xchg.h for details) + * + * Copyright 2006-2009 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#ifndef _ASM_MUTEX_H +#define _ASM_MUTEX_H + +#ifndef CONFIG_SMP +#include +#else + +static inline void +__mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *)) +{ + if (unlikely(atomic_dec_return(count) < 0)) + fail_fn(count); + else + smp_mb(); +} + +static inline int +__mutex_fastpath_lock_retval(atomic_t *count, int (*fail_fn)(atomic_t *)) +{ + if (unlikely(atomic_dec_return(count) < 0)) + return fail_fn(count); + else { + smp_mb(); + return 0; + } +} + +static inline void +__mutex_fastpath_unlock(atomic_t *count, void (*fail_fn)(atomic_t *)) +{ + smp_mb(); + if (unlikely(atomic_inc_return(count) <= 0)) + fail_fn(count); +} + +#define __mutex_slowpath_needs_to_unlock() 1 + +static inline int +__mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *)) +{ + /* + * We have two variants here. The cmpxchg based one is the best one + * because it never induce a false contention state. It is included + * here because architectures using the inc/dec algorithms over the + * xchg ones are much more likely to support cmpxchg natively. + * + * If not we fall back to the spinlock based variant - that is + * just as efficient (and simpler) as a 'destructive' probing of + * the mutex state would be. + */ +#ifdef __HAVE_ARCH_CMPXCHG + if (likely(atomic_cmpxchg(count, 1, 0) == 1)) { + smp_mb(); + return 1; + } + return 0; +#else + return fail_fn(count); +#endif +} + +#endif + +#endif diff --git a/trunk/arch/blackfin/include/asm/page.h b/trunk/arch/blackfin/include/asm/page.h index 7202404966f6..d0ce975bcd48 100644 --- a/trunk/arch/blackfin/include/asm/page.h +++ b/trunk/arch/blackfin/include/asm/page.h @@ -1,8 +1,8 @@ /* - * Copyright 2004-2009 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ + * Copyright 2004-2009 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ #ifndef _BLACKFIN_PAGE_H #define _BLACKFIN_PAGE_H diff --git a/trunk/arch/blackfin/include/asm/param.h b/trunk/arch/blackfin/include/asm/param.h new file mode 100644 index 000000000000..965d45427975 --- /dev/null +++ b/trunk/arch/blackfin/include/asm/param.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/pda.h b/trunk/arch/blackfin/include/asm/pda.h index 28c2498c9c98..d49bb261d9b7 100644 --- a/trunk/arch/blackfin/include/asm/pda.h +++ b/trunk/arch/blackfin/include/asm/pda.h @@ -54,16 +54,6 @@ struct blackfin_pda { /* Per-processor Data Area */ #endif }; -struct blackfin_initial_pda { - void *retx; -#ifdef CONFIG_DEBUG_DOUBLEFAULT - void *dcplb_doublefault_addr; - void *icplb_doublefault_addr; - void *retx_doublefault; - unsigned seqstat_doublefault; -#endif -}; - extern struct blackfin_pda cpu_pda[]; #endif /* __ASSEMBLY__ */ diff --git a/trunk/arch/blackfin/include/asm/percpu.h b/trunk/arch/blackfin/include/asm/percpu.h new file mode 100644 index 000000000000..06a959d67234 --- /dev/null +++ b/trunk/arch/blackfin/include/asm/percpu.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/pgalloc.h b/trunk/arch/blackfin/include/asm/pgalloc.h new file mode 100644 index 000000000000..f261cb7dda06 --- /dev/null +++ b/trunk/arch/blackfin/include/asm/pgalloc.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/resource.h b/trunk/arch/blackfin/include/asm/resource.h new file mode 100644 index 000000000000..04bc4db8921b --- /dev/null +++ b/trunk/arch/blackfin/include/asm/resource.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/scatterlist.h b/trunk/arch/blackfin/include/asm/scatterlist.h new file mode 100644 index 000000000000..d177a1588958 --- /dev/null +++ b/trunk/arch/blackfin/include/asm/scatterlist.h @@ -0,0 +1,6 @@ +#ifndef _BLACKFIN_SCATTERLIST_H +#define _BLACKFIN_SCATTERLIST_H + +#include + +#endif /* !(_BLACKFIN_SCATTERLIST_H) */ diff --git a/trunk/arch/blackfin/include/asm/sections.h b/trunk/arch/blackfin/include/asm/sections.h index fbd408475725..14a3e66d9167 100644 --- a/trunk/arch/blackfin/include/asm/sections.h +++ b/trunk/arch/blackfin/include/asm/sections.h @@ -1,8 +1,8 @@ /* - * Copyright 2004-2009 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ + * Copyright 2004-2009 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ #ifndef _BLACKFIN_SECTIONS_H #define _BLACKFIN_SECTIONS_H diff --git a/trunk/arch/blackfin/include/asm/sembuf.h b/trunk/arch/blackfin/include/asm/sembuf.h new file mode 100644 index 000000000000..7673b83cfef7 --- /dev/null +++ b/trunk/arch/blackfin/include/asm/sembuf.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/serial.h b/trunk/arch/blackfin/include/asm/serial.h new file mode 100644 index 000000000000..a0cb0caff152 --- /dev/null +++ b/trunk/arch/blackfin/include/asm/serial.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/setup.h b/trunk/arch/blackfin/include/asm/setup.h new file mode 100644 index 000000000000..552df83f1a49 --- /dev/null +++ b/trunk/arch/blackfin/include/asm/setup.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/shmbuf.h b/trunk/arch/blackfin/include/asm/shmbuf.h new file mode 100644 index 000000000000..83c05fc2de38 --- /dev/null +++ b/trunk/arch/blackfin/include/asm/shmbuf.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/shmparam.h b/trunk/arch/blackfin/include/asm/shmparam.h new file mode 100644 index 000000000000..93f30deb95d0 --- /dev/null +++ b/trunk/arch/blackfin/include/asm/shmparam.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/sigcontext.h b/trunk/arch/blackfin/include/asm/sigcontext.h index 906bdc1f5fda..ce4081a4d815 100644 --- a/trunk/arch/blackfin/include/asm/sigcontext.h +++ b/trunk/arch/blackfin/include/asm/sigcontext.h @@ -1,8 +1,8 @@ /* - * Copyright 2004-2008 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ + * Copyright 2004-2008 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ #ifndef _ASM_BLACKFIN_SIGCONTEXT_H #define _ASM_BLACKFIN_SIGCONTEXT_H diff --git a/trunk/arch/blackfin/include/asm/socket.h b/trunk/arch/blackfin/include/asm/socket.h new file mode 100644 index 000000000000..6b71384b9d8b --- /dev/null +++ b/trunk/arch/blackfin/include/asm/socket.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/sockios.h b/trunk/arch/blackfin/include/asm/sockios.h new file mode 100644 index 000000000000..def6d4746ee7 --- /dev/null +++ b/trunk/arch/blackfin/include/asm/sockios.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/spinlock.h b/trunk/arch/blackfin/include/asm/spinlock.h index 2336093fca23..1f286e71c21f 100644 --- a/trunk/arch/blackfin/include/asm/spinlock.h +++ b/trunk/arch/blackfin/include/asm/spinlock.h @@ -1,8 +1,8 @@ /* - * Copyright 2004-2009 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ + * Copyright 2004-2009 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ #ifndef __BFIN_SPINLOCK_H #define __BFIN_SPINLOCK_H diff --git a/trunk/arch/blackfin/include/asm/statfs.h b/trunk/arch/blackfin/include/asm/statfs.h new file mode 100644 index 000000000000..0b91fe198c20 --- /dev/null +++ b/trunk/arch/blackfin/include/asm/statfs.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/termbits.h b/trunk/arch/blackfin/include/asm/termbits.h new file mode 100644 index 000000000000..3935b106de79 --- /dev/null +++ b/trunk/arch/blackfin/include/asm/termbits.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/termios.h b/trunk/arch/blackfin/include/asm/termios.h new file mode 100644 index 000000000000..280d78a9d966 --- /dev/null +++ b/trunk/arch/blackfin/include/asm/termios.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/topology.h b/trunk/arch/blackfin/include/asm/topology.h new file mode 100644 index 000000000000..5428f333a02c --- /dev/null +++ b/trunk/arch/blackfin/include/asm/topology.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/types.h b/trunk/arch/blackfin/include/asm/types.h new file mode 100644 index 000000000000..b9e79bc580dd --- /dev/null +++ b/trunk/arch/blackfin/include/asm/types.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/ucontext.h b/trunk/arch/blackfin/include/asm/ucontext.h new file mode 100644 index 000000000000..9bc07b9f30fb --- /dev/null +++ b/trunk/arch/blackfin/include/asm/ucontext.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/unaligned.h b/trunk/arch/blackfin/include/asm/unaligned.h new file mode 100644 index 000000000000..6cecbbb2111f --- /dev/null +++ b/trunk/arch/blackfin/include/asm/unaligned.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/user.h b/trunk/arch/blackfin/include/asm/user.h new file mode 100644 index 000000000000..4792a60831e4 --- /dev/null +++ b/trunk/arch/blackfin/include/asm/user.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/include/asm/xor.h b/trunk/arch/blackfin/include/asm/xor.h new file mode 100644 index 000000000000..c82eb12a5b18 --- /dev/null +++ b/trunk/arch/blackfin/include/asm/xor.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/blackfin/kernel/Makefile b/trunk/arch/blackfin/kernel/Makefile index b7bdc42fe1a3..d550b24d9e9b 100644 --- a/trunk/arch/blackfin/kernel/Makefile +++ b/trunk/arch/blackfin/kernel/Makefile @@ -21,7 +21,6 @@ obj-$(CONFIG_FUNCTION_TRACER) += ftrace-entry.o obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o CFLAGS_REMOVE_ftrace.o = -pg -obj-$(CONFIG_HAVE_PWM) += pwm.o obj-$(CONFIG_IPIPE) += ipipe.o obj-$(CONFIG_BFIN_GPTIMERS) += gptimers.o obj-$(CONFIG_CPLB_INFO) += cplbinfo.o diff --git a/trunk/arch/blackfin/kernel/asm-offsets.c b/trunk/arch/blackfin/kernel/asm-offsets.c index 17e35465a416..bd32c09b9349 100644 --- a/trunk/arch/blackfin/kernel/asm-offsets.c +++ b/trunk/arch/blackfin/kernel/asm-offsets.c @@ -138,16 +138,6 @@ int main(void) DEFINE(PDA_DF_SEQSTAT, offsetof(struct blackfin_pda, seqstat_doublefault)); DEFINE(PDA_DF_RETX, offsetof(struct blackfin_pda, retx_doublefault)); #endif - - /* PDA initial management */ - DEFINE(PDA_INIT_RETX, offsetof(struct blackfin_initial_pda, retx)); -#ifdef CONFIG_DEBUG_DOUBLEFAULT - DEFINE(PDA_INIT_DF_DCPLB, offsetof(struct blackfin_initial_pda, dcplb_doublefault_addr)); - DEFINE(PDA_INIT_DF_ICPLB, offsetof(struct blackfin_initial_pda, icplb_doublefault_addr)); - DEFINE(PDA_INIT_DF_SEQSTAT, offsetof(struct blackfin_initial_pda, seqstat_doublefault)); - DEFINE(PDA_INIT_DF_RETX, offsetof(struct blackfin_initial_pda, retx_doublefault)); -#endif - #ifdef CONFIG_SMP /* Inter-core lock (in L2 SRAM) */ DEFINE(SIZEOF_CORELOCK, sizeof(struct corelock_slot)); diff --git a/trunk/arch/blackfin/kernel/bfin_gpio.c b/trunk/arch/blackfin/kernel/bfin_gpio.c index 02796b88443d..bcf8cf6fe412 100644 --- a/trunk/arch/blackfin/kernel/bfin_gpio.c +++ b/trunk/arch/blackfin/kernel/bfin_gpio.c @@ -118,9 +118,6 @@ static struct str_ident { #if defined(CONFIG_PM) static struct gpio_port_s gpio_bank_saved[GPIO_BANK_NUM]; -# ifdef BF538_FAMILY -static unsigned short port_fer_saved[3]; -# endif #endif static void gpio_error(unsigned gpio) @@ -607,11 +604,6 @@ void bfin_gpio_pm_hibernate_suspend(void) { int i, bank; -#ifdef BF538_FAMILY - for (i = 0; i < ARRAY_SIZE(port_fer_saved); ++i) - port_fer_saved[i] = *port_fer[i]; -#endif - for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE) { bank = gpio_bank(i); @@ -633,10 +625,6 @@ void bfin_gpio_pm_hibernate_suspend(void) gpio_bank_saved[bank].maska = gpio_array[bank]->maska; } -#ifdef BFIN_SPECIAL_GPIO_BANKS - bfin_special_gpio_pm_hibernate_suspend(); -#endif - AWA_DUMMY_READ(maska); } @@ -644,11 +632,6 @@ void bfin_gpio_pm_hibernate_restore(void) { int i, bank; -#ifdef BF538_FAMILY - for (i = 0; i < ARRAY_SIZE(port_fer_saved); ++i) - *port_fer[i] = port_fer_saved[i]; -#endif - for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE) { bank = gpio_bank(i); @@ -670,11 +653,6 @@ void bfin_gpio_pm_hibernate_restore(void) gpio_array[bank]->both = gpio_bank_saved[bank].both; gpio_array[bank]->maska = gpio_bank_saved[bank].maska; } - -#ifdef BFIN_SPECIAL_GPIO_BANKS - bfin_special_gpio_pm_hibernate_restore(); -#endif - AWA_DUMMY_READ(maska); } @@ -713,9 +691,9 @@ void bfin_gpio_pm_hibernate_restore(void) gpio_array[bank]->port_mux = gpio_bank_saved[bank].mux; gpio_array[bank]->port_fer = gpio_bank_saved[bank].fer; gpio_array[bank]->inen = gpio_bank_saved[bank].inen; - gpio_array[bank]->data_set = gpio_bank_saved[bank].data - & gpio_bank_saved[bank].dir; gpio_array[bank]->dir_set = gpio_bank_saved[bank].dir; + gpio_array[bank]->data_set = gpio_bank_saved[bank].data + | gpio_bank_saved[bank].dir; } } #endif diff --git a/trunk/arch/blackfin/kernel/debug-mmrs.c b/trunk/arch/blackfin/kernel/debug-mmrs.c index 92f664826281..fce4807ceef9 100644 --- a/trunk/arch/blackfin/kernel/debug-mmrs.c +++ b/trunk/arch/blackfin/kernel/debug-mmrs.c @@ -27,7 +27,7 @@ #define PORT_MUX BFIN_PORT_MUX #endif -#define _d(name, bits, addr, perms) debugfs_create_x##bits(name, perms, parent, (u##bits *)(addr)) +#define _d(name, bits, addr, perms) debugfs_create_x##bits(name, perms, parent, (u##bits *)addr) #define d(name, bits, addr) _d(name, bits, addr, S_IRUSR|S_IWUSR) #define d_RO(name, bits, addr) _d(name, bits, addr, S_IRUSR) #define d_WO(name, bits, addr) _d(name, bits, addr, S_IWUSR) @@ -223,8 +223,7 @@ bfin_debug_mmrs_dma(struct dentry *parent, unsigned long base, int num, char mdm __DMA(CURR_DESC_PTR, curr_desc_ptr); __DMA(CURR_ADDR, curr_addr); __DMA(IRQ_STATUS, irq_status); - if (strcmp(pfx, "IMDMA") != 0) - __DMA(PERIPHERAL_MAP, peripheral_map); + __DMA(PERIPHERAL_MAP, peripheral_map); __DMA(CURR_X_COUNT, curr_x_count); __DMA(CURR_Y_COUNT, curr_y_count); } @@ -278,32 +277,6 @@ bfin_debug_mmrs_gptimer(struct dentry *parent, unsigned long base, int num) } #define GPTIMER(num) bfin_debug_mmrs_gptimer(parent, TIMER##num##_CONFIG, num) -#define GPTIMER_GROUP_OFF(mmr) REGS_OFF(gptimer_group, mmr) -#define __GPTIMER_GROUP(uname, lname) __REGS(gptimer_group, #uname, lname) -static void __init __maybe_unused -bfin_debug_mmrs_gptimer_group(struct dentry *parent, unsigned long base, int num) -{ - char buf[32], *_buf; - - if (num == -1) { - _buf = buf + sprintf(buf, "TIMER_"); - __GPTIMER_GROUP(ENABLE, enable); - __GPTIMER_GROUP(DISABLE, disable); - __GPTIMER_GROUP(STATUS, status); - } else { - /* These MMRs are a bit odd as the group # is a suffix */ - _buf = buf + sprintf(buf, "TIMER_ENABLE%i", num); - d(buf, 16, base + GPTIMER_GROUP_OFF(enable)); - - _buf = buf + sprintf(buf, "TIMER_DISABLE%i", num); - d(buf, 16, base + GPTIMER_GROUP_OFF(disable)); - - _buf = buf + sprintf(buf, "TIMER_STATUS%i", num); - d(buf, 32, base + GPTIMER_GROUP_OFF(status)); - } -} -#define GPTIMER_GROUP(mmr, num) bfin_debug_mmrs_gptimer_group(parent, mmr, num) - /* * Handshake MDMA */ @@ -322,29 +295,6 @@ bfin_debug_mmrs_hmdma(struct dentry *parent, unsigned long base, int num) } #define HMDMA(num) bfin_debug_mmrs_hmdma(parent, HMDMA##num##_CONTROL, num) -/* - * Peripheral Interrupts (PINT/GPIO) - */ -#ifdef PINT0_MASK_SET -#define __PINT(uname, lname) __REGS(pint, #uname, lname) -static void __init __maybe_unused -bfin_debug_mmrs_pint(struct dentry *parent, unsigned long base, int num) -{ - char buf[32], *_buf = REGS_STR_PFX(buf, PINT, num); - __PINT(MASK_SET, mask_set); - __PINT(MASK_CLEAR, mask_clear); - __PINT(REQUEST, request); - __PINT(ASSIGN, assign); - __PINT(EDGE_SET, edge_set); - __PINT(EDGE_CLEAR, edge_clear); - __PINT(INVERT_SET, invert_set); - __PINT(INVERT_CLEAR, invert_clear); - __PINT(PINSTATE, pinstate); - __PINT(LATCH, latch); -} -#define PINT(num) bfin_debug_mmrs_pint(parent, PINT##num##_MASK_SET, num) -#endif - /* * Port/GPIO */ @@ -797,7 +747,7 @@ static int __init bfin_debug_mmrs_init(void) #endif parent = debugfs_create_dir("dmac", top); -#ifdef DMAC_TC_CNT +#ifdef DMA_TC_CNT D16(DMAC_TC_CNT); D16(DMAC_TC_PER); #endif @@ -1055,19 +1005,29 @@ static int __init bfin_debug_mmrs_init(void) #endif parent = debugfs_create_dir("gptimer", top); -#ifdef TIMER_ENABLE - GPTIMER_GROUP(TIMER_ENABLE, -1); +#ifdef TIMER_DISABLE + D16(TIMER_DISABLE); + D16(TIMER_ENABLE); + D32(TIMER_STATUS); #endif -#ifdef TIMER_ENABLE0 - GPTIMER_GROUP(TIMER_ENABLE0, 0); +#ifdef TIMER_DISABLE0 + D16(TIMER_DISABLE0); + D16(TIMER_ENABLE0); + D32(TIMER_STATUS0); #endif -#ifdef TIMER_ENABLE1 - GPTIMER_GROUP(TIMER_ENABLE1, 1); +#ifdef TIMER_DISABLE1 + D16(TIMER_DISABLE1); + D16(TIMER_ENABLE1); + D32(TIMER_STATUS1); #endif /* XXX: Should convert BF561 MMR names */ #ifdef TMRS4_DISABLE - GPTIMER_GROUP(TMRS4_ENABLE, 0); - GPTIMER_GROUP(TMRS8_ENABLE, 1); + D16(TMRS4_DISABLE); + D16(TMRS4_ENABLE); + D32(TMRS4_STATUS); + D16(TMRS8_DISABLE); + D16(TMRS8_ENABLE); + D32(TMRS8_STATUS); #endif GPTIMER(0); GPTIMER(1); @@ -1293,14 +1253,6 @@ static int __init bfin_debug_mmrs_init(void) D32(OTP_DATA3); #endif -#ifdef PINT0_MASK_SET - parent = debugfs_create_dir("pint", top); - PINT(0); - PINT(1); - PINT(2); - PINT(3); -#endif - #ifdef PIXC_CTL parent = debugfs_create_dir("pixc", top); D16(PIXC_CTL); @@ -1864,6 +1816,7 @@ static int __init bfin_debug_mmrs_init(void) { int num; unsigned long base; + char *_buf, buf[32]; base = PORTA_FER; for (num = 0; num < 10; ++num) { @@ -1871,6 +1824,24 @@ static int __init bfin_debug_mmrs_init(void) base += sizeof(struct bfin_gpio_regs); } +#define __PINT(uname, lname) __REGS(pint, #uname, lname) + parent = debugfs_create_dir("pint", top); + base = PINT0_MASK_SET; + for (num = 0; num < 4; ++num) { + _buf = REGS_STR_PFX(buf, PINT, num); + __PINT(MASK_SET, mask_set); + __PINT(MASK_CLEAR, mask_clear); + __PINT(IRQ, irq); + __PINT(ASSIGN, assign); + __PINT(EDGE_SET, edge_set); + __PINT(EDGE_CLEAR, edge_clear); + __PINT(INVERT_SET, invert_set); + __PINT(INVERT_CLEAR, invert_clear); + __PINT(PINSTATE, pinstate); + __PINT(LATCH, latch); + base += sizeof(struct bfin_pint_regs); + } + } #endif /* BF54x */ diff --git a/trunk/arch/blackfin/kernel/gptimers.c b/trunk/arch/blackfin/kernel/gptimers.c index 06459f4bf43a..8b81dc04488a 100644 --- a/trunk/arch/blackfin/kernel/gptimers.c +++ b/trunk/arch/blackfin/kernel/gptimers.c @@ -25,33 +25,49 @@ #define BFIN_TIMER_NUM_GROUP (BFIN_TIMER_OCTET(MAX_BLACKFIN_GPTIMERS - 1) + 1) -static struct bfin_gptimer_regs * const timer_regs[MAX_BLACKFIN_GPTIMERS] = +typedef struct { + uint16_t config; + uint16_t __pad; + uint32_t counter; + uint32_t period; + uint32_t width; +} GPTIMER_timer_regs; + +typedef struct { + uint16_t enable; + uint16_t __pad0; + uint16_t disable; + uint16_t __pad1; + uint32_t status; +} GPTIMER_group_regs; + +static volatile GPTIMER_timer_regs *const timer_regs[MAX_BLACKFIN_GPTIMERS] = { - (void *)TIMER0_CONFIG, - (void *)TIMER1_CONFIG, - (void *)TIMER2_CONFIG, + (GPTIMER_timer_regs *)TIMER0_CONFIG, + (GPTIMER_timer_regs *)TIMER1_CONFIG, + (GPTIMER_timer_regs *)TIMER2_CONFIG, #if (MAX_BLACKFIN_GPTIMERS > 3) - (void *)TIMER3_CONFIG, - (void *)TIMER4_CONFIG, - (void *)TIMER5_CONFIG, - (void *)TIMER6_CONFIG, - (void *)TIMER7_CONFIG, + (GPTIMER_timer_regs *)TIMER3_CONFIG, + (GPTIMER_timer_regs *)TIMER4_CONFIG, + (GPTIMER_timer_regs *)TIMER5_CONFIG, + (GPTIMER_timer_regs *)TIMER6_CONFIG, + (GPTIMER_timer_regs *)TIMER7_CONFIG, # if (MAX_BLACKFIN_GPTIMERS > 8) - (void *)TIMER8_CONFIG, - (void *)TIMER9_CONFIG, - (void *)TIMER10_CONFIG, + (GPTIMER_timer_regs *)TIMER8_CONFIG, + (GPTIMER_timer_regs *)TIMER9_CONFIG, + (GPTIMER_timer_regs *)TIMER10_CONFIG, # if (MAX_BLACKFIN_GPTIMERS > 11) - (void *)TIMER11_CONFIG, + (GPTIMER_timer_regs *)TIMER11_CONFIG, # endif # endif #endif }; -static struct bfin_gptimer_group_regs * const group_regs[BFIN_TIMER_NUM_GROUP] = +static volatile GPTIMER_group_regs *const group_regs[BFIN_TIMER_NUM_GROUP] = { - (void *)TIMER0_GROUP_REG, + (GPTIMER_group_regs *)TIMER0_GROUP_REG, #if (MAX_BLACKFIN_GPTIMERS > 8) - (void *)TIMER8_GROUP_REG, + (GPTIMER_group_regs *)TIMER8_GROUP_REG, #endif }; @@ -124,7 +140,7 @@ static uint32_t const timil_mask[MAX_BLACKFIN_GPTIMERS] = void set_gptimer_pwidth(unsigned int timer_id, uint32_t value) { tassert(timer_id < MAX_BLACKFIN_GPTIMERS); - bfin_write(&timer_regs[timer_id]->width, value); + timer_regs[timer_id]->width = value; SSYNC(); } EXPORT_SYMBOL(set_gptimer_pwidth); @@ -132,14 +148,14 @@ EXPORT_SYMBOL(set_gptimer_pwidth); uint32_t get_gptimer_pwidth(unsigned int timer_id) { tassert(timer_id < MAX_BLACKFIN_GPTIMERS); - return bfin_read(&timer_regs[timer_id]->width); + return timer_regs[timer_id]->width; } EXPORT_SYMBOL(get_gptimer_pwidth); void set_gptimer_period(unsigned int timer_id, uint32_t period) { tassert(timer_id < MAX_BLACKFIN_GPTIMERS); - bfin_write(&timer_regs[timer_id]->period, period); + timer_regs[timer_id]->period = period; SSYNC(); } EXPORT_SYMBOL(set_gptimer_period); @@ -147,76 +163,71 @@ EXPORT_SYMBOL(set_gptimer_period); uint32_t get_gptimer_period(unsigned int timer_id) { tassert(timer_id < MAX_BLACKFIN_GPTIMERS); - return bfin_read(&timer_regs[timer_id]->period); + return timer_regs[timer_id]->period; } EXPORT_SYMBOL(get_gptimer_period); uint32_t get_gptimer_count(unsigned int timer_id) { tassert(timer_id < MAX_BLACKFIN_GPTIMERS); - return bfin_read(&timer_regs[timer_id]->counter); + return timer_regs[timer_id]->counter; } EXPORT_SYMBOL(get_gptimer_count); uint32_t get_gptimer_status(unsigned int group) { tassert(group < BFIN_TIMER_NUM_GROUP); - return bfin_read(&group_regs[group]->status); + return group_regs[group]->status; } EXPORT_SYMBOL(get_gptimer_status); void set_gptimer_status(unsigned int group, uint32_t value) { tassert(group < BFIN_TIMER_NUM_GROUP); - bfin_write(&group_regs[group]->status, value); + group_regs[group]->status = value; SSYNC(); } EXPORT_SYMBOL(set_gptimer_status); -static uint32_t read_gptimer_status(unsigned int timer_id) -{ - return bfin_read(&group_regs[BFIN_TIMER_OCTET(timer_id)]->status); -} - int get_gptimer_intr(unsigned int timer_id) { tassert(timer_id < MAX_BLACKFIN_GPTIMERS); - return !!(read_gptimer_status(timer_id) & timil_mask[timer_id]); + return !!(group_regs[BFIN_TIMER_OCTET(timer_id)]->status & timil_mask[timer_id]); } EXPORT_SYMBOL(get_gptimer_intr); void clear_gptimer_intr(unsigned int timer_id) { tassert(timer_id < MAX_BLACKFIN_GPTIMERS); - bfin_write(&group_regs[BFIN_TIMER_OCTET(timer_id)]->status, timil_mask[timer_id]); + group_regs[BFIN_TIMER_OCTET(timer_id)]->status = timil_mask[timer_id]; } EXPORT_SYMBOL(clear_gptimer_intr); int get_gptimer_over(unsigned int timer_id) { tassert(timer_id < MAX_BLACKFIN_GPTIMERS); - return !!(read_gptimer_status(timer_id) & tovf_mask[timer_id]); + return !!(group_regs[BFIN_TIMER_OCTET(timer_id)]->status & tovf_mask[timer_id]); } EXPORT_SYMBOL(get_gptimer_over); void clear_gptimer_over(unsigned int timer_id) { tassert(timer_id < MAX_BLACKFIN_GPTIMERS); - bfin_write(&group_regs[BFIN_TIMER_OCTET(timer_id)]->status, tovf_mask[timer_id]); + group_regs[BFIN_TIMER_OCTET(timer_id)]->status = tovf_mask[timer_id]; } EXPORT_SYMBOL(clear_gptimer_over); int get_gptimer_run(unsigned int timer_id) { tassert(timer_id < MAX_BLACKFIN_GPTIMERS); - return !!(read_gptimer_status(timer_id) & trun_mask[timer_id]); + return !!(group_regs[BFIN_TIMER_OCTET(timer_id)]->status & trun_mask[timer_id]); } EXPORT_SYMBOL(get_gptimer_run); void set_gptimer_config(unsigned int timer_id, uint16_t config) { tassert(timer_id < MAX_BLACKFIN_GPTIMERS); - bfin_write(&timer_regs[timer_id]->config, config); + timer_regs[timer_id]->config = config; SSYNC(); } EXPORT_SYMBOL(set_gptimer_config); @@ -224,7 +235,7 @@ EXPORT_SYMBOL(set_gptimer_config); uint16_t get_gptimer_config(unsigned int timer_id) { tassert(timer_id < MAX_BLACKFIN_GPTIMERS); - return bfin_read(&timer_regs[timer_id]->config); + return timer_regs[timer_id]->config; } EXPORT_SYMBOL(get_gptimer_config); @@ -233,7 +244,7 @@ void enable_gptimers(uint16_t mask) int i; tassert((mask & ~BLACKFIN_GPTIMER_IDMASK) == 0); for (i = 0; i < BFIN_TIMER_NUM_GROUP; ++i) { - bfin_write(&group_regs[i]->enable, mask & 0xFF); + group_regs[i]->enable = mask & 0xFF; mask >>= 8; } SSYNC(); @@ -246,7 +257,7 @@ static void _disable_gptimers(uint16_t mask) uint16_t m = mask; tassert((mask & ~BLACKFIN_GPTIMER_IDMASK) == 0); for (i = 0; i < BFIN_TIMER_NUM_GROUP; ++i) { - bfin_write(&group_regs[i]->disable, m & 0xFF); + group_regs[i]->disable = m & 0xFF; m >>= 8; } } @@ -257,7 +268,7 @@ void disable_gptimers(uint16_t mask) _disable_gptimers(mask); for (i = 0; i < MAX_BLACKFIN_GPTIMERS; ++i) if (mask & (1 << i)) - bfin_write(&group_regs[BFIN_TIMER_OCTET(i)]->status, trun_mask[i]); + group_regs[BFIN_TIMER_OCTET(i)]->status = trun_mask[i]; SSYNC(); } EXPORT_SYMBOL(disable_gptimers); @@ -272,7 +283,7 @@ EXPORT_SYMBOL(disable_gptimers_sync); void set_gptimer_pulse_hi(unsigned int timer_id) { tassert(timer_id < MAX_BLACKFIN_GPTIMERS); - bfin_write_or(&timer_regs[timer_id]->config, TIMER_PULSE_HI); + timer_regs[timer_id]->config |= TIMER_PULSE_HI; SSYNC(); } EXPORT_SYMBOL(set_gptimer_pulse_hi); @@ -280,7 +291,7 @@ EXPORT_SYMBOL(set_gptimer_pulse_hi); void clear_gptimer_pulse_hi(unsigned int timer_id) { tassert(timer_id < MAX_BLACKFIN_GPTIMERS); - bfin_write_and(&timer_regs[timer_id]->config, ~TIMER_PULSE_HI); + timer_regs[timer_id]->config &= ~TIMER_PULSE_HI; SSYNC(); } EXPORT_SYMBOL(clear_gptimer_pulse_hi); @@ -290,7 +301,7 @@ uint16_t get_enabled_gptimers(void) int i; uint16_t result = 0; for (i = 0; i < BFIN_TIMER_NUM_GROUP; ++i) - result |= (bfin_read(&group_regs[i]->enable) << (i << 3)); + result |= (group_regs[i]->enable << (i << 3)); return result; } EXPORT_SYMBOL(get_enabled_gptimers); diff --git a/trunk/arch/blackfin/kernel/module.c b/trunk/arch/blackfin/kernel/module.c index 4489efc52883..35e350cad9d9 100644 --- a/trunk/arch/blackfin/kernel/module.c +++ b/trunk/arch/blackfin/kernel/module.c @@ -16,6 +16,19 @@ #include #include +void *module_alloc(unsigned long size) +{ + if (size == 0) + return NULL; + return vmalloc(size); +} + +/* Free memory returned from module_alloc */ +void module_free(struct module *mod, void *module_region) +{ + vfree(module_region); +} + /* Transfer the section to the L1 memory */ int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, @@ -137,6 +150,14 @@ module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, return 0; } +int +apply_relocate(Elf_Shdr * sechdrs, const char *strtab, + unsigned int symindex, unsigned int relsec, struct module *mod) +{ + pr_err(".rel unsupported\n"); + return -ENOEXEC; +} + /*************************************************************************/ /* FUNCTION : apply_relocate_add */ /* ABSTRACT : Blackfin specific relocation handling for the loadable */ diff --git a/trunk/arch/blackfin/kernel/process.c b/trunk/arch/blackfin/kernel/process.c index 6a80a9e9fc4a..6a660fa921b5 100644 --- a/trunk/arch/blackfin/kernel/process.c +++ b/trunk/arch/blackfin/kernel/process.c @@ -140,6 +140,7 @@ EXPORT_SYMBOL(kernel_thread); */ void start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp) { + set_fs(USER_DS); regs->pc = new_ip; if (current->mm) regs->p5 = current->mm->start_data; diff --git a/trunk/arch/blackfin/kernel/pwm.c b/trunk/arch/blackfin/kernel/pwm.c deleted file mode 100644 index 33f5942733bd..000000000000 --- a/trunk/arch/blackfin/kernel/pwm.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Blackfin Pulse Width Modulation (PWM) core - * - * Copyright (c) 2011 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ - -#include -#include -#include - -#include -#include - -struct pwm_device { - unsigned id; - unsigned short pin; -}; - -static const unsigned short pwm_to_gptimer_per[] = { - P_TMR0, P_TMR1, P_TMR2, P_TMR3, P_TMR4, P_TMR5, - P_TMR6, P_TMR7, P_TMR8, P_TMR9, P_TMR10, P_TMR11, -}; - -struct pwm_device *pwm_request(int pwm_id, const char *label) -{ - struct pwm_device *pwm; - int ret; - - /* XXX: pwm_id really should be unsigned */ - if (pwm_id < 0) - return NULL; - - pwm = kzalloc(sizeof(*pwm), GFP_KERNEL); - if (!pwm) - return pwm; - - pwm->id = pwm_id; - if (pwm->id >= ARRAY_SIZE(pwm_to_gptimer_per)) - goto err; - - pwm->pin = pwm_to_gptimer_per[pwm->id]; - ret = peripheral_request(pwm->pin, label); - if (ret) - goto err; - - return pwm; - err: - kfree(pwm); - return NULL; -} -EXPORT_SYMBOL(pwm_request); - -void pwm_free(struct pwm_device *pwm) -{ - peripheral_free(pwm->pin); - kfree(pwm); -} -EXPORT_SYMBOL(pwm_free); - -int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) -{ - unsigned long period, duty; - unsigned long long val; - - if (duty_ns < 0 || duty_ns > period_ns) - return -EINVAL; - - val = (unsigned long long)get_sclk() * period_ns; - do_div(val, NSEC_PER_SEC); - period = val; - - val = (unsigned long long)period * duty_ns; - do_div(val, period_ns); - duty = period - val; - - if (duty >= period) - duty = period - 1; - - set_gptimer_config(pwm->id, TIMER_MODE_PWM | TIMER_PERIOD_CNT); - set_gptimer_pwidth(pwm->id, duty); - set_gptimer_period(pwm->id, period); - - return 0; -} -EXPORT_SYMBOL(pwm_config); - -int pwm_enable(struct pwm_device *pwm) -{ - enable_gptimer(pwm->id); - return 0; -} -EXPORT_SYMBOL(pwm_enable); - -void pwm_disable(struct pwm_device *pwm) -{ - disable_gptimer(pwm->id); -} -EXPORT_SYMBOL(pwm_disable); diff --git a/trunk/arch/blackfin/kernel/reboot.c b/trunk/arch/blackfin/kernel/reboot.c index c4c0081b1996..488bdc51aaa5 100644 --- a/trunk/arch/blackfin/kernel/reboot.c +++ b/trunk/arch/blackfin/kernel/reboot.c @@ -54,9 +54,7 @@ static void bfin_reset(void) /* The BF526 ROM will crash during reset */ #if defined(__ADSPBF522__) || defined(__ADSPBF524__) || defined(__ADSPBF526__) - /* Seems to be fixed with newer parts though ... */ - if (__SILICON_REVISION__ < 1 && bfin_revid() < 1) - bfin_read_SWRST(); + bfin_read_SWRST(); #endif /* Wait for the SWRST write to complete. Cannot rely on SSYNC diff --git a/trunk/arch/blackfin/kernel/setup.c b/trunk/arch/blackfin/kernel/setup.c index dfa2525a442d..536bd9d7e0cf 100644 --- a/trunk/arch/blackfin/kernel/setup.c +++ b/trunk/arch/blackfin/kernel/setup.c @@ -54,7 +54,8 @@ EXPORT_SYMBOL(mtd_size); #endif char __initdata command_line[COMMAND_LINE_SIZE]; -struct blackfin_initial_pda __initdata initial_pda; +void __initdata *init_retx, *init_saved_retx, *init_saved_seqstat, + *init_saved_icplb_fault_addr, *init_saved_dcplb_fault_addr; /* boot memmap, for parsing "memmap=" */ #define BFIN_MEMMAP_MAX 128 /* number of entries in bfin_memmap */ @@ -956,16 +957,13 @@ void __init setup_arch(char **cmdline_p) printk(KERN_EMERG "Recovering from DOUBLE FAULT event\n"); #ifdef CONFIG_DEBUG_DOUBLEFAULT /* We assume the crashing kernel, and the current symbol table match */ - printk(KERN_EMERG " While handling exception (EXCAUSE = %#x) at %pF\n", - initial_pda.seqstat_doublefault & SEQSTAT_EXCAUSE, - initial_pda.retx_doublefault); - printk(KERN_NOTICE " DCPLB_FAULT_ADDR: %pF\n", - initial_pda.dcplb_doublefault_addr); - printk(KERN_NOTICE " ICPLB_FAULT_ADDR: %pF\n", - initial_pda.icplb_doublefault_addr); + printk(KERN_EMERG " While handling exception (EXCAUSE = 0x%x) at %pF\n", + (int)init_saved_seqstat & SEQSTAT_EXCAUSE, init_saved_retx); + printk(KERN_NOTICE " DCPLB_FAULT_ADDR: %pF\n", init_saved_dcplb_fault_addr); + printk(KERN_NOTICE " ICPLB_FAULT_ADDR: %pF\n", init_saved_icplb_fault_addr); #endif printk(KERN_NOTICE " The instruction at %pF caused a double exception\n", - initial_pda.retx); + init_retx); } else if (_bfin_swrst & RESET_WDOG) printk(KERN_INFO "Recovering from Watchdog event\n"); else if (_bfin_swrst & RESET_SOFTWARE) diff --git a/trunk/arch/blackfin/kernel/time.c b/trunk/arch/blackfin/kernel/time.c index ceb2bf63dfe2..8d73724c0092 100644 --- a/trunk/arch/blackfin/kernel/time.c +++ b/trunk/arch/blackfin/kernel/time.c @@ -51,7 +51,7 @@ void __init setup_core_timer(void) u32 tcount; /* power up the timer, but don't enable it just yet */ - bfin_write_TCNTL(TMPWR); + bfin_write_TCNTL(1); CSYNC(); /* the TSCALE prescaler counter */ @@ -64,7 +64,7 @@ void __init setup_core_timer(void) /* now enable the timer */ CSYNC(); - bfin_write_TCNTL(TAUTORLD | TMREN | TMPWR); + bfin_write_TCNTL(7); } #endif diff --git a/trunk/arch/blackfin/kernel/vmlinux.lds.S b/trunk/arch/blackfin/kernel/vmlinux.lds.S index ba35864b2b74..3ac5b66d14aa 100644 --- a/trunk/arch/blackfin/kernel/vmlinux.lds.S +++ b/trunk/arch/blackfin/kernel/vmlinux.lds.S @@ -155,7 +155,6 @@ SECTIONS SECURITY_INITCALL INIT_RAM_FS - . = ALIGN(PAGE_SIZE); ___per_cpu_load = .; PERCPU_INPUT(32) diff --git a/trunk/arch/blackfin/mach-bf518/Kconfig b/trunk/arch/blackfin/mach-bf518/Kconfig index bde92a19970e..1d9f631a7f94 100644 --- a/trunk/arch/blackfin/mach-bf518/Kconfig +++ b/trunk/arch/blackfin/mach-bf518/Kconfig @@ -11,75 +11,55 @@ menu "BF518 Specific Configuration" comment "Alternative Multiplexing Scheme" choice - prompt "PWM Channel Pins" - default BF518_PWM_ALL_PORTF + prompt "SPORT0" + default BF518_SPORT0_PORTG help - Select pins used for the PWM channels: - PWM_AH PWM_AL PWM_BH PWM_BL PWM_CH PWM_CL + Select PORT used for SPORT0. See Hardware Reference Manual - See the Hardware Reference Manual for more details. - -config BF518_PWM_ALL_PORTF - bool "PF1 - PF6" +config BF518_SPORT0_PORTF + bool "PORT F" help - PF{1,2,3,4,5,6} <-> PWM_{AH,AL,BH,BL,CH,CL} + PORT F -config BF518_PWM_PORTF_PORTG - bool "PF11 - PF14 / PG1 - PG2" +config BF518_SPORT0_PORTG + bool "PORT G" help - PF{11,12,13,14} <-> PWM_{AH,AL,BH,BL} - PG{1,2} <-> PWM_{CH,CL} - + PORT G endchoice choice - prompt "PWM Sync Pin" - default BF518_PWM_SYNC_PF7 + prompt "SPORT0 TSCLK Location" + depends on BF518_SPORT0_PORTG + default BF518_SPORT0_TSCLK_PG10 help - Select the pin used for PWM_SYNC. - - See the Hardware Reference Manual for more details. - -config BF518_PWM_SYNC_PF7 - bool "PF7" -config BF518_PWM_SYNC_PF15 - bool "PF15" -endchoice + Select PIN used for SPORT0_TSCLK. See Hardware Reference Manual -choice - prompt "PWM Trip B Pin" - default BF518_PWM_TRIPB_PG10 +config BF518_SPORT0_TSCLK_PG10 + bool "PORT PG10" help - Select the pin used for PWM_TRIPB. - - See the Hardware Reference Manual for more details. + PORT PG10 -config BF518_PWM_TRIPB_PG10 - bool "PG10" -config BF518_PWM_TRIPB_PG14 - bool "PG14" +config BF518_SPORT0_TSCLK_PG14 + bool "PORT PG14" + help + PORT PG14 endchoice choice - prompt "PPI / Timer Pins" - default BF518_PPI_TMR_PG5 + prompt "UART1" + default BF518_UART1_PORTF help - Select pins used for PPI/Timer: - PPICLK PPIFS1 PPIFS2 - TMRCLK TMR0 TMR1 + Select PORT used for UART1. See Hardware Reference Manual - See the Hardware Reference Manual for more details. - -config BF518_PPI_TMR_PG5 - bool "PG5 - PG7" +config BF518_UART1_PORTF + bool "PORT F" help - PG{5,6,7} <-> {PPICLK/TMRCLK,TMR0/PPIFS1,TMR1/PPIFS2} + PORT F -config BF518_PPI_TMR_PG12 - bool "PG12 - PG14" +config BF518_UART1_PORTG + bool "PORT G" help - PG{12,13,14} <-> {PPICLK/TMRCLK,TMR0/PPIFS1,TMR1/PPIFS2} - + PORT G endchoice comment "Hysteresis/Schmitt Trigger Control" diff --git a/trunk/arch/blackfin/mach-bf518/boards/ezbrd.c b/trunk/arch/blackfin/mach-bf518/boards/ezbrd.c index d78fc2cc7d16..c0ccadcfa44e 100644 --- a/trunk/arch/blackfin/mach-bf518/boards/ezbrd.c +++ b/trunk/arch/blackfin/mach-bf518/boards/ezbrd.c @@ -187,16 +187,43 @@ static struct flash_platform_data bfin_spi_flash_data = { /* SPI flash chip (m25p64) */ static struct bfin5xx_spi_chip spi_flash_chip_info = { .enable_dma = 0, /* use dma transfer with this chip*/ + .bits_per_word = 8, }; #endif +#if defined(CONFIG_BFIN_SPI_ADC) \ + || defined(CONFIG_BFIN_SPI_ADC_MODULE) +/* SPI ADC chip */ +static struct bfin5xx_spi_chip spi_adc_chip_info = { + .enable_dma = 1, /* use dma transfer with this chip*/ + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE) +#if defined(CONFIG_NET_DSA_KSZ8893M) \ + || defined(CONFIG_NET_DSA_KSZ8893M_MODULE) +/* SPI SWITCH CHIP */ +static struct bfin5xx_spi_chip spi_switch_info = { + .enable_dma = 0, + .bits_per_word = 8, +}; +#endif +#endif + #if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE) static struct bfin5xx_spi_chip mmc_spi_chip_info = { .enable_dma = 0, + .bits_per_word = 8, }; #endif #if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE) +static struct bfin5xx_spi_chip spi_ad7877_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; + static const struct ad7877_platform_data bfin_ad7877_ts_info = { .model = 7877, .vref_delay_usecs = 50, /* internal, no capacitor */ @@ -212,6 +239,21 @@ static const struct ad7877_platform_data bfin_ad7877_ts_info = { }; #endif +#if defined(CONFIG_SND_SOC_WM8731) || defined(CONFIG_SND_SOC_WM8731_MODULE) \ + && defined(CONFIG_SND_SOC_WM8731_SPI) +static struct bfin5xx_spi_chip spi_wm8731_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE) +static struct bfin5xx_spi_chip spidev_chip_info = { + .enable_dma = 0, + .bits_per_word = 8, +}; +#endif + static struct spi_board_info bfin_spi_board_info[] __initdata = { #if defined(CONFIG_MTD_M25P80) \ || defined(CONFIG_MTD_M25P80_MODULE) @@ -227,6 +269,18 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { }, #endif +#if defined(CONFIG_BFIN_SPI_ADC) \ + || defined(CONFIG_BFIN_SPI_ADC_MODULE) + { + .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */ + .max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 0, /* Framework bus number */ + .chip_select = 1, /* Framework chip select. */ + .platform_data = NULL, /* No spi_driver specific config */ + .controller_data = &spi_adc_chip_info, + }, +#endif + #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE) #if defined(CONFIG_NET_DSA_KSZ8893M) \ || defined(CONFIG_NET_DSA_KSZ8893M_MODULE) @@ -236,6 +290,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .bus_num = 0, .chip_select = 1, .platform_data = NULL, + .controller_data = &spi_switch_info, .mode = SPI_MODE_3, }, #endif @@ -259,6 +314,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 2, + .controller_data = &spi_ad7877_chip_info, }, #endif #if defined(CONFIG_SND_SOC_WM8731) || defined(CONFIG_SND_SOC_WM8731_MODULE) \ @@ -268,6 +324,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 5, + .controller_data = &spi_wm8731_chip_info, .mode = SPI_MODE_0, }, #endif @@ -277,6 +334,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 1, + .controller_data = &spidev_chip_info, }, #endif #if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE) @@ -285,6 +343,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 20000000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 1, + .controller_data = &lq035q1_spi_chip_info, .mode = SPI_CPHA | SPI_CPOL, }, #endif diff --git a/trunk/arch/blackfin/mach-bf518/boards/tcm-bf518.c b/trunk/arch/blackfin/mach-bf518/boards/tcm-bf518.c index 55c127908815..50fc5c89e379 100644 --- a/trunk/arch/blackfin/mach-bf518/boards/tcm-bf518.c +++ b/trunk/arch/blackfin/mach-bf518/boards/tcm-bf518.c @@ -138,16 +138,32 @@ static struct flash_platform_data bfin_spi_flash_data = { /* SPI flash chip (m25p64) */ static struct bfin5xx_spi_chip spi_flash_chip_info = { .enable_dma = 0, /* use dma transfer with this chip*/ + .bits_per_word = 8, +}; +#endif + +#if defined(CONFIG_BFIN_SPI_ADC) \ + || defined(CONFIG_BFIN_SPI_ADC_MODULE) +/* SPI ADC chip */ +static struct bfin5xx_spi_chip spi_adc_chip_info = { + .enable_dma = 1, /* use dma transfer with this chip*/ + .bits_per_word = 16, }; #endif #if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE) static struct bfin5xx_spi_chip mmc_spi_chip_info = { .enable_dma = 0, + .bits_per_word = 8, }; #endif #if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE) +static struct bfin5xx_spi_chip spi_ad7877_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; + static const struct ad7877_platform_data bfin_ad7877_ts_info = { .model = 7877, .vref_delay_usecs = 50, /* internal, no capacitor */ @@ -163,6 +179,21 @@ static const struct ad7877_platform_data bfin_ad7877_ts_info = { }; #endif +#if defined(CONFIG_SND_SOC_WM8731) || defined(CONFIG_SND_SOC_WM8731_MODULE) \ + && defined(CONFIG_SND_SOC_WM8731_SPI) +static struct bfin5xx_spi_chip spi_wm8731_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE) +static struct bfin5xx_spi_chip spidev_chip_info = { + .enable_dma = 0, + .bits_per_word = 8, +}; +#endif + static struct spi_board_info bfin_spi_board_info[] __initdata = { #if defined(CONFIG_MTD_M25P80) \ || defined(CONFIG_MTD_M25P80_MODULE) @@ -178,6 +209,18 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { }, #endif +#if defined(CONFIG_BFIN_SPI_ADC) \ + || defined(CONFIG_BFIN_SPI_ADC_MODULE) + { + .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */ + .max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 0, /* Framework bus number */ + .chip_select = 1, /* Framework chip select. */ + .platform_data = NULL, /* No spi_driver specific config */ + .controller_data = &spi_adc_chip_info, + }, +#endif + #if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE) { .modalias = "mmc_spi", @@ -196,6 +239,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 2, + .controller_data = &spi_ad7877_chip_info, }, #endif #if defined(CONFIG_SND_SOC_WM8731) || defined(CONFIG_SND_SOC_WM8731_MODULE) \ @@ -205,6 +249,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 5, + .controller_data = &spi_wm8731_chip_info, .mode = SPI_MODE_0, }, #endif @@ -214,6 +259,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 1, + .controller_data = &spidev_chip_info, }, #endif #if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE) @@ -222,6 +268,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 20000000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 1, + .controller_data = &lq035q1_spi_chip_info, .mode = SPI_CPHA | SPI_CPOL, }, #endif diff --git a/trunk/arch/blackfin/mach-bf518/include/mach/anomaly.h b/trunk/arch/blackfin/mach-bf518/include/mach/anomaly.h index 56383f7cbc07..d2f076fbbc9e 100644 --- a/trunk/arch/blackfin/mach-bf518/include/mach/anomaly.h +++ b/trunk/arch/blackfin/mach-bf518/include/mach/anomaly.h @@ -11,9 +11,10 @@ */ /* This file should be up to date with: - * - Revision F, 05/23/2011; ADSP-BF512/BF514/BF516/BF518 Blackfin Processor Anomaly List + * - Revision E, 01/26/2010; ADSP-BF512/BF514/BF516/BF518 Blackfin Processor Anomaly List */ +/* We plan on not supporting 0.0 silicon, but 0.1 isn't out yet - sorry */ #if __SILICON_REVISION__ < 0 # error will not work on BF518 silicon version #endif @@ -76,29 +77,19 @@ /* False Hardware Error when RETI Points to Invalid Memory */ #define ANOMALY_05000461 (1) /* Synchronization Problem at Startup May Cause SPORT Transmit Channels to Misalign */ -#define ANOMALY_05000462 (__SILICON_REVISION__ < 2) +#define ANOMALY_05000462 (1) +/* PLL Latches Incorrect Settings During Reset */ +#define ANOMALY_05000469 (1) /* Incorrect Default MSEL Value in PLL_CTL */ -#define ANOMALY_05000472 (__SILICON_REVISION__ < 2) +#define ANOMALY_05000472 (1) /* Interrupted SPORT Receive Data Register Read Results In Underflow when SLEN > 15 */ #define ANOMALY_05000473 (1) /* TESTSET Instruction Cannot Be Interrupted */ #define ANOMALY_05000477 (1) /* Reads of ITEST_COMMAND and ITEST_DATA Registers Cause Cache Corruption */ #define ANOMALY_05000481 (1) -/* PLL Latches Incorrect Settings During Reset */ -#define ANOMALY_05000482 (__SILICON_REVISION__ < 2) -/* PLL_CTL Change Using bfrom_SysControl() Can Result in Processor Overclocking */ -#define ANOMALY_05000485 (__SILICON_REVISION__ < 2) -/* SPI Master Boot Can Fail Under Certain Conditions */ -#define ANOMALY_05000490 (1) -/* Instruction Memory Stalls Can Cause IFLUSH to Fail */ +/* IFLUSH sucks at life */ #define ANOMALY_05000491 (1) -/* EXCPT Instruction May Be Lost If NMI Happens Simultaneously */ -#define ANOMALY_05000494 (1) -/* CNT_COMMAND Functionality Depends on CNT_IMASK Configuration */ -#define ANOMALY_05000498 (1) -/* RXS Bit in SPI_STAT May Become Stuck In RX DMA Modes */ -#define ANOMALY_05000501 (1) /* Anomalies that don't exist on this proc */ #define ANOMALY_05000099 (0) @@ -166,5 +157,6 @@ #define ANOMALY_05000474 (0) #define ANOMALY_05000475 (0) #define ANOMALY_05000480 (0) +#define ANOMALY_05000485 (0) #endif diff --git a/trunk/arch/blackfin/mach-bf518/include/mach/portmux.h b/trunk/arch/blackfin/mach-bf518/include/mach/portmux.h index b3b806f468da..cd84a569b04e 100644 --- a/trunk/arch/blackfin/mach-bf518/include/mach/portmux.h +++ b/trunk/arch/blackfin/mach-bf518/include/mach/portmux.h @@ -81,15 +81,9 @@ #define P_PPI0_D14 (P_DEFINED | P_IDENT(GPIO_PF14) | P_FUNCT(1)) #define P_PPI0_D15 (P_DEFINED | P_IDENT(GPIO_PF15) | P_FUNCT(1)) -#ifndef CONFIG_BF518_PPI_TMR_PG12 -#define P_PPI0_CLK (P_DEFINED | P_IDENT(GPIO_PG5) | P_FUNCT(1)) -#define P_PPI0_FS1 (P_DEFINED | P_IDENT(GPIO_PG6) | P_FUNCT(1)) -#define P_PPI0_FS2 (P_DEFINED | P_IDENT(GPIO_PG7) | P_FUNCT(1)) -#else #define P_PPI0_CLK (P_DEFINED | P_IDENT(GPIO_PG12) | P_FUNCT(1)) #define P_PPI0_FS1 (P_DEFINED | P_IDENT(GPIO_PG13) | P_FUNCT(1)) #define P_PPI0_FS2 (P_DEFINED | P_IDENT(GPIO_PG14) | P_FUNCT(1)) -#endif #define P_PPI0_FS3 (P_DEFINED | P_IDENT(GPIO_PG15) | P_FUNCT(1)) /* SPI Port Mux */ @@ -145,15 +139,9 @@ #define P_UART1_RX (P_DEFINED | P_IDENT(GPIO_PH7) | P_FUNCT(1)) /* Timer */ -#ifndef CONFIG_BF518_PPI_TMR_PG12 #define P_TMRCLK (P_DEFINED | P_IDENT(GPIO_PG5) | P_FUNCT(2)) #define P_TMR0 (P_DEFINED | P_IDENT(GPIO_PG6) | P_FUNCT(2)) #define P_TMR1 (P_DEFINED | P_IDENT(GPIO_PG7) | P_FUNCT(2)) -#else -#define P_TMRCLK (P_DEFINED | P_IDENT(GPIO_PG12) | P_FUNCT(2)) -#define P_TMR0 (P_DEFINED | P_IDENT(GPIO_PG13) | P_FUNCT(2)) -#define P_TMR1 (P_DEFINED | P_IDENT(GPIO_PG14) | P_FUNCT(2)) -#endif #define P_TMR2 (P_DEFINED | P_IDENT(GPIO_PF9) | P_FUNCT(2)) #define P_TMR3 (P_DEFINED | P_IDENT(GPIO_PF10) | P_FUNCT(2)) #define P_TMR4 (P_DEFINED | P_IDENT(GPIO_PG9) | P_FUNCT(2)) @@ -170,33 +158,23 @@ #define P_TWI0_SDA (P_DONTCARE) /* PWM */ -#ifndef CONFIG_BF518_PWM_PORTF_PORTG -#define P_PWM_AH (P_DEFINED | P_IDENT(GPIO_PF1) | P_FUNCT(2)) -#define P_PWM_AL (P_DEFINED | P_IDENT(GPIO_PF2) | P_FUNCT(2)) -#define P_PWM_BH (P_DEFINED | P_IDENT(GPIO_PF3) | P_FUNCT(2)) -#define P_PWM_BL (P_DEFINED | P_IDENT(GPIO_PF4) | P_FUNCT(2)) -#define P_PWM_CH (P_DEFINED | P_IDENT(GPIO_PF5) | P_FUNCT(2)) -#define P_PWM_CL (P_DEFINED | P_IDENT(GPIO_PF6) | P_FUNCT(2)) -#else -#define P_PWM_AH (P_DEFINED | P_IDENT(GPIO_PF11) | P_FUNCT(2)) -#define P_PWM_AL (P_DEFINED | P_IDENT(GPIO_PF12) | P_FUNCT(2)) -#define P_PWM_BH (P_DEFINED | P_IDENT(GPIO_PF13) | P_FUNCT(2)) -#define P_PWM_BL (P_DEFINED | P_IDENT(GPIO_PF14) | P_FUNCT(2)) -#define P_PWM_CH (P_DEFINED | P_IDENT(GPIO_PG1) | P_FUNCT(2)) -#define P_PWM_CL (P_DEFINED | P_IDENT(GPIO_PG2) | P_FUNCT(2)) -#endif - -#ifndef CONFIG_BF518_PWM_SYNC_PF15 -#define P_PWM_SYNC (P_DEFINED | P_IDENT(GPIO_PF7) | P_FUNCT(2)) -#else -#define P_PWM_SYNC (P_DEFINED | P_IDENT(GPIO_PF15) | P_FUNCT(2)) -#endif - -#ifndef CONFIG_BF518_PWM_TRIPB_PG14 -#define P_PWM_TRIPB (P_DEFINED | P_IDENT(GPIO_PG10) | P_FUNCT(2)) -#else +#define P_PWM0_AH (P_DEFINED | P_IDENT(GPIO_PF1) | P_FUNCT(2)) +#define P_PWM0_AL (P_DEFINED | P_IDENT(GPIO_PF2) | P_FUNCT(2)) +#define P_PWM0_BH (P_DEFINED | P_IDENT(GPIO_PF3) | P_FUNCT(2)) +#define P_PWM0_BL (P_DEFINED | P_IDENT(GPIO_PF4) | P_FUNCT(2)) +#define P_PWM0_CH (P_DEFINED | P_IDENT(GPIO_PF5) | P_FUNCT(2)) +#define P_PWM0_CL (P_DEFINED | P_IDENT(GPIO_PF6) | P_FUNCT(2)) +#define P_PWM0_SYNC (P_DEFINED | P_IDENT(GPIO_PF7) | P_FUNCT(2)) + +#define P_PWM1_AH (P_DEFINED | P_IDENT(GPIO_PF11) | P_FUNCT(2)) +#define P_PWM1_AL (P_DEFINED | P_IDENT(GPIO_PF12) | P_FUNCT(2)) +#define P_PWM1_BH (P_DEFINED | P_IDENT(GPIO_PF13) | P_FUNCT(2)) +#define P_PWM1_BL (P_DEFINED | P_IDENT(GPIO_PF14) | P_FUNCT(2)) +#define P_PWM1_CH (P_DEFINED | P_IDENT(GPIO_PG1) | P_FUNCT(2)) +#define P_PWM1_CL (P_DEFINED | P_IDENT(GPIO_PG2) | P_FUNCT(2)) +#define P_PWM1_SYNC (P_DEFINED | P_IDENT(GPIO_PF15) | P_FUNCT(2)) + #define P_PWM_TRIPB (P_DEFINED | P_IDENT(GPIO_PG14) | P_FUNCT(2)) -#endif /* RSI */ #define P_RSI_DATA0 (P_DEFINED | P_IDENT(GPIO_PG3) | P_FUNCT(1)) diff --git a/trunk/arch/blackfin/mach-bf527/boards/ad7160eval.c b/trunk/arch/blackfin/mach-bf527/boards/ad7160eval.c index c04df43f6391..ccab4c689dc3 100644 --- a/trunk/arch/blackfin/mach-bf527/boards/ad7160eval.c +++ b/trunk/arch/blackfin/mach-bf527/boards/ad7160eval.c @@ -265,12 +265,29 @@ static struct flash_platform_data bfin_spi_flash_data = { /* SPI flash chip (m25p64) */ static struct bfin5xx_spi_chip spi_flash_chip_info = { .enable_dma = 0, /* use dma transfer with this chip*/ + .bits_per_word = 8, +}; +#endif + +#if defined(CONFIG_SND_BF5XX_SOC_AD183X) \ + || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE) +static struct bfin5xx_spi_chip ad1836_spi_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, }; #endif #if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE) static struct bfin5xx_spi_chip mmc_spi_chip_info = { .enable_dma = 0, + .bits_per_word = 8, +}; +#endif + +#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE) +static struct bfin5xx_spi_chip spidev_chip_info = { + .enable_dma = 0, + .bits_per_word = 8, }; #endif @@ -311,6 +328,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 4, + .controller_data = &ad1836_spi_chip_info, }, #endif #if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE) @@ -329,6 +347,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 1, + .controller_data = &spidev_chip_info, }, #endif }; diff --git a/trunk/arch/blackfin/mach-bf527/boards/cm_bf527.c b/trunk/arch/blackfin/mach-bf527/boards/cm_bf527.c index 6400341cc230..c9d6dc88f0e6 100644 --- a/trunk/arch/blackfin/mach-bf527/boards/cm_bf527.c +++ b/trunk/arch/blackfin/mach-bf527/boards/cm_bf527.c @@ -354,16 +354,40 @@ static struct flash_platform_data bfin_spi_flash_data = { /* SPI flash chip (m25p64) */ static struct bfin5xx_spi_chip spi_flash_chip_info = { .enable_dma = 0, /* use dma transfer with this chip*/ + .bits_per_word = 8, +}; +#endif + +#if defined(CONFIG_BFIN_SPI_ADC) \ + || defined(CONFIG_BFIN_SPI_ADC_MODULE) +/* SPI ADC chip */ +static struct bfin5xx_spi_chip spi_adc_chip_info = { + .enable_dma = 1, /* use dma transfer with this chip*/ + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_SND_BF5XX_SOC_AD183X) \ + || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE) +static struct bfin5xx_spi_chip ad1836_spi_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, }; #endif #if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE) static struct bfin5xx_spi_chip mmc_spi_chip_info = { .enable_dma = 0, + .bits_per_word = 8, }; #endif #if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE) +static struct bfin5xx_spi_chip spi_ad7877_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; + static const struct ad7877_platform_data bfin_ad7877_ts_info = { .model = 7877, .vref_delay_usecs = 50, /* internal, no capacitor */ @@ -379,6 +403,21 @@ static const struct ad7877_platform_data bfin_ad7877_ts_info = { }; #endif +#if defined(CONFIG_SND_SOC_WM8731) || defined(CONFIG_SND_SOC_WM8731_MODULE) \ + && defined(CONFIG_SND_SOC_WM8731_SPI) +static struct bfin5xx_spi_chip spi_wm8731_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE) +static struct bfin5xx_spi_chip spidev_chip_info = { + .enable_dma = 0, + .bits_per_word = 8, +}; +#endif + static struct spi_board_info bfin_spi_board_info[] __initdata = { #if defined(CONFIG_MTD_M25P80) \ || defined(CONFIG_MTD_M25P80_MODULE) @@ -394,6 +433,18 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { }, #endif +#if defined(CONFIG_BFIN_SPI_ADC) \ + || defined(CONFIG_BFIN_SPI_ADC_MODULE) + { + .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */ + .max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 0, /* Framework bus number */ + .chip_select = 1, /* Framework chip select. */ + .platform_data = NULL, /* No spi_driver specific config */ + .controller_data = &spi_adc_chip_info, + }, +#endif + #if defined(CONFIG_SND_BF5XX_SOC_AD183X) \ || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE) { @@ -401,6 +452,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 4, + .controller_data = &ad1836_spi_chip_info, }, #endif #if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE) @@ -421,6 +473,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 2, + .controller_data = &spi_ad7877_chip_info, }, #endif #if defined(CONFIG_SND_SOC_WM8731) || defined(CONFIG_SND_SOC_WM8731_MODULE) \ @@ -430,6 +483,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 5, + .controller_data = &spi_wm8731_chip_info, .mode = SPI_MODE_0, }, #endif @@ -439,6 +493,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 1, + .controller_data = &spidev_chip_info, }, #endif }; diff --git a/trunk/arch/blackfin/mach-bf527/boards/ezbrd.c b/trunk/arch/blackfin/mach-bf527/boards/ezbrd.c index 6dbb1b403763..b7101aa6e3aa 100644 --- a/trunk/arch/blackfin/mach-bf527/boards/ezbrd.c +++ b/trunk/arch/blackfin/mach-bf527/boards/ezbrd.c @@ -253,16 +253,32 @@ static struct flash_platform_data bfin_spi_flash_data = { /* SPI flash chip (sst25wf040) */ static struct bfin5xx_spi_chip spi_flash_chip_info = { .enable_dma = 0, /* use dma transfer with this chip*/ + .bits_per_word = 8, +}; +#endif + +#if defined(CONFIG_BFIN_SPI_ADC) \ + || defined(CONFIG_BFIN_SPI_ADC_MODULE) +/* SPI ADC chip */ +static struct bfin5xx_spi_chip spi_adc_chip_info = { + .enable_dma = 1, /* use dma transfer with this chip*/ + .bits_per_word = 16, }; #endif #if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE) static struct bfin5xx_spi_chip mmc_spi_chip_info = { .enable_dma = 0, + .bits_per_word = 8, }; #endif #if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE) +static struct bfin5xx_spi_chip spi_ad7877_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; + static const struct ad7877_platform_data bfin_ad7877_ts_info = { .model = 7877, .vref_delay_usecs = 50, /* internal, no capacitor */ @@ -295,6 +311,35 @@ static const struct ad7879_platform_data bfin_ad7879_ts_info = { }; #endif +#if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) || defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE) +static struct bfin5xx_spi_chip spi_ad7879_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_SND_SOC_WM8731) || defined(CONFIG_SND_SOC_WM8731_MODULE) \ + && defined(CONFIG_SND_SOC_WM8731_SPI) +static struct bfin5xx_spi_chip spi_wm8731_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE) +static struct bfin5xx_spi_chip spidev_chip_info = { + .enable_dma = 0, + .bits_per_word = 8, +}; +#endif + +#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE) +static struct bfin5xx_spi_chip lq035q1_spi_chip_info = { + .enable_dma = 0, + .bits_per_word = 8, +}; +#endif + static struct spi_board_info bfin_spi_board_info[] __initdata = { #if defined(CONFIG_MTD_M25P80) \ || defined(CONFIG_MTD_M25P80_MODULE) @@ -310,6 +355,18 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { }, #endif +#if defined(CONFIG_BFIN_SPI_ADC) \ + || defined(CONFIG_BFIN_SPI_ADC_MODULE) + { + .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */ + .max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 0, /* Framework bus number */ + .chip_select = 1, /* Framework chip select. */ + .platform_data = NULL, /* No spi_driver specific config */ + .controller_data = &spi_adc_chip_info, + }, +#endif + #if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE) { .modalias = "mmc_spi", @@ -328,6 +385,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 2, + .controller_data = &spi_ad7877_chip_info, }, #endif #if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) || defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE) @@ -338,6 +396,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 5000000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 5, + .controller_data = &spi_ad7879_chip_info, .mode = SPI_CPHA | SPI_CPOL, }, #endif @@ -348,6 +407,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 5, + .controller_data = &spi_wm8731_chip_info, .mode = SPI_MODE_0, }, #endif @@ -357,6 +417,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 1, + .controller_data = &spidev_chip_info, }, #endif #if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE) @@ -365,6 +426,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 20000000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 1, + .controller_data = &lq035q1_spi_chip_info, .mode = SPI_CPHA | SPI_CPOL, }, #endif diff --git a/trunk/arch/blackfin/mach-bf527/boards/ezkit.c b/trunk/arch/blackfin/mach-bf527/boards/ezkit.c index 4e9dc9cf8241..e67ac7720668 100644 --- a/trunk/arch/blackfin/mach-bf527/boards/ezkit.c +++ b/trunk/arch/blackfin/mach-bf527/boards/ezkit.c @@ -408,9 +408,6 @@ static struct resource net2272_bfin_resources[] = { .start = 0x20300000, .end = 0x20300000 + 0x100, .flags = IORESOURCE_MEM, - }, { - .start = 1, - .flags = IORESOURCE_BUS, }, { .start = IRQ_PF7, .end = IRQ_PF7, @@ -451,16 +448,40 @@ static struct flash_platform_data bfin_spi_flash_data = { /* SPI flash chip (m25p64) */ static struct bfin5xx_spi_chip spi_flash_chip_info = { .enable_dma = 0, /* use dma transfer with this chip*/ + .bits_per_word = 8, +}; +#endif + +#if defined(CONFIG_BFIN_SPI_ADC) \ + || defined(CONFIG_BFIN_SPI_ADC_MODULE) +/* SPI ADC chip */ +static struct bfin5xx_spi_chip spi_adc_chip_info = { + .enable_dma = 1, /* use dma transfer with this chip*/ + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_SND_BF5XX_SOC_AD183X) \ + || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE) +static struct bfin5xx_spi_chip ad1836_spi_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, }; #endif #if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE) static struct bfin5xx_spi_chip mmc_spi_chip_info = { .enable_dma = 0, + .bits_per_word = 8, }; #endif #if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE) +static struct bfin5xx_spi_chip spi_ad7877_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; + static const struct ad7877_platform_data bfin_ad7877_ts_info = { .model = 7877, .vref_delay_usecs = 50, /* internal, no capacitor */ @@ -492,6 +513,20 @@ static const struct ad7879_platform_data bfin_ad7879_ts_info = { }; #endif +#if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) || defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE) +static struct bfin5xx_spi_chip spi_ad7879_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE) +static struct bfin5xx_spi_chip spidev_chip_info = { + .enable_dma = 0, + .bits_per_word = 8, +}; +#endif + #if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) || \ defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE) @@ -539,25 +574,9 @@ static struct resource bfin_snd_resources[][4] = { BFIN_SND_RES(0), BFIN_SND_RES(1), }; -#endif -#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) -static struct platform_device bfin_i2s_pcm = { - .name = "bfin-i2s-pcm-audio", - .id = -1, -}; -#endif - -#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE) -static struct platform_device bfin_tdm_pcm = { - .name = "bfin-tdm-pcm-audio", - .id = -1, -}; -#endif - -#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE) -static struct platform_device bfin_ac97_pcm = { - .name = "bfin-ac97-pcm-audio", +static struct platform_device bfin_pcm = { + .name = "bfin-pcm-audio", .id = -1, }; #endif @@ -586,6 +605,13 @@ static struct platform_device bfin_tdm = { }; #endif +#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE) +static struct bfin5xx_spi_chip lq035q1_spi_chip_info = { + .enable_dma = 0, + .bits_per_word = 8, +}; +#endif + static struct spi_board_info bfin_spi_board_info[] __initdata = { #if defined(CONFIG_MTD_M25P80) \ || defined(CONFIG_MTD_M25P80_MODULE) @@ -601,6 +627,18 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { }, #endif +#if defined(CONFIG_BFIN_SPI_ADC) \ + || defined(CONFIG_BFIN_SPI_ADC_MODULE) + { + .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */ + .max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 0, /* Framework bus number */ + .chip_select = 1, /* Framework chip select. */ + .platform_data = NULL, /* No spi_driver specific config */ + .controller_data = &spi_adc_chip_info, + }, +#endif + #if defined(CONFIG_SND_BF5XX_SOC_AD183X) \ || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE) { @@ -609,6 +647,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .bus_num = 0, .chip_select = 4, .platform_data = "ad1836", + .controller_data = &ad1836_spi_chip_info, .mode = SPI_MODE_3, }, #endif @@ -631,6 +670,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 2, + .controller_data = &spi_ad7877_chip_info, }, #endif #if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) || defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE) @@ -641,6 +681,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 5000000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 3, + .controller_data = &spi_ad7879_chip_info, .mode = SPI_CPHA | SPI_CPOL, }, #endif @@ -650,6 +691,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 1, + .controller_data = &spidev_chip_info, }, #endif #if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE) @@ -658,6 +700,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 20000000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 7, + .controller_data = &lq035q1_spi_chip_info, .mode = SPI_CPHA | SPI_CPOL, }, #endif @@ -1233,16 +1276,9 @@ static struct platform_device *stamp_devices[] __initdata = { &ezkit_flash_device, #endif -#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) - &bfin_i2s_pcm, -#endif - -#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE) - &bfin_tdm_pcm, -#endif - -#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE) - &bfin_ac97_pcm, +#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) || \ + defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE) + &bfin_pcm, #endif #if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) diff --git a/trunk/arch/blackfin/mach-bf527/boards/tll6527m.c b/trunk/arch/blackfin/mach-bf527/boards/tll6527m.c index ec4bc7429c9f..18d303dd5627 100644 --- a/trunk/arch/blackfin/mach-bf527/boards/tll6527m.c +++ b/trunk/arch/blackfin/mach-bf527/boards/tll6527m.c @@ -314,12 +314,29 @@ static struct flash_platform_data bfin_spi_flash_data = { /* SPI flash chip (m25p64) */ static struct bfin5xx_spi_chip spi_flash_chip_info = { .enable_dma = 0, /* use dma transfer with this chip*/ + .bits_per_word = 8, +}; +#endif + +#if defined(CONFIG_BFIN_SPI_ADC) \ + || defined(CONFIG_BFIN_SPI_ADC_MODULE) +/* SPI ADC chip */ +static struct bfin5xx_spi_chip spi_adc_chip_info = { + .enable_dma = 0, /* use dma transfer with this chip*/ +/* + * tll6527m V1.0 does not support native spi slave selects + * hence DMA mode will not be useful since the ADC needs + * CS to toggle for each sample and cs_change_per_word + * seems to be removed from spi_bfin5xx.c + */ + .bits_per_word = 16, }; #endif #if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE) static struct bfin5xx_spi_chip mmc_spi_chip_info = { .enable_dma = 0, + .bits_per_word = 8, }; #endif @@ -342,6 +359,21 @@ static const struct ad7879_platform_data bfin_ad7879_ts_info = { }; #endif +#if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) \ + || defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE) +static struct bfin5xx_spi_chip spi_ad7879_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE) +static struct bfin5xx_spi_chip spidev_chip_info = { + .enable_dma = 0, + .bits_per_word = 8, +}; +#endif + #if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) static struct platform_device bfin_i2s = { .name = "bfin-i2s", @@ -350,7 +382,24 @@ static struct platform_device bfin_i2s = { }; #endif +#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE) +static struct bfin5xx_spi_chip lq035q1_spi_chip_info = { + .enable_dma = 0, + .bits_per_word = 8, +}; +#endif + #if defined(CONFIG_GPIO_MCP23S08) || defined(CONFIG_GPIO_MCP23S08_MODULE) +static struct bfin5xx_spi_chip spi_mcp23s08_sys_chip_info = { + .enable_dma = 0, + .bits_per_word = 8, +}; + +static struct bfin5xx_spi_chip spi_mcp23s08_usr_chip_info = { + .enable_dma = 0, + .bits_per_word = 8, +}; + #include static const struct mcp23s08_platform_data bfin_mcp23s08_sys_gpio_info = { .chip[0].is_present = true, @@ -380,6 +429,22 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { }, #endif +#if defined(CONFIG_BFIN_SPI_ADC) + || defined(CONFIG_BFIN_SPI_ADC_MODULE) + { + .modalias = "bfin_spi_adc", + /* Name of spi_driver for this device */ + .max_speed_hz = 10000000, + /* max spi clock (SCK) speed in HZ */ + .bus_num = 0, /* Framework bus number */ + .chip_select = EXP_GPIO_SPISEL_BASE + 0x04 + MAX_CTRL_CS, + /* Framework chip select. */ + .platform_data = NULL, /* No spi_driver specific config */ + .controller_data = &spi_adc_chip_info, + .mode = SPI_MODE_0, + }, +#endif + #if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE) { .modalias = "mmc_spi", @@ -405,6 +470,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = EXP_GPIO_SPISEL_BASE + 0x07 + MAX_CTRL_CS, + .controller_data = &spi_ad7879_chip_info, .mode = SPI_CPHA | SPI_CPOL, }, #endif @@ -416,6 +482,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .bus_num = 0, .chip_select = EXP_GPIO_SPISEL_BASE + 0x03 + MAX_CTRL_CS, .mode = SPI_CPHA | SPI_CPOL, + .controller_data = &spidev_chip_info, }, #endif #if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE) @@ -424,6 +491,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 20000000, .bus_num = 0, .chip_select = EXP_GPIO_SPISEL_BASE + 0x06 + MAX_CTRL_CS, + .controller_data = &lq035q1_spi_chip_info, .mode = SPI_CPHA | SPI_CPOL, }, #endif @@ -434,6 +502,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 5000000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = EXP_GPIO_SPISEL_BASE + 0x01 + MAX_CTRL_CS, + .controller_data = &spi_mcp23s08_sys_chip_info, .mode = SPI_CPHA | SPI_CPOL, }, { @@ -442,6 +511,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 5000000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = EXP_GPIO_SPISEL_BASE + 0x02 + MAX_CTRL_CS, + .controller_data = &spi_mcp23s08_usr_chip_info, .mode = SPI_CPHA | SPI_CPOL, }, #endif diff --git a/trunk/arch/blackfin/mach-bf527/include/mach/anomaly.h b/trunk/arch/blackfin/mach-bf527/include/mach/anomaly.h index 688470611e15..e66a7e89cd3c 100644 --- a/trunk/arch/blackfin/mach-bf527/include/mach/anomaly.h +++ b/trunk/arch/blackfin/mach-bf527/include/mach/anomaly.h @@ -11,8 +11,8 @@ */ /* This file should be up to date with: - * - Revision F, 05/23/2011; ADSP-BF526 Blackfin Processor Anomaly List - * - Revision I, 05/23/2011; ADSP-BF527 Blackfin Processor Anomaly List + * - Revision E, 03/15/2010; ADSP-BF526 Blackfin Processor Anomaly List + * - Revision H, 04/29/2010; ADSP-BF527 Blackfin Processor Anomaly List */ #ifndef _MACH_ANOMALY_H_ @@ -57,7 +57,7 @@ /* Incorrect Access of OTP_STATUS During otp_write() Function */ #define ANOMALY_05000328 (_ANOMALY_BF527(< 2)) /* Host DMA Boot Modes Are Not Functional */ -#define ANOMALY_05000330 (_ANOMALY_BF527(< 2)) +#define ANOMALY_05000330 (__SILICON_REVISION__ < 2) /* Disallowed Configuration Prevents Subsequent Allowed Configuration on Host DMA Port */ #define ANOMALY_05000337 (_ANOMALY_BF527(< 2)) /* Ethernet MAC MDIO Reads Do Not Meet IEEE Specification */ @@ -135,7 +135,7 @@ /* Incorrect Default Internal Voltage Regulator Setting */ #define ANOMALY_05000410 (_ANOMALY_BF527(< 2)) /* bfrom_SysControl() Firmware Function Cannot be Used to Enter Power Saving Modes */ -#define ANOMALY_05000411 (_ANOMALY_BF526(< 1)) +#define ANOMALY_05000411 (_ANOMALY_BF526_BF527(< 1, < 2)) /* OTP_CHECK_FOR_PREV_WRITE Bit is Not Functional in bfrom_OtpWrite() API */ #define ANOMALY_05000414 (_ANOMALY_BF526_BF527(< 1, < 2)) /* DEB2_URGENT Bit Not Functional */ @@ -181,11 +181,11 @@ /* IFLUSH Instruction at End of Hardware Loop Causes Infinite Stall */ #define ANOMALY_05000443 (1) /* The WURESET Bit in the SYSCR Register is not Functional */ -#define ANOMALY_05000445 (_ANOMALY_BF527(>= 0)) -/* USB DMA Short Packet Data Corruption */ +#define ANOMALY_05000445 (1) +/* USB DMA Mode 1 Short Packet Data Corruption */ #define ANOMALY_05000450 (1) /* BCODE_QUICKBOOT, BCODE_ALLBOOT, and BCODE_FULLBOOT Settings in SYSCR Register Not Functional */ -#define ANOMALY_05000451 (_ANOMALY_BF527(>= 0)) +#define ANOMALY_05000451 (1) /* Incorrect Default Hysteresis Setting for RESET, NMI, and BMODE Signals */ #define ANOMALY_05000452 (_ANOMALY_BF526_BF527(< 1, >= 0)) /* USB Receive Interrupt Is Not Generated in DMA Mode 1 */ @@ -198,19 +198,19 @@ #define ANOMALY_05000461 (1) /* Synchronization Problem at Startup May Cause SPORT Transmit Channels to Misalign */ #define ANOMALY_05000462 (1) -/* USB Rx DMA Hang */ +/* USB Rx DMA hang */ #define ANOMALY_05000465 (1) /* TxPktRdy Bit Not Set for Transmit Endpoint When Core and DMA Access USB Endpoint FIFOs Simultaneously */ #define ANOMALY_05000466 (1) -/* Possible USB RX Data Corruption When Control & Data EP FIFOs are Accessed via the Core */ +/* Possible RX data corruption when control & data EP FIFOs are accessed via the core */ #define ANOMALY_05000467 (1) /* PLL Latches Incorrect Settings During Reset */ #define ANOMALY_05000469 (1) /* Incorrect Default MSEL Value in PLL_CTL */ #define ANOMALY_05000472 (_ANOMALY_BF526(>= 0)) -/* Interrupted SPORT Receive Data Register Read Results In Underflow when SLEN > 15 */ +/* Interrupted 32-Bit SPORT Data Register Access Results In Underflow */ #define ANOMALY_05000473 (1) -/* Possible Lockup Condition when Modifying PLL from External Memory */ +/* Possible Lockup Condition whem Modifying PLL from External Memory */ #define ANOMALY_05000475 (1) /* TESTSET Instruction Cannot Be Interrupted */ #define ANOMALY_05000477 (1) @@ -219,19 +219,11 @@ /* Possible USB Data Corruption When Multiple Endpoints Are Accessed by the Core */ #define ANOMALY_05000483 (1) /* PLL_CTL Change Using bfrom_SysControl() Can Result in Processor Overclocking */ -#define ANOMALY_05000485 (_ANOMALY_BF526_BF527(< 2, >= 0)) +#define ANOMALY_05000485 (_ANOMALY_BF526_BF527(< 2, < 3)) /* The CODEC Zero-Cross Detect Feature is not Functional */ #define ANOMALY_05000487 (1) -/* SPI Master Boot Can Fail Under Certain Conditions */ -#define ANOMALY_05000490 (1) -/* Instruction Memory Stalls Can Cause IFLUSH to Fail */ +/* IFLUSH sucks at life */ #define ANOMALY_05000491 (1) -/* EXCPT Instruction May Be Lost If NMI Happens Simultaneously */ -#define ANOMALY_05000494 (1) -/* CNT_COMMAND Functionality Depends on CNT_IMASK Configuration */ -#define ANOMALY_05000498 (1) -/* RXS Bit in SPI_STAT May Become Stuck In RX DMA Modes */ -#define ANOMALY_05000501 (1) /* Anomalies that don't exist on this proc */ #define ANOMALY_05000099 (0) diff --git a/trunk/arch/blackfin/mach-bf533/boards/H8606.c b/trunk/arch/blackfin/mach-bf533/boards/H8606.c index eb325ed6607e..d4bfcea56828 100644 --- a/trunk/arch/blackfin/mach-bf533/boards/H8606.c +++ b/trunk/arch/blackfin/mach-bf533/boards/H8606.c @@ -159,6 +159,22 @@ static struct flash_platform_data bfin_spi_flash_data = { /* SPI flash chip (m25p64) */ static struct bfin5xx_spi_chip spi_flash_chip_info = { .enable_dma = 0, /* use dma transfer with this chip*/ + .bits_per_word = 8, +}; +#endif + +#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE) +/* SPI ADC chip */ +static struct bfin5xx_spi_chip spi_adc_chip_info = { + .enable_dma = 1, /* use dma transfer with this chip*/ + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_SND_BF5XX_SOC_AD183X) || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE) +static struct bfin5xx_spi_chip ad1836_spi_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, }; #endif @@ -179,12 +195,24 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { }, #endif +#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE) + { + .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */ + .max_speed_hz = 4, /* actual baudrate is SCLK/(2xspeed_hz) */ + .bus_num = 1, /* Framework bus number */ + .chip_select = 1, /* Framework chip select. */ + .platform_data = NULL, /* No spi_driver specific config */ + .controller_data = &spi_adc_chip_info, + }, +#endif + #if defined(CONFIG_SND_BF5XX_SOC_AD183X) || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE) { .modalias = "ad183x", .max_speed_hz = 16, .bus_num = 1, .chip_select = 4, + .controller_data = &ad1836_spi_chip_info, }, #endif diff --git a/trunk/arch/blackfin/mach-bf533/boards/blackstamp.c b/trunk/arch/blackfin/mach-bf533/boards/blackstamp.c index b0ec825fb4ec..87b5af3693c1 100644 --- a/trunk/arch/blackfin/mach-bf533/boards/blackstamp.c +++ b/trunk/arch/blackfin/mach-bf533/boards/blackstamp.c @@ -102,12 +102,21 @@ static struct flash_platform_data bfin_spi_flash_data = { /* SPI flash chip (m25p64) */ static struct bfin5xx_spi_chip spi_flash_chip_info = { .enable_dma = 0, /* use dma transfer with this chip*/ + .bits_per_word = 8, }; #endif #if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE) static struct bfin5xx_spi_chip mmc_spi_chip_info = { .enable_dma = 0, + .bits_per_word = 8, +}; +#endif + +#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE) +static struct bfin5xx_spi_chip spidev_chip_info = { + .enable_dma = 0, + .bits_per_word = 8, }; #endif @@ -142,6 +151,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 7, + .controller_data = &spidev_chip_info, }, #endif }; diff --git a/trunk/arch/blackfin/mach-bf533/boards/cm_bf533.c b/trunk/arch/blackfin/mach-bf533/boards/cm_bf533.c index 14f54a31e74c..4d5604eaa7c2 100644 --- a/trunk/arch/blackfin/mach-bf533/boards/cm_bf533.c +++ b/trunk/arch/blackfin/mach-bf533/boards/cm_bf533.c @@ -59,12 +59,29 @@ static struct flash_platform_data bfin_spi_flash_data = { /* SPI flash chip (m25p64) */ static struct bfin5xx_spi_chip spi_flash_chip_info = { .enable_dma = 0, /* use dma transfer with this chip*/ + .bits_per_word = 8, +}; +#endif + +/* SPI ADC chip */ +#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE) +static struct bfin5xx_spi_chip spi_adc_chip_info = { + .enable_dma = 1, /* use dma transfer with this chip*/ + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_SND_BF5XX_SOC_AD183X) || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE) +static struct bfin5xx_spi_chip ad1836_spi_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, }; #endif #if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE) static struct bfin5xx_spi_chip mmc_spi_chip_info = { .enable_dma = 0, + .bits_per_word = 8, }; #endif @@ -82,12 +99,24 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { }, #endif +#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE) + { + .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */ + .max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 0, /* Framework bus number */ + .chip_select = 2, /* Framework chip select. */ + .platform_data = NULL, /* No spi_driver specific config */ + .controller_data = &spi_adc_chip_info, + }, +#endif + #if defined(CONFIG_SND_BF5XX_SOC_AD183X) || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE) { .modalias = "ad183x", .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 4, + .controller_data = &ad1836_spi_chip_info, }, #endif diff --git a/trunk/arch/blackfin/mach-bf533/boards/ezkit.c b/trunk/arch/blackfin/mach-bf533/boards/ezkit.c index ecd2801f050d..b67b91d82242 100644 --- a/trunk/arch/blackfin/mach-bf533/boards/ezkit.c +++ b/trunk/arch/blackfin/mach-bf533/boards/ezkit.c @@ -210,6 +210,29 @@ static struct flash_platform_data bfin_spi_flash_data = { /* SPI flash chip (m25p64) */ static struct bfin5xx_spi_chip spi_flash_chip_info = { .enable_dma = 0, /* use dma transfer with this chip*/ + .bits_per_word = 8, +}; +#endif + +#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE) +/* SPI ADC chip */ +static struct bfin5xx_spi_chip spi_adc_chip_info = { + .enable_dma = 1, /* use dma transfer with this chip*/ + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_SND_BF5XX_SOC_AD183X) || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE) +static struct bfin5xx_spi_chip ad1836_spi_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE) +static struct bfin5xx_spi_chip spidev_chip_info = { + .enable_dma = 0, + .bits_per_word = 8, }; #endif @@ -227,12 +250,24 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { }, #endif +#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE) + { + .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */ + .max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 0, /* Framework bus number */ + .chip_select = 1, /* Framework chip select. */ + .platform_data = NULL, /* No spi_driver specific config */ + .controller_data = &spi_adc_chip_info, + }, +#endif + #if defined(CONFIG_SND_BF5XX_SOC_AD183X) || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE) { .modalias = "ad183x", .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 4, + .controller_data = &ad1836_spi_chip_info, }, #endif #if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE) @@ -241,6 +276,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 1, + .controller_data = &spidev_chip_info, }, #endif }; diff --git a/trunk/arch/blackfin/mach-bf533/boards/ip0x.c b/trunk/arch/blackfin/mach-bf533/boards/ip0x.c index fbee77fa9211..a377d8afea03 100644 --- a/trunk/arch/blackfin/mach-bf533/boards/ip0x.c +++ b/trunk/arch/blackfin/mach-bf533/boards/ip0x.c @@ -110,6 +110,7 @@ static struct platform_device dm9000_device2 = { #if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE) static struct bfin5xx_spi_chip mmc_spi_chip_info = { .enable_dma = 0, /* if 1 - block!!! */ + .bits_per_word = 8, }; #endif diff --git a/trunk/arch/blackfin/mach-bf533/boards/stamp.c b/trunk/arch/blackfin/mach-bf533/boards/stamp.c index 964a8e5f79b4..43224ef00b8c 100644 --- a/trunk/arch/blackfin/mach-bf533/boards/stamp.c +++ b/trunk/arch/blackfin/mach-bf533/boards/stamp.c @@ -79,9 +79,6 @@ static struct resource net2272_bfin_resources[] = { .start = 0x20300000, .end = 0x20300000 + 0x100, .flags = IORESOURCE_MEM, - }, { - .start = 1, - .flags = IORESOURCE_BUS, }, { .start = IRQ_PF10, .end = IRQ_PF10, @@ -175,6 +172,29 @@ static struct flash_platform_data bfin_spi_flash_data = { /* SPI flash chip (m25p64) */ static struct bfin5xx_spi_chip spi_flash_chip_info = { .enable_dma = 0, /* use dma transfer with this chip*/ + .bits_per_word = 8, +}; +#endif + +#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE) +/* SPI ADC chip */ +static struct bfin5xx_spi_chip spi_adc_chip_info = { + .enable_dma = 1, /* use dma transfer with this chip*/ + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_SND_BF5XX_SOC_AD183X) || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE) +static struct bfin5xx_spi_chip ad1836_spi_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE) +static struct bfin5xx_spi_chip spidev_chip_info = { + .enable_dma = 0, + .bits_per_word = 8, }; #endif @@ -201,6 +221,7 @@ static struct mmc_spi_platform_data bfin_mmc_spi_pdata = { static struct bfin5xx_spi_chip mmc_spi_chip_info = { .enable_dma = 0, + .bits_per_word = 8, .pio_interrupt = 0, }; #endif @@ -219,6 +240,17 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { }, #endif +#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE) + { + .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */ + .max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 0, /* Framework bus number */ + .chip_select = 1, /* Framework chip select. */ + .platform_data = NULL, /* No spi_driver specific config */ + .controller_data = &spi_adc_chip_info, + }, +#endif + #if defined(CONFIG_SND_BF5XX_SOC_AD183X) || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE) { .modalias = "ad183x", @@ -226,6 +258,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .bus_num = 0, .chip_select = 4, .platform_data = "ad1836", /* only includes chip name for the moment */ + .controller_data = &ad1836_spi_chip_info, .mode = SPI_MODE_3, }, #endif @@ -236,6 +269,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 1, + .controller_data = &spidev_chip_info, }, #endif #if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE) @@ -625,41 +659,6 @@ static struct platform_device *stamp_devices[] __initdata = { #endif }; -static int __init net2272_init(void) -{ -#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE) - int ret; - - /* Set PF0 to 0, PF1 to 1 make /AMS3 work properly */ - ret = gpio_request(GPIO_PF0, "net2272"); - if (ret) - return ret; - - ret = gpio_request(GPIO_PF1, "net2272"); - if (ret) { - gpio_free(GPIO_PF0); - return ret; - } - - ret = gpio_request(GPIO_PF11, "net2272"); - if (ret) { - gpio_free(GPIO_PF0); - gpio_free(GPIO_PF1); - return ret; - } - - gpio_direction_output(GPIO_PF0, 0); - gpio_direction_output(GPIO_PF1, 1); - - /* Reset the USB chip */ - gpio_direction_output(GPIO_PF11, 0); - mdelay(2); - gpio_set_value(GPIO_PF11, 1); -#endif - - return 0; -} - static int __init stamp_init(void) { int ret; @@ -686,9 +685,6 @@ static int __init stamp_init(void) } #endif - if (net2272_init()) - pr_warning("unable to configure net2272; it probably won't work\n"); - spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info)); return 0; } diff --git a/trunk/arch/blackfin/mach-bf533/include/mach/anomaly.h b/trunk/arch/blackfin/mach-bf533/include/mach/anomaly.h index 03f2b40912a3..72aa59440f82 100644 --- a/trunk/arch/blackfin/mach-bf533/include/mach/anomaly.h +++ b/trunk/arch/blackfin/mach-bf533/include/mach/anomaly.h @@ -11,7 +11,7 @@ */ /* This file should be up to date with: - * - Revision G, 05/23/2011; ADSP-BF531/BF532/BF533 Blackfin Processor Anomaly List + * - Revision F, 05/25/2010; ADSP-BF531/BF532/BF533 Blackfin Processor Anomaly List */ #ifndef _MACH_ANOMALY_H_ @@ -152,7 +152,7 @@ #define ANOMALY_05000277 (__SILICON_REVISION__ < 6) /* Disabling Peripherals with DMA Running May Cause DMA System Instability */ #define ANOMALY_05000278 (__SILICON_REVISION__ < 6) -/* False Hardware Error when ISR Context Is Not Restored */ +/* False Hardware Error Exception when ISR Context Is Not Restored */ #define ANOMALY_05000281 (__SILICON_REVISION__ < 6) /* Memory DMA Corruption with 32-Bit Data and Traffic Control */ #define ANOMALY_05000282 (__SILICON_REVISION__ < 6) @@ -210,25 +210,18 @@ #define ANOMALY_05000462 (1) /* Boot Failure When SDRAM Control Signals Toggle Coming Out Of Reset */ #define ANOMALY_05000471 (1) -/* Interrupted SPORT Receive Data Register Read Results In Underflow when SLEN > 15 */ +/* Interrupted 32-Bit SPORT Data Register Access Results In Underflow */ #define ANOMALY_05000473 (1) -/* Possible Lockup Condition when Modifying PLL from External Memory */ +/* Possible Lockup Condition whem Modifying PLL from External Memory */ #define ANOMALY_05000475 (1) /* TESTSET Instruction Cannot Be Interrupted */ #define ANOMALY_05000477 (1) /* Reads of ITEST_COMMAND and ITEST_DATA Registers Cause Cache Corruption */ #define ANOMALY_05000481 (1) -/* PLL May Latch Incorrect Values Coming Out of Reset */ -#define ANOMALY_05000489 (1) -/* Instruction Memory Stalls Can Cause IFLUSH to Fail */ +/* IFLUSH sucks at life */ #define ANOMALY_05000491 (1) -/* EXCPT Instruction May Be Lost If NMI Happens Simultaneously */ -#define ANOMALY_05000494 (1) -/* RXS Bit in SPI_STAT May Become Stuck In RX DMA Modes */ -#define ANOMALY_05000501 (1) -/* - * These anomalies have been "phased" out of analog.com anomaly sheets and are +/* These anomalies have been "phased" out of analog.com anomaly sheets and are * here to show running on older silicon just isn't feasible. */ diff --git a/trunk/arch/blackfin/mach-bf537/boards/cm_bf537e.c b/trunk/arch/blackfin/mach-bf537/boards/cm_bf537e.c index 44fd8409db10..d582b810e7a7 100644 --- a/trunk/arch/blackfin/mach-bf537/boards/cm_bf537e.c +++ b/trunk/arch/blackfin/mach-bf537/boards/cm_bf537e.c @@ -61,12 +61,29 @@ static struct flash_platform_data bfin_spi_flash_data = { /* SPI flash chip (m25p64) */ static struct bfin5xx_spi_chip spi_flash_chip_info = { .enable_dma = 0, /* use dma transfer with this chip*/ + .bits_per_word = 8, +}; +#endif + +#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE) +/* SPI ADC chip */ +static struct bfin5xx_spi_chip spi_adc_chip_info = { + .enable_dma = 1, /* use dma transfer with this chip*/ + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_SND_BF5XX_SOC_AD183X) || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE) +static struct bfin5xx_spi_chip ad1836_spi_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, }; #endif #if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE) static struct bfin5xx_spi_chip mmc_spi_chip_info = { .enable_dma = 0, + .bits_per_word = 8, }; #endif @@ -84,12 +101,24 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { }, #endif +#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE) + { + .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */ + .max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 0, /* Framework bus number */ + .chip_select = 1, /* Framework chip select. */ + .platform_data = NULL, /* No spi_driver specific config */ + .controller_data = &spi_adc_chip_info, + }, +#endif + #if defined(CONFIG_SND_BF5XX_SOC_AD183X) || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE) { .modalias = "ad183x", .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 4, + .controller_data = &ad1836_spi_chip_info, }, #endif @@ -737,24 +766,6 @@ static struct platform_device *cm_bf537e_devices[] __initdata = { #endif }; -static int __init net2272_init(void) -{ -#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE) - int ret; - - ret = gpio_request(GPIO_PG14, "net2272"); - if (ret) - return ret; - - /* Reset USB Chip, PG14 */ - gpio_direction_output(GPIO_PG14, 0); - mdelay(2); - gpio_set_value(GPIO_PG14, 1); -#endif - - return 0; -} - static int __init cm_bf537e_init(void) { printk(KERN_INFO "%s(): registering device resources\n", __func__); @@ -766,10 +777,6 @@ static int __init cm_bf537e_init(void) #if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE) irq_set_status_flags(PATA_INT, IRQ_NOAUTOEN); #endif - - if (net2272_init()) - pr_warning("unable to configure net2272; it probably won't work\n"); - return 0; } diff --git a/trunk/arch/blackfin/mach-bf537/boards/cm_bf537u.c b/trunk/arch/blackfin/mach-bf537/boards/cm_bf537u.c index 1b4ac5c64aae..cbb8098604c5 100644 --- a/trunk/arch/blackfin/mach-bf537/boards/cm_bf537u.c +++ b/trunk/arch/blackfin/mach-bf537/boards/cm_bf537u.c @@ -62,12 +62,29 @@ static struct flash_platform_data bfin_spi_flash_data = { /* SPI flash chip (m25p64) */ static struct bfin5xx_spi_chip spi_flash_chip_info = { .enable_dma = 0, /* use dma transfer with this chip*/ + .bits_per_word = 8, +}; +#endif + +#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE) +/* SPI ADC chip */ +static struct bfin5xx_spi_chip spi_adc_chip_info = { + .enable_dma = 1, /* use dma transfer with this chip*/ + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_SND_BF5XX_SOC_AD183X) || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE) +static struct bfin5xx_spi_chip ad1836_spi_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, }; #endif #if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE) static struct bfin5xx_spi_chip mmc_spi_chip_info = { .enable_dma = 0, + .bits_per_word = 8, }; #endif @@ -85,12 +102,24 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { }, #endif +#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE) + { + .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */ + .max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 0, /* Framework bus number */ + .chip_select = 1, /* Framework chip select. */ + .platform_data = NULL, /* No spi_driver specific config */ + .controller_data = &spi_adc_chip_info, + }, +#endif + #if defined(CONFIG_SND_BF5XX_SOC_AD183X) || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE) { .modalias = "ad183x", .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 4, + .controller_data = &ad1836_spi_chip_info, }, #endif @@ -702,36 +731,6 @@ static struct platform_device *cm_bf537u_devices[] __initdata = { #endif }; -static int __init net2272_init(void) -{ -#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE) - int ret; - - ret = gpio_request(GPIO_PH15, driver_name); - if (ret) - return ret; - - ret = gpio_request(GPIO_PH13, "net2272"); - if (ret) { - gpio_free(GPIO_PH15); - return ret; - } - - /* Set PH15 Low make /AMS2 work properly */ - gpio_direction_output(GPIO_PH15, 0); - - /* enable CLKBUF output */ - bfin_write_VR_CTL(bfin_read_VR_CTL() | CLKBUFOE); - - /* Reset the USB chip */ - gpio_direction_output(GPIO_PH13, 0); - mdelay(2); - gpio_set_value(GPIO_PH13, 1); -#endif - - return 0; -} - static int __init cm_bf537u_init(void) { printk(KERN_INFO "%s(): registering device resources\n", __func__); @@ -743,10 +742,6 @@ static int __init cm_bf537u_init(void) #if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE) irq_set_status_flags(PATA_INT, IRQ_NOAUTOEN); #endif - - if (net2272_init()) - pr_warning("unable to configure net2272; it probably won't work\n"); - return 0; } diff --git a/trunk/arch/blackfin/mach-bf537/boards/dnp5370.c b/trunk/arch/blackfin/mach-bf537/boards/dnp5370.c index 8bc951de979d..6b4ff4605bff 100644 --- a/trunk/arch/blackfin/mach-bf537/boards/dnp5370.c +++ b/trunk/arch/blackfin/mach-bf537/boards/dnp5370.c @@ -130,6 +130,7 @@ static struct platform_device asmb_flash_device = { static struct bfin5xx_spi_chip mmc_spi_chip_info = { .enable_dma = 0, /* use no dma transfer with this chip*/ + .bits_per_word = 8, }; #endif @@ -160,6 +161,7 @@ static struct flash_platform_data bfin_spi_dataflash_data = { static struct bfin5xx_spi_chip spi_dataflash_chip_info = { .enable_dma = 0, /* use no dma transfer with this chip*/ + .bits_per_word = 8, }; #endif diff --git a/trunk/arch/blackfin/mach-bf537/boards/minotaur.c b/trunk/arch/blackfin/mach-bf537/boards/minotaur.c index c62f9dccd9f7..bfb3671a78da 100644 --- a/trunk/arch/blackfin/mach-bf537/boards/minotaur.c +++ b/trunk/arch/blackfin/mach-bf537/boards/minotaur.c @@ -159,12 +159,14 @@ static struct flash_platform_data bfin_spi_flash_data = { /* SPI flash chip (m25p64) */ static struct bfin5xx_spi_chip spi_flash_chip_info = { .enable_dma = 0, /* use dma transfer with this chip*/ + .bits_per_word = 8, }; #endif #if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE) static struct bfin5xx_spi_chip mmc_spi_chip_info = { .enable_dma = 0, + .bits_per_word = 8, }; #endif diff --git a/trunk/arch/blackfin/mach-bf537/boards/pnav10.c b/trunk/arch/blackfin/mach-bf537/boards/pnav10.c index 3b8151d99b9a..9389f03e3b0a 100644 --- a/trunk/arch/blackfin/mach-bf537/boards/pnav10.c +++ b/trunk/arch/blackfin/mach-bf537/boards/pnav10.c @@ -184,16 +184,40 @@ static struct flash_platform_data bfin_spi_flash_data = { /* SPI flash chip (m25p64) */ static struct bfin5xx_spi_chip spi_flash_chip_info = { .enable_dma = 0, /* use dma transfer with this chip*/ + .bits_per_word = 8, +}; +#endif + +#if defined(CONFIG_BFIN_SPI_ADC) \ + || defined(CONFIG_BFIN_SPI_ADC_MODULE) +/* SPI ADC chip */ +static struct bfin5xx_spi_chip spi_adc_chip_info = { + .enable_dma = 1, /* use dma transfer with this chip*/ + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_SND_BF5XX_SOC_AD183X) \ + || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE) +static struct bfin5xx_spi_chip ad1836_spi_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, }; #endif #if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE) static struct bfin5xx_spi_chip mmc_spi_chip_info = { .enable_dma = 0, + .bits_per_word = 8, }; #endif #if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE) +static struct bfin5xx_spi_chip spi_ad7877_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; + static const struct ad7877_platform_data bfin_ad7877_ts_info = { .model = 7877, .vref_delay_usecs = 50, /* internal, no capacitor */ @@ -224,6 +248,18 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { }, #endif +#if defined(CONFIG_BFIN_SPI_ADC) \ + || defined(CONFIG_BFIN_SPI_ADC_MODULE) + { + .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */ + .max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 0, /* Framework bus number */ + .chip_select = 1, /* Framework chip select. */ + .platform_data = NULL, /* No spi_driver specific config */ + .controller_data = &spi_adc_chip_info, + }, +#endif + #if defined(CONFIG_SND_BF5XX_SOC_AD183X) \ || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE) { @@ -231,6 +267,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 4, + .controller_data = &ad1836_spi_chip_info, }, #endif #if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE) @@ -251,6 +288,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 5, + .controller_data = &spi_ad7877_chip_info, }, #endif diff --git a/trunk/arch/blackfin/mach-bf537/boards/stamp.c b/trunk/arch/blackfin/mach-bf537/boards/stamp.c index b52e6728f64f..76db1d483173 100644 --- a/trunk/arch/blackfin/mach-bf537/boards/stamp.c +++ b/trunk/arch/blackfin/mach-bf537/boards/stamp.c @@ -366,9 +366,6 @@ static struct resource net2272_bfin_resources[] = { .start = 0x20300000, .end = 0x20300000 + 0x100, .flags = IORESOURCE_MEM, - }, { - .start = 1, - .flags = IORESOURCE_BUS, }, { .start = IRQ_PF7, .end = IRQ_PF7, @@ -536,11 +533,49 @@ static struct flash_platform_data bfin_spi_flash_data = { /* SPI flash chip (m25p64) */ static struct bfin5xx_spi_chip spi_flash_chip_info = { .enable_dma = 0, /* use dma transfer with this chip*/ + .bits_per_word = 8, +}; +#endif + +#if defined(CONFIG_BFIN_SPI_ADC) \ + || defined(CONFIG_BFIN_SPI_ADC_MODULE) +/* SPI ADC chip */ +static struct bfin5xx_spi_chip spi_adc_chip_info = { + .enable_dma = 1, /* use dma transfer with this chip*/ + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_SND_BF5XX_SOC_AD183X) \ + || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE) +static struct bfin5xx_spi_chip ad1836_spi_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_SND_BF5XX_SOC_AD193X) \ + || defined(CONFIG_SND_BF5XX_SOC_AD193X_MODULE) +static struct bfin5xx_spi_chip ad1938_spi_chip_info = { + .enable_dma = 0, + .bits_per_word = 8, +}; +#endif + +#if defined(CONFIG_SND_BF5XX_SOC_ADAV80X) \ + || defined(CONFIG_SND_BF5XX_SOC_ADAV80X_MODULE) +static struct bfin5xx_spi_chip adav801_spi_chip_info = { + .enable_dma = 0, + .bits_per_word = 8, }; #endif #if defined(CONFIG_INPUT_AD714X_SPI) || defined(CONFIG_INPUT_AD714X_SPI_MODULE) #include +static struct bfin5xx_spi_chip ad7147_spi_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; static struct ad714x_slider_plat ad7147_spi_slider_plat[] = { { @@ -650,6 +685,7 @@ static struct ad714x_platform_data ad7142_i2c_platform_data = { #if defined(CONFIG_AD2S90) || defined(CONFIG_AD2S90_MODULE) static struct bfin5xx_spi_chip ad2s90_spi_chip_info = { .enable_dma = 0, + .bits_per_word = 16, }; #endif @@ -661,6 +697,7 @@ static unsigned short ad2s120x_platform_data[] = { static struct bfin5xx_spi_chip ad2s120x_spi_chip_info = { .enable_dma = 0, + .bits_per_word = 16, }; #endif @@ -677,12 +714,14 @@ static unsigned short ad2s1210_platform_data[] = { static struct bfin5xx_spi_chip ad2s1210_spi_chip_info = { .enable_dma = 0, + .bits_per_word = 8, }; #endif #if defined(CONFIG_AD7314) || defined(CONFIG_AD7314_MODULE) static struct bfin5xx_spi_chip ad7314_spi_chip_info = { .enable_dma = 0, + .bits_per_word = 16, }; #endif @@ -696,6 +735,7 @@ static unsigned short ad7816_platform_data[] = { static struct bfin5xx_spi_chip ad7816_spi_chip_info = { .enable_dma = 0, + .bits_per_word = 8, }; #endif @@ -709,6 +749,7 @@ static unsigned long adt7310_platform_data[3] = { static struct bfin5xx_spi_chip adt7310_spi_chip_info = { .enable_dma = 0, + .bits_per_word = 8, }; #endif @@ -717,6 +758,11 @@ static unsigned short ad7298_platform_data[] = { GPIO_PF7, /* busy_pin */ 0, }; + +static struct bfin5xx_spi_chip ad7298_spi_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; #endif #if defined(CONFIG_ADT7316_SPI) || defined(CONFIG_ADT7316_SPI_MODULE) @@ -727,6 +773,7 @@ static unsigned long adt7316_spi_data[2] = { static struct bfin5xx_spi_chip adt7316_spi_chip_info = { .enable_dma = 0, + .bits_per_word = 8, }; #endif @@ -753,12 +800,18 @@ static struct mmc_spi_platform_data bfin_mmc_spi_pdata = { static struct bfin5xx_spi_chip mmc_spi_chip_info = { .enable_dma = 0, + .bits_per_word = 8, .pio_interrupt = 0, }; #endif #if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE) #include +static struct bfin5xx_spi_chip spi_ad7877_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; + static const struct ad7877_platform_data bfin_ad7877_ts_info = { .model = 7877, .vref_delay_usecs = 50, /* internal, no capacitor */ @@ -830,13 +883,39 @@ static const struct adxl34x_platform_data adxl34x_info = { }; #endif +#if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) || defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE) +static struct bfin5xx_spi_chip spi_ad7879_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE) +static struct bfin5xx_spi_chip spidev_chip_info = { + .enable_dma = 0, + .bits_per_word = 8, +}; +#endif + +#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE) +static struct bfin5xx_spi_chip lq035q1_spi_chip_info = { + .enable_dma = 0, + .bits_per_word = 8, +}; +#endif + #if defined(CONFIG_ENC28J60) || defined(CONFIG_ENC28J60_MODULE) static struct bfin5xx_spi_chip enc28j60_spi_chip_info = { .enable_dma = 1, + .bits_per_word = 8, }; #endif #if defined(CONFIG_ADF702X) || defined(CONFIG_ADF702X_MODULE) +static struct bfin5xx_spi_chip adf7021_spi_chip_info = { + .bits_per_word = 16, +}; + #include #define TXREG 0x0160A470 static const u32 adf7021_regs[] = { @@ -880,6 +959,10 @@ static inline void adf702x_mac_init(void) {} #if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE) #include +static struct bfin5xx_spi_chip ad7873_spi_chip_info = { + .bits_per_word = 8, +}; + static int ads7873_get_pendown_state(void) { return gpio_get_value(GPIO_PF6); @@ -926,12 +1009,21 @@ static struct flash_platform_data bfin_spi_dataflash_data = { /* DataFlash chip */ static struct bfin5xx_spi_chip data_flash_chip_info = { .enable_dma = 0, /* use dma transfer with this chip*/ + .bits_per_word = 8, +}; +#endif + +#if defined(CONFIG_INPUT_ADXL34X_SPI) || defined(CONFIG_INPUT_ADXL34X_SPI_MODULE) +static struct bfin5xx_spi_chip spi_adxl34x_chip_info = { + .enable_dma = 0, /* use dma transfer with this chip*/ + .bits_per_word = 8, }; #endif #if defined(CONFIG_AD7476) || defined(CONFIG_AD7476_MODULE) static struct bfin5xx_spi_chip spi_ad7476_chip_info = { .enable_dma = 0, /* use dma transfer with this chip*/ + .bits_per_word = 8, }; #endif @@ -961,6 +1053,17 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .mode = SPI_MODE_3, }, #endif +#if defined(CONFIG_BFIN_SPI_ADC) \ + || defined(CONFIG_BFIN_SPI_ADC_MODULE) + { + .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */ + .max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 0, /* Framework bus number */ + .chip_select = 1, /* Framework chip select. */ + .platform_data = NULL, /* No spi_driver specific config */ + .controller_data = &spi_adc_chip_info, + }, +#endif #if defined(CONFIG_SND_BF5XX_SOC_AD183X) \ || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE) @@ -970,6 +1073,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .bus_num = 0, .chip_select = 4, .platform_data = "ad1836", /* only includes chip name for the moment */ + .controller_data = &ad1836_spi_chip_info, .mode = SPI_MODE_3, }, #endif @@ -980,6 +1084,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 5, + .controller_data = &ad1938_spi_chip_info, .mode = SPI_MODE_3, }, #endif @@ -990,6 +1095,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 1, + .controller_data = &adav801_spi_chip_info, .mode = SPI_MODE_3, }, #endif @@ -1003,6 +1109,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .chip_select = 5, .mode = SPI_MODE_3, .platform_data = &ad7147_spi_platform_data, + .controller_data = &ad7147_spi_chip_info, }, #endif @@ -1081,6 +1188,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .bus_num = 0, .chip_select = 4, /* CS, change it for your board */ .platform_data = ad7298_platform_data, + .controller_data = &ad7298_spi_chip_info, .mode = SPI_MODE_3, }, #endif @@ -1117,6 +1225,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 1, + .controller_data = &spi_ad7877_chip_info, }, #endif #if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) || defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE) @@ -1127,6 +1236,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 5000000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 1, + .controller_data = &spi_ad7879_chip_info, .mode = SPI_CPHA | SPI_CPOL, }, #endif @@ -1136,6 +1246,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 1, + .controller_data = &spidev_chip_info, }, #endif #if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE) @@ -1144,6 +1255,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 20000000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 2, + .controller_data = &lq035q1_spi_chip_info, .mode = SPI_CPHA | SPI_CPOL, }, #endif @@ -1166,6 +1278,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 5000000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 2, + .controller_data = &spi_adxl34x_chip_info, .mode = SPI_MODE_3, }, #endif @@ -1175,6 +1288,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 16000000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = GPIO_PF10 + MAX_CTRL_CS, /* GPIO controlled SSEL */ + .controller_data = &adf7021_spi_chip_info, .platform_data = &adf7021_platform_data, .mode = SPI_MODE_0, }, @@ -1186,6 +1300,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .bus_num = 0, .irq = IRQ_PF6, .chip_select = GPIO_PF10 + MAX_CTRL_CS, /* GPIO controlled SSEL */ + .controller_data = &ad7873_spi_chip_info, .platform_data = &ad7873_pdata, .mode = SPI_MODE_0, }, @@ -2517,25 +2632,9 @@ static struct resource bfin_snd_resources[][4] = { BFIN_SND_RES(0), BFIN_SND_RES(1), }; -#endif - -#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) -static struct platform_device bfin_i2s_pcm = { - .name = "bfin-i2s-pcm-audio", - .id = -1, -}; -#endif -#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE) -static struct platform_device bfin_tdm_pcm = { - .name = "bfin-tdm-pcm-audio", - .id = -1, -}; -#endif - -#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE) -static struct platform_device bfin_ac97_pcm = { - .name = "bfin-ac97-pcm-audio", +static struct platform_device bfin_pcm = { + .name = "bfin-pcm-audio", .id = -1, }; #endif @@ -2770,16 +2869,10 @@ static struct platform_device *stamp_devices[] __initdata = { &stamp_flash_device, #endif -#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) - &bfin_i2s_pcm, -#endif - -#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE) - &bfin_tdm_pcm, -#endif - -#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE) - &bfin_ac97_pcm, +#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) || \ + defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE) || \ + defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE) + &bfin_pcm, #endif #if defined(CONFIG_SND_BF5XX_SOC_AD73311) || defined(CONFIG_SND_BF5XX_SOC_AD73311_MODULE) @@ -2823,24 +2916,6 @@ static struct platform_device *stamp_devices[] __initdata = { #endif }; -static int __init net2272_init(void) -{ -#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE) - int ret; - - ret = gpio_request(GPIO_PF6, "net2272"); - if (ret) - return ret; - - /* Reset the USB chip */ - gpio_direction_output(GPIO_PF6, 0); - mdelay(2); - gpio_set_value(GPIO_PF6, 1); -#endif - - return 0; -} - static int __init stamp_init(void) { printk(KERN_INFO "%s(): registering device resources\n", __func__); @@ -2851,9 +2926,6 @@ static int __init stamp_init(void) ARRAY_SIZE(bfin_i2c_board_info)); spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info)); - if (net2272_init()) - pr_warning("unable to configure net2272; it probably won't work\n"); - return 0; } diff --git a/trunk/arch/blackfin/mach-bf537/boards/tcm_bf537.c b/trunk/arch/blackfin/mach-bf537/boards/tcm_bf537.c index 9b7287abdfa1..164a7e02c022 100644 --- a/trunk/arch/blackfin/mach-bf537/boards/tcm_bf537.c +++ b/trunk/arch/blackfin/mach-bf537/boards/tcm_bf537.c @@ -62,12 +62,29 @@ static struct flash_platform_data bfin_spi_flash_data = { /* SPI flash chip (m25p64) */ static struct bfin5xx_spi_chip spi_flash_chip_info = { .enable_dma = 0, /* use dma transfer with this chip*/ + .bits_per_word = 8, +}; +#endif + +#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE) +/* SPI ADC chip */ +static struct bfin5xx_spi_chip spi_adc_chip_info = { + .enable_dma = 1, /* use dma transfer with this chip*/ + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_SND_BF5XX_SOC_AD183X) || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE) +static struct bfin5xx_spi_chip ad1836_spi_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, }; #endif #if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE) static struct bfin5xx_spi_chip mmc_spi_chip_info = { .enable_dma = 0, + .bits_per_word = 8, }; #endif @@ -85,12 +102,24 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { }, #endif +#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE) + { + .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */ + .max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 0, /* Framework bus number */ + .chip_select = 1, /* Framework chip select. */ + .platform_data = NULL, /* No spi_driver specific config */ + .controller_data = &spi_adc_chip_info, + }, +#endif + #if defined(CONFIG_SND_BF5XX_SOC_AD183X) || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE) { .modalias = "ad183x", .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 4, + .controller_data = &ad1836_spi_chip_info, }, #endif @@ -704,24 +733,6 @@ static struct platform_device *cm_bf537_devices[] __initdata = { #endif }; -static int __init net2272_init(void) -{ -#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE) - int ret; - - ret = gpio_request(GPIO_PG14, "net2272"); - if (ret) - return ret; - - /* Reset USB Chip, PG14 */ - gpio_direction_output(GPIO_PG14, 0); - mdelay(2); - gpio_set_value(GPIO_PG14, 1); -#endif - - return 0; -} - static int __init tcm_bf537_init(void) { printk(KERN_INFO "%s(): registering device resources\n", __func__); @@ -733,10 +744,6 @@ static int __init tcm_bf537_init(void) #if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE) irq_set_status_flags(PATA_INT, IRQ_NOAUTOEN); #endif - - if (net2272_init()) - pr_warning("unable to configure net2272; it probably won't work\n"); - return 0; } diff --git a/trunk/arch/blackfin/mach-bf537/include/mach/anomaly.h b/trunk/arch/blackfin/mach-bf537/include/mach/anomaly.h index 543cd3fb305e..7f8e5a9f5db6 100644 --- a/trunk/arch/blackfin/mach-bf537/include/mach/anomaly.h +++ b/trunk/arch/blackfin/mach-bf537/include/mach/anomaly.h @@ -11,7 +11,7 @@ */ /* This file should be up to date with: - * - Revision F, 05/23/2011; ADSP-BF534/ADSP-BF536/ADSP-BF537 Blackfin Processor Anomaly List + * - Revision E, 05/25/2010; ADSP-BF534/ADSP-BF536/ADSP-BF537 Blackfin Processor Anomaly List */ #ifndef _MACH_ANOMALY_H_ @@ -44,12 +44,18 @@ #define ANOMALY_05000119 (1) /* Rx.H Cannot Be Used to Access 16-bit System MMR Registers */ #define ANOMALY_05000122 (1) +/* Killed 32-Bit MMR Write Leads to Next System MMR Access Thinking It Should Be 32-Bit */ +#define ANOMALY_05000157 (__SILICON_REVISION__ < 2) /* PPI_DELAY Not Functional in PPI Modes with 0 Frame Syncs */ #define ANOMALY_05000180 (1) +/* Instruction Cache Is Not Functional */ +#define ANOMALY_05000237 (__SILICON_REVISION__ < 2) /* If I-Cache Is On, CSYNC/SSYNC/IDLE Around Change of Control Causes Failures */ #define ANOMALY_05000244 (__SILICON_REVISION__ < 3) /* False Hardware Error from an Access in the Shadow of a Conditional Branch */ #define ANOMALY_05000245 (1) +/* Buffered CLKIN Output Is Disabled by Default */ +#define ANOMALY_05000247 (1) /* Incorrect Bit Shift of Data Word in Multichannel (TDM) Mode in Certain Conditions */ #define ANOMALY_05000250 (__SILICON_REVISION__ < 3) /* EMAC TX DMA Error After an Early Frame Abort */ @@ -92,7 +98,7 @@ #define ANOMALY_05000278 (((ANOMALY_BF536 || ANOMALY_BF537) && __SILICON_REVISION__ < 3) || (ANOMALY_BF534 && __SILICON_REVISION__ < 2)) /* SPI Master Boot Mode Does Not Work Well with Atmel Data Flash Devices */ #define ANOMALY_05000280 (1) -/* False Hardware Error when ISR Context Is Not Restored */ +/* False Hardware Error Exception when ISR Context Is Not Restored */ #define ANOMALY_05000281 (__SILICON_REVISION__ < 3) /* Memory DMA Corruption with 32-Bit Data and Traffic Control */ #define ANOMALY_05000282 (__SILICON_REVISION__ < 3) @@ -156,9 +162,9 @@ #define ANOMALY_05000461 (1) /* Synchronization Problem at Startup May Cause SPORT Transmit Channels to Misalign */ #define ANOMALY_05000462 (1) -/* Interrupted SPORT Receive Data Register Read Results In Underflow when SLEN > 15 */ +/* Interrupted 32-Bit SPORT Data Register Access Results In Underflow */ #define ANOMALY_05000473 (1) -/* Possible Lockup Condition when Modifying PLL from External Memory */ +/* Possible Lockup Condition whem Modifying PLL from External Memory */ #define ANOMALY_05000475 (1) /* TESTSET Instruction Cannot Be Interrupted */ #define ANOMALY_05000477 (1) @@ -166,26 +172,8 @@ #define ANOMALY_05000480 (__SILICON_REVISION__ < 3) /* Reads of ITEST_COMMAND and ITEST_DATA Registers Cause Cache Corruption */ #define ANOMALY_05000481 (1) -/* PLL May Latch Incorrect Values Coming Out of Reset */ -#define ANOMALY_05000489 (1) -/* Instruction Memory Stalls Can Cause IFLUSH to Fail */ +/* IFLUSH sucks at life */ #define ANOMALY_05000491 (1) -/* EXCPT Instruction May Be Lost If NMI Happens Simultaneously */ -#define ANOMALY_05000494 (1) -/* RXS Bit in SPI_STAT May Become Stuck In RX DMA Modes */ -#define ANOMALY_05000501 (1) - -/* - * These anomalies have been "phased" out of analog.com anomaly sheets and are - * here to show running on older silicon just isn't feasible. - */ - -/* Killed 32-Bit MMR Write Leads to Next System MMR Access Thinking It Should Be 32-Bit */ -#define ANOMALY_05000157 (__SILICON_REVISION__ < 2) -/* Instruction Cache Is Not Functional */ -#define ANOMALY_05000237 (__SILICON_REVISION__ < 2) -/* Buffered CLKIN Output Is Disabled by Default */ -#define ANOMALY_05000247 (__SILICON_REVISION__ < 2) /* Anomalies that don't exist on this proc */ #define ANOMALY_05000099 (0) diff --git a/trunk/arch/blackfin/mach-bf538/boards/ezkit.c b/trunk/arch/blackfin/mach-bf538/boards/ezkit.c index 629f3c333415..e61424ef35eb 100644 --- a/trunk/arch/blackfin/mach-bf538/boards/ezkit.c +++ b/trunk/arch/blackfin/mach-bf538/boards/ezkit.c @@ -502,6 +502,7 @@ static struct flash_platform_data bfin_spi_flash_data = { static struct bfin5xx_spi_chip spi_flash_chip_info = { .enable_dma = 0, /* use dma transfer with this chip*/ + .bits_per_word = 8, }; #endif @@ -522,6 +523,13 @@ static const struct ad7879_platform_data bfin_ad7879_ts_info = { }; #endif +#if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) || defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE) +static struct bfin5xx_spi_chip spi_ad7879_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; +#endif + #if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE) #include @@ -551,6 +559,20 @@ static struct platform_device bfin_lq035q1_device = { }; #endif +#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE) +static struct bfin5xx_spi_chip spidev_chip_info = { + .enable_dma = 0, + .bits_per_word = 8, +}; +#endif + +#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE) +static struct bfin5xx_spi_chip lq035q1_spi_chip_info = { + .enable_dma = 0, + .bits_per_word = 8, +}; +#endif + static struct spi_board_info bf538_spi_board_info[] __initdata = { #if defined(CONFIG_MTD_M25P80) \ || defined(CONFIG_MTD_M25P80_MODULE) @@ -573,6 +595,7 @@ static struct spi_board_info bf538_spi_board_info[] __initdata = { .max_speed_hz = 5000000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 1, + .controller_data = &spi_ad7879_chip_info, .mode = SPI_CPHA | SPI_CPOL, }, #endif @@ -582,6 +605,7 @@ static struct spi_board_info bf538_spi_board_info[] __initdata = { .max_speed_hz = 20000000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 2, + .controller_data = &lq035q1_spi_chip_info, .mode = SPI_CPHA | SPI_CPOL, }, #endif @@ -591,6 +615,7 @@ static struct spi_board_info bf538_spi_board_info[] __initdata = { .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 1, + .controller_data = &spidev_chip_info, }, #endif }; diff --git a/trunk/arch/blackfin/mach-bf538/ext-gpio.c b/trunk/arch/blackfin/mach-bf538/ext-gpio.c index 471a9b184d5b..180b1252679f 100644 --- a/trunk/arch/blackfin/mach-bf538/ext-gpio.c +++ b/trunk/arch/blackfin/mach-bf538/ext-gpio.c @@ -1,7 +1,7 @@ /* * GPIOLIB interface for BF538/9 PORT C, D, and E GPIOs * - * Copyright 2009-2011 Analog Devices Inc. + * Copyright 2009 Analog Devices Inc. * * Licensed under the GPL-2 or later. */ @@ -121,38 +121,3 @@ static int __init bf538_extgpio_setup(void) gpiochip_add(&bf538_porte_chip); } arch_initcall(bf538_extgpio_setup); - -#ifdef CONFIG_PM -static struct { - u16 data, dir, inen; -} gpio_bank_saved[3]; - -static void __iomem * const port_bases[3] = { - (void *)PORTCIO, - (void *)PORTDIO, - (void *)PORTEIO, -}; - -void bfin_special_gpio_pm_hibernate_suspend(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(port_bases); ++i) { - gpio_bank_saved[i].data = read_PORTIO(port_bases[i]); - gpio_bank_saved[i].inen = read_PORTIO_INEN(port_bases[i]); - gpio_bank_saved[i].dir = read_PORTIO_DIR(port_bases[i]); - } -} - -void bfin_special_gpio_pm_hibernate_restore(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(port_bases); ++i) { - write_PORTIO_INEN(port_bases[i], gpio_bank_saved[i].inen); - write_PORTIO_SET(port_bases[i], - gpio_bank_saved[i].data & gpio_bank_saved[i].dir); - write_PORTIO_DIR(port_bases[i], gpio_bank_saved[i].dir); - } -} -#endif diff --git a/trunk/arch/blackfin/mach-bf538/include/mach/anomaly.h b/trunk/arch/blackfin/mach-bf538/include/mach/anomaly.h index b6ca99788710..55e7d0712a94 100644 --- a/trunk/arch/blackfin/mach-bf538/include/mach/anomaly.h +++ b/trunk/arch/blackfin/mach-bf538/include/mach/anomaly.h @@ -11,8 +11,8 @@ */ /* This file should be up to date with: - * - Revision J, 05/23/2011; ADSP-BF538/BF538F Blackfin Processor Anomaly List - * - Revision O, 05/23/2011; ADSP-BF539/BF539F Blackfin Processor Anomaly List + * - Revision I, 05/25/2010; ADSP-BF538/BF538F Blackfin Processor Anomaly List + * - Revision N, 05/25/2010; ADSP-BF539/BF539F Blackfin Processor Anomaly List */ #ifndef _MACH_ANOMALY_H_ @@ -56,21 +56,25 @@ #define ANOMALY_05000229 (1) /* PPI_FS3 Is Not Driven in 2 or 3 Internal Frame Sync Transmit Modes */ #define ANOMALY_05000233 (1) +/* If I-Cache Is On, CSYNC/SSYNC/IDLE Around Change of Control Causes Failures */ +#define ANOMALY_05000244 (__SILICON_REVISION__ < 3) /* False Hardware Error from an Access in the Shadow of a Conditional Branch */ #define ANOMALY_05000245 (1) /* Maximum External Clock Speed for Timers */ #define ANOMALY_05000253 (1) +/* DCPLB_FAULT_ADDR MMR Register May Be Corrupted */ +#define ANOMALY_05000261 (__SILICON_REVISION__ < 3) /* High I/O Activity Causes Output Voltage of Internal Voltage Regulator (Vddint) to Decrease */ #define ANOMALY_05000270 (__SILICON_REVISION__ < 4) /* Certain Data Cache Writethrough Modes Fail for Vddint <= 0.9V */ -#define ANOMALY_05000272 (ANOMALY_BF538) +#define ANOMALY_05000272 (1) /* Writes to Synchronous SDRAM Memory May Be Lost */ #define ANOMALY_05000273 (__SILICON_REVISION__ < 4) /* Writes to an I/O Data Register One SCLK Cycle after an Edge Is Detected May Clear Interrupt */ #define ANOMALY_05000277 (__SILICON_REVISION__ < 4) /* Disabling Peripherals with DMA Running May Cause DMA System Instability */ #define ANOMALY_05000278 (__SILICON_REVISION__ < 4) -/* False Hardware Error when ISR Context Is Not Restored */ +/* False Hardware Error Exception when ISR Context Is Not Restored */ #define ANOMALY_05000281 (__SILICON_REVISION__ < 4) /* Memory DMA Corruption with 32-Bit Data and Traffic Control */ #define ANOMALY_05000282 (__SILICON_REVISION__ < 4) @@ -98,10 +102,8 @@ #define ANOMALY_05000313 (__SILICON_REVISION__ < 4) /* Killed System MMR Write Completes Erroneously on Next System MMR Access */ #define ANOMALY_05000315 (__SILICON_REVISION__ < 4) -/* PFx Glitch on Write to PORTFIO or PORTFIO_TOGGLE */ -#define ANOMALY_05000317 (__SILICON_REVISION__ < 4) /* XXX: Same as 05000318 */ /* PFx Glitch on Write to FIO_FLAG_D or FIO_FLAG_T */ -#define ANOMALY_05000318 (__SILICON_REVISION__ < 4) /* XXX: Same as 05000317 */ +#define ANOMALY_05000318 (ANOMALY_BF539 && __SILICON_REVISION__ < 4) /* Regulator Programming Blocked when Hibernate Wakeup Source Remains Active */ #define ANOMALY_05000355 (__SILICON_REVISION__ < 5) /* Serial Port (SPORT) Multichannel Transmit Failure when Channel 0 Is Disabled */ @@ -132,32 +134,16 @@ #define ANOMALY_05000461 (1) /* Synchronization Problem at Startup May Cause SPORT Transmit Channels to Misalign */ #define ANOMALY_05000462 (1) -/* Interrupted SPORT Receive Data Register Read Results In Underflow when SLEN > 15 */ +/* Interrupted 32-Bit SPORT Data Register Access Results In Underflow */ #define ANOMALY_05000473 (1) -/* Possible Lockup Condition when Modifying PLL from External Memory */ +/* Possible Lockup Condition whem Modifying PLL from External Memory */ #define ANOMALY_05000475 (1) /* TESTSET Instruction Cannot Be Interrupted */ #define ANOMALY_05000477 (1) /* Reads of ITEST_COMMAND and ITEST_DATA Registers Cause Cache Corruption */ #define ANOMALY_05000481 (1) -/* PLL May Latch Incorrect Values Coming Out of Reset */ -#define ANOMALY_05000489 (1) -/* Instruction Memory Stalls Can Cause IFLUSH to Fail */ +/* IFLUSH sucks at life */ #define ANOMALY_05000491 (1) -/* EXCPT Instruction May Be Lost If NMI Happens Simultaneously */ -#define ANOMALY_05000494 (1) -/* RXS Bit in SPI_STAT May Become Stuck In RX DMA Modes */ -#define ANOMALY_05000501 (1) - -/* - * These anomalies have been "phased" out of analog.com anomaly sheets and are - * here to show running on older silicon just isn't feasible. - */ - -/* If I-Cache Is On, CSYNC/SSYNC/IDLE Around Change of Control Causes Failures */ -#define ANOMALY_05000244 (__SILICON_REVISION__ < 3) -/* DCPLB_FAULT_ADDR MMR Register May Be Corrupted */ -#define ANOMALY_05000261 (__SILICON_REVISION__ < 3) /* Anomalies that don't exist on this proc */ #define ANOMALY_05000099 (0) diff --git a/trunk/arch/blackfin/mach-bf538/include/mach/gpio.h b/trunk/arch/blackfin/mach-bf538/include/mach/gpio.h index 3561c7d8935b..8a5beeece996 100644 --- a/trunk/arch/blackfin/mach-bf538/include/mach/gpio.h +++ b/trunk/arch/blackfin/mach-bf538/include/mach/gpio.h @@ -8,10 +8,7 @@ #define _MACH_GPIO_H_ #define MAX_BLACKFIN_GPIOS 16 -#ifdef CONFIG_GPIOLIB -/* We only use the special logic with GPIOLIB devices */ #define BFIN_SPECIAL_GPIO_BANKS 3 -#endif #define GPIO_PF0 0 /* PF */ #define GPIO_PF1 1 diff --git a/trunk/arch/blackfin/mach-bf548/boards/cm_bf548.c b/trunk/arch/blackfin/mach-bf548/boards/cm_bf548.c index 212b9e0a08c8..d11502ac5623 100644 --- a/trunk/arch/blackfin/mach-bf548/boards/cm_bf548.c +++ b/trunk/arch/blackfin/mach-bf548/boards/cm_bf548.c @@ -861,10 +861,16 @@ static struct flash_platform_data bfin_spi_flash_data = { static struct bfin5xx_spi_chip spi_flash_chip_info = { .enable_dma = 0, /* use dma transfer with this chip*/ + .bits_per_word = 8, }; #endif #if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE) +static struct bfin5xx_spi_chip spi_ad7877_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; + static const struct ad7877_platform_data bfin_ad7877_ts_info = { .model = 7877, .vref_delay_usecs = 50, /* internal, no capacitor */ @@ -880,6 +886,13 @@ static const struct ad7877_platform_data bfin_ad7877_ts_info = { }; #endif +#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE) +static struct bfin5xx_spi_chip spidev_chip_info = { + .enable_dma = 0, + .bits_per_word = 8, +}; +#endif + static struct spi_board_info bf54x_spi_board_info[] __initdata = { #if defined(CONFIG_MTD_M25P80) \ || defined(CONFIG_MTD_M25P80_MODULE) @@ -902,6 +915,7 @@ static struct spi_board_info bf54x_spi_board_info[] __initdata = { .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 2, + .controller_data = &spi_ad7877_chip_info, }, #endif #if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE) @@ -910,6 +924,7 @@ static struct spi_board_info bf54x_spi_board_info[] __initdata = { .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 1, + .controller_data = &spidev_chip_info, }, #endif }; diff --git a/trunk/arch/blackfin/mach-bf548/boards/ezkit.c b/trunk/arch/blackfin/mach-bf548/boards/ezkit.c index cd9cbb68de69..311bf9970fe7 100644 --- a/trunk/arch/blackfin/mach-bf548/boards/ezkit.c +++ b/trunk/arch/blackfin/mach-bf548/boards/ezkit.c @@ -1018,10 +1018,24 @@ static struct flash_platform_data bfin_spi_flash_data = { static struct bfin5xx_spi_chip spi_flash_chip_info = { .enable_dma = 0, /* use dma transfer with this chip*/ + .bits_per_word = 8, +}; +#endif + +#if defined(CONFIG_SND_BF5XX_SOC_AD183X) \ + || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE) +static struct bfin5xx_spi_chip ad1836_spi_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, }; #endif #if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE) +static struct bfin5xx_spi_chip spi_ad7877_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; + static const struct ad7877_platform_data bfin_ad7877_ts_info = { .model = 7877, .vref_delay_usecs = 50, /* internal, no capacitor */ @@ -1037,6 +1051,20 @@ static const struct ad7877_platform_data bfin_ad7877_ts_info = { }; #endif +#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE) +static struct bfin5xx_spi_chip spidev_chip_info = { + .enable_dma = 0, + .bits_per_word = 8, +}; +#endif + +#if defined(CONFIG_INPUT_ADXL34X_SPI) || defined(CONFIG_INPUT_ADXL34X_SPI_MODULE) +static struct bfin5xx_spi_chip spi_adxl34x_chip_info = { + .enable_dma = 0, /* use dma transfer with this chip*/ + .bits_per_word = 8, +}; +#endif + static struct spi_board_info bfin_spi_board_info[] __initdata = { #if defined(CONFIG_MTD_M25P80) \ || defined(CONFIG_MTD_M25P80_MODULE) @@ -1058,6 +1086,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ .bus_num = 1, .chip_select = 4, + .controller_data = &ad1836_spi_chip_info, }, #endif #if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE) @@ -1068,6 +1097,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 2, + .controller_data = &spi_ad7877_chip_info, }, #endif #if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE) @@ -1076,6 +1106,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 1, + .controller_data = &spidev_chip_info, }, #endif #if defined(CONFIG_INPUT_ADXL34X_SPI) || defined(CONFIG_INPUT_ADXL34X_SPI_MODULE) @@ -1086,6 +1117,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 5000000, /* max spi clock (SCK) speed in HZ */ .bus_num = 1, .chip_select = 2, + .controller_data = &spi_adxl34x_chip_info, .mode = SPI_MODE_3, }, #endif diff --git a/trunk/arch/blackfin/mach-bf548/include/mach/anomaly.h b/trunk/arch/blackfin/mach-bf548/include/mach/anomaly.h index ac96ee83b00e..9e70785bdde3 100644 --- a/trunk/arch/blackfin/mach-bf548/include/mach/anomaly.h +++ b/trunk/arch/blackfin/mach-bf548/include/mach/anomaly.h @@ -11,7 +11,7 @@ */ /* This file should be up to date with: - * - Revision K, 05/23/2011; ADSP-BF542/BF544/BF547/BF548/BF549 Blackfin Processor Anomaly List + * - Revision J, 06/03/2010; ADSP-BF542/BF544/BF547/BF548/BF549 Blackfin Processor Anomaly List */ #ifndef _MACH_ANOMALY_H_ @@ -29,37 +29,117 @@ /* Rx.H Cannot Be Used to Access 16-bit System MMR Registers */ #define ANOMALY_05000122 (1) /* Data Corruption/Core Hang with L2/L3 Configured in Writeback Cache Mode */ -#define ANOMALY_05000220 (__SILICON_REVISION__ < 4) +#define ANOMALY_05000220 (1) /* False Hardware Error from an Access in the Shadow of a Conditional Branch */ #define ANOMALY_05000245 (1) /* Sensitivity To Noise with Slow Input Edge Rates on External SPORT TX and RX Clocks */ #define ANOMALY_05000265 (1) /* Certain Data Cache Writethrough Modes Fail for Vddint <= 0.9V */ #define ANOMALY_05000272 (1) +/* False Hardware Error Exception when ISR Context Is Not Restored */ +#define ANOMALY_05000281 (__SILICON_REVISION__ < 1) +/* SSYNCs After Writes To CAN/DMA MMR Registers Are Not Always Handled Correctly */ +#define ANOMALY_05000304 (__SILICON_REVISION__ < 1) /* False Hardware Errors Caused by Fetches at the Boundary of Reserved Memory */ #define ANOMALY_05000310 (1) +/* Errors when SSYNC, CSYNC, or Loads to LT, LB and LC Registers Are Interrupted */ +#define ANOMALY_05000312 (__SILICON_REVISION__ < 1) +/* TWI Slave Boot Mode Is Not Functional */ +#define ANOMALY_05000324 (__SILICON_REVISION__ < 1) /* FIFO Boot Mode Not Functional */ #define ANOMALY_05000325 (__SILICON_REVISION__ < 2) +/* Data Lost When Core and DMA Accesses Are Made to the USB FIFO Simultaneously */ +#define ANOMALY_05000327 (__SILICON_REVISION__ < 1) +/* Incorrect Access of OTP_STATUS During otp_write() Function */ +#define ANOMALY_05000328 (__SILICON_REVISION__ < 1) +/* Synchronous Burst Flash Boot Mode Is Not Functional */ +#define ANOMALY_05000329 (__SILICON_REVISION__ < 1) +/* Host DMA Boot Modes Are Not Functional */ +#define ANOMALY_05000330 (__SILICON_REVISION__ < 1) +/* Inadequate Timing Margins on DDR DQS to DQ and DQM Skew */ +#define ANOMALY_05000334 (__SILICON_REVISION__ < 1) +/* Inadequate Rotary Debounce Logic Duration */ +#define ANOMALY_05000335 (__SILICON_REVISION__ < 1) +/* Phantom Interrupt Occurs After First Configuration of Host DMA Port */ +#define ANOMALY_05000336 (__SILICON_REVISION__ < 1) +/* Disallowed Configuration Prevents Subsequent Allowed Configuration on Host DMA Port */ +#define ANOMALY_05000337 (__SILICON_REVISION__ < 1) +/* Slave-Mode SPI0 MISO Failure With CPHA = 0 */ +#define ANOMALY_05000338 (__SILICON_REVISION__ < 1) +/* If Memory Reads Are Enabled on SDH or HOSTDP, Other DMAC1 Peripherals Cannot Read */ +#define ANOMALY_05000340 (__SILICON_REVISION__ < 1) +/* Boot Host Wait (HWAIT) and Boot Host Wait Alternate (HWAITA) Signals Are Swapped */ +#define ANOMALY_05000344 (__SILICON_REVISION__ < 1) +/* USB Calibration Value Is Not Initialized */ +#define ANOMALY_05000346 (__SILICON_REVISION__ < 1) +/* USB Calibration Value to use */ +#define ANOMALY_05000346_value 0x5411 +/* Preboot Routine Incorrectly Alters Reset Value of USB Register */ +#define ANOMALY_05000347 (__SILICON_REVISION__ < 1) +/* Data Lost when Core Reads SDH Data FIFO */ +#define ANOMALY_05000349 (__SILICON_REVISION__ < 1) +/* PLL Status Register Is Inaccurate */ +#define ANOMALY_05000351 (__SILICON_REVISION__ < 1) /* bfrom_SysControl() Firmware Function Performs Improper System Reset */ /* * Note: anomaly sheet says this is fixed with bf54x-0.2+, but testing * shows that the fix itself does not cover all cases. */ #define ANOMALY_05000353 (1) +/* Regulator Programming Blocked when Hibernate Wakeup Source Remains Active */ +#define ANOMALY_05000355 (__SILICON_REVISION__ < 1) +/* System Stalled During A Core Access To AMC While A Core Access To NFC FIFO Is Required */ +#define ANOMALY_05000356 (__SILICON_REVISION__ < 1) /* Serial Port (SPORT) Multichannel Transmit Failure when Channel 0 Is Disabled */ #define ANOMALY_05000357 (1) /* External Memory Read Access Hangs Core With PLL Bypass */ #define ANOMALY_05000360 (1) /* DMAs that Go Urgent during Tight Core Writes to External Memory Are Blocked */ #define ANOMALY_05000365 (1) +/* WURESET Bit In SYSCR Register Does Not Properly Indicate Hibernate Wake-Up */ +#define ANOMALY_05000367 (__SILICON_REVISION__ < 1) /* Addressing Conflict between Boot ROM and Asynchronous Memory */ #define ANOMALY_05000369 (1) +/* Default PLL MSEL and SSEL Settings Can Cause 400MHz Product To Violate Specifications */ +#define ANOMALY_05000370 (__SILICON_REVISION__ < 1) /* Possible RETS Register Corruption when Subroutine Is under 5 Cycles in Duration */ #define ANOMALY_05000371 (__SILICON_REVISION__ < 2) +/* USB DP/DM Data Pins May Lose State When Entering Hibernate */ +#define ANOMALY_05000372 (__SILICON_REVISION__ < 1) /* Security/Authentication Speedpath Causes Authentication To Fail To Initiate */ #define ANOMALY_05000378 (__SILICON_REVISION__ < 2) /* 16-Bit NAND FLASH Boot Mode Is Not Functional */ #define ANOMALY_05000379 (1) +/* 8-Bit NAND Flash Boot Mode Not Functional */ +#define ANOMALY_05000382 (__SILICON_REVISION__ < 1) +/* Some ATAPI Modes Are Not Functional */ +#define ANOMALY_05000383 (1) +/* Boot from OTP Memory Not Functional */ +#define ANOMALY_05000385 (__SILICON_REVISION__ < 1) +/* bfrom_SysControl() Firmware Routine Not Functional */ +#define ANOMALY_05000386 (__SILICON_REVISION__ < 1) +/* Programmable Preboot Settings Not Functional */ +#define ANOMALY_05000387 (__SILICON_REVISION__ < 1) +/* CRC32 Checksum Support Not Functional */ +#define ANOMALY_05000388 (__SILICON_REVISION__ < 1) +/* Reset Vector Must Not Be in SDRAM Memory Space */ +#define ANOMALY_05000389 (__SILICON_REVISION__ < 1) +/* Changed Meaning of BCODE Field in SYSCR Register */ +#define ANOMALY_05000390 (__SILICON_REVISION__ < 1) +/* Repeated Boot from Page-Mode or Burst-Mode Flash Memory May Fail */ +#define ANOMALY_05000391 (__SILICON_REVISION__ < 1) +/* pTempCurrent Not Present in ADI_BOOT_DATA Structure */ +#define ANOMALY_05000392 (__SILICON_REVISION__ < 1) +/* Deprecated Value of dTempByteCount in ADI_BOOT_DATA Structure */ +#define ANOMALY_05000393 (__SILICON_REVISION__ < 1) +/* Log Buffer Not Functional */ +#define ANOMALY_05000394 (__SILICON_REVISION__ < 1) +/* Hook Routine Not Functional */ +#define ANOMALY_05000395 (__SILICON_REVISION__ < 1) +/* Header Indirect Bit Not Functional */ +#define ANOMALY_05000396 (__SILICON_REVISION__ < 1) +/* BK_ONES, BK_ZEROS, and BK_DATECODE Constants Not Functional */ +#define ANOMALY_05000397 (__SILICON_REVISION__ < 1) /* Lockbox SESR Disallows Certain User Interrupts */ #define ANOMALY_05000404 (__SILICON_REVISION__ < 2) /* Lockbox SESR Firmware Does Not Save/Restore Full Context */ @@ -81,7 +161,7 @@ /* Speculative Fetches Can Cause Undesired External FIFO Operations */ #define ANOMALY_05000416 (1) /* Multichannel SPORT Channel Misalignment Under Specific Configuration */ -#define ANOMALY_05000425 (__SILICON_REVISION__ < 4) +#define ANOMALY_05000425 (1) /* Speculative Fetches of Indirect-Pointer Instructions Can Cause False Hardware Errors */ #define ANOMALY_05000426 (1) /* CORE_EPPI_PRIO bit and SYS_EPPI_PRIO bit in the HMDMA1_CONTROL register are not functional */ @@ -94,6 +174,8 @@ #define ANOMALY_05000431 (__SILICON_REVISION__ < 3) /* SW Breakpoints Ignored Upon Return From Lockbox Authentication */ #define ANOMALY_05000434 (1) +/* OTP Write Accesses Not Supported */ +#define ANOMALY_05000442 (__SILICON_REVISION__ < 1) /* IFLUSH Instruction at End of Hardware Loop Causes Infinite Stall */ #define ANOMALY_05000443 (1) /* CDMAPRIO and L2DMAPRIO Bits in the SYSCR Register Are Not Functional */ @@ -104,32 +186,34 @@ #define ANOMALY_05000448 (__SILICON_REVISION__ == 1) /* Reduced Timing Margins on DDR Output Setup and Hold (tDS and tDH) */ #define ANOMALY_05000449 (__SILICON_REVISION__ == 1) -/* USB DMA Short Packet Data Corruption */ +/* USB DMA Mode 1 Short Packet Data Corruption */ #define ANOMALY_05000450 (1) +/* Incorrect Default Hysteresis Setting for RESET, NMI, and BMODE Signals */ +#define ANOMALY_05000452 (__SILICON_REVISION__ < 1) /* USB Receive Interrupt Is Not Generated in DMA Mode 1 */ #define ANOMALY_05000456 (1) /* Host DMA Port Responds to Certain Bus Activity Without HOST_CE Assertion */ #define ANOMALY_05000457 (1) /* USB DMA Mode 1 Failure When Multiple USB DMA Channels Are Concurrently Enabled */ -#define ANOMALY_05000460 (__SILICON_REVISION__ < 4) +#define ANOMALY_05000460 (1) /* False Hardware Error when RETI Points to Invalid Memory */ #define ANOMALY_05000461 (1) /* Synchronization Problem at Startup May Cause SPORT Transmit Channels to Misalign */ -#define ANOMALY_05000462 (__SILICON_REVISION__ < 4) +#define ANOMALY_05000462 (1) /* USB DMA RX Data Corruption */ -#define ANOMALY_05000463 (__SILICON_REVISION__ < 4) +#define ANOMALY_05000463 (1) /* USB TX DMA Hang */ -#define ANOMALY_05000464 (__SILICON_REVISION__ < 4) -/* USB Rx DMA Hang */ +#define ANOMALY_05000464 (1) +/* USB Rx DMA hang */ #define ANOMALY_05000465 (1) /* TxPktRdy Bit Not Set for Transmit Endpoint When Core and DMA Access USB Endpoint FIFOs Simultaneously */ -#define ANOMALY_05000466 (__SILICON_REVISION__ < 4) -/* Possible USB RX Data Corruption When Control & Data EP FIFOs are Accessed via the Core */ -#define ANOMALY_05000467 (__SILICON_REVISION__ < 4) -/* Interrupted SPORT Receive Data Register Read Results In Underflow when SLEN > 15 */ +#define ANOMALY_05000466 (1) +/* Possible RX data corruption when control & data EP FIFOs are accessed via the core */ +#define ANOMALY_05000467 (1) +/* Interrupted 32-Bit SPORT Data Register Access Results In Underflow */ #define ANOMALY_05000473 (1) -/* Access to DDR SDRAM Causes System Hang with Certain PLL Settings */ -#define ANOMALY_05000474 (__SILICON_REVISION__ < 4) +/* Access to DDR-SDRAM causes system hang under certain PLL/VR settings */ +#define ANOMALY_05000474 (1) /* TESTSET Instruction Cannot Be Interrupted */ #define ANOMALY_05000477 (1) /* Reads of ITEST_COMMAND and ITEST_DATA Registers Cause Cache Corruption */ @@ -139,111 +223,9 @@ /* DDR Trim May Not Be Performed for Certain VLEV Values in OTP Page PBS00L */ #define ANOMALY_05000484 (__SILICON_REVISION__ < 3) /* PLL_CTL Change Using bfrom_SysControl() Can Result in Processor Overclocking */ -#define ANOMALY_05000485 (__SILICON_REVISION__ > 1 && __SILICON_REVISION__ < 4) -/* PLL May Latch Incorrect Values Coming Out of Reset */ -#define ANOMALY_05000489 (1) -/* SPI Master Boot Can Fail Under Certain Conditions */ -#define ANOMALY_05000490 (1) -/* Instruction Memory Stalls Can Cause IFLUSH to Fail */ +#define ANOMALY_05000485 (__SILICON_REVISION__ >= 2) +/* IFLUSH sucks at life */ #define ANOMALY_05000491 (1) -/* EXCPT Instruction May Be Lost If NMI Happens Simultaneously */ -#define ANOMALY_05000494 (1) -/* CNT_COMMAND Functionality Depends on CNT_IMASK Configuration */ -#define ANOMALY_05000498 (1) -/* Nand Flash Controller Hangs When the AMC Requests the Async Pins During the last 16 Bytes of a Page Write Operation. */ -#define ANOMALY_05000500 (1) -/* RXS Bit in SPI_STAT May Become Stuck In RX DMA Modes */ -#define ANOMALY_05000501 (1) -/* Async Memory Writes May Be Skipped When Using Odd Clock Ratios */ -#define ANOMALY_05000502 (1) - -/* - * These anomalies have been "phased" out of analog.com anomaly sheets and are - * here to show running on older silicon just isn't feasible. - */ - -/* False Hardware Error when ISR Context Is Not Restored */ -#define ANOMALY_05000281 (__SILICON_REVISION__ < 1) -/* SSYNCs After Writes To CAN/DMA MMR Registers Are Not Always Handled Correctly */ -#define ANOMALY_05000304 (__SILICON_REVISION__ < 1) -/* Errors when SSYNC, CSYNC, or Loads to LT, LB and LC Registers Are Interrupted */ -#define ANOMALY_05000312 (__SILICON_REVISION__ < 1) -/* TWI Slave Boot Mode Is Not Functional */ -#define ANOMALY_05000324 (__SILICON_REVISION__ < 1) -/* Data Lost When Core and DMA Accesses Are Made to the USB FIFO Simultaneously */ -#define ANOMALY_05000327 (__SILICON_REVISION__ < 1) -/* Incorrect Access of OTP_STATUS During otp_write() Function */ -#define ANOMALY_05000328 (__SILICON_REVISION__ < 1) -/* Synchronous Burst Flash Boot Mode Is Not Functional */ -#define ANOMALY_05000329 (__SILICON_REVISION__ < 1) -/* Host DMA Boot Modes Are Not Functional */ -#define ANOMALY_05000330 (__SILICON_REVISION__ < 1) -/* Inadequate Timing Margins on DDR DQS to DQ and DQM Skew */ -#define ANOMALY_05000334 (__SILICON_REVISION__ < 1) -/* Inadequate Rotary Debounce Logic Duration */ -#define ANOMALY_05000335 (__SILICON_REVISION__ < 1) -/* Phantom Interrupt Occurs After First Configuration of Host DMA Port */ -#define ANOMALY_05000336 (__SILICON_REVISION__ < 1) -/* Disallowed Configuration Prevents Subsequent Allowed Configuration on Host DMA Port */ -#define ANOMALY_05000337 (__SILICON_REVISION__ < 1) -/* Slave-Mode SPI0 MISO Failure With CPHA = 0 */ -#define ANOMALY_05000338 (__SILICON_REVISION__ < 1) -/* If Memory Reads Are Enabled on SDH or HOSTDP, Other DMAC1 Peripherals Cannot Read */ -#define ANOMALY_05000340 (__SILICON_REVISION__ < 1) -/* Boot Host Wait (HWAIT) and Boot Host Wait Alternate (HWAITA) Signals Are Swapped */ -#define ANOMALY_05000344 (__SILICON_REVISION__ < 1) -/* USB Calibration Value Is Not Initialized */ -#define ANOMALY_05000346 (__SILICON_REVISION__ < 1) -/* USB Calibration Value to use */ -#define ANOMALY_05000346_value 0x5411 -/* Preboot Routine Incorrectly Alters Reset Value of USB Register */ -#define ANOMALY_05000347 (__SILICON_REVISION__ < 1) -/* Data Lost when Core Reads SDH Data FIFO */ -#define ANOMALY_05000349 (__SILICON_REVISION__ < 1) -/* PLL Status Register Is Inaccurate */ -#define ANOMALY_05000351 (__SILICON_REVISION__ < 1) -/* Regulator Programming Blocked when Hibernate Wakeup Source Remains Active */ -#define ANOMALY_05000355 (__SILICON_REVISION__ < 1) -/* System Stalled During A Core Access To AMC While A Core Access To NFC FIFO Is Required */ -#define ANOMALY_05000356 (__SILICON_REVISION__ < 1) -/* WURESET Bit In SYSCR Register Does Not Properly Indicate Hibernate Wake-Up */ -#define ANOMALY_05000367 (__SILICON_REVISION__ < 1) -/* Default PLL MSEL and SSEL Settings Can Cause 400MHz Product To Violate Specifications */ -#define ANOMALY_05000370 (__SILICON_REVISION__ < 1) -/* USB DP/DM Data Pins May Lose State When Entering Hibernate */ -#define ANOMALY_05000372 (__SILICON_REVISION__ < 1) -/* 8-Bit NAND Flash Boot Mode Not Functional */ -#define ANOMALY_05000382 (__SILICON_REVISION__ < 1) -/* Boot from OTP Memory Not Functional */ -#define ANOMALY_05000385 (__SILICON_REVISION__ < 1) -/* bfrom_SysControl() Firmware Routine Not Functional */ -#define ANOMALY_05000386 (__SILICON_REVISION__ < 1) -/* Programmable Preboot Settings Not Functional */ -#define ANOMALY_05000387 (__SILICON_REVISION__ < 1) -/* CRC32 Checksum Support Not Functional */ -#define ANOMALY_05000388 (__SILICON_REVISION__ < 1) -/* Reset Vector Must Not Be in SDRAM Memory Space */ -#define ANOMALY_05000389 (__SILICON_REVISION__ < 1) -/* Changed Meaning of BCODE Field in SYSCR Register */ -#define ANOMALY_05000390 (__SILICON_REVISION__ < 1) -/* Repeated Boot from Page-Mode or Burst-Mode Flash Memory May Fail */ -#define ANOMALY_05000391 (__SILICON_REVISION__ < 1) -/* pTempCurrent Not Present in ADI_BOOT_DATA Structure */ -#define ANOMALY_05000392 (__SILICON_REVISION__ < 1) -/* Deprecated Value of dTempByteCount in ADI_BOOT_DATA Structure */ -#define ANOMALY_05000393 (__SILICON_REVISION__ < 1) -/* Log Buffer Not Functional */ -#define ANOMALY_05000394 (__SILICON_REVISION__ < 1) -/* Hook Routine Not Functional */ -#define ANOMALY_05000395 (__SILICON_REVISION__ < 1) -/* Header Indirect Bit Not Functional */ -#define ANOMALY_05000396 (__SILICON_REVISION__ < 1) -/* BK_ONES, BK_ZEROS, and BK_DATECODE Constants Not Functional */ -#define ANOMALY_05000397 (__SILICON_REVISION__ < 1) -/* OTP Write Accesses Not Supported */ -#define ANOMALY_05000442 (__SILICON_REVISION__ < 1) -/* Incorrect Default Hysteresis Setting for RESET, NMI, and BMODE Signals */ -#define ANOMALY_05000452 (__SILICON_REVISION__ < 1) /* Anomalies that don't exist on this proc */ #define ANOMALY_05000099 (0) diff --git a/trunk/arch/blackfin/mach-bf548/include/mach/gpio.h b/trunk/arch/blackfin/mach-bf548/include/mach/gpio.h index 35c8ced46158..7db433514e3f 100644 --- a/trunk/arch/blackfin/mach-bf548/include/mach/gpio.h +++ b/trunk/arch/blackfin/mach-bf548/include/mach/gpio.h @@ -170,8 +170,6 @@ #define MAX_BLACKFIN_GPIOS 160 -#define BFIN_GPIO_PINT 1 - #ifndef __ASSEMBLY__ struct gpio_port_t { diff --git a/trunk/arch/blackfin/mach-bf548/include/mach/irq.h b/trunk/arch/blackfin/mach-bf548/include/mach/irq.h index 10dc142c518d..533b8095b540 100644 --- a/trunk/arch/blackfin/mach-bf548/include/mach/irq.h +++ b/trunk/arch/blackfin/mach-bf548/include/mach/irq.h @@ -438,7 +438,7 @@ struct bfin_pint_regs { u32 mask_set; u32 mask_clear; - u32 request; + u32 irq; u32 assign; u32 edge_set; u32 edge_clear; diff --git a/trunk/arch/blackfin/mach-bf561/boards/acvilon.c b/trunk/arch/blackfin/mach-bf561/boards/acvilon.c index 972e1347c6bc..9231a942892b 100644 --- a/trunk/arch/blackfin/mach-bf561/boards/acvilon.c +++ b/trunk/arch/blackfin/mach-bf561/boards/acvilon.c @@ -364,6 +364,14 @@ static struct flash_platform_data bfin_spi_dataflash_data = { /* DataFlash chip */ static struct bfin5xx_spi_chip data_flash_chip_info = { .enable_dma = 0, /* use dma transfer with this chip */ + .bits_per_word = 8, +}; +#endif + +#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE) +static struct bfin5xx_spi_chip spidev_chip_info = { + .enable_dma = 0, + .bits_per_word = 8, }; #endif @@ -412,6 +420,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 3, + .controller_data = &spidev_chip_info, }, #endif #if defined(CONFIG_MTD_DATAFLASH) || defined(CONFIG_MTD_DATAFLASH_MODULE) diff --git a/trunk/arch/blackfin/mach-bf561/boards/cm_bf561.c b/trunk/arch/blackfin/mach-bf561/boards/cm_bf561.c index e4f397d1d65b..87595cd38afe 100644 --- a/trunk/arch/blackfin/mach-bf561/boards/cm_bf561.c +++ b/trunk/arch/blackfin/mach-bf561/boards/cm_bf561.c @@ -60,6 +60,29 @@ static struct flash_platform_data bfin_spi_flash_data = { /* SPI flash chip (m25p64) */ static struct bfin5xx_spi_chip spi_flash_chip_info = { .enable_dma = 0, /* use dma transfer with this chip*/ + .bits_per_word = 8, +}; +#endif + +#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE) +/* SPI ADC chip */ +static struct bfin5xx_spi_chip spi_adc_chip_info = { + .enable_dma = 1, /* use dma transfer with this chip*/ + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_SND_BF5XX_SOC_AD183X) || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE) +static struct bfin5xx_spi_chip ad1836_spi_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE) +static struct bfin5xx_spi_chip mmc_spi_chip_info = { + .enable_dma = 0, + .bits_per_word = 8, }; #endif @@ -77,12 +100,24 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { }, #endif +#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE) + { + .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */ + .max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 0, /* Framework bus number */ + .chip_select = 1, /* Framework chip select. */ + .platform_data = NULL, /* No spi_driver specific config */ + .controller_data = &spi_adc_chip_info, + }, +#endif + #if defined(CONFIG_SND_BF5XX_SOC_AD183X) || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE) { .modalias = "ad183x", .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 4, + .controller_data = &ad1836_spi_chip_info, }, #endif #if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE) @@ -91,6 +126,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 20000000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 1, + .controller_data = &mmc_spi_chip_info, .mode = SPI_MODE_3, }, #endif @@ -496,24 +532,6 @@ static struct platform_device *cm_bf561_devices[] __initdata = { #endif }; -static int __init net2272_init(void) -{ -#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE) - int ret; - - ret = gpio_request(GPIO_PF46, "net2272"); - if (ret) - return ret; - - /* Reset USB Chip, PF46 */ - gpio_direction_output(GPIO_PF46, 0); - mdelay(2); - gpio_set_value(GPIO_PF46, 1); -#endif - - return 0; -} - static int __init cm_bf561_init(void) { printk(KERN_INFO "%s(): registering device resources\n", __func__); @@ -525,10 +543,6 @@ static int __init cm_bf561_init(void) #if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE) irq_set_status_flags(PATA_INT, IRQ_NOAUTOEN); #endif - - if (net2272_init()) - pr_warning("unable to configure net2272; it probably won't work\n"); - return 0; } diff --git a/trunk/arch/blackfin/mach-bf561/boards/ezkit.c b/trunk/arch/blackfin/mach-bf561/boards/ezkit.c index 9490dc800ca5..5067984a62e7 100644 --- a/trunk/arch/blackfin/mach-bf561/boards/ezkit.c +++ b/trunk/arch/blackfin/mach-bf561/boards/ezkit.c @@ -107,9 +107,6 @@ static struct resource net2272_bfin_resources[] = { .start = 0x2C000000, .end = 0x2C000000 + 0x7F, .flags = IORESOURCE_MEM, - }, { - .start = 1, - .flags = IORESOURCE_BUS, }, { .start = IRQ_PF10, .end = IRQ_PF10, @@ -286,6 +283,21 @@ static struct platform_device ezkit_flash_device = { }; #endif +#if defined(CONFIG_SND_BF5XX_SOC_AD183X) \ + || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE) +static struct bfin5xx_spi_chip ad1836_spi_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE) +static struct bfin5xx_spi_chip spidev_chip_info = { + .enable_dma = 0, + .bits_per_word = 8, +}; +#endif + #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) /* SPI (0) */ static struct resource bfin_spi0_resource[] = { @@ -333,6 +345,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .bus_num = 0, .chip_select = 4, .platform_data = "ad1836", /* only includes chip name for the moment */ + .controller_data = &ad1836_spi_chip_info, .mode = SPI_MODE_3, }, #endif @@ -342,6 +355,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, .chip_select = 1, + .controller_data = &spidev_chip_info, }, #endif }; @@ -502,24 +516,6 @@ static struct platform_device *ezkit_devices[] __initdata = { #endif }; -static int __init net2272_init(void) -{ -#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE) - int ret; - - ret = gpio_request(GPIO_PF11, "net2272"); - if (ret) - return ret; - - /* Reset the USB chip */ - gpio_direction_output(GPIO_PF11, 0); - mdelay(2); - gpio_set_value(GPIO_PF11, 1); -#endif - - return 0; -} - static int __init ezkit_init(void) { int ret; @@ -546,9 +542,6 @@ static int __init ezkit_init(void) udelay(400); #endif - if (net2272_init()) - pr_warning("unable to configure net2272; it probably won't work\n"); - spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info)); return 0; } diff --git a/trunk/arch/blackfin/mach-bf561/include/mach/anomaly.h b/trunk/arch/blackfin/mach-bf561/include/mach/anomaly.h index 836baeed303a..22b5ab773027 100644 --- a/trunk/arch/blackfin/mach-bf561/include/mach/anomaly.h +++ b/trunk/arch/blackfin/mach-bf561/include/mach/anomaly.h @@ -11,7 +11,7 @@ */ /* This file should be up to date with: - * - Revision S, 05/23/2011; ADSP-BF561 Blackfin Processor Anomaly List + * - Revision R, 05/25/2010; ADSP-BF561 Blackfin Processor Anomaly List */ #ifndef _MACH_ANOMALY_H_ @@ -26,16 +26,62 @@ #define ANOMALY_05000074 (1) /* UART Line Status Register (UART_LSR) Bits Are Not Updated at the Same Time */ #define ANOMALY_05000099 (__SILICON_REVISION__ < 5) +/* Trace Buffers May Contain Errors in Emulation Mode and/or Exception, NMI, Reset Handlers */ +#define ANOMALY_05000116 (__SILICON_REVISION__ < 3) /* TESTSET Instructions Restricted to 32-Bit Aligned Memory Locations */ #define ANOMALY_05000120 (1) /* Rx.H Cannot Be Used to Access 16-bit System MMR Registers */ #define ANOMALY_05000122 (1) +/* Erroneous Exception when Enabling Cache */ +#define ANOMALY_05000125 (__SILICON_REVISION__ < 3) /* SIGNBITS Instruction Not Functional under Certain Conditions */ #define ANOMALY_05000127 (1) +/* Two bits in the Watchpoint Status Register (WPSTAT) are swapped */ +#define ANOMALY_05000134 (__SILICON_REVISION__ < 3) +/* Enable wires from the Data Watchpoint Address Control Register (WPDACTL) are swapped */ +#define ANOMALY_05000135 (__SILICON_REVISION__ < 3) +/* Stall in multi-unit DMA operations */ +#define ANOMALY_05000136 (__SILICON_REVISION__ < 3) +/* Allowing the SPORT RX FIFO to fill will cause an overflow */ +#define ANOMALY_05000140 (__SILICON_REVISION__ < 3) +/* Infinite Stall may occur with a particular sequence of consecutive dual dag events */ +#define ANOMALY_05000141 (__SILICON_REVISION__ < 3) +/* Interrupts may be lost when a programmable input flag is configured to be edge sensitive */ +#define ANOMALY_05000142 (__SILICON_REVISION__ < 3) +/* DMA and TESTSET conflict when both are accessing external memory */ +#define ANOMALY_05000144 (__SILICON_REVISION__ < 3) +/* In PWM_OUT mode, you must enable the PPI block to generate a waveform from PPI_CLK */ +#define ANOMALY_05000145 (__SILICON_REVISION__ < 3) +/* MDMA may lose the first few words of a descriptor chain */ +#define ANOMALY_05000146 (__SILICON_REVISION__ < 3) +/* Source MDMA descriptor may stop with a DMA Error near beginning of descriptor fetch */ +#define ANOMALY_05000147 (__SILICON_REVISION__ < 3) /* IMDMA S1/D1 Channel May Stall */ #define ANOMALY_05000149 (1) +/* DMA engine may lose data due to incorrect handshaking */ +#define ANOMALY_05000150 (__SILICON_REVISION__ < 3) +/* DMA stalls when all three controllers read data from the same source */ +#define ANOMALY_05000151 (__SILICON_REVISION__ < 3) +/* Execution stall when executing in L2 and doing external accesses */ +#define ANOMALY_05000152 (__SILICON_REVISION__ < 3) +/* Frame Delay in SPORT Multichannel Mode */ +#define ANOMALY_05000153 (__SILICON_REVISION__ < 3) +/* SPORT TFS signal stays active in multichannel mode outside of valid channels */ +#define ANOMALY_05000154 (__SILICON_REVISION__ < 3) /* Timers in PWM-Out Mode with PPI GP Receive (Input) Mode with 0 Frame Syncs */ #define ANOMALY_05000156 (__SILICON_REVISION__ < 4) +/* Killed 32-Bit MMR Write Leads to Next System MMR Access Thinking It Should Be 32-Bit */ +#define ANOMALY_05000157 (__SILICON_REVISION__ < 3) +/* DMA Lock-up at CCLK to SCLK ratios of 4:1, 2:1, or 1:1 */ +#define ANOMALY_05000159 (__SILICON_REVISION__ < 3) +/* A read from external memory may return a wrong value with data cache enabled */ +#define ANOMALY_05000160 (__SILICON_REVISION__ < 3) +/* Data Cache Fill data can be corrupted after/during Instruction DMA if certain core stalls exist */ +#define ANOMALY_05000161 (__SILICON_REVISION__ < 3) +/* DMEM_CONTROL<12> is not set on Reset */ +#define ANOMALY_05000162 (__SILICON_REVISION__ < 3) +/* SPORT Transmit Data Is Not Gated by External Frame Sync in Certain Conditions */ +#define ANOMALY_05000163 (__SILICON_REVISION__ < 3) /* PPI Data Lengths between 8 and 16 Do Not Zero Out Upper Bits */ #define ANOMALY_05000166 (1) /* Turning SPORTs on while External Frame Sync Is Active May Corrupt Data */ @@ -46,6 +92,10 @@ #define ANOMALY_05000169 (__SILICON_REVISION__ < 5) /* Boot-ROM Modifies SICA_IWRx Wakeup Registers */ #define ANOMALY_05000171 (__SILICON_REVISION__ < 5) +/* DSPID register values incorrect */ +#define ANOMALY_05000172 (__SILICON_REVISION__ < 3) +/* DMA vs Core accesses to external memory */ +#define ANOMALY_05000173 (__SILICON_REVISION__ < 3) /* Cache Fill Buffer Data lost */ #define ANOMALY_05000174 (__SILICON_REVISION__ < 5) /* Overlapping Sequencer and Memory Stalls */ @@ -74,6 +124,8 @@ #define ANOMALY_05000189 (__SILICON_REVISION__ < 5) /* PPI Not Functional at Core Voltage < 1Volt */ #define ANOMALY_05000190 (1) +/* PPI does not invert the Driving PPICLK edge in Transmit Modes */ +#define ANOMALY_05000191 (__SILICON_REVISION__ < 3) /* False I/O Pin Interrupts on Edge-Sensitive Inputs When Polarity Setting Is Changed */ #define ANOMALY_05000193 (__SILICON_REVISION__ < 5) /* Restarting SPORT in Specific Modes May Cause Data Corruption */ @@ -165,10 +217,10 @@ /* Timing Requirements Change for External Frame Sync PPI Modes with Non-Zero PPI_DELAY */ #define ANOMALY_05000276 (__SILICON_REVISION__ < 5) /* Writes to an I/O Data Register One SCLK Cycle after an Edge Is Detected May Clear Interrupt */ -#define ANOMALY_05000277 (__SILICON_REVISION__ < 5) +#define ANOMALY_05000277 (__SILICON_REVISION__ < 3) /* Disabling Peripherals with DMA Running May Cause DMA System Instability */ #define ANOMALY_05000278 (__SILICON_REVISION__ < 5) -/* False Hardware Error when ISR Context Is Not Restored */ +/* False Hardware Error Exception when ISR Context Is Not Restored */ /* Temporarily walk around for bug 5423 till this issue is confirmed by * official anomaly document. It looks 05000281 still exists on bf561 * v0.5. @@ -222,6 +274,8 @@ #define ANOMALY_05000366 (1) /* Possible RETS Register Corruption when Subroutine Is under 5 Cycles in Duration */ #define ANOMALY_05000371 (1) +/* SSYNC Stalls Processor when Executed from Non-Cacheable Memory */ +#define ANOMALY_05000402 (__SILICON_REVISION__ == 4) /* Level-Sensitive External GPIO Wakeups May Cause Indefinite Stall */ #define ANOMALY_05000403 (1) /* TESTSET Instruction Causes Data Corruption with Writeback Data Cache Enabled */ @@ -244,82 +298,16 @@ #define ANOMALY_05000462 (1) /* Boot Failure When SDRAM Control Signals Toggle Coming Out Of Reset */ #define ANOMALY_05000471 (1) -/* Interrupted SPORT Receive Data Register Read Results In Underflow when SLEN > 15 */ +/* Interrupted 32-Bit SPORT Data Register Access Results In Underflow */ #define ANOMALY_05000473 (1) -/* Possible Lockup Condition when Modifying PLL from External Memory */ +/* Possible Lockup Condition whem Modifying PLL from External Memory */ #define ANOMALY_05000475 (1) /* TESTSET Instruction Cannot Be Interrupted */ #define ANOMALY_05000477 (1) /* Reads of ITEST_COMMAND and ITEST_DATA Registers Cause Cache Corruption */ #define ANOMALY_05000481 (1) -/* PLL May Latch Incorrect Values Coming Out of Reset */ -#define ANOMALY_05000489 (1) -/* Instruction Memory Stalls Can Cause IFLUSH to Fail */ +/* IFLUSH sucks at life */ #define ANOMALY_05000491 (1) -/* EXCPT Instruction May Be Lost If NMI Happens Simultaneously */ -#define ANOMALY_05000494 (1) -/* RXS Bit in SPI_STAT May Become Stuck In RX DMA Modes */ -#define ANOMALY_05000501 (1) - -/* - * These anomalies have been "phased" out of analog.com anomaly sheets and are - * here to show running on older silicon just isn't feasible. - */ - -/* Trace Buffers May Contain Errors in Emulation Mode and/or Exception, NMI, Reset Handlers */ -#define ANOMALY_05000116 (__SILICON_REVISION__ < 3) -/* Erroneous Exception when Enabling Cache */ -#define ANOMALY_05000125 (__SILICON_REVISION__ < 3) -/* Two bits in the Watchpoint Status Register (WPSTAT) are swapped */ -#define ANOMALY_05000134 (__SILICON_REVISION__ < 3) -/* Enable wires from the Data Watchpoint Address Control Register (WPDACTL) are swapped */ -#define ANOMALY_05000135 (__SILICON_REVISION__ < 3) -/* Stall in multi-unit DMA operations */ -#define ANOMALY_05000136 (__SILICON_REVISION__ < 3) -/* Allowing the SPORT RX FIFO to fill will cause an overflow */ -#define ANOMALY_05000140 (__SILICON_REVISION__ < 3) -/* Infinite Stall may occur with a particular sequence of consecutive dual dag events */ -#define ANOMALY_05000141 (__SILICON_REVISION__ < 3) -/* Interrupts may be lost when a programmable input flag is configured to be edge sensitive */ -#define ANOMALY_05000142 (__SILICON_REVISION__ < 3) -/* DMA and TESTSET conflict when both are accessing external memory */ -#define ANOMALY_05000144 (__SILICON_REVISION__ < 3) -/* In PWM_OUT mode, you must enable the PPI block to generate a waveform from PPI_CLK */ -#define ANOMALY_05000145 (__SILICON_REVISION__ < 3) -/* MDMA may lose the first few words of a descriptor chain */ -#define ANOMALY_05000146 (__SILICON_REVISION__ < 3) -/* Source MDMA descriptor may stop with a DMA Error near beginning of descriptor fetch */ -#define ANOMALY_05000147 (__SILICON_REVISION__ < 3) -/* DMA engine may lose data due to incorrect handshaking */ -#define ANOMALY_05000150 (__SILICON_REVISION__ < 3) -/* DMA stalls when all three controllers read data from the same source */ -#define ANOMALY_05000151 (__SILICON_REVISION__ < 3) -/* Execution stall when executing in L2 and doing external accesses */ -#define ANOMALY_05000152 (__SILICON_REVISION__ < 3) -/* Frame Delay in SPORT Multichannel Mode */ -#define ANOMALY_05000153 (__SILICON_REVISION__ < 3) -/* SPORT TFS signal stays active in multichannel mode outside of valid channels */ -#define ANOMALY_05000154 (__SILICON_REVISION__ < 3) -/* Killed 32-Bit MMR Write Leads to Next System MMR Access Thinking It Should Be 32-Bit */ -#define ANOMALY_05000157 (__SILICON_REVISION__ < 3) -/* DMA Lock-up at CCLK to SCLK ratios of 4:1, 2:1, or 1:1 */ -#define ANOMALY_05000159 (__SILICON_REVISION__ < 3) -/* A read from external memory may return a wrong value with data cache enabled */ -#define ANOMALY_05000160 (__SILICON_REVISION__ < 3) -/* Data Cache Fill data can be corrupted after/during Instruction DMA if certain core stalls exist */ -#define ANOMALY_05000161 (__SILICON_REVISION__ < 3) -/* DMEM_CONTROL<12> is not set on Reset */ -#define ANOMALY_05000162 (__SILICON_REVISION__ < 3) -/* SPORT Transmit Data Is Not Gated by External Frame Sync in Certain Conditions */ -#define ANOMALY_05000163 (__SILICON_REVISION__ < 3) -/* DSPID register values incorrect */ -#define ANOMALY_05000172 (__SILICON_REVISION__ < 3) -/* DMA vs Core accesses to external memory */ -#define ANOMALY_05000173 (__SILICON_REVISION__ < 3) -/* PPI does not invert the Driving PPICLK edge in Transmit Modes */ -#define ANOMALY_05000191 (__SILICON_REVISION__ < 3) -/* SSYNC Stalls Processor when Executed from Non-Cacheable Memory */ -#define ANOMALY_05000402 (__SILICON_REVISION__ == 4) /* Anomalies that don't exist on this proc */ #define ANOMALY_05000119 (0) diff --git a/trunk/arch/blackfin/mach-bf561/include/mach/gpio.h b/trunk/arch/blackfin/mach-bf561/include/mach/gpio.h index f9f8b2adf4ba..57d5eab59faf 100644 --- a/trunk/arch/blackfin/mach-bf561/include/mach/gpio.h +++ b/trunk/arch/blackfin/mach-bf561/include/mach/gpio.h @@ -58,9 +58,9 @@ #define GPIO_PF46 46 #define GPIO_PF47 47 -#define PORT_FIO0 GPIO_PF0 -#define PORT_FIO1 GPIO_PF16 -#define PORT_FIO2 GPIO_PF32 +#define PORT_FIO0 GPIO_0 +#define PORT_FIO1 GPIO_16 +#define PORT_FIO2 GPIO_32 #include diff --git a/trunk/arch/blackfin/mach-bf561/secondary.S b/trunk/arch/blackfin/mach-bf561/secondary.S index 01e5408620ac..4c462838f4e1 100644 --- a/trunk/arch/blackfin/mach-bf561/secondary.S +++ b/trunk/arch/blackfin/mach-bf561/secondary.S @@ -23,78 +23,108 @@ #define INITIAL_STACK (COREB_L1_SCRATCH_START + L1_SCRATCH_LENGTH - 12) ENTRY(_coreb_trampoline_start) - /* Enable Cycle Counter and Nesting Of Interrupts */ -#ifdef CONFIG_BFIN_SCRATCH_REG_CYCLES - R0 = SYSCFG_SNEN; -#else - R0 = SYSCFG_SNEN | SYSCFG_CCEN; -#endif - SYSCFG = R0; - - /* Optimization register tricks: keep a base value in the - * reserved P registers so we use the load/store with an - * offset syntax. R0 = [P5 + ]; - * P5 - core MMR base - * R6 - 0 - */ - r6 = 0; - p5.l = 0; - p5.h = hi(COREMMR_BASE); - - /* Zero out registers required by Blackfin ABI */ - - /* Disable circular buffers */ - L0 = r6; - L1 = r6; - L2 = r6; - L3 = r6; - - /* Disable hardware loops in case we were started by 'go' */ - LC0 = r6; - LC1 = r6; - - /* - * Clear ITEST_COMMAND and DTEST_COMMAND registers, - * Leaving these as non-zero can confuse the emulator - */ - [p5 + (DTEST_COMMAND - COREMMR_BASE)] = r6; - [p5 + (ITEST_COMMAND - COREMMR_BASE)] = r6; - CSYNC; + /* Set the SYSCFG register */ + R0 = 0x36; + SYSCFG = R0; /*Enable Cycle Counter and Nesting Of Interrupts(3rd Bit)*/ + R0 = 0; + + /*Clear Out All the data and pointer Registers*/ + R1 = R0; + R2 = R0; + R3 = R0; + R4 = R0; + R5 = R0; + R6 = R0; + R7 = R0; + + P0 = R0; + P1 = R0; + P2 = R0; + P3 = R0; + P4 = R0; + P5 = R0; + + LC0 = r0; + LC1 = r0; + L0 = r0; + L1 = r0; + L2 = r0; + L3 = r0; + + /* Clear Out All the DAG Registers*/ + B0 = r0; + B1 = r0; + B2 = r0; + B3 = r0; + + I0 = r0; + I1 = r0; + I2 = r0; + I3 = r0; + + M0 = r0; + M1 = r0; + M2 = r0; + M3 = r0; trace_buffer_init(p0,r0); /* Turn off the icache */ - r1 = [p5 + (IMEM_CONTROL - COREMMR_BASE)]; - BITCLR (r1, ENICPLB_P); - [p5 + (IMEM_CONTROL - COREMMR_BASE)] = r1; + p0.l = LO(IMEM_CONTROL); + p0.h = HI(IMEM_CONTROL); + R1 = [p0]; + R0 = ~ENICPLB; + R0 = R0 & R1; + + /* Disabling of CPLBs should be proceeded by a CSYNC */ + CSYNC; + [p0] = R0; SSYNC; /* Turn off the dcache */ - r1 = [p5 + (DMEM_CONTROL - COREMMR_BASE)]; - BITCLR (r1, ENDCPLB_P); - [p5 + (DMEM_CONTROL - COREMMR_BASE)] = r1; + p0.l = LO(DMEM_CONTROL); + p0.h = HI(DMEM_CONTROL); + R1 = [p0]; + R0 = ~ENDCPLB; + R0 = R0 & R1; + + /* Disabling of CPLBs should be proceeded by a CSYNC */ + CSYNC; + [p0] = R0; SSYNC; /* in case of double faults, save a few things */ - p1.l = _initial_pda_coreb; - p1.h = _initial_pda_coreb; - r4 = RETX; + p0.l = _init_retx_coreb; + p0.h = _init_retx_coreb; + R0 = RETX; + [P0] = R0; + #ifdef CONFIG_DEBUG_DOUBLEFAULT /* Only save these if we are storing them, * This happens here, since L1 gets clobbered * below */ GET_PDA(p0, r0); - r0 = [p0 + PDA_DF_RETX]; - r1 = [p0 + PDA_DF_DCPLB]; - r2 = [p0 + PDA_DF_ICPLB]; - r3 = [p0 + PDA_DF_SEQSTAT]; - [p1 + PDA_INIT_DF_RETX] = r0; - [p1 + PDA_INIT_DF_DCPLB] = r1; - [p1 + PDA_INIT_DF_ICPLB] = r2; - [p1 + PDA_INIT_DF_SEQSTAT] = r3; + r7 = [p0 + PDA_DF_RETX]; + p1.l = _init_saved_retx_coreb; + p1.h = _init_saved_retx_coreb; + [p1] = r7; + + r7 = [p0 + PDA_DF_DCPLB]; + p1.l = _init_saved_dcplb_fault_addr_coreb; + p1.h = _init_saved_dcplb_fault_addr_coreb; + [p1] = r7; + + r7 = [p0 + PDA_DF_ICPLB]; + p1.l = _init_saved_icplb_fault_addr_coreb; + p1.h = _init_saved_icplb_fault_addr_coreb; + [p1] = r7; + + r7 = [p0 + PDA_DF_SEQSTAT]; + p1.l = _init_saved_seqstat_coreb; + p1.h = _init_saved_seqstat_coreb; + [p1] = r7; #endif - [p1 + PDA_INIT_RETX] = r4; /* Initialize stack pointer */ sp.l = lo(INITIAL_STACK); @@ -108,13 +138,19 @@ ENTRY(_coreb_trampoline_start) /* EVT15 = _real_start */ + p0.l = lo(EVT15); + p0.h = hi(EVT15); p1.l = _coreb_start; p1.h = _coreb_start; - [p5 + (EVT15 - COREMMR_BASE)] = p1; + [p0] = p1; csync; - r0 = EVT_IVG15 (z); - sti r0; + p0.l = lo(IMASK); + p0.h = hi(IMASK); + p1.l = IMASK_IVG15; + p1.h = 0x0; + [p0] = p1; + csync; raise 15; p0.l = .LWAIT_HERE; diff --git a/trunk/arch/blackfin/mach-common/dpmc_modes.S b/trunk/arch/blackfin/mach-common/dpmc_modes.S index 1c534d298de4..9cfdd49a3127 100644 --- a/trunk/arch/blackfin/mach-common/dpmc_modes.S +++ b/trunk/arch/blackfin/mach-common/dpmc_modes.S @@ -12,8 +12,8 @@ .section .l1.text ENTRY(_sleep_mode) - [--SP] = (R7:4, P5:3); - [--SP] = RETS; + [--SP] = ( R7:0, P5:0 ); + [--SP] = RETS; call _set_sic_iwr; @@ -46,25 +46,15 @@ ENTRY(_sleep_mode) call _test_pll_locked; RETS = [SP++]; - (R7:4, P5:3) = [SP++]; + ( R7:0, P5:0 ) = [SP++]; RTS; ENDPROC(_sleep_mode) -/* - * This func never returns as it puts the part into hibernate, and - * is only called from do_hibernate, so we don't bother saving or - * restoring any of the normal C runtime state. When we wake up, - * the entry point will be in do_hibernate and not here. - * - * We accept just one argument -- the value to write to VR_CTL. - */ ENTRY(_hibernate_mode) - /* Save/setup the regs we need early for minor pipeline optimization */ - R4 = R0; - P3.H = hi(VR_CTL); - P3.L = lo(VR_CTL); + [--SP] = ( R7:0, P5:0 ); + [--SP] = RETS; - /* Disable all wakeup sources */ + R3 = R0; R0 = IWR_DISABLE_ALL; R1 = IWR_DISABLE_ALL; R2 = IWR_DISABLE_ALL; @@ -72,8 +62,10 @@ ENTRY(_hibernate_mode) call _set_dram_srfs; SSYNC; - /* Finally, we climb into our cave to hibernate */ - W[P3] = R4.L; + P0.H = hi(VR_CTL); + P0.L = lo(VR_CTL); + + W[P0] = R3.L; CLI R2; IDLE; .Lforever: @@ -81,8 +73,8 @@ ENTRY(_hibernate_mode) ENDPROC(_hibernate_mode) ENTRY(_sleep_deeper) - [--SP] = (R7:4, P5:3); - [--SP] = RETS; + [--SP] = ( R7:0, P5:0 ); + [--SP] = RETS; CLI R4; @@ -175,7 +167,7 @@ ENTRY(_sleep_deeper) STI R4; RETS = [SP++]; - (R7:4, P5:3) = [SP++]; + ( R7:0, P5:0 ) = [SP++]; RTS; ENDPROC(_sleep_deeper) @@ -196,20 +188,21 @@ ENTRY(_set_dram_srfs) #else /* SDRAM */ P0.L = lo(EBIU_SDGCTL); P0.H = hi(EBIU_SDGCTL); - P1.L = lo(EBIU_SDSTAT); - P1.H = hi(EBIU_SDSTAT); - R2 = [P0]; BITSET(R2, 24); /* SRFS enter self-refresh mode */ [P0] = R2; SSYNC; + P0.L = lo(EBIU_SDSTAT); + P0.H = hi(EBIU_SDSTAT); 1: - R2 = w[P1]; + R2 = w[P0]; SSYNC; cc = BITTST(R2, 1); /* SDSRA poll self-refresh status */ if !cc jump 1b; + P0.L = lo(EBIU_SDGCTL); + P0.H = hi(EBIU_SDGCTL); R2 = [P0]; BITCLR(R2, 0); /* SCTLE disable CLKOUT */ [P0] = R2; @@ -219,7 +212,6 @@ ENDPROC(_set_dram_srfs) ENTRY(_unset_dram_srfs) /* set the dram out of self refresh mode */ - #if defined(EBIU_RSTCTL) /* DDR */ P0.H = hi(EBIU_RSTCTL); P0.L = lo(EBIU_RSTCTL); @@ -227,39 +219,42 @@ ENTRY(_unset_dram_srfs) BITCLR(R2, 3); /* clear SRREQ bit */ [P0] = R2; #elif defined(EBIU_SDGCTL) /* SDRAM */ - /* release CLKOUT from self-refresh */ - P0.L = lo(EBIU_SDGCTL); - P0.H = hi(EBIU_SDGCTL); + P0.L = lo(EBIU_SDGCTL); /* release CLKOUT from self-refresh */ + P0.H = hi(EBIU_SDGCTL); R2 = [P0]; BITSET(R2, 0); /* SCTLE enable CLKOUT */ [P0] = R2 SSYNC; - /* release SDRAM from self-refresh */ + P0.L = lo(EBIU_SDGCTL); /* release SDRAM from self-refresh */ + P0.H = hi(EBIU_SDGCTL); R2 = [P0]; BITCLR(R2, 24); /* clear SRFS bit */ [P0] = R2 #endif - SSYNC; RTS; ENDPROC(_unset_dram_srfs) ENTRY(_set_sic_iwr) -#ifdef SIC_IWR0 - P0.H = hi(SYSMMR_BASE); - P0.L = lo(SYSMMR_BASE); - [P0 + (SIC_IWR0 - SYSMMR_BASE)] = R0; - [P0 + (SIC_IWR1 - SYSMMR_BASE)] = R1; -# ifdef SIC_IWR2 - [P0 + (SIC_IWR2 - SYSMMR_BASE)] = R2; -# endif +#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561) || \ + defined(CONFIG_BF538) || defined(CONFIG_BF539) || defined(CONFIG_BF51x) + P0.H = hi(SIC_IWR0); + P0.L = lo(SIC_IWR0); + P1.H = hi(SIC_IWR1); + P1.L = lo(SIC_IWR1); + [P1] = R1; +#if defined(CONFIG_BF54x) + P1.H = hi(SIC_IWR2); + P1.L = lo(SIC_IWR2); + [P1] = R2; +#endif #else P0.H = hi(SIC_IWR); P0.L = lo(SIC_IWR); - [P0] = R0; #endif + [P0] = R0; SSYNC; RTS; @@ -277,55 +272,206 @@ ENDPROC(_test_pll_locked) .section .text -#define PM_REG0 R7 -#define PM_REG1 R6 -#define PM_REG2 R5 -#define PM_REG3 R4 -#define PM_REG4 R3 -#define PM_REG5 R2 -#define PM_REG6 R1 -#define PM_REG7 R0 -#define PM_REG8 P5 -#define PM_REG9 P4 -#define PM_REG10 P3 -#define PM_REG11 P2 -#define PM_REG12 P1 -#define PM_REG13 P0 - -#define PM_REGSET0 R7:7 -#define PM_REGSET1 R7:6 -#define PM_REGSET2 R7:5 -#define PM_REGSET3 R7:4 -#define PM_REGSET4 R7:3 -#define PM_REGSET5 R7:2 -#define PM_REGSET6 R7:1 -#define PM_REGSET7 R7:0 -#define PM_REGSET8 R7:0, P5:5 -#define PM_REGSET9 R7:0, P5:4 -#define PM_REGSET10 R7:0, P5:3 -#define PM_REGSET11 R7:0, P5:2 -#define PM_REGSET12 R7:0, P5:1 -#define PM_REGSET13 R7:0, P5:0 - -#define _PM_PUSH(n, x, w, base) PM_REG##n = w[FP + ((x) - (base))]; -#define _PM_POP(n, x, w, base) w[FP + ((x) - (base))] = PM_REG##n; -#define PM_PUSH_SYNC(n) [--sp] = (PM_REGSET##n); -#define PM_POP_SYNC(n) (PM_REGSET##n) = [sp++]; -#define PM_PUSH(n, x) PM_REG##n = [FP++]; -#define PM_POP(n, x) [FP--] = PM_REG##n; -#define PM_CORE_PUSH(n, x) _PM_PUSH(n, x, , COREMMR_BASE) -#define PM_CORE_POP(n, x) _PM_POP(n, x, , COREMMR_BASE) -#define PM_SYS_PUSH(n, x) _PM_PUSH(n, x, , SYSMMR_BASE) -#define PM_SYS_POP(n, x) _PM_POP(n, x, , SYSMMR_BASE) -#define PM_SYS_PUSH16(n, x) _PM_PUSH(n, x, w, SYSMMR_BASE) -#define PM_SYS_POP16(n, x) _PM_POP(n, x, w, SYSMMR_BASE) - ENTRY(_do_hibernate) - /* - * Save the core regs early so we can blow them away when - * saving/restoring MMR states - */ - [--sp] = (R7:0, P5:0); + [--SP] = ( R7:0, P5:0 ); + [--SP] = RETS; + /* Save System MMRs */ + R2 = R0; + P0.H = hi(PLL_CTL); + P0.L = lo(PLL_CTL); + +#ifdef SIC_IMASK0 + PM_SYS_PUSH(SIC_IMASK0) +#endif +#ifdef SIC_IMASK1 + PM_SYS_PUSH(SIC_IMASK1) +#endif +#ifdef SIC_IMASK2 + PM_SYS_PUSH(SIC_IMASK2) +#endif +#ifdef SIC_IMASK + PM_SYS_PUSH(SIC_IMASK) +#endif +#ifdef SIC_IAR0 + PM_SYS_PUSH(SIC_IAR0) + PM_SYS_PUSH(SIC_IAR1) + PM_SYS_PUSH(SIC_IAR2) +#endif +#ifdef SIC_IAR3 + PM_SYS_PUSH(SIC_IAR3) +#endif +#ifdef SIC_IAR4 + PM_SYS_PUSH(SIC_IAR4) + PM_SYS_PUSH(SIC_IAR5) + PM_SYS_PUSH(SIC_IAR6) +#endif +#ifdef SIC_IAR7 + PM_SYS_PUSH(SIC_IAR7) +#endif +#ifdef SIC_IAR8 + PM_SYS_PUSH(SIC_IAR8) + PM_SYS_PUSH(SIC_IAR9) + PM_SYS_PUSH(SIC_IAR10) + PM_SYS_PUSH(SIC_IAR11) +#endif + +#ifdef SIC_IWR + PM_SYS_PUSH(SIC_IWR) +#endif +#ifdef SIC_IWR0 + PM_SYS_PUSH(SIC_IWR0) +#endif +#ifdef SIC_IWR1 + PM_SYS_PUSH(SIC_IWR1) +#endif +#ifdef SIC_IWR2 + PM_SYS_PUSH(SIC_IWR2) +#endif + +#ifdef PINT0_ASSIGN + PM_SYS_PUSH(PINT0_MASK_SET) + PM_SYS_PUSH(PINT1_MASK_SET) + PM_SYS_PUSH(PINT2_MASK_SET) + PM_SYS_PUSH(PINT3_MASK_SET) + PM_SYS_PUSH(PINT0_ASSIGN) + PM_SYS_PUSH(PINT1_ASSIGN) + PM_SYS_PUSH(PINT2_ASSIGN) + PM_SYS_PUSH(PINT3_ASSIGN) + PM_SYS_PUSH(PINT0_INVERT_SET) + PM_SYS_PUSH(PINT1_INVERT_SET) + PM_SYS_PUSH(PINT2_INVERT_SET) + PM_SYS_PUSH(PINT3_INVERT_SET) + PM_SYS_PUSH(PINT0_EDGE_SET) + PM_SYS_PUSH(PINT1_EDGE_SET) + PM_SYS_PUSH(PINT2_EDGE_SET) + PM_SYS_PUSH(PINT3_EDGE_SET) +#endif + + PM_SYS_PUSH(EBIU_AMBCTL0) + PM_SYS_PUSH(EBIU_AMBCTL1) + PM_SYS_PUSH16(EBIU_AMGCTL) + +#ifdef EBIU_FCTL + PM_SYS_PUSH(EBIU_MBSCTL) + PM_SYS_PUSH(EBIU_MODE) + PM_SYS_PUSH(EBIU_FCTL) +#endif + +#ifdef PORTCIO_FER + PM_SYS_PUSH16(PORTCIO_DIR) + PM_SYS_PUSH16(PORTCIO_INEN) + PM_SYS_PUSH16(PORTCIO) + PM_SYS_PUSH16(PORTCIO_FER) + PM_SYS_PUSH16(PORTDIO_DIR) + PM_SYS_PUSH16(PORTDIO_INEN) + PM_SYS_PUSH16(PORTDIO) + PM_SYS_PUSH16(PORTDIO_FER) + PM_SYS_PUSH16(PORTEIO_DIR) + PM_SYS_PUSH16(PORTEIO_INEN) + PM_SYS_PUSH16(PORTEIO) + PM_SYS_PUSH16(PORTEIO_FER) +#endif + + PM_SYS_PUSH16(SYSCR) + + /* Save Core MMRs */ + P0.H = hi(SRAM_BASE_ADDRESS); + P0.L = lo(SRAM_BASE_ADDRESS); + + PM_PUSH(DMEM_CONTROL) + PM_PUSH(DCPLB_ADDR0) + PM_PUSH(DCPLB_ADDR1) + PM_PUSH(DCPLB_ADDR2) + PM_PUSH(DCPLB_ADDR3) + PM_PUSH(DCPLB_ADDR4) + PM_PUSH(DCPLB_ADDR5) + PM_PUSH(DCPLB_ADDR6) + PM_PUSH(DCPLB_ADDR7) + PM_PUSH(DCPLB_ADDR8) + PM_PUSH(DCPLB_ADDR9) + PM_PUSH(DCPLB_ADDR10) + PM_PUSH(DCPLB_ADDR11) + PM_PUSH(DCPLB_ADDR12) + PM_PUSH(DCPLB_ADDR13) + PM_PUSH(DCPLB_ADDR14) + PM_PUSH(DCPLB_ADDR15) + PM_PUSH(DCPLB_DATA0) + PM_PUSH(DCPLB_DATA1) + PM_PUSH(DCPLB_DATA2) + PM_PUSH(DCPLB_DATA3) + PM_PUSH(DCPLB_DATA4) + PM_PUSH(DCPLB_DATA5) + PM_PUSH(DCPLB_DATA6) + PM_PUSH(DCPLB_DATA7) + PM_PUSH(DCPLB_DATA8) + PM_PUSH(DCPLB_DATA9) + PM_PUSH(DCPLB_DATA10) + PM_PUSH(DCPLB_DATA11) + PM_PUSH(DCPLB_DATA12) + PM_PUSH(DCPLB_DATA13) + PM_PUSH(DCPLB_DATA14) + PM_PUSH(DCPLB_DATA15) + PM_PUSH(IMEM_CONTROL) + PM_PUSH(ICPLB_ADDR0) + PM_PUSH(ICPLB_ADDR1) + PM_PUSH(ICPLB_ADDR2) + PM_PUSH(ICPLB_ADDR3) + PM_PUSH(ICPLB_ADDR4) + PM_PUSH(ICPLB_ADDR5) + PM_PUSH(ICPLB_ADDR6) + PM_PUSH(ICPLB_ADDR7) + PM_PUSH(ICPLB_ADDR8) + PM_PUSH(ICPLB_ADDR9) + PM_PUSH(ICPLB_ADDR10) + PM_PUSH(ICPLB_ADDR11) + PM_PUSH(ICPLB_ADDR12) + PM_PUSH(ICPLB_ADDR13) + PM_PUSH(ICPLB_ADDR14) + PM_PUSH(ICPLB_ADDR15) + PM_PUSH(ICPLB_DATA0) + PM_PUSH(ICPLB_DATA1) + PM_PUSH(ICPLB_DATA2) + PM_PUSH(ICPLB_DATA3) + PM_PUSH(ICPLB_DATA4) + PM_PUSH(ICPLB_DATA5) + PM_PUSH(ICPLB_DATA6) + PM_PUSH(ICPLB_DATA7) + PM_PUSH(ICPLB_DATA8) + PM_PUSH(ICPLB_DATA9) + PM_PUSH(ICPLB_DATA10) + PM_PUSH(ICPLB_DATA11) + PM_PUSH(ICPLB_DATA12) + PM_PUSH(ICPLB_DATA13) + PM_PUSH(ICPLB_DATA14) + PM_PUSH(ICPLB_DATA15) + PM_PUSH(EVT0) + PM_PUSH(EVT1) + PM_PUSH(EVT2) + PM_PUSH(EVT3) + PM_PUSH(EVT4) + PM_PUSH(EVT5) + PM_PUSH(EVT6) + PM_PUSH(EVT7) + PM_PUSH(EVT8) + PM_PUSH(EVT9) + PM_PUSH(EVT10) + PM_PUSH(EVT11) + PM_PUSH(EVT12) + PM_PUSH(EVT13) + PM_PUSH(EVT14) + PM_PUSH(EVT15) + PM_PUSH(IMASK) + PM_PUSH(ILAT) + PM_PUSH(IPRIO) + PM_PUSH(TCNTL) + PM_PUSH(TPERIOD) + PM_PUSH(TSCALE) + PM_PUSH(TCOUNT) + PM_PUSH(TBUFCTL) + + /* Save Core Registers */ + [--sp] = SYSCFG; + [--sp] = ( R7:0, P5:0 ); [--sp] = fp; [--sp] = usp; @@ -360,497 +506,47 @@ ENTRY(_do_hibernate) [--sp] = LB0; [--sp] = LB1; - /* We can't push RETI directly as that'll change IPEND[4] */ - r7 = RETI; - [--sp] = RETS; [--sp] = ASTAT; [--sp] = CYCLES; [--sp] = CYCLES2; - [--sp] = SYSCFG; + + [--sp] = RETS; + r0 = RETI; + [--sp] = r0; [--sp] = RETX; + [--sp] = RETN; + [--sp] = RETE; [--sp] = SEQSTAT; - [--sp] = r7; - - /* Save first func arg in M3 */ - M3 = R0; - - /* Save system MMRs */ - FP.H = hi(SYSMMR_BASE); - FP.L = lo(SYSMMR_BASE); - -#ifdef SIC_IMASK0 - PM_SYS_PUSH(0, SIC_IMASK0) - PM_SYS_PUSH(1, SIC_IMASK1) -# ifdef SIC_IMASK2 - PM_SYS_PUSH(2, SIC_IMASK2) -# endif -#else - PM_SYS_PUSH(0, SIC_IMASK) -#endif -#ifdef SIC_IAR0 - PM_SYS_PUSH(3, SIC_IAR0) - PM_SYS_PUSH(4, SIC_IAR1) - PM_SYS_PUSH(5, SIC_IAR2) -#endif -#ifdef SIC_IAR3 - PM_SYS_PUSH(6, SIC_IAR3) -#endif -#ifdef SIC_IAR4 - PM_SYS_PUSH(7, SIC_IAR4) - PM_SYS_PUSH(8, SIC_IAR5) - PM_SYS_PUSH(9, SIC_IAR6) -#endif -#ifdef SIC_IAR7 - PM_SYS_PUSH(10, SIC_IAR7) -#endif -#ifdef SIC_IAR8 - PM_SYS_PUSH(11, SIC_IAR8) - PM_SYS_PUSH(12, SIC_IAR9) - PM_SYS_PUSH(13, SIC_IAR10) -#endif - PM_PUSH_SYNC(13) -#ifdef SIC_IAR11 - PM_SYS_PUSH(0, SIC_IAR11) -#endif - -#ifdef SIC_IWR - PM_SYS_PUSH(1, SIC_IWR) -#endif -#ifdef SIC_IWR0 - PM_SYS_PUSH(1, SIC_IWR0) -#endif -#ifdef SIC_IWR1 - PM_SYS_PUSH(2, SIC_IWR1) -#endif -#ifdef SIC_IWR2 - PM_SYS_PUSH(3, SIC_IWR2) -#endif - -#ifdef PINT0_ASSIGN - PM_SYS_PUSH(4, PINT0_MASK_SET) - PM_SYS_PUSH(5, PINT1_MASK_SET) - PM_SYS_PUSH(6, PINT2_MASK_SET) - PM_SYS_PUSH(7, PINT3_MASK_SET) - PM_SYS_PUSH(8, PINT0_ASSIGN) - PM_SYS_PUSH(9, PINT1_ASSIGN) - PM_SYS_PUSH(10, PINT2_ASSIGN) - PM_SYS_PUSH(11, PINT3_ASSIGN) - PM_SYS_PUSH(12, PINT0_INVERT_SET) - PM_SYS_PUSH(13, PINT1_INVERT_SET) - PM_PUSH_SYNC(13) - PM_SYS_PUSH(0, PINT2_INVERT_SET) - PM_SYS_PUSH(1, PINT3_INVERT_SET) - PM_SYS_PUSH(2, PINT0_EDGE_SET) - PM_SYS_PUSH(3, PINT1_EDGE_SET) - PM_SYS_PUSH(4, PINT2_EDGE_SET) - PM_SYS_PUSH(5, PINT3_EDGE_SET) -#endif - - PM_SYS_PUSH16(6, SYSCR) - - PM_SYS_PUSH16(7, EBIU_AMGCTL) - PM_SYS_PUSH(8, EBIU_AMBCTL0) - PM_SYS_PUSH(9, EBIU_AMBCTL1) -#ifdef EBIU_FCTL - PM_SYS_PUSH(10, EBIU_MBSCTL) - PM_SYS_PUSH(11, EBIU_MODE) - PM_SYS_PUSH(12, EBIU_FCTL) - PM_PUSH_SYNC(12) -#else - PM_PUSH_SYNC(9) -#endif - - /* Save Core MMRs */ - I0.H = hi(COREMMR_BASE); - I0.L = lo(COREMMR_BASE); - I1 = I0; - I2 = I0; - I3 = I0; - B0 = I0; - B1 = I0; - B2 = I0; - B3 = I0; - I1.L = lo(DCPLB_ADDR0); - I2.L = lo(DCPLB_DATA0); - I3.L = lo(ICPLB_ADDR0); - B0.L = lo(ICPLB_DATA0); - B1.L = lo(EVT2); - B2.L = lo(IMASK); - B3.L = lo(TCNTL); - - /* DCPLB Addr */ - FP = I1; - PM_PUSH(0, DCPLB_ADDR0) - PM_PUSH(1, DCPLB_ADDR1) - PM_PUSH(2, DCPLB_ADDR2) - PM_PUSH(3, DCPLB_ADDR3) - PM_PUSH(4, DCPLB_ADDR4) - PM_PUSH(5, DCPLB_ADDR5) - PM_PUSH(6, DCPLB_ADDR6) - PM_PUSH(7, DCPLB_ADDR7) - PM_PUSH(8, DCPLB_ADDR8) - PM_PUSH(9, DCPLB_ADDR9) - PM_PUSH(10, DCPLB_ADDR10) - PM_PUSH(11, DCPLB_ADDR11) - PM_PUSH(12, DCPLB_ADDR12) - PM_PUSH(13, DCPLB_ADDR13) - PM_PUSH_SYNC(13) - PM_PUSH(0, DCPLB_ADDR14) - PM_PUSH(1, DCPLB_ADDR15) - - /* DCPLB Data */ - FP = I2; - PM_PUSH(2, DCPLB_DATA0) - PM_PUSH(3, DCPLB_DATA1) - PM_PUSH(4, DCPLB_DATA2) - PM_PUSH(5, DCPLB_DATA3) - PM_PUSH(6, DCPLB_DATA4) - PM_PUSH(7, DCPLB_DATA5) - PM_PUSH(8, DCPLB_DATA6) - PM_PUSH(9, DCPLB_DATA7) - PM_PUSH(10, DCPLB_DATA8) - PM_PUSH(11, DCPLB_DATA9) - PM_PUSH(12, DCPLB_DATA10) - PM_PUSH(13, DCPLB_DATA11) - PM_PUSH_SYNC(13) - PM_PUSH(0, DCPLB_DATA12) - PM_PUSH(1, DCPLB_DATA13) - PM_PUSH(2, DCPLB_DATA14) - PM_PUSH(3, DCPLB_DATA15) - - /* ICPLB Addr */ - FP = I3; - PM_PUSH(4, ICPLB_ADDR0) - PM_PUSH(5, ICPLB_ADDR1) - PM_PUSH(6, ICPLB_ADDR2) - PM_PUSH(7, ICPLB_ADDR3) - PM_PUSH(8, ICPLB_ADDR4) - PM_PUSH(9, ICPLB_ADDR5) - PM_PUSH(10, ICPLB_ADDR6) - PM_PUSH(11, ICPLB_ADDR7) - PM_PUSH(12, ICPLB_ADDR8) - PM_PUSH(13, ICPLB_ADDR9) - PM_PUSH_SYNC(13) - PM_PUSH(0, ICPLB_ADDR10) - PM_PUSH(1, ICPLB_ADDR11) - PM_PUSH(2, ICPLB_ADDR12) - PM_PUSH(3, ICPLB_ADDR13) - PM_PUSH(4, ICPLB_ADDR14) - PM_PUSH(5, ICPLB_ADDR15) - - /* ICPLB Data */ - FP = B0; - PM_PUSH(6, ICPLB_DATA0) - PM_PUSH(7, ICPLB_DATA1) - PM_PUSH(8, ICPLB_DATA2) - PM_PUSH(9, ICPLB_DATA3) - PM_PUSH(10, ICPLB_DATA4) - PM_PUSH(11, ICPLB_DATA5) - PM_PUSH(12, ICPLB_DATA6) - PM_PUSH(13, ICPLB_DATA7) - PM_PUSH_SYNC(13) - PM_PUSH(0, ICPLB_DATA8) - PM_PUSH(1, ICPLB_DATA9) - PM_PUSH(2, ICPLB_DATA10) - PM_PUSH(3, ICPLB_DATA11) - PM_PUSH(4, ICPLB_DATA12) - PM_PUSH(5, ICPLB_DATA13) - PM_PUSH(6, ICPLB_DATA14) - PM_PUSH(7, ICPLB_DATA15) - - /* Event Vectors */ - FP = B1; - PM_PUSH(8, EVT2) - PM_PUSH(9, EVT3) - FP += 4; /* EVT4 */ - PM_PUSH(10, EVT5) - PM_PUSH(11, EVT6) - PM_PUSH(12, EVT7) - PM_PUSH(13, EVT8) - PM_PUSH_SYNC(13) - PM_PUSH(0, EVT9) - PM_PUSH(1, EVT10) - PM_PUSH(2, EVT11) - PM_PUSH(3, EVT12) - PM_PUSH(4, EVT13) - PM_PUSH(5, EVT14) - PM_PUSH(6, EVT15) - - /* CEC */ - FP = B2; - PM_PUSH(7, IMASK) - FP += 4; /* IPEND */ - PM_PUSH(8, ILAT) - PM_PUSH(9, IPRIO) - - /* Core Timer */ - FP = B3; - PM_PUSH(10, TCNTL) - PM_PUSH(11, TPERIOD) - PM_PUSH(12, TSCALE) - PM_PUSH(13, TCOUNT) - PM_PUSH_SYNC(13) - - /* Misc non-contiguous registers */ - FP = I0; - PM_CORE_PUSH(0, DMEM_CONTROL); - PM_CORE_PUSH(1, IMEM_CONTROL); - PM_CORE_PUSH(2, TBUFCTL); - PM_PUSH_SYNC(2) - - /* Setup args to hibernate mode early for pipeline optimization */ - R0 = M3; - P1.H = _hibernate_mode; - P1.L = _hibernate_mode; /* Save Magic, return address and Stack Pointer */ - P0 = 0; - R1.H = 0xDEAD; /* Hibernate Magic */ - R1.L = 0xBEEF; - R2.H = .Lpm_resume_here; - R2.L = .Lpm_resume_here; - [P0++] = R1; /* Store Hibernate Magic */ - [P0++] = R2; /* Save Return Address */ + P0.H = 0; + P0.L = 0; + R0.H = 0xDEAD; /* Hibernate Magic */ + R0.L = 0xBEEF; + [P0++] = R0; /* Store Hibernate Magic */ + R0.H = .Lpm_resume_here; + R0.L = .Lpm_resume_here; + [P0++] = R0; /* Save Return Address */ [P0++] = SP; /* Save Stack Pointer */ - - /* Must use an indirect call as we need to jump to L1 */ - call (P1); /* Goodbye */ + P0.H = _hibernate_mode; + P0.L = _hibernate_mode; + R0 = R2; + call (P0); /* Goodbye */ .Lpm_resume_here: - /* Restore Core MMRs */ - I0.H = hi(COREMMR_BASE); - I0.L = lo(COREMMR_BASE); - I1 = I0; - I2 = I0; - I3 = I0; - B0 = I0; - B1 = I0; - B2 = I0; - B3 = I0; - I1.L = lo(DCPLB_ADDR15); - I2.L = lo(DCPLB_DATA15); - I3.L = lo(ICPLB_ADDR15); - B0.L = lo(ICPLB_DATA15); - B1.L = lo(EVT15); - B2.L = lo(IPRIO); - B3.L = lo(TCOUNT); - - /* Misc non-contiguous registers */ - FP = I0; - PM_POP_SYNC(2) - PM_CORE_POP(2, TBUFCTL) - PM_CORE_POP(1, IMEM_CONTROL) - PM_CORE_POP(0, DMEM_CONTROL) - - /* Core Timer */ - PM_POP_SYNC(13) - FP = B3; - PM_POP(13, TCOUNT) - PM_POP(12, TSCALE) - PM_POP(11, TPERIOD) - PM_POP(10, TCNTL) - - /* CEC */ - FP = B2; - PM_POP(9, IPRIO) - PM_POP(8, ILAT) - FP += -4; /* IPEND */ - PM_POP(7, IMASK) - - /* Event Vectors */ - FP = B1; - PM_POP(6, EVT15) - PM_POP(5, EVT14) - PM_POP(4, EVT13) - PM_POP(3, EVT12) - PM_POP(2, EVT11) - PM_POP(1, EVT10) - PM_POP(0, EVT9) - PM_POP_SYNC(13) - PM_POP(13, EVT8) - PM_POP(12, EVT7) - PM_POP(11, EVT6) - PM_POP(10, EVT5) - FP += -4; /* EVT4 */ - PM_POP(9, EVT3) - PM_POP(8, EVT2) - - /* ICPLB Data */ - FP = B0; - PM_POP(7, ICPLB_DATA15) - PM_POP(6, ICPLB_DATA14) - PM_POP(5, ICPLB_DATA13) - PM_POP(4, ICPLB_DATA12) - PM_POP(3, ICPLB_DATA11) - PM_POP(2, ICPLB_DATA10) - PM_POP(1, ICPLB_DATA9) - PM_POP(0, ICPLB_DATA8) - PM_POP_SYNC(13) - PM_POP(13, ICPLB_DATA7) - PM_POP(12, ICPLB_DATA6) - PM_POP(11, ICPLB_DATA5) - PM_POP(10, ICPLB_DATA4) - PM_POP(9, ICPLB_DATA3) - PM_POP(8, ICPLB_DATA2) - PM_POP(7, ICPLB_DATA1) - PM_POP(6, ICPLB_DATA0) - - /* ICPLB Addr */ - FP = I3; - PM_POP(5, ICPLB_ADDR15) - PM_POP(4, ICPLB_ADDR14) - PM_POP(3, ICPLB_ADDR13) - PM_POP(2, ICPLB_ADDR12) - PM_POP(1, ICPLB_ADDR11) - PM_POP(0, ICPLB_ADDR10) - PM_POP_SYNC(13) - PM_POP(13, ICPLB_ADDR9) - PM_POP(12, ICPLB_ADDR8) - PM_POP(11, ICPLB_ADDR7) - PM_POP(10, ICPLB_ADDR6) - PM_POP(9, ICPLB_ADDR5) - PM_POP(8, ICPLB_ADDR4) - PM_POP(7, ICPLB_ADDR3) - PM_POP(6, ICPLB_ADDR2) - PM_POP(5, ICPLB_ADDR1) - PM_POP(4, ICPLB_ADDR0) - - /* DCPLB Data */ - FP = I2; - PM_POP(3, DCPLB_DATA15) - PM_POP(2, DCPLB_DATA14) - PM_POP(1, DCPLB_DATA13) - PM_POP(0, DCPLB_DATA12) - PM_POP_SYNC(13) - PM_POP(13, DCPLB_DATA11) - PM_POP(12, DCPLB_DATA10) - PM_POP(11, DCPLB_DATA9) - PM_POP(10, DCPLB_DATA8) - PM_POP(9, DCPLB_DATA7) - PM_POP(8, DCPLB_DATA6) - PM_POP(7, DCPLB_DATA5) - PM_POP(6, DCPLB_DATA4) - PM_POP(5, DCPLB_DATA3) - PM_POP(4, DCPLB_DATA2) - PM_POP(3, DCPLB_DATA1) - PM_POP(2, DCPLB_DATA0) - - /* DCPLB Addr */ - FP = I1; - PM_POP(1, DCPLB_ADDR15) - PM_POP(0, DCPLB_ADDR14) - PM_POP_SYNC(13) - PM_POP(13, DCPLB_ADDR13) - PM_POP(12, DCPLB_ADDR12) - PM_POP(11, DCPLB_ADDR11) - PM_POP(10, DCPLB_ADDR10) - PM_POP(9, DCPLB_ADDR9) - PM_POP(8, DCPLB_ADDR8) - PM_POP(7, DCPLB_ADDR7) - PM_POP(6, DCPLB_ADDR6) - PM_POP(5, DCPLB_ADDR5) - PM_POP(4, DCPLB_ADDR4) - PM_POP(3, DCPLB_ADDR3) - PM_POP(2, DCPLB_ADDR2) - PM_POP(1, DCPLB_ADDR1) - PM_POP(0, DCPLB_ADDR0) - - /* Restore System MMRs */ - FP.H = hi(SYSMMR_BASE); - FP.L = lo(SYSMMR_BASE); - -#ifdef EBIU_FCTL - PM_POP_SYNC(12) - PM_SYS_POP(12, EBIU_FCTL) - PM_SYS_POP(11, EBIU_MODE) - PM_SYS_POP(10, EBIU_MBSCTL) -#else - PM_POP_SYNC(9) -#endif - PM_SYS_POP(9, EBIU_AMBCTL1) - PM_SYS_POP(8, EBIU_AMBCTL0) - PM_SYS_POP16(7, EBIU_AMGCTL) - - PM_SYS_POP16(6, SYSCR) - -#ifdef PINT0_ASSIGN - PM_SYS_POP(5, PINT3_EDGE_SET) - PM_SYS_POP(4, PINT2_EDGE_SET) - PM_SYS_POP(3, PINT1_EDGE_SET) - PM_SYS_POP(2, PINT0_EDGE_SET) - PM_SYS_POP(1, PINT3_INVERT_SET) - PM_SYS_POP(0, PINT2_INVERT_SET) - PM_POP_SYNC(13) - PM_SYS_POP(13, PINT1_INVERT_SET) - PM_SYS_POP(12, PINT0_INVERT_SET) - PM_SYS_POP(11, PINT3_ASSIGN) - PM_SYS_POP(10, PINT2_ASSIGN) - PM_SYS_POP(9, PINT1_ASSIGN) - PM_SYS_POP(8, PINT0_ASSIGN) - PM_SYS_POP(7, PINT3_MASK_SET) - PM_SYS_POP(6, PINT2_MASK_SET) - PM_SYS_POP(5, PINT1_MASK_SET) - PM_SYS_POP(4, PINT0_MASK_SET) -#endif - -#ifdef SIC_IWR2 - PM_SYS_POP(3, SIC_IWR2) -#endif -#ifdef SIC_IWR1 - PM_SYS_POP(2, SIC_IWR1) -#endif -#ifdef SIC_IWR0 - PM_SYS_POP(1, SIC_IWR0) -#endif -#ifdef SIC_IWR - PM_SYS_POP(1, SIC_IWR) -#endif - -#ifdef SIC_IAR11 - PM_SYS_POP(0, SIC_IAR11) -#endif - PM_POP_SYNC(13) -#ifdef SIC_IAR8 - PM_SYS_POP(13, SIC_IAR10) - PM_SYS_POP(12, SIC_IAR9) - PM_SYS_POP(11, SIC_IAR8) -#endif -#ifdef SIC_IAR7 - PM_SYS_POP(10, SIC_IAR7) -#endif -#ifdef SIC_IAR6 - PM_SYS_POP(9, SIC_IAR6) - PM_SYS_POP(8, SIC_IAR5) - PM_SYS_POP(7, SIC_IAR4) -#endif -#ifdef SIC_IAR3 - PM_SYS_POP(6, SIC_IAR3) -#endif -#ifdef SIC_IAR0 - PM_SYS_POP(5, SIC_IAR2) - PM_SYS_POP(4, SIC_IAR1) - PM_SYS_POP(3, SIC_IAR0) -#endif -#ifdef SIC_IMASK0 -# ifdef SIC_IMASK2 - PM_SYS_POP(2, SIC_IMASK2) -# endif - PM_SYS_POP(1, SIC_IMASK1) - PM_SYS_POP(0, SIC_IMASK0) -#else - PM_SYS_POP(0, SIC_IMASK) -#endif - /* Restore Core Registers */ - RETI = [sp++]; SEQSTAT = [sp++]; + RETE = [sp++]; + RETN = [sp++]; RETX = [sp++]; - SYSCFG = [sp++]; + r0 = [sp++]; + RETI = r0; + RETS = [sp++]; + CYCLES2 = [sp++]; CYCLES = [sp++]; ASTAT = [sp++]; - RETS = [sp++]; LB1 = [sp++]; LB0 = [sp++]; @@ -885,10 +581,204 @@ ENTRY(_do_hibernate) usp = [sp++]; fp = [sp++]; - (R7:0, P5:0) = [sp++]; + + ( R7 : 0, P5 : 0) = [ SP ++ ]; + SYSCFG = [sp++]; + + /* Restore Core MMRs */ + + PM_POP(TBUFCTL) + PM_POP(TCOUNT) + PM_POP(TSCALE) + PM_POP(TPERIOD) + PM_POP(TCNTL) + PM_POP(IPRIO) + PM_POP(ILAT) + PM_POP(IMASK) + PM_POP(EVT15) + PM_POP(EVT14) + PM_POP(EVT13) + PM_POP(EVT12) + PM_POP(EVT11) + PM_POP(EVT10) + PM_POP(EVT9) + PM_POP(EVT8) + PM_POP(EVT7) + PM_POP(EVT6) + PM_POP(EVT5) + PM_POP(EVT4) + PM_POP(EVT3) + PM_POP(EVT2) + PM_POP(EVT1) + PM_POP(EVT0) + PM_POP(ICPLB_DATA15) + PM_POP(ICPLB_DATA14) + PM_POP(ICPLB_DATA13) + PM_POP(ICPLB_DATA12) + PM_POP(ICPLB_DATA11) + PM_POP(ICPLB_DATA10) + PM_POP(ICPLB_DATA9) + PM_POP(ICPLB_DATA8) + PM_POP(ICPLB_DATA7) + PM_POP(ICPLB_DATA6) + PM_POP(ICPLB_DATA5) + PM_POP(ICPLB_DATA4) + PM_POP(ICPLB_DATA3) + PM_POP(ICPLB_DATA2) + PM_POP(ICPLB_DATA1) + PM_POP(ICPLB_DATA0) + PM_POP(ICPLB_ADDR15) + PM_POP(ICPLB_ADDR14) + PM_POP(ICPLB_ADDR13) + PM_POP(ICPLB_ADDR12) + PM_POP(ICPLB_ADDR11) + PM_POP(ICPLB_ADDR10) + PM_POP(ICPLB_ADDR9) + PM_POP(ICPLB_ADDR8) + PM_POP(ICPLB_ADDR7) + PM_POP(ICPLB_ADDR6) + PM_POP(ICPLB_ADDR5) + PM_POP(ICPLB_ADDR4) + PM_POP(ICPLB_ADDR3) + PM_POP(ICPLB_ADDR2) + PM_POP(ICPLB_ADDR1) + PM_POP(ICPLB_ADDR0) + PM_POP(IMEM_CONTROL) + PM_POP(DCPLB_DATA15) + PM_POP(DCPLB_DATA14) + PM_POP(DCPLB_DATA13) + PM_POP(DCPLB_DATA12) + PM_POP(DCPLB_DATA11) + PM_POP(DCPLB_DATA10) + PM_POP(DCPLB_DATA9) + PM_POP(DCPLB_DATA8) + PM_POP(DCPLB_DATA7) + PM_POP(DCPLB_DATA6) + PM_POP(DCPLB_DATA5) + PM_POP(DCPLB_DATA4) + PM_POP(DCPLB_DATA3) + PM_POP(DCPLB_DATA2) + PM_POP(DCPLB_DATA1) + PM_POP(DCPLB_DATA0) + PM_POP(DCPLB_ADDR15) + PM_POP(DCPLB_ADDR14) + PM_POP(DCPLB_ADDR13) + PM_POP(DCPLB_ADDR12) + PM_POP(DCPLB_ADDR11) + PM_POP(DCPLB_ADDR10) + PM_POP(DCPLB_ADDR9) + PM_POP(DCPLB_ADDR8) + PM_POP(DCPLB_ADDR7) + PM_POP(DCPLB_ADDR6) + PM_POP(DCPLB_ADDR5) + PM_POP(DCPLB_ADDR4) + PM_POP(DCPLB_ADDR3) + PM_POP(DCPLB_ADDR2) + PM_POP(DCPLB_ADDR1) + PM_POP(DCPLB_ADDR0) + PM_POP(DMEM_CONTROL) + + /* Restore System MMRs */ + + P0.H = hi(PLL_CTL); + P0.L = lo(PLL_CTL); + PM_SYS_POP16(SYSCR) + +#ifdef PORTCIO_FER + PM_SYS_POP16(PORTEIO_FER) + PM_SYS_POP16(PORTEIO) + PM_SYS_POP16(PORTEIO_INEN) + PM_SYS_POP16(PORTEIO_DIR) + PM_SYS_POP16(PORTDIO_FER) + PM_SYS_POP16(PORTDIO) + PM_SYS_POP16(PORTDIO_INEN) + PM_SYS_POP16(PORTDIO_DIR) + PM_SYS_POP16(PORTCIO_FER) + PM_SYS_POP16(PORTCIO) + PM_SYS_POP16(PORTCIO_INEN) + PM_SYS_POP16(PORTCIO_DIR) +#endif + +#ifdef EBIU_FCTL + PM_SYS_POP(EBIU_FCTL) + PM_SYS_POP(EBIU_MODE) + PM_SYS_POP(EBIU_MBSCTL) +#endif + PM_SYS_POP16(EBIU_AMGCTL) + PM_SYS_POP(EBIU_AMBCTL1) + PM_SYS_POP(EBIU_AMBCTL0) + +#ifdef PINT0_ASSIGN + PM_SYS_POP(PINT3_EDGE_SET) + PM_SYS_POP(PINT2_EDGE_SET) + PM_SYS_POP(PINT1_EDGE_SET) + PM_SYS_POP(PINT0_EDGE_SET) + PM_SYS_POP(PINT3_INVERT_SET) + PM_SYS_POP(PINT2_INVERT_SET) + PM_SYS_POP(PINT1_INVERT_SET) + PM_SYS_POP(PINT0_INVERT_SET) + PM_SYS_POP(PINT3_ASSIGN) + PM_SYS_POP(PINT2_ASSIGN) + PM_SYS_POP(PINT1_ASSIGN) + PM_SYS_POP(PINT0_ASSIGN) + PM_SYS_POP(PINT3_MASK_SET) + PM_SYS_POP(PINT2_MASK_SET) + PM_SYS_POP(PINT1_MASK_SET) + PM_SYS_POP(PINT0_MASK_SET) +#endif + +#ifdef SIC_IWR2 + PM_SYS_POP(SIC_IWR2) +#endif +#ifdef SIC_IWR1 + PM_SYS_POP(SIC_IWR1) +#endif +#ifdef SIC_IWR0 + PM_SYS_POP(SIC_IWR0) +#endif +#ifdef SIC_IWR + PM_SYS_POP(SIC_IWR) +#endif + +#ifdef SIC_IAR8 + PM_SYS_POP(SIC_IAR11) + PM_SYS_POP(SIC_IAR10) + PM_SYS_POP(SIC_IAR9) + PM_SYS_POP(SIC_IAR8) +#endif +#ifdef SIC_IAR7 + PM_SYS_POP(SIC_IAR7) +#endif +#ifdef SIC_IAR6 + PM_SYS_POP(SIC_IAR6) + PM_SYS_POP(SIC_IAR5) + PM_SYS_POP(SIC_IAR4) +#endif +#ifdef SIC_IAR3 + PM_SYS_POP(SIC_IAR3) +#endif +#ifdef SIC_IAR0 + PM_SYS_POP(SIC_IAR2) + PM_SYS_POP(SIC_IAR1) + PM_SYS_POP(SIC_IAR0) +#endif +#ifdef SIC_IMASK + PM_SYS_POP(SIC_IMASK) +#endif +#ifdef SIC_IMASK2 + PM_SYS_POP(SIC_IMASK2) +#endif +#ifdef SIC_IMASK1 + PM_SYS_POP(SIC_IMASK1) +#endif +#ifdef SIC_IMASK0 + PM_SYS_POP(SIC_IMASK0) +#endif [--sp] = RETI; /* Clear Global Interrupt Disable */ SP += 4; + RETS = [SP++]; + ( R7:0, P5:0 ) = [SP++]; RTS; ENDPROC(_do_hibernate) diff --git a/trunk/arch/blackfin/mach-common/head.S b/trunk/arch/blackfin/mach-common/head.S index 8b4d98854403..76de5724c1e3 100644 --- a/trunk/arch/blackfin/mach-common/head.S +++ b/trunk/arch/blackfin/mach-common/head.S @@ -85,25 +85,37 @@ ENTRY(__start) SSYNC; /* in case of double faults, save a few things */ - p1.l = _initial_pda; - p1.h = _initial_pda; - r4 = RETX; + p0.l = _init_retx; + p0.h = _init_retx; + R0 = RETX; + [P0] = R0; + #ifdef CONFIG_DEBUG_DOUBLEFAULT /* Only save these if we are storing them, * This happens here, since L1 gets clobbered * below */ GET_PDA(p0, r0); - r0 = [p0 + PDA_DF_RETX]; - r1 = [p0 + PDA_DF_DCPLB]; - r2 = [p0 + PDA_DF_ICPLB]; - r3 = [p0 + PDA_DF_SEQSTAT]; - [p1 + PDA_INIT_DF_RETX] = r0; - [p1 + PDA_INIT_DF_DCPLB] = r1; - [p1 + PDA_INIT_DF_ICPLB] = r2; - [p1 + PDA_INIT_DF_SEQSTAT] = r3; + r5 = [p0 + PDA_DF_RETX]; + p1.l = _init_saved_retx; + p1.h = _init_saved_retx; + [p1] = r5; + + r5 = [p0 + PDA_DF_DCPLB]; + p1.l = _init_saved_dcplb_fault_addr; + p1.h = _init_saved_dcplb_fault_addr; + [p1] = r5; + + r5 = [p0 + PDA_DF_ICPLB]; + p1.l = _init_saved_icplb_fault_addr; + p1.h = _init_saved_icplb_fault_addr; + [p1] = r5; + + r5 = [p0 + PDA_DF_SEQSTAT]; + p1.l = _init_saved_seqstat; + p1.h = _init_saved_seqstat; + [p1] = r5; #endif - [p1 + PDA_INIT_RETX] = r4; /* Initialize stack pointer */ sp.l = _init_thread_union + THREAD_SIZE; diff --git a/trunk/arch/blackfin/mach-common/ints-priority.c b/trunk/arch/blackfin/mach-common/ints-priority.c index 332dace6af34..1177369f9922 100644 --- a/trunk/arch/blackfin/mach-common/ints-priority.c +++ b/trunk/arch/blackfin/mach-common/ints-priority.c @@ -444,7 +444,7 @@ static inline void bfin_set_irq_handler(unsigned irq, irq_flow_handler_t handle) static DECLARE_BITMAP(gpio_enabled, MAX_BLACKFIN_GPIOS); extern void bfin_gpio_irq_prepare(unsigned gpio); -#if !BFIN_GPIO_PINT +#if !defined(CONFIG_BF54x) static void bfin_gpio_ack_irq(struct irq_data *d) { @@ -633,7 +633,7 @@ void bfin_demux_gpio_irq(unsigned int inta_irq, bfin_demux_gpio_block(irq); } -#else +#else /* CONFIG_BF54x */ #define NR_PINT_SYS_IRQS 4 #define NR_PINT_BITS 32 @@ -647,11 +647,24 @@ void bfin_demux_gpio_irq(unsigned int inta_irq, static unsigned char irq2pint_lut[NR_PINTS]; static unsigned char pint2irq_lut[NR_PINT_SYS_IRQS * NR_PINT_BITS]; -static struct bfin_pint_regs * const pint[NR_PINT_SYS_IRQS] = { - (struct bfin_pint_regs *)PINT0_MASK_SET, - (struct bfin_pint_regs *)PINT1_MASK_SET, - (struct bfin_pint_regs *)PINT2_MASK_SET, - (struct bfin_pint_regs *)PINT3_MASK_SET, +struct pin_int_t { + unsigned int mask_set; + unsigned int mask_clear; + unsigned int request; + unsigned int assign; + unsigned int edge_set; + unsigned int edge_clear; + unsigned int invert_set; + unsigned int invert_clear; + unsigned int pinstate; + unsigned int latch; +}; + +static struct pin_int_t *pint[NR_PINT_SYS_IRQS] = { + (struct pin_int_t *)PINT0_MASK_SET, + (struct pin_int_t *)PINT1_MASK_SET, + (struct pin_int_t *)PINT2_MASK_SET, + (struct pin_int_t *)PINT3_MASK_SET, }; inline unsigned int get_irq_base(u32 bank, u8 bmap) @@ -968,7 +981,7 @@ int __init init_arch_irq(void) local_irq_disable(); -#if BFIN_GPIO_PINT +#ifdef CONFIG_BF54x # ifdef CONFIG_PINTx_REASSIGN pint[0]->assign = CONFIG_PINT0_ASSIGN; pint[1]->assign = CONFIG_PINT1_ASSIGN; @@ -986,16 +999,16 @@ int __init init_arch_irq(void) irq_set_chip(irq, &bfin_internal_irqchip); switch (irq) { -#if BFIN_GPIO_PINT - case IRQ_PINT0: - case IRQ_PINT1: - case IRQ_PINT2: - case IRQ_PINT3: -#elif defined(BF537_FAMILY) +#if defined(BF537_FAMILY) case IRQ_PH_INTA_MAC_RX: case IRQ_PF_INTA_PG_INTA: #elif defined(BF533_FAMILY) case IRQ_PROG_INTA: +#elif defined(CONFIG_BF54x) + case IRQ_PINT0: + case IRQ_PINT1: + case IRQ_PINT2: + case IRQ_PINT3: #elif defined(CONFIG_BF52x) || defined(CONFIG_BF51x) case IRQ_PORTF_INTA: case IRQ_PORTG_INTA: diff --git a/trunk/arch/blackfin/mach-common/smp.c b/trunk/arch/blackfin/mach-common/smp.c index 1c143a4de5f5..35e7e1eb0188 100644 --- a/trunk/arch/blackfin/mach-common/smp.c +++ b/trunk/arch/blackfin/mach-common/smp.c @@ -45,7 +45,9 @@ struct corelock_slot corelock __attribute__ ((__section__(".l2.bss"))); unsigned long blackfin_iflush_l1_entry[NR_CPUS]; #endif -struct blackfin_initial_pda __cpuinitdata initial_pda_coreb; +void __cpuinitdata *init_retx_coreb, *init_saved_retx_coreb, + *init_saved_seqstat_coreb, *init_saved_icplb_fault_addr_coreb, + *init_saved_dcplb_fault_addr_coreb; #define BFIN_IPI_RESCHEDULE 0 #define BFIN_IPI_CALL_FUNC 1 @@ -367,16 +369,13 @@ void __cpuinit secondary_start_kernel(void) if (_bfin_swrst & SWRST_DBL_FAULT_B) { printk(KERN_EMERG "CoreB Recovering from DOUBLE FAULT event\n"); #ifdef CONFIG_DEBUG_DOUBLEFAULT - printk(KERN_EMERG " While handling exception (EXCAUSE = %#x) at %pF\n", - initial_pda_coreb.seqstat_doublefault & SEQSTAT_EXCAUSE, - initial_pda_coreb.retx_doublefault); - printk(KERN_NOTICE " DCPLB_FAULT_ADDR: %pF\n", - initial_pda_coreb.dcplb_doublefault_addr); - printk(KERN_NOTICE " ICPLB_FAULT_ADDR: %pF\n", - initial_pda_coreb.icplb_doublefault_addr); + printk(KERN_EMERG " While handling exception (EXCAUSE = 0x%x) at %pF\n", + (int)init_saved_seqstat_coreb & SEQSTAT_EXCAUSE, init_saved_retx_coreb); + printk(KERN_NOTICE " DCPLB_FAULT_ADDR: %pF\n", init_saved_dcplb_fault_addr_coreb); + printk(KERN_NOTICE " ICPLB_FAULT_ADDR: %pF\n", init_saved_icplb_fault_addr_coreb); #endif printk(KERN_NOTICE " The instruction at %pF caused a double exception\n", - initial_pda_coreb.retx); + init_retx_coreb); } /* diff --git a/trunk/arch/cris/kernel/module.c b/trunk/arch/cris/kernel/module.c index 37400f5869e6..bcd502f74cda 100644 --- a/trunk/arch/cris/kernel/module.c +++ b/trunk/arch/cris/kernel/module.c @@ -30,19 +30,45 @@ #endif #ifdef CONFIG_ETRAX_KMALLOCED_MODULES +#define MALLOC_MODULE(size) kmalloc(size, GFP_KERNEL) +#define FREE_MODULE(region) kfree(region) +#else +#define MALLOC_MODULE(size) vmalloc_exec(size) +#define FREE_MODULE(region) vfree(region) +#endif + void *module_alloc(unsigned long size) { if (size == 0) return NULL; - return kmalloc(size, GFP_KERNEL); + return MALLOC_MODULE(size); } + /* Free memory returned from module_alloc */ void module_free(struct module *mod, void *module_region) { - kfree(module_region); + FREE_MODULE(module_region); +} + +/* We don't need anything special. */ +int module_frob_arch_sections(Elf_Ehdr *hdr, + Elf_Shdr *sechdrs, + char *secstrings, + struct module *mod) +{ + return 0; +} + +int apply_relocate(Elf32_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *me) +{ + printk(KERN_ERR "module %s: REL relocation unsupported\n", me->name); + return -ENOEXEC; } -#endif int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab, @@ -82,3 +108,14 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, return 0; } + +int module_finalize(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + struct module *me) +{ + return 0; +} + +void module_arch_cleanup(struct module *mod) +{ +} diff --git a/trunk/arch/frv/kernel/module.c b/trunk/arch/frv/kernel/module.c index 9d9835f1fe2b..711763c8a6f3 100644 --- a/trunk/arch/frv/kernel/module.c +++ b/trunk/arch/frv/kernel/module.c @@ -22,6 +22,57 @@ #define DEBUGP(fmt...) #endif -/* TODO: At least one of apply_relocate or apply_relocate_add must be - * implemented in order to get working module support. - */ +void *module_alloc(unsigned long size) +{ + if (size == 0) + return NULL; + + return vmalloc_exec(size); +} + + +/* Free memory returned from module_alloc */ +void module_free(struct module *mod, void *module_region) +{ + vfree(module_region); +} + +/* We don't need anything special. */ +int module_frob_arch_sections(Elf_Ehdr *hdr, + Elf_Shdr *sechdrs, + char *secstrings, + struct module *mod) +{ + return 0; +} + +int apply_relocate(Elf32_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *me) +{ + printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n", me->name); + return -ENOEXEC; +} + +int apply_relocate_add(Elf32_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *me) +{ + printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n", me->name); + return -ENOEXEC; +} + +int module_finalize(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + struct module *me) +{ + return 0; +} + +void module_arch_cleanup(struct module *mod) +{ +} diff --git a/trunk/arch/h8300/Kconfig.cpu b/trunk/arch/h8300/Kconfig.cpu index 15c22286ae79..d236ab4232ca 100644 --- a/trunk/arch/h8300/Kconfig.cpu +++ b/trunk/arch/h8300/Kconfig.cpu @@ -162,7 +162,9 @@ config H8300_TPU_CH int "TPU channel" depends on H8300_TPU -source "kernel/Kconfig.preempt" +config PREEMPT + bool "Preemptible Kernel" + default n source "mm/Kconfig" diff --git a/trunk/arch/h8300/kernel/module.c b/trunk/arch/h8300/kernel/module.c index 1d526e05db19..db4953dc4e1b 100644 --- a/trunk/arch/h8300/kernel/module.c +++ b/trunk/arch/h8300/kernel/module.c @@ -11,6 +11,40 @@ #define DEBUGP(fmt...) #endif +void *module_alloc(unsigned long size) +{ + if (size == 0) + return NULL; + return vmalloc(size); +} + + +/* Free memory returned from module_alloc */ +void module_free(struct module *mod, void *module_region) +{ + vfree(module_region); +} + +/* We don't need anything special. */ +int module_frob_arch_sections(Elf_Ehdr *hdr, + Elf_Shdr *sechdrs, + char *secstrings, + struct module *mod) +{ + return 0; +} + +int apply_relocate(Elf32_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *me) +{ + printk(KERN_ERR "module %s: RELOCATION unsupported\n", + me->name); + return -ENOEXEC; +} + int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, @@ -73,3 +107,14 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, me->name, rela[i].r_offset); return -ENOEXEC; } + +int module_finalize(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + struct module *me) +{ + return 0; +} + +void module_arch_cleanup(struct module *mod) +{ +} diff --git a/trunk/arch/ia64/Kconfig b/trunk/arch/ia64/Kconfig index 137b277f7e56..38280ef4a2af 100644 --- a/trunk/arch/ia64/Kconfig +++ b/trunk/arch/ia64/Kconfig @@ -101,9 +101,6 @@ config GENERIC_IOMAP bool default y -config ARCH_CLOCKSOURCE_DATA - def_bool y - config SCHED_OMIT_FRAME_POINTER bool default y @@ -630,6 +627,27 @@ source "drivers/pci/hotplug/Kconfig" source "drivers/pcmcia/Kconfig" +config DMAR + bool "Support for DMA Remapping Devices (EXPERIMENTAL)" + depends on IA64_GENERIC && ACPI && EXPERIMENTAL + help + DMA remapping (DMAR) devices support enables independent address + translations for Direct Memory Access (DMA) from devices. + These DMA remapping devices are reported via ACPI tables + and include PCI device scope covered by these DMA + remapping devices. + +config DMAR_DEFAULT_ON + def_bool y + prompt "Enable DMA Remapping Devices by default" + depends on DMAR + help + Selecting this option will enable a DMAR device at boot time if + one is found. If this option is not selected, DMAR support can + be enabled by passing intel_iommu=on to the kernel. It is + recommended you say N here while the DMAR code remains + experimental. + endmenu endif @@ -663,3 +681,6 @@ source "lib/Kconfig" config IOMMU_HELPER def_bool (IA64_HP_ZX1 || IA64_HP_ZX1_SWIOTLB || IA64_GENERIC || SWIOTLB) + +config IOMMU_API + def_bool (DMAR) diff --git a/trunk/arch/ia64/include/asm/clocksource.h b/trunk/arch/ia64/include/asm/clocksource.h deleted file mode 100644 index 5c8596e4cb02..000000000000 --- a/trunk/arch/ia64/include/asm/clocksource.h +++ /dev/null @@ -1,10 +0,0 @@ -/* IA64-specific clocksource additions */ - -#ifndef _ASM_IA64_CLOCKSOURCE_H -#define _ASM_IA64_CLOCKSOURCE_H - -struct arch_clocksource_data { - void *fsys_mmio; /* used by fsyscall asm code */ -}; - -#endif /* _ASM_IA64_CLOCKSOURCE_H */ diff --git a/trunk/arch/ia64/include/asm/paravirt.h b/trunk/arch/ia64/include/asm/paravirt.h index 32551d304cd7..2eb0a981a09a 100644 --- a/trunk/arch/ia64/include/asm/paravirt.h +++ b/trunk/arch/ia64/include/asm/paravirt.h @@ -281,10 +281,6 @@ paravirt_init_missing_ticks_accounting(int cpu) pv_time_ops.init_missing_ticks_accounting(cpu); } -struct jump_label_key; -extern struct jump_label_key paravirt_steal_enabled; -extern struct jump_label_key paravirt_steal_rq_enabled; - static inline int paravirt_do_steal_accounting(unsigned long *new_itm) { diff --git a/trunk/arch/ia64/kernel/cyclone.c b/trunk/arch/ia64/kernel/cyclone.c index 4826ff957a3d..f64097b5118a 100644 --- a/trunk/arch/ia64/kernel/cyclone.c +++ b/trunk/arch/ia64/kernel/cyclone.c @@ -115,7 +115,7 @@ int __init init_cyclone_clock(void) } /* initialize last tick */ cyclone_mc = cyclone_timer; - clocksource_cyclone.archdata.fsys_mmio = cyclone_timer; + clocksource_cyclone.fsys_mmio = cyclone_timer; clocksource_register_hz(&clocksource_cyclone, CYCLONE_TIMER_FREQ); return 0; diff --git a/trunk/arch/ia64/kernel/module.c b/trunk/arch/ia64/kernel/module.c index 24603be24c14..1481b0a28ca0 100644 --- a/trunk/arch/ia64/kernel/module.c +++ b/trunk/arch/ia64/kernel/module.c @@ -304,6 +304,14 @@ plt_target (struct plt_entry *plt) #endif /* !USE_BRL */ +void * +module_alloc (unsigned long size) +{ + if (!size) + return NULL; + return vmalloc(size); +} + void module_free (struct module *mod, void *module_region) { @@ -845,6 +853,14 @@ apply_relocate_add (Elf64_Shdr *sechdrs, const char *strtab, unsigned int symind return 0; } +int +apply_relocate (Elf64_Shdr *sechdrs, const char *strtab, unsigned int symindex, + unsigned int relsec, struct module *mod) +{ + printk(KERN_ERR "module %s: REL relocs in section %u unsupported\n", mod->name, relsec); + return -ENOEXEC; +} + /* * Modules contain a single unwind table which covers both the core and the init text * sections but since the two are not contiguous, we need to split this table up such that diff --git a/trunk/arch/ia64/kernel/paravirt.c b/trunk/arch/ia64/kernel/paravirt.c index 100868216c55..a21d7bb9c69c 100644 --- a/trunk/arch/ia64/kernel/paravirt.c +++ b/trunk/arch/ia64/kernel/paravirt.c @@ -634,8 +634,6 @@ struct pv_irq_ops pv_irq_ops = { * pv_time_ops * time operations */ -struct jump_label_key paravirt_steal_enabled; -struct jump_label_key paravirt_steal_rq_enabled; static int ia64_native_do_steal_accounting(unsigned long *new_itm) diff --git a/trunk/arch/ia64/kernel/time.c b/trunk/arch/ia64/kernel/time.c index 43920de425f1..85118dfe9bb5 100644 --- a/trunk/arch/ia64/kernel/time.c +++ b/trunk/arch/ia64/kernel/time.c @@ -468,7 +468,7 @@ void update_vsyscall(struct timespec *wall, struct timespec *wtm, fsyscall_gtod_data.clk_mask = c->mask; fsyscall_gtod_data.clk_mult = mult; fsyscall_gtod_data.clk_shift = c->shift; - fsyscall_gtod_data.clk_fsys_mmio = c->archdata.fsys_mmio; + fsyscall_gtod_data.clk_fsys_mmio = c->fsys_mmio; fsyscall_gtod_data.clk_cycle_last = c->cycle_last; /* copy kernel time structures */ diff --git a/trunk/arch/ia64/kvm/Kconfig b/trunk/arch/ia64/kvm/Kconfig index 9806e55f91be..fa4d1e59deb0 100644 --- a/trunk/arch/ia64/kvm/Kconfig +++ b/trunk/arch/ia64/kvm/Kconfig @@ -49,5 +49,6 @@ config KVM_INTEL extensions. source drivers/vhost/Kconfig +source drivers/virtio/Kconfig endif # VIRTUALIZATION diff --git a/trunk/arch/ia64/sn/kernel/irq.c b/trunk/arch/ia64/sn/kernel/irq.c index 485c42d97e83..81a1f4e6bcd8 100644 --- a/trunk/arch/ia64/sn/kernel/irq.c +++ b/trunk/arch/ia64/sn/kernel/irq.c @@ -112,6 +112,8 @@ static void sn_ack_irq(struct irq_data *data) irq_move_irq(data); } +static void sn_irq_info_free(struct rcu_head *head); + struct sn_irq_info *sn_retarget_vector(struct sn_irq_info *sn_irq_info, nasid_t nasid, int slice) { @@ -175,7 +177,7 @@ struct sn_irq_info *sn_retarget_vector(struct sn_irq_info *sn_irq_info, spin_lock(&sn_irq_info_lock); list_replace_rcu(&sn_irq_info->list, &new_irq_info->list); spin_unlock(&sn_irq_info_lock); - kfree_rcu(sn_irq_info, rcu); + call_rcu(&sn_irq_info->rcu, sn_irq_info_free); finish_up: @@ -336,6 +338,14 @@ static void unregister_intr_pda(struct sn_irq_info *sn_irq_info) rcu_read_unlock(); } +static void sn_irq_info_free(struct rcu_head *head) +{ + struct sn_irq_info *sn_irq_info; + + sn_irq_info = container_of(head, struct sn_irq_info, rcu); + kfree(sn_irq_info); +} + void sn_irq_fixup(struct pci_dev *pci_dev, struct sn_irq_info *sn_irq_info) { nasid_t nasid = sn_irq_info->irq_nasid; @@ -389,7 +399,7 @@ void sn_irq_unfixup(struct pci_dev *pci_dev) spin_unlock(&sn_irq_info_lock); if (list_empty(sn_irq_lh[sn_irq_info->irq_irq])) free_irq_vector(sn_irq_info->irq_irq); - kfree_rcu(sn_irq_info, rcu); + call_rcu(&sn_irq_info->rcu, sn_irq_info_free); pci_dev_put(pci_dev); } diff --git a/trunk/arch/ia64/sn/kernel/sn2/timer.c b/trunk/arch/ia64/sn/kernel/sn2/timer.c index 0f8844e49363..c34efda122e1 100644 --- a/trunk/arch/ia64/sn/kernel/sn2/timer.c +++ b/trunk/arch/ia64/sn/kernel/sn2/timer.c @@ -54,7 +54,7 @@ ia64_sn_udelay (unsigned long usecs) void __init sn_timer_init(void) { - clocksource_sn2.archdata.fsys_mmio = RTC_COUNTER_ADDR; + clocksource_sn2.fsys_mmio = RTC_COUNTER_ADDR; clocksource_register_hz(&clocksource_sn2, sn_rtc_cycles_per_second); ia64_udelay = &ia64_sn_udelay; diff --git a/trunk/arch/m32r/Kconfig b/trunk/arch/m32r/Kconfig index b92b9445255d..85b44e858225 100644 --- a/trunk/arch/m32r/Kconfig +++ b/trunk/arch/m32r/Kconfig @@ -268,7 +268,17 @@ config SCHED_OMIT_FRAME_POINTER bool default y -source "kernel/Kconfig.preempt" +config PREEMPT + bool "Preemptible Kernel" + help + This option reduces the latency of the kernel when reacting to + real-time or interactive events by allowing a low priority process to + be preempted even if it is in kernel mode executing a system call. + This allows applications to run more reliably even when the system is + under load. + + Say Y here if you are building a kernel for a desktop, embedded + or real-time system. Say N if you are unsure. config SMP bool "Symmetric multi-processing support" diff --git a/trunk/arch/m32r/include/asm/delay.h b/trunk/arch/m32r/include/asm/delay.h index 9670e127b7b2..9dd9e999ea69 100644 --- a/trunk/arch/m32r/include/asm/delay.h +++ b/trunk/arch/m32r/include/asm/delay.h @@ -1 +1,26 @@ -#include +#ifndef _ASM_M32R_DELAY_H +#define _ASM_M32R_DELAY_H + +/* + * Copyright (C) 1993 Linus Torvalds + * + * Delay routines calling functions in arch/m32r/lib/delay.c + */ + +extern void __bad_udelay(void); +extern void __bad_ndelay(void); + +extern void __udelay(unsigned long usecs); +extern void __ndelay(unsigned long nsecs); +extern void __const_udelay(unsigned long xloops); +extern void __delay(unsigned long loops); + +#define udelay(n) (__builtin_constant_p(n) ? \ + ((n) > 20000 ? __bad_udelay() : __const_udelay((n) * 0x10c7ul)) : \ + __udelay(n)) + +#define ndelay(n) (__builtin_constant_p(n) ? \ + ((n) > 20000 ? __bad_ndelay() : __const_udelay((n) * 5ul)) : \ + __ndelay(n)) + +#endif /* _ASM_M32R_DELAY_H */ diff --git a/trunk/arch/m32r/kernel/module.c b/trunk/arch/m32r/kernel/module.c index 3071fe83ffc8..cb5f37d78d49 100644 --- a/trunk/arch/m32r/kernel/module.c +++ b/trunk/arch/m32r/kernel/module.c @@ -28,6 +28,33 @@ #define DEBUGP(fmt...) #endif +void *module_alloc(unsigned long size) +{ + if (size == 0) + return NULL; +#ifdef CONFIG_MMU + return vmalloc_exec(size); +#else + return vmalloc(size); +#endif +} + + +/* Free memory returned from module_alloc */ +void module_free(struct module *mod, void *module_region) +{ + vfree(module_region); +} + +/* We don't need anything special. */ +int module_frob_arch_sections(Elf_Ehdr *hdr, + Elf_Shdr *sechdrs, + char *secstrings, + struct module *mod) +{ + return 0; +} + #define COPY_UNALIGNED_WORD(sw, tw, align) \ { \ void *__s = &(sw), *__t = &(tw); \ @@ -216,3 +243,14 @@ int apply_relocate(Elf32_Shdr *sechdrs, return 0; } + +int module_finalize(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + struct module *me) +{ + return 0; +} + +void module_arch_cleanup(struct module *mod) +{ +} diff --git a/trunk/arch/m68k/kernel/module_mm.c b/trunk/arch/m68k/kernel/module_mm.c index ceafc47c96d5..cd6bcb1c957e 100644 --- a/trunk/arch/m68k/kernel/module_mm.c +++ b/trunk/arch/m68k/kernel/module_mm.c @@ -19,6 +19,29 @@ #ifdef CONFIG_MODULES +void *module_alloc(unsigned long size) +{ + if (size == 0) + return NULL; + return vmalloc(size); +} + + +/* Free memory returned from module_alloc */ +void module_free(struct module *mod, void *module_region) +{ + vfree(module_region); +} + +/* We don't need anything special. */ +int module_frob_arch_sections(Elf_Ehdr *hdr, + Elf_Shdr *sechdrs, + char *secstrings, + struct module *mod) +{ + return 0; +} + int apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, @@ -108,6 +131,10 @@ int module_finalize(const Elf_Ehdr *hdr, return 0; } +void module_arch_cleanup(struct module *mod) +{ +} + #endif /* CONFIG_MODULES */ void module_fixup(struct module *mod, struct m68k_fixup_info *start, diff --git a/trunk/arch/m68k/kernel/module_no.c b/trunk/arch/m68k/kernel/module_no.c index 5a097c6063fa..d11ffae7956a 100644 --- a/trunk/arch/m68k/kernel/module_no.c +++ b/trunk/arch/m68k/kernel/module_no.c @@ -11,6 +11,29 @@ #define DEBUGP(fmt...) #endif +void *module_alloc(unsigned long size) +{ + if (size == 0) + return NULL; + return vmalloc(size); +} + + +/* Free memory returned from module_alloc */ +void module_free(struct module *mod, void *module_region) +{ + vfree(module_region); +} + +/* We don't need anything special. */ +int module_frob_arch_sections(Elf_Ehdr *hdr, + Elf_Shdr *sechdrs, + char *secstrings, + struct module *mod) +{ + return 0; +} + int apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, @@ -90,3 +113,14 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, } return 0; } + +int module_finalize(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + struct module *me) +{ + return 0; +} + +void module_arch_cleanup(struct module *mod) +{ +} diff --git a/trunk/arch/microblaze/kernel/module.c b/trunk/arch/microblaze/kernel/module.c index 142426f631bb..0e73f6606547 100644 --- a/trunk/arch/microblaze/kernel/module.c +++ b/trunk/arch/microblaze/kernel/module.c @@ -18,6 +18,37 @@ #include #include +void *module_alloc(unsigned long size) +{ + void *ret; + ret = (size == 0) ? NULL : vmalloc(size); + pr_debug("module_alloc (%08lx@%08lx)\n", size, (unsigned long int)ret); + return ret; +} + +void module_free(struct module *module, void *region) +{ + pr_debug("module_free(%s,%08lx)\n", module->name, + (unsigned long)region); + vfree(region); +} + +int module_frob_arch_sections(Elf_Ehdr *hdr, + Elf_Shdr *sechdrs, + char *secstrings, + struct module *mod) +{ + return 0; +} + +int apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, + unsigned int symindex, unsigned int relsec, struct module *module) +{ + printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n", + module->name); + return -ENOEXEC; +} + int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, unsigned int relsec, struct module *module) { @@ -124,3 +155,7 @@ int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs, flush_dcache(); return 0; } + +void module_arch_cleanup(struct module *mod) +{ +} diff --git a/trunk/arch/mips/Kconfig b/trunk/arch/mips/Kconfig index 177cdaf83564..653da62d0682 100644 --- a/trunk/arch/mips/Kconfig +++ b/trunk/arch/mips/Kconfig @@ -185,7 +185,6 @@ config MACH_JAZZ select CSRC_R4K select DEFAULT_SGI_PARTITION if CPU_BIG_ENDIAN select GENERIC_ISA_DMA - select HAVE_PCSPKR_PLATFORM select IRQ_CPU select I8253 select I8259 @@ -267,7 +266,6 @@ config MIPS_MALTA select CSRC_R4K select DMA_NONCOHERENT select GENERIC_ISA_DMA - select HAVE_PCSPKR_PLATFORM select IRQ_CPU select IRQ_GIC select HW_HAS_PCI @@ -642,7 +640,6 @@ config SNI_RM select DEFAULT_SGI_PARTITION if CPU_BIG_ENDIAN select DMA_NONCOHERENT select GENERIC_ISA_DMA - select HAVE_PCSPKR_PLATFORM select HW_HAS_EISA select HW_HAS_PCI select IRQ_CPU @@ -2391,7 +2388,6 @@ config MMU config I8253 bool select CLKSRC_I8253 - select CLKEVT_I8253 select MIPS_EXTERNAL_TIMER config ZONE_DMA32 @@ -2493,4 +2489,20 @@ source "security/Kconfig" source "crypto/Kconfig" +menuconfig VIRTUALIZATION + bool "Virtualization" + default n + ---help--- + Say Y here to get to see options for using your Linux host to run other + operating systems inside virtual machines (guests). + This option alone does not add any kernel code. + + If you say N, all options in this submenu will be skipped and disabled. + +if VIRTUALIZATION + +source drivers/virtio/Kconfig + +endif # VIRTUALIZATION + source "lib/Kconfig" diff --git a/trunk/arch/mips/cobalt/time.c b/trunk/arch/mips/cobalt/time.c index 3bff3b820baf..0162f9edc693 100644 --- a/trunk/arch/mips/cobalt/time.c +++ b/trunk/arch/mips/cobalt/time.c @@ -17,10 +17,10 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include #include #include +#include #include #define GT641XX_BASE_CLOCK 50000000 /* 50MHz */ diff --git a/trunk/arch/mips/include/asm/i8253.h b/trunk/arch/mips/include/asm/i8253.h new file mode 100644 index 000000000000..9ad011366f73 --- /dev/null +++ b/trunk/arch/mips/include/asm/i8253.h @@ -0,0 +1,24 @@ +/* + * Machine specific IO port address definition for generic. + * Written by Osamu Tomita + */ +#ifndef __ASM_I8253_H +#define __ASM_I8253_H + +#include + +/* i8253A PIT registers */ +#define PIT_MODE 0x43 +#define PIT_CH0 0x40 +#define PIT_CH2 0x42 + +#define PIT_LATCH LATCH + +extern raw_spinlock_t i8253_lock; + +extern void setup_pit_timer(void); + +#define inb_pit inb_p +#define outb_pit outb_p + +#endif /* __ASM_I8253_H */ diff --git a/trunk/arch/mips/include/asm/stacktrace.h b/trunk/arch/mips/include/asm/stacktrace.h index 780ee2c2a2ac..0bf82818aa53 100644 --- a/trunk/arch/mips/include/asm/stacktrace.h +++ b/trunk/arch/mips/include/asm/stacktrace.h @@ -7,10 +7,6 @@ extern int raw_show_trace; extern unsigned long unwind_stack(struct task_struct *task, unsigned long *sp, unsigned long pc, unsigned long *ra); -extern unsigned long unwind_stack_by_address(unsigned long stack_page, - unsigned long *sp, - unsigned long pc, - unsigned long *ra); #else #define raw_show_trace 1 static inline unsigned long unwind_stack(struct task_struct *task, diff --git a/trunk/arch/mips/jazz/irq.c b/trunk/arch/mips/jazz/irq.c index ca9bd2069142..260df4750949 100644 --- a/trunk/arch/mips/jazz/irq.c +++ b/trunk/arch/mips/jazz/irq.c @@ -7,7 +7,6 @@ * Copyright (C) 1994 - 2001, 2003, 07 Ralf Baechle */ #include -#include #include #include #include @@ -16,6 +15,7 @@ #include #include +#include #include #include #include diff --git a/trunk/arch/mips/kernel/i8253.c b/trunk/arch/mips/kernel/i8253.c index be4ee7d63e04..391221b6a6aa 100644 --- a/trunk/arch/mips/kernel/i8253.c +++ b/trunk/arch/mips/kernel/i8253.c @@ -3,16 +3,96 @@ * */ #include -#include +#include +#include +#include #include #include +#include #include +#include +#include +#include #include +DEFINE_RAW_SPINLOCK(i8253_lock); +EXPORT_SYMBOL(i8253_lock); + +/* + * Initialize the PIT timer. + * + * This is also called after resume to bring the PIT into operation again. + */ +static void init_pit_timer(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + raw_spin_lock(&i8253_lock); + + switch(mode) { + case CLOCK_EVT_MODE_PERIODIC: + /* binary, mode 2, LSB/MSB, ch 0 */ + outb_p(0x34, PIT_MODE); + outb_p(LATCH & 0xff , PIT_CH0); /* LSB */ + outb(LATCH >> 8 , PIT_CH0); /* MSB */ + break; + + case CLOCK_EVT_MODE_SHUTDOWN: + case CLOCK_EVT_MODE_UNUSED: + if (evt->mode == CLOCK_EVT_MODE_PERIODIC || + evt->mode == CLOCK_EVT_MODE_ONESHOT) { + outb_p(0x30, PIT_MODE); + outb_p(0, PIT_CH0); + outb_p(0, PIT_CH0); + } + break; + + case CLOCK_EVT_MODE_ONESHOT: + /* One shot setup */ + outb_p(0x38, PIT_MODE); + break; + + case CLOCK_EVT_MODE_RESUME: + /* Nothing to do here */ + break; + } + raw_spin_unlock(&i8253_lock); +} + +/* + * Program the next event in oneshot mode + * + * Delta is given in PIT ticks + */ +static int pit_next_event(unsigned long delta, struct clock_event_device *evt) +{ + raw_spin_lock(&i8253_lock); + outb_p(delta & 0xff , PIT_CH0); /* LSB */ + outb(delta >> 8 , PIT_CH0); /* MSB */ + raw_spin_unlock(&i8253_lock); + + return 0; +} + +/* + * On UP the PIT can serve all of the possible timer functions. On SMP systems + * it can be solely used for the global tick. + * + * The profiling and update capabilites are switched off once the local apic is + * registered. This mechanism replaces the previous #ifdef LOCAL_APIC - + * !using_apic_timer decisions in do_timer_interrupt_hook() + */ +static struct clock_event_device pit_clockevent = { + .name = "pit", + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .set_mode = init_pit_timer, + .set_next_event = pit_next_event, + .irq = 0, +}; + static irqreturn_t timer_interrupt(int irq, void *dev_id) { - i8253_clockevent.event_handler(&i8253_clockevent); + pit_clockevent.event_handler(&pit_clockevent); return IRQ_HANDLED; } @@ -23,9 +103,25 @@ static struct irqaction irq0 = { .name = "timer" }; +/* + * Initialize the conversion factor and the min/max deltas of the clock event + * structure and register the clock event source with the framework. + */ void __init setup_pit_timer(void) { - clockevent_i8253_init(true); + struct clock_event_device *cd = &pit_clockevent; + unsigned int cpu = smp_processor_id(); + + /* + * Start pit with the boot cpu mask and make it global after the + * IO_APIC has been initialized. + */ + cd->cpumask = cpumask_of(cpu); + clockevent_set_clock(cd, CLOCK_TICK_RATE); + cd->max_delta_ns = clockevent_delta2ns(0x7FFF, cd); + cd->min_delta_ns = clockevent_delta2ns(0xF, cd); + clockevents_register_device(cd); + setup_irq(0, &irq0); } diff --git a/trunk/arch/mips/kernel/module.c b/trunk/arch/mips/kernel/module.c index 4b930ac4aff2..dd940b701963 100644 --- a/trunk/arch/mips/kernel/module.c +++ b/trunk/arch/mips/kernel/module.c @@ -45,14 +45,30 @@ static struct mips_hi16 *mips_hi16_list; static LIST_HEAD(dbe_list); static DEFINE_SPINLOCK(dbe_lock); -#ifdef MODULE_START void *module_alloc(unsigned long size) { +#ifdef MODULE_START return __vmalloc_node_range(size, 1, MODULE_START, MODULE_END, GFP_KERNEL, PAGE_KERNEL, -1, __builtin_return_address(0)); -} +#else + if (size == 0) + return NULL; + return vmalloc(size); #endif +} + +/* Free memory returned from module_alloc */ +void module_free(struct module *mod, void *module_region) +{ + vfree(module_region); +} + +int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, + char *secstrings, struct module *mod) +{ + return 0; +} static int apply_r_mips_none(struct module *me, u32 *location, Elf_Addr v) { diff --git a/trunk/arch/mips/kernel/perf_event.c b/trunk/arch/mips/kernel/perf_event.c index d0deaab9ace2..a8244854d3dc 100644 --- a/trunk/arch/mips/kernel/perf_event.c +++ b/trunk/arch/mips/kernel/perf_event.c @@ -527,7 +527,7 @@ handle_associated_event(struct cpu_hw_events *cpuc, if (!mipspmu_event_set_period(event, hwc, idx)) return; - if (perf_event_overflow(event, data, regs)) + if (perf_event_overflow(event, 0, data, regs)) mipspmu->disable_event(idx); } diff --git a/trunk/arch/mips/kernel/perf_event_mipsxx.c b/trunk/arch/mips/kernel/perf_event_mipsxx.c index e5ad09a9baf7..75266ff4cc33 100644 --- a/trunk/arch/mips/kernel/perf_event_mipsxx.c +++ b/trunk/arch/mips/kernel/perf_event_mipsxx.c @@ -377,20 +377,6 @@ static const struct mips_perf_event mipsxxcore_cache_map [C(RESULT_MISS)] = { UNSUPPORTED_PERF_EVENT_ID }, }, }, -[C(NODE)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = { UNSUPPORTED_PERF_EVENT_ID }, - [C(RESULT_MISS)] = { UNSUPPORTED_PERF_EVENT_ID }, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = { UNSUPPORTED_PERF_EVENT_ID }, - [C(RESULT_MISS)] = { UNSUPPORTED_PERF_EVENT_ID }, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = { UNSUPPORTED_PERF_EVENT_ID }, - [C(RESULT_MISS)] = { UNSUPPORTED_PERF_EVENT_ID }, - }, -}, }; /* 74K core has completely different cache event map. */ @@ -494,20 +480,6 @@ static const struct mips_perf_event mipsxx74Kcore_cache_map [C(RESULT_MISS)] = { UNSUPPORTED_PERF_EVENT_ID }, }, }, -[C(NODE)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = { UNSUPPORTED_PERF_EVENT_ID }, - [C(RESULT_MISS)] = { UNSUPPORTED_PERF_EVENT_ID }, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = { UNSUPPORTED_PERF_EVENT_ID }, - [C(RESULT_MISS)] = { UNSUPPORTED_PERF_EVENT_ID }, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = { UNSUPPORTED_PERF_EVENT_ID }, - [C(RESULT_MISS)] = { UNSUPPORTED_PERF_EVENT_ID }, - }, -}, }; #ifdef CONFIG_MIPS_MT_SMP diff --git a/trunk/arch/mips/kernel/process.c b/trunk/arch/mips/kernel/process.c index c28fbe6107bc..d2112d3cf115 100644 --- a/trunk/arch/mips/kernel/process.c +++ b/trunk/arch/mips/kernel/process.c @@ -373,18 +373,18 @@ unsigned long thread_saved_pc(struct task_struct *tsk) #ifdef CONFIG_KALLSYMS -/* generic stack unwinding function */ -unsigned long notrace unwind_stack_by_address(unsigned long stack_page, - unsigned long *sp, - unsigned long pc, - unsigned long *ra) +/* used by show_backtrace() */ +unsigned long unwind_stack(struct task_struct *task, unsigned long *sp, + unsigned long pc, unsigned long *ra) { + unsigned long stack_page; struct mips_frame_info info; unsigned long size, ofs; int leaf; extern void ret_from_irq(void); extern void ret_from_exception(void); + stack_page = (unsigned long)task_stack_page(task); if (!stack_page) return 0; @@ -443,15 +443,6 @@ unsigned long notrace unwind_stack_by_address(unsigned long stack_page, *ra = 0; return __kernel_text_address(pc) ? pc : 0; } -EXPORT_SYMBOL(unwind_stack_by_address); - -/* used by show_backtrace() */ -unsigned long unwind_stack(struct task_struct *task, unsigned long *sp, - unsigned long pc, unsigned long *ra) -{ - unsigned long stack_page = (unsigned long)task_stack_page(task); - return unwind_stack_by_address(stack_page, sp, pc, ra); -} #endif /* diff --git a/trunk/arch/mips/kernel/traps.c b/trunk/arch/mips/kernel/traps.c index b7517e3abc85..e9b3af27d844 100644 --- a/trunk/arch/mips/kernel/traps.c +++ b/trunk/arch/mips/kernel/traps.c @@ -578,12 +578,12 @@ static int simulate_llsc(struct pt_regs *regs, unsigned int opcode) { if ((opcode & OPCODE) == LL) { perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, - 1, regs, 0); + 1, 0, regs, 0); return simulate_ll(regs, opcode); } if ((opcode & OPCODE) == SC) { perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, - 1, regs, 0); + 1, 0, regs, 0); return simulate_sc(regs, opcode); } @@ -602,7 +602,7 @@ static int simulate_rdhwr(struct pt_regs *regs, unsigned int opcode) int rd = (opcode & RD) >> 11; int rt = (opcode & RT) >> 16; perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, - 1, regs, 0); + 1, 0, regs, 0); switch (rd) { case 0: /* CPU number */ regs->regs[rt] = smp_processor_id(); @@ -640,7 +640,7 @@ static int simulate_sync(struct pt_regs *regs, unsigned int opcode) { if ((opcode & OPCODE) == SPEC0 && (opcode & FUNC) == SYNC) { perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, - 1, regs, 0); + 1, 0, regs, 0); return 0; } diff --git a/trunk/arch/mips/kernel/unaligned.c b/trunk/arch/mips/kernel/unaligned.c index eb319b580353..cfea1adfa153 100644 --- a/trunk/arch/mips/kernel/unaligned.c +++ b/trunk/arch/mips/kernel/unaligned.c @@ -111,7 +111,8 @@ static void emulate_load_store_insn(struct pt_regs *regs, unsigned long value; unsigned int res; - perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0); + perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, + 1, 0, regs, 0); /* * This load never faults. @@ -516,7 +517,7 @@ asmlinkage void do_ade(struct pt_regs *regs) mm_segment_t seg; perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, - 1, regs, regs->cp0_badvaddr); + 1, 0, regs, regs->cp0_badvaddr); /* * Did we catch a fault trying to load an instruction? * Or are we running in MIPS16 mode? diff --git a/trunk/arch/mips/math-emu/cp1emu.c b/trunk/arch/mips/math-emu/cp1emu.c index dbf2f93a5091..d32cb0503110 100644 --- a/trunk/arch/mips/math-emu/cp1emu.c +++ b/trunk/arch/mips/math-emu/cp1emu.c @@ -272,7 +272,8 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, } emul: - perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, xcp, 0); + perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, + 1, 0, xcp, 0); MIPS_FPU_EMU_INC_STATS(emulated); switch (MIPSInst_OPCODE(ir)) { case ldc1_op:{ diff --git a/trunk/arch/mips/mm/fault.c b/trunk/arch/mips/mm/fault.c index 937cf3368164..137ee76a0045 100644 --- a/trunk/arch/mips/mm/fault.c +++ b/trunk/arch/mips/mm/fault.c @@ -145,7 +145,7 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, unsigned long writ * the fault. */ fault = handle_mm_fault(mm, vma, address, write ? FAULT_FLAG_WRITE : 0); - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address); + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address); if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; @@ -154,10 +154,12 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, unsigned long writ BUG(); } if (fault & VM_FAULT_MAJOR) { - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, regs, address); + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, + 1, 0, regs, address); tsk->maj_flt++; } else { - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, regs, address); + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, + 1, 0, regs, address); tsk->min_flt++; } diff --git a/trunk/arch/mips/mti-malta/malta-time.c b/trunk/arch/mips/mti-malta/malta-time.c index f8ee945ee411..1620b83cd13e 100644 --- a/trunk/arch/mips/mti-malta/malta-time.c +++ b/trunk/arch/mips/mti-malta/malta-time.c @@ -19,7 +19,6 @@ */ #include -#include #include #include #include @@ -32,6 +31,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/arch/mips/oprofile/Makefile b/trunk/arch/mips/oprofile/Makefile index 29f2f13eb31c..4b9d7044e26c 100644 --- a/trunk/arch/mips/oprofile/Makefile +++ b/trunk/arch/mips/oprofile/Makefile @@ -8,7 +8,7 @@ DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \ oprofilefs.o oprofile_stats.o \ timer_int.o ) -oprofile-y := $(DRIVER_OBJS) common.o backtrace.o +oprofile-y := $(DRIVER_OBJS) common.o oprofile-$(CONFIG_CPU_MIPS32) += op_model_mipsxx.o oprofile-$(CONFIG_CPU_MIPS64) += op_model_mipsxx.o diff --git a/trunk/arch/mips/oprofile/backtrace.c b/trunk/arch/mips/oprofile/backtrace.c deleted file mode 100644 index 6854ed5097d2..000000000000 --- a/trunk/arch/mips/oprofile/backtrace.c +++ /dev/null @@ -1,175 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct stackframe { - unsigned long sp; - unsigned long pc; - unsigned long ra; -}; - -static inline int get_mem(unsigned long addr, unsigned long *result) -{ - unsigned long *address = (unsigned long *) addr; - if (!access_ok(VERIFY_READ, addr, sizeof(unsigned long))) - return -1; - if (__copy_from_user_inatomic(result, address, sizeof(unsigned long))) - return -3; - return 0; -} - -/* - * These two instruction helpers were taken from process.c - */ -static inline int is_ra_save_ins(union mips_instruction *ip) -{ - /* sw / sd $ra, offset($sp) */ - return (ip->i_format.opcode == sw_op || ip->i_format.opcode == sd_op) - && ip->i_format.rs == 29 && ip->i_format.rt == 31; -} - -static inline int is_sp_move_ins(union mips_instruction *ip) -{ - /* addiu/daddiu sp,sp,-imm */ - if (ip->i_format.rs != 29 || ip->i_format.rt != 29) - return 0; - if (ip->i_format.opcode == addiu_op || ip->i_format.opcode == daddiu_op) - return 1; - return 0; -} - -/* - * Looks for specific instructions that mark the end of a function. - * This usually means we ran into the code area of the previous function. - */ -static inline int is_end_of_function_marker(union mips_instruction *ip) -{ - /* jr ra */ - if (ip->r_format.func == jr_op && ip->r_format.rs == 31) - return 1; - /* lui gp */ - if (ip->i_format.opcode == lui_op && ip->i_format.rt == 28) - return 1; - return 0; -} - -/* - * TODO for userspace stack unwinding: - * - handle cases where the stack is adjusted inside a function - * (generally doesn't happen) - * - find optimal value for max_instr_check - * - try to find a way to handle leaf functions - */ - -static inline int unwind_user_frame(struct stackframe *old_frame, - const unsigned int max_instr_check) -{ - struct stackframe new_frame = *old_frame; - off_t ra_offset = 0; - size_t stack_size = 0; - unsigned long addr; - - if (old_frame->pc == 0 || old_frame->sp == 0 || old_frame->ra == 0) - return -9; - - for (addr = new_frame.pc; (addr + max_instr_check > new_frame.pc) - && (!ra_offset || !stack_size); --addr) { - union mips_instruction ip; - - if (get_mem(addr, (unsigned long *) &ip)) - return -11; - - if (is_sp_move_ins(&ip)) { - int stack_adjustment = ip.i_format.simmediate; - if (stack_adjustment > 0) - /* This marks the end of the previous function, - which means we overran. */ - break; - stack_size = (unsigned) stack_adjustment; - } else if (is_ra_save_ins(&ip)) { - int ra_slot = ip.i_format.simmediate; - if (ra_slot < 0) - /* This shouldn't happen. */ - break; - ra_offset = ra_slot; - } else if (is_end_of_function_marker(&ip)) - break; - } - - if (!ra_offset || !stack_size) - return -1; - - if (ra_offset) { - new_frame.ra = old_frame->sp + ra_offset; - if (get_mem(new_frame.ra, &(new_frame.ra))) - return -13; - } - - if (stack_size) { - new_frame.sp = old_frame->sp + stack_size; - if (get_mem(new_frame.sp, &(new_frame.sp))) - return -14; - } - - if (new_frame.sp > old_frame->sp) - return -2; - - new_frame.pc = old_frame->ra; - *old_frame = new_frame; - - return 0; -} - -static inline void do_user_backtrace(unsigned long low_addr, - struct stackframe *frame, - unsigned int depth) -{ - const unsigned int max_instr_check = 512; - const unsigned long high_addr = low_addr + THREAD_SIZE; - - while (depth-- && !unwind_user_frame(frame, max_instr_check)) { - oprofile_add_trace(frame->ra); - if (frame->sp < low_addr || frame->sp > high_addr) - break; - } -} - -#ifndef CONFIG_KALLSYMS -static inline void do_kernel_backtrace(unsigned long low_addr, - struct stackframe *frame, - unsigned int depth) { } -#else -static inline void do_kernel_backtrace(unsigned long low_addr, - struct stackframe *frame, - unsigned int depth) -{ - while (depth-- && frame->pc) { - frame->pc = unwind_stack_by_address(low_addr, - &(frame->sp), - frame->pc, - &(frame->ra)); - oprofile_add_trace(frame->ra); - } -} -#endif - -void notrace op_mips_backtrace(struct pt_regs *const regs, unsigned int depth) -{ - struct stackframe frame = { .sp = regs->regs[29], - .pc = regs->cp0_epc, - .ra = regs->regs[31] }; - const int userspace = user_mode(regs); - const unsigned long low_addr = ALIGN(frame.sp, THREAD_SIZE); - - if (userspace) - do_user_backtrace(low_addr, &frame, depth); - else - do_kernel_backtrace(low_addr, &frame, depth); -} diff --git a/trunk/arch/mips/oprofile/common.c b/trunk/arch/mips/oprofile/common.c index d1f2d4c52d42..f9eb1aba6345 100644 --- a/trunk/arch/mips/oprofile/common.c +++ b/trunk/arch/mips/oprofile/common.c @@ -115,7 +115,6 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) ops->start = op_mips_start; ops->stop = op_mips_stop; ops->cpu_type = lmodel->cpu_type; - ops->backtrace = op_mips_backtrace; printk(KERN_INFO "oprofile: using %s performance monitoring.\n", lmodel->cpu_type); diff --git a/trunk/arch/mips/oprofile/op_impl.h b/trunk/arch/mips/oprofile/op_impl.h index 7c2da27ece04..f04b54fb37d1 100644 --- a/trunk/arch/mips/oprofile/op_impl.h +++ b/trunk/arch/mips/oprofile/op_impl.h @@ -36,6 +36,4 @@ struct op_mips_model { unsigned char num_counters; }; -void op_mips_backtrace(struct pt_regs * const regs, unsigned int depth); - #endif diff --git a/trunk/arch/mips/sgi-ip22/ip22-time.c b/trunk/arch/mips/sgi-ip22/ip22-time.c index 607192449335..1a94c9894188 100644 --- a/trunk/arch/mips/sgi-ip22/ip22-time.c +++ b/trunk/arch/mips/sgi-ip22/ip22-time.c @@ -10,7 +10,6 @@ * Copyright (C) 2003, 06 Ralf Baechle (ralf@linux-mips.org) */ #include -#include #include #include #include @@ -21,6 +20,7 @@ #include #include +#include #include #include #include diff --git a/trunk/arch/mips/sni/time.c b/trunk/arch/mips/sni/time.c index ec0be14996a4..0904d4d30cb3 100644 --- a/trunk/arch/mips/sni/time.c +++ b/trunk/arch/mips/sni/time.c @@ -1,11 +1,11 @@ #include -#include #include #include #include #include #include +#include #include #include #include diff --git a/trunk/arch/mn10300/kernel/module.c b/trunk/arch/mn10300/kernel/module.c index 216ad23c9570..196a111e2e29 100644 --- a/trunk/arch/mn10300/kernel/module.c +++ b/trunk/arch/mn10300/kernel/module.c @@ -32,6 +32,36 @@ #define DEBUGP(fmt, ...) #endif +/* + * allocate storage for a module + */ +void *module_alloc(unsigned long size) +{ + if (size == 0) + return NULL; + return vmalloc_exec(size); +} + +/* + * free memory returned from module_alloc() + */ +void module_free(struct module *mod, void *module_region) +{ + vfree(module_region); +} + +/* + * allow the arch to fix up the section table + * - we don't need anything special + */ +int module_frob_arch_sections(Elf_Ehdr *hdr, + Elf_Shdr *sechdrs, + char *secstrings, + struct module *mod) +{ + return 0; +} + static void reloc_put16(uint8_t *p, uint32_t val) { p[0] = val & 0xff; @@ -50,6 +80,20 @@ static void reloc_put32(uint8_t *p, uint32_t val) reloc_put16(p+2, val >> 16); } +/* + * apply a REL relocation + */ +int apply_relocate(Elf32_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *me) +{ + printk(KERN_ERR "module %s: RELOCATION unsupported\n", + me->name); + return -ENOEXEC; +} + /* * apply a RELA relocation */ @@ -154,3 +198,20 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, } return 0; } + +/* + * finish loading the module + */ +int module_finalize(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + struct module *me) +{ + return 0; +} + +/* + * finish clearing the module + */ +void module_arch_cleanup(struct module *mod) +{ +} diff --git a/trunk/arch/openrisc/Kconfig b/trunk/arch/openrisc/Kconfig deleted file mode 100644 index 4558bafbd1a2..000000000000 --- a/trunk/arch/openrisc/Kconfig +++ /dev/null @@ -1,207 +0,0 @@ -# -# For a description of the syntax of this configuration file, -# see Documentation/kbuild/config-language.txt. -# - -config OPENRISC - def_bool y - select OF - select OF_EARLY_FLATTREE - select HAVE_MEMBLOCK - select ARCH_WANT_OPTIONAL_GPIOLIB - select HAVE_ARCH_TRACEHOOK - select HAVE_GENERIC_HARDIRQS - select GENERIC_IRQ_CHIP - select GENERIC_IRQ_PROBE - select GENERIC_IRQ_SHOW - select GENERIC_IOMAP - -config MMU - def_bool y - -config WISHBONE_BUS_BIG_ENDIAN - def_bool y - -config SYMBOL_PREFIX - string - default "" - -config HAVE_DMA_ATTRS - def_bool y - -config UID16 - def_bool y - -config RWSEM_GENERIC_SPINLOCK - def_bool y - -config RWSEM_XCHGADD_ALGORITHM - def_bool n - -config GENERIC_HWEIGHT - def_bool y - -config GENERIC_IOMAP - def_bool y - -config NO_IOPORT - def_bool y - -config GENERIC_GPIO - def_bool y - -config GENERIC_CLOCKEVENTS - def_bool y - -config TRACE_IRQFLAGS_SUPPORT - def_bool y - -# For now, use generic checksum functions -#These can be reimplemented in assembly later if so inclined -config GENERIC_CSUM - def_bool y - -config GENERIC_FIND_NEXT_BIT - def_bool y - -source "init/Kconfig" - - -menu "Processor type and features" - -choice - prompt "Subarchitecture" - default OR1K_1200 - -config OR1K_1200 - bool "OR1200" - help - Generic OpenRISC 1200 architecture - -endchoice - -config OPENRISC_BUILTIN_DTB - string "Builtin DTB" - default "" - -menu "Class II Instructions" - -config OPENRISC_HAVE_INST_FF1 - bool "Have instruction l.ff1" - default y - help - Select this if your implementation has the Class II instruction l.ff1 - -config OPENRISC_HAVE_INST_FL1 - bool "Have instruction l.fl1" - default y - help - Select this if your implementation has the Class II instruction l.fl1 - -config OPENRISC_HAVE_INST_MUL - bool "Have instruction l.mul for hardware multiply" - default y - help - Select this if your implementation has a hardware multiply instruction - -config OPENRISC_HAVE_INST_DIV - bool "Have instruction l.div for hardware divide" - default y - help - Select this if your implementation has a hardware divide instruction -endmenu - - -source "kernel/time/Kconfig" -source kernel/Kconfig.hz -source kernel/Kconfig.preempt -source "mm/Kconfig" - -config OPENRISC_NO_SPR_SR_DSX - bool "use SPR_SR_DSX software emulation" if OR1K_1200 - default y - help - SPR_SR_DSX bit is status register bit indicating whether - the last exception has happened in delay slot. - - OpenRISC architecture makes it optional to have it implemented - in hardware and the OR1200 does not have it. - - Say N here if you know that your OpenRISC processor has - SPR_SR_DSX bit implemented. Say Y if you are unsure. - -config CMDLINE - string "Default kernel command string" - default "" - help - On some architectures there is currently no way for the boot loader - to pass arguments to the kernel. For these architectures, you should - supply some command-line options at build time by entering them - here. - -menu "Debugging options" - -config DEBUG_STACKOVERFLOW - bool "Check for kernel stack overflow" - default y - help - Make extra checks for space avaliable on stack in some - critical functions. This will cause kernel to run a bit slower, - but will catch most of kernel stack overruns and exit gracefuly. - - Say Y if you are unsure. - -config JUMP_UPON_UNHANDLED_EXCEPTION - bool "Try to die gracefully" - default y - help - Now this puts kernel into infinite loop after first oops. Till - your kernel crashes this doesn't have any influence. - - Say Y if you are unsure. - -config OPENRISC_EXCEPTION_DEBUG - bool "Print processor state at each exception" - default n - help - This option will make your kernel unusable for all but kernel - debugging. - - Say N if you are unsure. - -config OPENRISC_ESR_EXCEPTION_BUG_CHECK - bool "Check for possible ESR exception bug" - default n - help - This option enables some checks that might expose some problems - in kernel. - - Say N if you are unsure. - -endmenu - -endmenu - -menu "Executable file formats" - -source "fs/Kconfig.binfmt" - -endmenu - -source "net/Kconfig" - -source "drivers/Kconfig" - -source "fs/Kconfig" - -source "security/Kconfig" - -source "crypto/Kconfig" - -source "lib/Kconfig" - -menu "Kernel hacking" - -source "lib/Kconfig.debug" - -endmenu diff --git a/trunk/arch/openrisc/Makefile b/trunk/arch/openrisc/Makefile deleted file mode 100644 index 158ae4c0dc6c..000000000000 --- a/trunk/arch/openrisc/Makefile +++ /dev/null @@ -1,55 +0,0 @@ -# BK Id: %F% %I% %G% %U% %#% -# -# This file is included by the global makefile so that you can add your own -# architecture-specific flags and dependencies. Remember to do have actions -# for "archclean" and "archdep" for cleaning up and making dependencies for -# this architecture -# -# 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. -# -# Copyright (C) 1994 by Linus Torvalds -# Modifications for the OpenRISC architecture: -# Copyright (C) 2003 Matjaz Breskvar -# Copyright (C) 2010-2011 Jonas Bonn -# -# Based on: -# arch/i386/Makefile - -KBUILD_DEFCONFIG := or1ksim_defconfig - -LDFLAGS := -OBJCOPYFLAGS := -O binary -R .note -R .comment -S -LDFLAGS_vmlinux := -LIBGCC := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name) - -KBUILD_CFLAGS += -pipe -ffixed-r10 - -ifeq ($(CONFIG_OPENRISC_HAVE_INST_MUL),y) - KBUILD_CFLAGS += $(call cc-option,-mhard-mul) -else - KBUILD_CFLAGS += $(call cc-option,-msoft-mul) -endif - -ifeq ($(CONFIG_OPENRISC_HAVE_INST_DIV),y) - KBUILD_CFLAGS += $(call cc-option,-mhard-div) -else - KBUILD_CFLAGS += $(call cc-option,-msoft-div) -endif - -head-y := arch/openrisc/kernel/head.o arch/openrisc/kernel/init_task.o - -core-y += arch/openrisc/lib/ \ - arch/openrisc/kernel/ \ - arch/openrisc/mm/ -libs-y += $(LIBGCC) - -ifneq '$(CONFIG_OPENRISC_BUILTIN_DTB)' '""' -BUILTIN_DTB := y -else -BUILTIN_DTB := n -endif -core-$(BUILTIN_DTB) += arch/openrisc/boot/ - -all: vmlinux diff --git a/trunk/arch/openrisc/README.openrisc b/trunk/arch/openrisc/README.openrisc deleted file mode 100644 index c9f7edf2b9a2..000000000000 --- a/trunk/arch/openrisc/README.openrisc +++ /dev/null @@ -1,99 +0,0 @@ -OpenRISC Linux -============== - -This is a port of Linux to the OpenRISC class of microprocessors; the initial -target architecture, specifically, is the 32-bit OpenRISC 1000 family (or1k). - -For information about OpenRISC processors and ongoing development: - - website http://openrisc.net - -For more information about Linux on OpenRISC, please contact South Pole AB. - - email: info@southpole.se - - website: http://southpole.se - http://southpoleconsulting.com - ---------------------------------------------------------------------- - -Build instructions for OpenRISC toolchain and Linux -=================================================== - -In order to build and run Linux for OpenRISC, you'll need at least a basic -toolchain and, perhaps, the architectural simulator. Steps to get these bits -in place are outlined here. - -1) The toolchain can be obtained from openrisc.net. Instructions for building -a toolchain can be found at: - -http://openrisc.net/toolchain-build.html - -2) or1ksim (optional) - -or1ksim is the architectural simulator which will allow you to actually run -your OpenRISC Linux kernel if you don't have an OpenRISC processor at hand. - - git clone git://openrisc.net/jonas/or1ksim-svn - - cd or1ksim - ./configure --prefix=$OPENRISC_PREFIX - make - make install - -3) Linux kernel - -Build the kernel as usual - - make ARCH=openrisc defconfig - make ARCH=openrisc - -4) Run in architectural simulator - -Grab the or1ksim platform configuration file (from the or1ksim source) and -together with your freshly built vmlinux, run your kernel with the following -incantation: - - sim -f arch/openrisc/or1ksim.cfg vmlinux - ---------------------------------------------------------------------- - -Terminology -=========== - -In the code, the following particles are used on symbols to limit the scope -to more or less specific processor implementations: - -openrisc: the OpenRISC class of processors -or1k: the OpenRISC 1000 family of processors -or1200: the OpenRISC 1200 processor - ---------------------------------------------------------------------- - -History -======== - -18. 11. 2003 Matjaz Breskvar (phoenix@bsemi.com) - initial port of linux to OpenRISC/or32 architecture. - all the core stuff is implemented and seams usable. - -08. 12. 2003 Matjaz Breskvar (phoenix@bsemi.com) - complete change of TLB miss handling. - rewrite of exceptions handling. - fully functional sash-3.6 in default initrd. - a much improved version with changes all around. - -10. 04. 2004 Matjaz Breskvar (phoenix@bsemi.com) - alot of bugfixes all over. - ethernet support, functional http and telnet servers. - running many standard linux apps. - -26. 06. 2004 Matjaz Breskvar (phoenix@bsemi.com) - port to 2.6.x - -30. 11. 2004 Matjaz Breskvar (phoenix@bsemi.com) - lots of bugfixes and enhancments. - added opencores framebuffer driver. - -09. 10. 2010 Jonas Bonn (jonas@southpole.se) - major rewrite to bring up to par with upstream Linux 2.6.36 diff --git a/trunk/arch/openrisc/TODO.openrisc b/trunk/arch/openrisc/TODO.openrisc deleted file mode 100644 index acfeef9c58e3..000000000000 --- a/trunk/arch/openrisc/TODO.openrisc +++ /dev/null @@ -1,16 +0,0 @@ -The OpenRISC Linux port is fully functional and has been tracking upstream -since 2.6.35. There are, however, remaining items to be completed within -the coming months. Here's a list of known-to-be-less-than-stellar items -that are due for investigation shortly, i.e. our TODO list: - --- Implement the rest of the DMA API... dma_map_sg, etc. - --- Consolidate usage of memblock and bootmem... move everything over to - memblock. - --- Finish the renaming cleanup... there are references to or32 in the code - which was an older name for the architecture. The name we've settled on is - or1k and this change is slowly trickling through the stack. For the time - being, or32 is equivalent to or1k. - --- Implement optimized version of memcpy and memset diff --git a/trunk/arch/openrisc/boot/Makefile b/trunk/arch/openrisc/boot/Makefile deleted file mode 100644 index 98ca185097a5..000000000000 --- a/trunk/arch/openrisc/boot/Makefile +++ /dev/null @@ -1,15 +0,0 @@ - - -ifneq '$(CONFIG_OPENRISC_BUILTIN_DTB)' '""' -BUILTIN_DTB := $(patsubst "%",%,$(CONFIG_OPENRISC_BUILTIN_DTB)).dtb.o -else -BUILTIN_DTB := -endif -obj-y += $(BUILTIN_DTB) - -clean-files := *.dtb.S - -#DTC_FLAGS ?= -p 1024 - -$(obj)/%.dtb: $(src)/dts/%.dts - $(call cmd,dtc) diff --git a/trunk/arch/openrisc/boot/dts/or1ksim.dts b/trunk/arch/openrisc/boot/dts/or1ksim.dts deleted file mode 100644 index 5d4f9027afaf..000000000000 --- a/trunk/arch/openrisc/boot/dts/or1ksim.dts +++ /dev/null @@ -1,50 +0,0 @@ -/dts-v1/; -/ { - compatible = "opencores,or1ksim"; - #address-cells = <1>; - #size-cells = <1>; - interrupt-parent = <&pic>; - - chosen { - bootargs = "console=uart,mmio,0x90000000,115200"; - }; - - memory@0 { - device_type = "memory"; - reg = <0x00000000 0x02000000>; - }; - - cpus { - #address-cells = <1>; - #size-cells = <0>; - cpu@0 { - compatible = "opencores,or1200-rtlsvn481"; - reg = <0>; - clock-frequency = <20000000>; - }; - }; - - /* - * OR1K PIC is built into CPU and accessed via special purpose - * registers. It is not addressable and, hence, has no 'reg' - * property. - */ - pic: pic { - compatible = "opencores,or1k-pic"; - #interrupt-cells = <1>; - interrupt-controller; - }; - - serial0: serial@90000000 { - compatible = "opencores,uart16550-rtlsvn105", "ns16550a"; - reg = <0x90000000 0x100>; - interrupts = <2>; - clock-frequency = <20000000>; - }; - - enet0: ethoc@92000000 { - compatible = "opencores,ethmac-rtlsvn338"; - reg = <0x92000000 0x100>; - interrupts = <4>; - }; -}; diff --git a/trunk/arch/openrisc/configs/or1ksim_defconfig b/trunk/arch/openrisc/configs/or1ksim_defconfig deleted file mode 100644 index ea172bdfa36a..000000000000 --- a/trunk/arch/openrisc/configs/or1ksim_defconfig +++ /dev/null @@ -1,65 +0,0 @@ -CONFIG_CROSS_COMPILE="or32-linux-" -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_BLK_DEV_INITRD=y -# CONFIG_RD_GZIP is not set -CONFIG_EXPERT=y -# CONFIG_SYSCTL_SYSCALL is not set -# CONFIG_KALLSYMS is not set -# CONFIG_EPOLL is not set -# CONFIG_TIMERFD is not set -# CONFIG_EVENTFD is not set -# CONFIG_AIO is not set -# CONFIG_VM_EVENT_COUNTERS is not set -# CONFIG_COMPAT_BRK is not set -CONFIG_SLOB=y -CONFIG_MODULES=y -# CONFIG_BLOCK is not set -CONFIG_OPENRISC_BUILTIN_DTB="or1ksim" -CONFIG_NO_HZ=y -CONFIG_HZ_100=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y -# CONFIG_INET_XFRM_MODE_TRANSPORT is not set -# CONFIG_INET_XFRM_MODE_TUNNEL is not set -# CONFIG_INET_XFRM_MODE_BEET is not set -# CONFIG_INET_LRO is not set -# CONFIG_INET_DIAG is not set -CONFIG_TCP_CONG_ADVANCED=y -# CONFIG_TCP_CONG_BIC is not set -# CONFIG_TCP_CONG_CUBIC is not set -# CONFIG_TCP_CONG_WESTWOOD is not set -# CONFIG_TCP_CONG_HTCP is not set -# CONFIG_IPV6 is not set -# CONFIG_WIRELESS is not set -CONFIG_DEVTMPFS=y -CONFIG_DEVTMPFS_MOUNT=y -# CONFIG_PREVENT_FIRMWARE_BUILD is not set -# CONFIG_FW_LOADER is not set -CONFIG_PROC_DEVICETREE=y -CONFIG_NETDEVICES=y -CONFIG_MICREL_PHY=y -CONFIG_NET_ETHERNET=y -CONFIG_ETHOC=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set -# CONFIG_WLAN is not set -# CONFIG_INPUT is not set -# CONFIG_SERIO is not set -# CONFIG_VT is not set -# CONFIG_LEGACY_PTYS is not set -# CONFIG_DEVKMEM is not set -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_OF_PLATFORM=y -# CONFIG_HW_RANDOM is not set -# CONFIG_HWMON is not set -# CONFIG_MFD_SUPPORT is not set -# CONFIG_USB_SUPPORT is not set -# CONFIG_DNOTIFY is not set -CONFIG_TMPFS=y -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -# CONFIG_ENABLE_WARN_DEPRECATED is not set -# CONFIG_ENABLE_MUST_CHECK is not set diff --git a/trunk/arch/openrisc/include/asm/Kbuild b/trunk/arch/openrisc/include/asm/Kbuild deleted file mode 100644 index 11162e6c878f..000000000000 --- a/trunk/arch/openrisc/include/asm/Kbuild +++ /dev/null @@ -1,64 +0,0 @@ -include include/asm-generic/Kbuild.asm - -header-y += spr_defs.h - -generic-y += atomic.h -generic-y += auxvec.h -generic-y += bitsperlong.h -generic-y += bug.h -generic-y += bugs.h -generic-y += cacheflush.h -generic-y += checksum.h -generic-y += cmpxchg.h -generic-y += cmpxchg-local.h -generic-y += cpumask.h -generic-y += cputime.h -generic-y += current.h -generic-y += device.h -generic-y += div64.h -generic-y += dma.h -generic-y += emergency-restart.h -generic-y += errno.h -generic-y += fb.h -generic-y += fcntl.h -generic-y += ftrace.h -generic-y += futex.h -generic-y += hardirq.h -generic-y += hw_irq.h -generic-y += ioctl.h -generic-y += ioctls.h -generic-y += ipcbuf.h -generic-y += irq_regs.h -generic-y += kdebug.h -generic-y += kmap_types.h -generic-y += local.h -generic-y += mman.h -generic-y += module.h -generic-y += msgbuf.h -generic-y += pci.h -generic-y += percpu.h -generic-y += poll.h -generic-y += posix_types.h -generic-y += resource.h -generic-y += rmap.h -generic-y += scatterlist.h -generic-y += sections.h -generic-y += segment.h -generic-y += sembuf.h -generic-y += setup.h -generic-y += shmbuf.h -generic-y += shmparam.h -generic-y += siginfo.h -generic-y += signal.h -generic-y += socket.h -generic-y += sockios.h -generic-y += statfs.h -generic-y += stat.h -generic-y += string.h -generic-y += swab.h -generic-y += termbits.h -generic-y += termios.h -generic-y += topology.h -generic-y += types.h -generic-y += ucontext.h -generic-y += user.h diff --git a/trunk/arch/openrisc/include/asm/asm-offsets.h b/trunk/arch/openrisc/include/asm/asm-offsets.h deleted file mode 100644 index d370ee36a182..000000000000 --- a/trunk/arch/openrisc/include/asm/asm-offsets.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/openrisc/include/asm/bitops.h b/trunk/arch/openrisc/include/asm/bitops.h deleted file mode 100644 index a9e11efae14d..000000000000 --- a/trunk/arch/openrisc/include/asm/bitops.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * OpenRISC implementation: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * et al. - * - * 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 __ASM_OPENRISC_BITOPS_H -#define __ASM_OPENRISC_BITOPS_H - -/* - * Where we haven't written assembly versions yet, we fall back to the - * generic implementations. Otherwise, we pull in our (hopefully) - * optimized versions. - */ - -#include -#include - -/* - * clear_bit may not imply a memory barrier - */ -#ifndef smp_mb__before_clear_bit -#define smp_mb__before_clear_bit() smp_mb() -#define smp_mb__after_clear_bit() smp_mb() -#endif - -#include -#include -#include -#include -#include -#include - -#ifndef _LINUX_BITOPS_H -#error only can be included directly -#endif - -#include -#include -#include -#include - -#include -#include -#include - -#endif /* __ASM_GENERIC_BITOPS_H */ diff --git a/trunk/arch/openrisc/include/asm/bitops/__ffs.h b/trunk/arch/openrisc/include/asm/bitops/__ffs.h deleted file mode 100644 index 6c8368a34059..000000000000 --- a/trunk/arch/openrisc/include/asm/bitops/__ffs.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * OpenRISC Linux - * - * Copyright (C) 2010-2011 Jonas Bonn - * - * 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 __ASM_OPENRISC___FFS_H -#define __ASM_OPENRISC___FFS_H - - -#ifdef CONFIG_OPENRISC_HAVE_INST_FF1 - -static inline unsigned long __ffs(unsigned long x) -{ - int ret; - - __asm__ ("l.ff1 %0,%1" - : "=r" (ret) - : "r" (x)); - - return ret-1; -} - -#else -#include -#endif - -#endif /* __ASM_OPENRISC___FFS_H */ diff --git a/trunk/arch/openrisc/include/asm/bitops/__fls.h b/trunk/arch/openrisc/include/asm/bitops/__fls.h deleted file mode 100644 index c4ecdb4c523b..000000000000 --- a/trunk/arch/openrisc/include/asm/bitops/__fls.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * OpenRISC Linux - * - * Copyright (C) 2010-2011 Jonas Bonn - * - * 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 __ASM_OPENRISC___FLS_H -#define __ASM_OPENRISC___FLS_H - - -#ifdef CONFIG_OPENRISC_HAVE_INST_FL1 - -static inline unsigned long __fls(unsigned long x) -{ - int ret; - - __asm__ ("l.fl1 %0,%1" - : "=r" (ret) - : "r" (x)); - - return ret-1; -} - -#else -#include -#endif - -#endif /* __ASM_OPENRISC___FLS_H */ diff --git a/trunk/arch/openrisc/include/asm/bitops/ffs.h b/trunk/arch/openrisc/include/asm/bitops/ffs.h deleted file mode 100644 index 9de46246ebc7..000000000000 --- a/trunk/arch/openrisc/include/asm/bitops/ffs.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * OpenRISC Linux - * - * Copyright (C) 2010-2011 Jonas Bonn - * - * 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 __ASM_OPENRISC_FFS_H -#define __ASM_OPENRISC_FFS_H - -#ifdef CONFIG_OPENRISC_HAVE_INST_FF1 - -static inline int ffs(int x) -{ - int ret; - - __asm__ ("l.ff1 %0,%1" - : "=r" (ret) - : "r" (x)); - - return ret; -} - -#else -#include -#endif - -#endif /* __ASM_OPENRISC_FFS_H */ diff --git a/trunk/arch/openrisc/include/asm/bitops/fls.h b/trunk/arch/openrisc/include/asm/bitops/fls.h deleted file mode 100644 index 9efbf9ad86c4..000000000000 --- a/trunk/arch/openrisc/include/asm/bitops/fls.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * OpenRISC Linux - * - * Copyright (C) 2010-2011 Jonas Bonn - * - * 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 __ASM_OPENRISC_FLS_H -#define __ASM_OPENRISC_FLS_H - - -#ifdef CONFIG_OPENRISC_HAVE_INST_FL1 - -static inline int fls(int x) -{ - int ret; - - __asm__ ("l.fl1 %0,%1" - : "=r" (ret) - : "r" (x)); - - return ret; -} - -#else -#include -#endif - -#endif /* __ASM_OPENRISC_FLS_H */ diff --git a/trunk/arch/openrisc/include/asm/byteorder.h b/trunk/arch/openrisc/include/asm/byteorder.h deleted file mode 100644 index 60d14f7e14e2..000000000000 --- a/trunk/arch/openrisc/include/asm/byteorder.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/openrisc/include/asm/cache.h b/trunk/arch/openrisc/include/asm/cache.h deleted file mode 100644 index 4ce7a01a252d..000000000000 --- a/trunk/arch/openrisc/include/asm/cache.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * OpenRISC implementation: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * et al. - * - * 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 __ASM_OPENRISC_CACHE_H -#define __ASM_OPENRISC_CACHE_H - -/* FIXME: How can we replace these with values from the CPU... - * they shouldn't be hard-coded! - */ - -#define L1_CACHE_BYTES 16 -#define L1_CACHE_SHIFT 4 - -#endif /* __ASM_OPENRISC_CACHE_H */ diff --git a/trunk/arch/openrisc/include/asm/cpuinfo.h b/trunk/arch/openrisc/include/asm/cpuinfo.h deleted file mode 100644 index 917318b6a970..000000000000 --- a/trunk/arch/openrisc/include/asm/cpuinfo.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * OpenRISC implementation: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * et al. - * - * 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 __ASM_OPENRISC_CPUINFO_H -#define __ASM_OPENRISC_CPUINFO_H - -struct cpuinfo { - u32 clock_frequency; - - u32 icache_size; - u32 icache_block_size; - - u32 dcache_size; - u32 dcache_block_size; -}; - -extern struct cpuinfo cpuinfo; - -#endif /* __ASM_OPENRISC_CPUINFO_H */ diff --git a/trunk/arch/openrisc/include/asm/delay.h b/trunk/arch/openrisc/include/asm/delay.h deleted file mode 100644 index 17f8bf5a5ac2..000000000000 --- a/trunk/arch/openrisc/include/asm/delay.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * OpenRISC implementation: - * Copyright (C) 2010-2011 Jonas Bonn - * - * 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 __ASM_OPENRISC_DELAY_H -#define __ASM_OPENRISC_DELAY_H - -#include - -extern unsigned long loops_per_jiffy; - -#endif diff --git a/trunk/arch/openrisc/include/asm/dma-mapping.h b/trunk/arch/openrisc/include/asm/dma-mapping.h deleted file mode 100644 index 052f877b52a5..000000000000 --- a/trunk/arch/openrisc/include/asm/dma-mapping.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * OpenRISC implementation: - * Copyright (C) 2010-2011 Jonas Bonn - * - * 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 __ASM_OPENRISC_DMA_MAPPING_H -#define __ASM_OPENRISC_DMA_MAPPING_H - -/* - * See Documentation/PCI/PCI-DMA-mapping.txt and - * Documentation/DMA-API.txt for documentation. - * - * This file is written with the intention of eventually moving over - * to largely using asm-generic/dma-mapping-common.h in its place. - */ - -#include -#include -#include - -#define DMA_ERROR_CODE (~(dma_addr_t)0x0) - -int dma_mapping_error(struct device *dev, dma_addr_t dma_addr); - -#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) -#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) - -void *or1k_dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t flag); -void or1k_dma_free_coherent(struct device *dev, size_t size, void *vaddr, - dma_addr_t dma_handle); -dma_addr_t or1k_map_page(struct device *dev, struct page *page, - unsigned long offset, size_t size, - enum dma_data_direction dir, - struct dma_attrs *attrs); -void or1k_unmap_page(struct device *dev, dma_addr_t dma_handle, - size_t size, enum dma_data_direction dir, - struct dma_attrs *attrs); -void or1k_sync_single_for_cpu(struct device *dev, - dma_addr_t dma_handle, size_t size, - enum dma_data_direction dir); -void or1k_sync_single_for_device(struct device *dev, - dma_addr_t dma_handle, size_t size, - enum dma_data_direction dir); - -static inline void *dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t flag) -{ - void *memory; - - memory = or1k_dma_alloc_coherent(dev, size, dma_handle, flag); - - debug_dma_alloc_coherent(dev, size, *dma_handle, memory); - return memory; -} - -static inline void dma_free_coherent(struct device *dev, size_t size, - void *cpu_addr, dma_addr_t dma_handle) -{ - debug_dma_free_coherent(dev, size, cpu_addr, dma_handle); - or1k_dma_free_coherent(dev, size, cpu_addr, dma_handle); -} - -static inline dma_addr_t dma_map_single(struct device *dev, void *ptr, - size_t size, - enum dma_data_direction dir) -{ - dma_addr_t addr; - - kmemcheck_mark_initialized(ptr, size); - BUG_ON(!valid_dma_direction(dir)); - addr = or1k_map_page(dev, virt_to_page(ptr), - (unsigned long)ptr & ~PAGE_MASK, size, - dir, NULL); - debug_dma_map_page(dev, virt_to_page(ptr), - (unsigned long)ptr & ~PAGE_MASK, size, - dir, addr, true); - return addr; -} - -static inline void dma_unmap_single(struct device *dev, dma_addr_t addr, - size_t size, - enum dma_data_direction dir) -{ - BUG_ON(!valid_dma_direction(dir)); - or1k_unmap_page(dev, addr, size, dir, NULL); - debug_dma_unmap_page(dev, addr, size, dir, true); -} - -static inline void dma_sync_single_for_cpu(struct device *dev, dma_addr_t addr, - size_t size, - enum dma_data_direction dir) -{ - BUG_ON(!valid_dma_direction(dir)); - or1k_sync_single_for_cpu(dev, addr, size, dir); - debug_dma_sync_single_for_cpu(dev, addr, size, dir); -} - -static inline void dma_sync_single_for_device(struct device *dev, - dma_addr_t addr, size_t size, - enum dma_data_direction dir) -{ - BUG_ON(!valid_dma_direction(dir)); - or1k_sync_single_for_device(dev, addr, size, dir); - debug_dma_sync_single_for_device(dev, addr, size, dir); -} - -static inline int dma_supported(struct device *dev, u64 dma_mask) -{ - /* Support 32 bit DMA mask exclusively */ - return dma_mask == 0xffffffffULL; -} - -static inline int dma_set_mask(struct device *dev, u64 dma_mask) -{ - if (!dev->dma_mask || !dma_supported(dev, dma_mask)) - return -EIO; - - *dev->dma_mask = dma_mask; - - return 0; -} -#endif /* __ASM_OPENRISC_DMA_MAPPING_H */ diff --git a/trunk/arch/openrisc/include/asm/elf.h b/trunk/arch/openrisc/include/asm/elf.h deleted file mode 100644 index 2ce603bbfdd3..000000000000 --- a/trunk/arch/openrisc/include/asm/elf.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * OpenRISC implementation: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * et al. - * - * 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 __ASM_OPENRISC_ELF_H -#define __ASM_OPENRISC_ELF_H - -/* - * ELF register definitions.. - */ -#include -#include - - -/* The OR1K relocation types... not all relevant for module loader */ -#define R_OR32_NONE 0 -#define R_OR32_32 1 -#define R_OR32_16 2 -#define R_OR32_8 3 -#define R_OR32_CONST 4 -#define R_OR32_CONSTH 5 -#define R_OR32_JUMPTARG 6 -#define R_OR32_VTINHERIT 7 -#define R_OR32_VTENTRY 8 - -typedef unsigned long elf_greg_t; - -/* - * Note that NGREG is defined to ELF_NGREG in include/linux/elfcore.h, and is - * thus exposed to user-space. - */ -#define ELF_NGREG (sizeof(struct user_regs_struct) / sizeof(elf_greg_t)) -typedef elf_greg_t elf_gregset_t[ELF_NGREG]; - -/* A placeholder; OR32 does not have fp support yes, so no fp regs for now. */ -typedef unsigned long elf_fpregset_t; - -/* This should be moved to include/linux/elf.h */ -#define EM_OR32 0x8472 -#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */ - -/* - * These are used to set parameters in the core dumps. - */ -#define ELF_ARCH EM_OR32 -#define ELF_CLASS ELFCLASS32 -#define ELF_DATA ELFDATA2MSB - -#ifdef __KERNEL__ - -/* - * This is used to ensure we don't load something for the wrong architecture. - */ - -#define elf_check_arch(x) \ - (((x)->e_machine == EM_OR32) || ((x)->e_machine == EM_OPENRISC)) - -/* This is the location that an ET_DYN program is loaded if exec'ed. Typical - use of this is to invoke "./ld.so someprog" to test out a new version of - the loader. We need to make sure that it is out of the way of the program - that it will "exec", and that there is sufficient room for the brk. */ - -#define ELF_ET_DYN_BASE (0x08000000) - -/* - * Enable dump using regset. - * This covers all of general/DSP/FPU regs. - */ -#define CORE_DUMP_USE_REGSET - -#define ELF_EXEC_PAGESIZE 8192 - -extern void dump_elf_thread(elf_greg_t *dest, struct pt_regs *pt); -#define ELF_CORE_COPY_REGS(dest, regs) dump_elf_thread(dest, regs); - -/* This yields a mask that user programs can use to figure out what - instruction set this cpu supports. This could be done in userspace, - but it's not easy, and we've already done it here. */ - -#define ELF_HWCAP (0) - -/* This yields a string that ld.so will use to load implementation - specific libraries for optimization. This is more specific in - intent than poking at uname or /proc/cpuinfo. - - For the moment, we have only optimizations for the Intel generations, - but that could change... */ - -#define ELF_PLATFORM (NULL) - -#define SET_PERSONALITY(ex) set_personality(PER_LINUX) - -#endif /* __KERNEL__ */ -#endif diff --git a/trunk/arch/openrisc/include/asm/fixmap.h b/trunk/arch/openrisc/include/asm/fixmap.h deleted file mode 100644 index 52733416c1f3..000000000000 --- a/trunk/arch/openrisc/include/asm/fixmap.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * OpenRISC implementation: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * et al. - * - * 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 __ASM_OPENRISC_FIXMAP_H -#define __ASM_OPENRISC_FIXMAP_H - -/* Why exactly do we need 2 empty pages between the top of the fixed - * addresses and the top of virtual memory? Something is using that - * memory space but not sure what right now... If you find it, leave - * a comment here. - */ -#define FIXADDR_TOP ((unsigned long) (-2*PAGE_SIZE)) - -#include -#include - -/* - * On OpenRISC we use these special fixed_addresses for doing ioremap - * early in the boot process before memory initialization is complete. - * This is used, in particular, by the early serial console code. - * - * It's not really 'fixmap', per se, but fits loosely into the same - * paradigm. - */ -enum fixed_addresses { - /* - * FIX_IOREMAP entries are useful for mapping physical address - * space before ioremap() is useable, e.g. really early in boot - * before kmalloc() is working. - */ -#define FIX_N_IOREMAPS 32 - FIX_IOREMAP_BEGIN, - FIX_IOREMAP_END = FIX_IOREMAP_BEGIN + FIX_N_IOREMAPS - 1, - __end_of_fixed_addresses -}; - -#define FIXADDR_SIZE (__end_of_fixed_addresses << PAGE_SHIFT) -/* FIXADDR_BOTTOM might be a better name here... */ -#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE) - -#define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT)) -#define __virt_to_fix(x) ((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT) - -/* - * 'index to address' translation. If anyone tries to use the idx - * directly without tranlation, we catch the bug with a NULL-deference - * kernel oops. Illegal ranges of incoming indices are caught too. - */ -static __always_inline unsigned long fix_to_virt(const unsigned int idx) -{ - /* - * this branch gets completely eliminated after inlining, - * except when someone tries to use fixaddr indices in an - * illegal way. (such as mixing up address types or using - * out-of-range indices). - * - * If it doesn't get removed, the linker will complain - * loudly with a reasonably clear error message.. - */ - if (idx >= __end_of_fixed_addresses) - BUG(); - - return __fix_to_virt(idx); -} - -static inline unsigned long virt_to_fix(const unsigned long vaddr) -{ - BUG_ON(vaddr >= FIXADDR_TOP || vaddr < FIXADDR_START); - return __virt_to_fix(vaddr); -} - -#endif diff --git a/trunk/arch/openrisc/include/asm/gpio.h b/trunk/arch/openrisc/include/asm/gpio.h deleted file mode 100644 index 0b0d174f47cd..000000000000 --- a/trunk/arch/openrisc/include/asm/gpio.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * OpenRISC implementation: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * et al. - * - * 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 __ASM_OPENRISC_GPIO_H -#define __ASM_OPENRISC_GPIO_H - -#include -#include - -#ifdef CONFIG_GPIOLIB - -/* - * OpenRISC (or1k) does not have on-chip GPIO's so there is not really - * any standardized implementation that makes sense here. If passing - * through gpiolib becomes a bottleneck then it may make sense, on a - * case-by-case basis, to implement these inlined/rapid versions. - * - * Just call gpiolib. - */ -static inline int gpio_get_value(unsigned int gpio) -{ - return __gpio_get_value(gpio); -} - -static inline void gpio_set_value(unsigned int gpio, int value) -{ - __gpio_set_value(gpio, value); -} - -static inline int gpio_cansleep(unsigned int gpio) -{ - return __gpio_cansleep(gpio); -} - -/* - * Not implemented, yet. - */ -static inline int gpio_to_irq(unsigned int gpio) -{ - return -ENOSYS; -} - -static inline int irq_to_gpio(unsigned int irq) -{ - return -EINVAL; -} - -#endif /* CONFIG_GPIOLIB */ - -#endif /* __ASM_OPENRISC_GPIO_H */ diff --git a/trunk/arch/openrisc/include/asm/io.h b/trunk/arch/openrisc/include/asm/io.h deleted file mode 100644 index 07f5299d6c28..000000000000 --- a/trunk/arch/openrisc/include/asm/io.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * OpenRISC implementation: - * Copyright (C) 2010-2011 Jonas Bonn - * et al. - * - * 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 __ASM_OPENRISC_IO_H -#define __ASM_OPENRISC_IO_H - -/* - * PCI: can we really do 0 here if we have no port IO? - */ -#define IO_SPACE_LIMIT 0 - -/* OpenRISC has no port IO */ -#define HAVE_ARCH_PIO_SIZE 1 -#define PIO_RESERVED 0X0UL -#define PIO_OFFSET 0 -#define PIO_MASK 0 - -#include - -extern void __iomem *__ioremap(phys_addr_t offset, unsigned long size, - pgprot_t prot); - -static inline void __iomem *ioremap(phys_addr_t offset, unsigned long size) -{ - return __ioremap(offset, size, PAGE_KERNEL); -} - -/* #define _PAGE_CI 0x002 */ -static inline void __iomem *ioremap_nocache(phys_addr_t offset, - unsigned long size) -{ - return __ioremap(offset, size, - __pgprot(pgprot_val(PAGE_KERNEL) | _PAGE_CI)); -} - -extern void iounmap(void *addr); -#endif diff --git a/trunk/arch/openrisc/include/asm/irq.h b/trunk/arch/openrisc/include/asm/irq.h deleted file mode 100644 index eb612b1865d2..000000000000 --- a/trunk/arch/openrisc/include/asm/irq.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * OpenRISC implementation: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * et al. - * - * 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 __ASM_OPENRISC_IRQ_H__ -#define __ASM_OPENRISC_IRQ_H__ - -#define NR_IRQS 32 -#include - -#define NO_IRQ (-1) - -#endif /* __ASM_OPENRISC_IRQ_H__ */ diff --git a/trunk/arch/openrisc/include/asm/irqflags.h b/trunk/arch/openrisc/include/asm/irqflags.h deleted file mode 100644 index dc86c653d70b..000000000000 --- a/trunk/arch/openrisc/include/asm/irqflags.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * OpenRISC implementation: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * et al. - * - * 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 ___ASM_OPENRISC_IRQFLAGS_H -#define ___ASM_OPENRISC_IRQFLAGS_H - -#include - -#define ARCH_IRQ_DISABLED 0x00 -#define ARCH_IRQ_ENABLED (SPR_SR_IEE|SPR_SR_TEE) - -#include - -#endif /* ___ASM_OPENRISC_IRQFLAGS_H */ diff --git a/trunk/arch/openrisc/include/asm/linkage.h b/trunk/arch/openrisc/include/asm/linkage.h deleted file mode 100644 index e2638752091a..000000000000 --- a/trunk/arch/openrisc/include/asm/linkage.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * OpenRISC implementation: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * et al. - * - * 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 __ASM_OPENRISC_LINKAGE_H -#define __ASM_OPENRISC_LINKAGE_H - -#define __ALIGN .align 0 -#define __ALIGN_STR ".align 0" - -#endif /* __ASM_OPENRISC_LINKAGE_H */ diff --git a/trunk/arch/openrisc/include/asm/memblock.h b/trunk/arch/openrisc/include/asm/memblock.h deleted file mode 100644 index bbe5a1c788cb..000000000000 --- a/trunk/arch/openrisc/include/asm/memblock.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * OpenRISC implementation: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * et al. - * - * 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 __ASM_OPENRISC_MEMBLOCK_H -#define __ASM_OPENRISC_MEMBLOCK_H - -/* empty */ - -#endif /* __ASM_OPENRISC_MEMBLOCK_H */ diff --git a/trunk/arch/openrisc/include/asm/mmu.h b/trunk/arch/openrisc/include/asm/mmu.h deleted file mode 100644 index d069bc2ddfa4..000000000000 --- a/trunk/arch/openrisc/include/asm/mmu.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * OpenRISC implementation: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * et al. - * - * 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 __ASM_OPENRISC_MMU_H -#define __ASM_OPENRISC_MMU_H - -#ifndef __ASSEMBLY__ -typedef unsigned long mm_context_t; -#endif - -#endif diff --git a/trunk/arch/openrisc/include/asm/mmu_context.h b/trunk/arch/openrisc/include/asm/mmu_context.h deleted file mode 100644 index e94b814d2e3c..000000000000 --- a/trunk/arch/openrisc/include/asm/mmu_context.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * OpenRISC implementation: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * et al. - * - * 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 __ASM_OPENRISC_MMU_CONTEXT_H -#define __ASM_OPENRISC_MMU_CONTEXT_H - -#include - -extern int init_new_context(struct task_struct *tsk, struct mm_struct *mm); -extern void destroy_context(struct mm_struct *mm); -extern void switch_mm(struct mm_struct *prev, struct mm_struct *next, - struct task_struct *tsk); - -#define deactivate_mm(tsk, mm) do { } while (0) - -#define activate_mm(prev, next) switch_mm((prev), (next), NULL) - -/* current active pgd - this is similar to other processors pgd - * registers like cr3 on the i386 - */ - -extern volatile pgd_t *current_pgd; /* defined in arch/openrisc/mm/fault.c */ - -static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) -{ -} - -#endif diff --git a/trunk/arch/openrisc/include/asm/mutex.h b/trunk/arch/openrisc/include/asm/mutex.h deleted file mode 100644 index b85a0cfa9fc9..000000000000 --- a/trunk/arch/openrisc/include/asm/mutex.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * OpenRISC implementation: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * et al. - * - * 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. - */ - -/* - * Pull in the generic implementation for the mutex fastpath. - * - * TODO: implement optimized primitives instead, or leave the generic - * implementation in place, or pick the atomic_xchg() based generic - * implementation. (see asm-generic/mutex-xchg.h for details) - */ - -#include diff --git a/trunk/arch/openrisc/include/asm/page.h b/trunk/arch/openrisc/include/asm/page.h deleted file mode 100644 index b041b344b229..000000000000 --- a/trunk/arch/openrisc/include/asm/page.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * OpenRISC implementation: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * et al. - * - * 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 __ASM_OPENRISC_PAGE_H -#define __ASM_OPENRISC_PAGE_H - - -/* PAGE_SHIFT determines the page size */ - -#define PAGE_SHIFT 13 -#ifdef __ASSEMBLY__ -#define PAGE_SIZE (1 << PAGE_SHIFT) -#else -#define PAGE_SIZE (1UL << PAGE_SHIFT) -#endif -#define PAGE_MASK (~(PAGE_SIZE-1)) - -#define PAGE_OFFSET 0xc0000000 -#define KERNELBASE PAGE_OFFSET - -/* This is not necessarily the right place for this, but it's needed by - * drivers/of/fdt.c - */ -#include - -#ifndef __ASSEMBLY__ - -#define get_user_page(vaddr) __get_free_page(GFP_KERNEL) -#define free_user_page(page, addr) free_page(addr) - -#define clear_page(page) memset((page), 0, PAGE_SIZE) -#define copy_page(to, from) memcpy((to), (from), PAGE_SIZE) - -#define clear_user_page(page, vaddr, pg) clear_page(page) -#define copy_user_page(to, from, vaddr, pg) copy_page(to, from) - -/* - * These are used to make use of C type-checking.. - */ -typedef struct { - unsigned long pte; -} pte_t; -typedef struct { - unsigned long pgd; -} pgd_t; -typedef struct { - unsigned long pgprot; -} pgprot_t; -typedef struct page *pgtable_t; - -#define pte_val(x) ((x).pte) -#define pgd_val(x) ((x).pgd) -#define pgprot_val(x) ((x).pgprot) - -#define __pte(x) ((pte_t) { (x) }) -#define __pgd(x) ((pgd_t) { (x) }) -#define __pgprot(x) ((pgprot_t) { (x) }) - -extern unsigned long memory_start; -extern unsigned long memory_end; - -#endif /* !__ASSEMBLY__ */ - - -#ifndef __ASSEMBLY__ - -#define __va(x) ((void *)((unsigned long)(x) + PAGE_OFFSET)) -#define __pa(x) ((unsigned long) (x) - PAGE_OFFSET) - -#define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT) -#define pfn_to_virt(pfn) __va((pfn) << PAGE_SHIFT) - -#define virt_to_page(addr) \ - (mem_map + (((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT)) -#define page_to_virt(page) \ - ((((page) - mem_map) << PAGE_SHIFT) + PAGE_OFFSET) - -#define page_to_phys(page) ((dma_addr_t)page_to_pfn(page) << PAGE_SHIFT) - -#define pfn_valid(pfn) ((pfn) < max_mapnr) - -#define virt_addr_valid(kaddr) (((void *)(kaddr) >= (void *)PAGE_OFFSET) && \ - ((void *)(kaddr) < (void *)memory_end)) - -#endif /* __ASSEMBLY__ */ - - -#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \ - VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) - - -#include -#include - -#endif /* __ASM_OPENRISC_PAGE_H */ diff --git a/trunk/arch/openrisc/include/asm/param.h b/trunk/arch/openrisc/include/asm/param.h deleted file mode 100644 index c39a336610e2..000000000000 --- a/trunk/arch/openrisc/include/asm/param.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * OpenRISC implementation: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * et al. - * - * 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 __ASM_OPENRISC_PARAM_H -#define __ASM_OPENRISC_PARAM_H - -#define EXEC_PAGESIZE 8192 - -#include - -#endif /* __ASM_OPENRISC_PARAM_H */ diff --git a/trunk/arch/openrisc/include/asm/pgalloc.h b/trunk/arch/openrisc/include/asm/pgalloc.h deleted file mode 100644 index 05c39ecd2efd..000000000000 --- a/trunk/arch/openrisc/include/asm/pgalloc.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * OpenRISC implementation: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * et al. - * - * 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 __ASM_OPENRISC_PGALLOC_H -#define __ASM_OPENRISC_PGALLOC_H - -#include -#include -#include -#include -#include - -extern int mem_init_done; - -#define pmd_populate_kernel(mm, pmd, pte) \ - set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(pte))) - -static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, - struct page *pte) -{ - set_pmd(pmd, __pmd(_KERNPG_TABLE + - ((unsigned long)page_to_pfn(pte) << - (unsigned long) PAGE_SHIFT))); -} - -/* - * Allocate and free page tables. - */ -static inline pgd_t *pgd_alloc(struct mm_struct *mm) -{ - pgd_t *ret = (pgd_t *)__get_free_page(GFP_KERNEL); - - if (ret) { - memset(ret, 0, USER_PTRS_PER_PGD * sizeof(pgd_t)); - memcpy(ret + USER_PTRS_PER_PGD, - swapper_pg_dir + USER_PTRS_PER_PGD, - (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); - - } - return ret; -} - -#if 0 -/* FIXME: This seems to be the preferred style, but we are using - * current_pgd (from mm->pgd) to load kernel pages so we need it - * initialized. This needs to be looked into. - */ -extern inline pgd_t *pgd_alloc(struct mm_struct *mm) -{ - return (pgd_t *)get_zeroed_page(GFP_KERNEL); -} -#endif - -static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd) -{ - free_page((unsigned long)pgd); -} - -extern pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address); - -static inline struct page *pte_alloc_one(struct mm_struct *mm, - unsigned long address) -{ - struct page *pte; - pte = alloc_pages(GFP_KERNEL|__GFP_REPEAT, 0); - if (pte) - clear_page(page_address(pte)); - return pte; -} - -static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte) -{ - free_page((unsigned long)pte); -} - -static inline void pte_free(struct mm_struct *mm, struct page *pte) -{ - __free_page(pte); -} - - -#define __pte_free_tlb(tlb, pte, addr) tlb_remove_page((tlb), (pte)) -#define pmd_pgtable(pmd) pmd_page(pmd) - -#define check_pgt_cache() do { } while (0) - -#endif diff --git a/trunk/arch/openrisc/include/asm/pgtable.h b/trunk/arch/openrisc/include/asm/pgtable.h deleted file mode 100644 index 043505d7f684..000000000000 --- a/trunk/arch/openrisc/include/asm/pgtable.h +++ /dev/null @@ -1,463 +0,0 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * OpenRISC implementation: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * et al. - * - * 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. - */ - -/* or32 pgtable.h - macros and functions to manipulate page tables - * - * Based on: - * include/asm-cris/pgtable.h - */ - -#ifndef __ASM_OPENRISC_PGTABLE_H -#define __ASM_OPENRISC_PGTABLE_H - -#include - -#ifndef __ASSEMBLY__ -#include -#include - -/* - * The Linux memory management assumes a three-level page table setup. On - * or32, we use that, but "fold" the mid level into the top-level page - * table. Since the MMU TLB is software loaded through an interrupt, it - * supports any page table structure, so we could have used a three-level - * setup, but for the amounts of memory we normally use, a two-level is - * probably more efficient. - * - * This file contains the functions and defines necessary to modify and use - * the or32 page table tree. - */ - -extern void paging_init(void); - -/* Certain architectures need to do special things when pte's - * within a page table are directly modified. Thus, the following - * hook is made available. - */ -#define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval)) -#define set_pte_at(mm, addr, ptep, pteval) set_pte(ptep, pteval) -/* - * (pmds are folded into pgds so this doesn't get actually called, - * but the define is needed for a generic inline function.) - */ -#define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval) - -#define PGDIR_SHIFT (PAGE_SHIFT + (PAGE_SHIFT-2)) -#define PGDIR_SIZE (1UL << PGDIR_SHIFT) -#define PGDIR_MASK (~(PGDIR_SIZE-1)) - -/* - * entries per page directory level: we use a two-level, so - * we don't really have any PMD directory physically. - * pointers are 4 bytes so we can use the page size and - * divide it by 4 (shift by 2). - */ -#define PTRS_PER_PTE (1UL << (PAGE_SHIFT-2)) - -#define PTRS_PER_PGD (1UL << (PAGE_SHIFT-2)) - -/* calculate how many PGD entries a user-level program can use - * the first mappable virtual address is 0 - * (TASK_SIZE is the maximum virtual address space) - */ - -#define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE) -#define FIRST_USER_ADDRESS 0 - -/* - * Kernels own virtual memory area. - */ - -/* - * The size and location of the vmalloc area are chosen so that modules - * placed in this area aren't more than a 28-bit signed offset from any - * kernel functions that they may need. This greatly simplifies handling - * of the relocations for l.j and l.jal instructions as we don't need to - * introduce any trampolines for reaching "distant" code. - * - * 64 MB of vmalloc area is comparable to what's available on other arches. - */ - -#define VMALLOC_START (PAGE_OFFSET-0x04000000) -#define VMALLOC_END (PAGE_OFFSET) -#define VMALLOC_VMADDR(x) ((unsigned long)(x)) - -/* Define some higher level generic page attributes. - * - * If you change _PAGE_CI definition be sure to change it in - * io.h for ioremap_nocache() too. - */ - -/* - * An OR32 PTE looks like this: - * - * | 31 ... 10 | 9 | 8 ... 6 | 5 | 4 | 3 | 2 | 1 | 0 | - * Phys pg.num L PP Index D A WOM WBC CI CC - * - * L : link - * PPI: Page protection index - * D : Dirty - * A : Accessed - * WOM: Weakly ordered memory - * WBC: Write-back cache - * CI : Cache inhibit - * CC : Cache coherent - * - * The protection bits below should correspond to the layout of the actual - * PTE as per above - */ - -#define _PAGE_CC 0x001 /* software: pte contains a translation */ -#define _PAGE_CI 0x002 /* cache inhibit */ -#define _PAGE_WBC 0x004 /* write back cache */ -#define _PAGE_FILE 0x004 /* set: pagecache, unset: swap (when !PRESENT) */ -#define _PAGE_WOM 0x008 /* weakly ordered memory */ - -#define _PAGE_A 0x010 /* accessed */ -#define _PAGE_D 0x020 /* dirty */ -#define _PAGE_URE 0x040 /* user read enable */ -#define _PAGE_UWE 0x080 /* user write enable */ - -#define _PAGE_SRE 0x100 /* superuser read enable */ -#define _PAGE_SWE 0x200 /* superuser write enable */ -#define _PAGE_EXEC 0x400 /* software: page is executable */ -#define _PAGE_U_SHARED 0x800 /* software: page is shared in user space */ - -/* 0x001 is cache coherency bit, which should always be set to - * 1 - for SMP (when we support it) - * 0 - otherwise - * - * we just reuse this bit in software for _PAGE_PRESENT and - * force it to 0 when loading it into TLB. - */ -#define _PAGE_PRESENT _PAGE_CC -#define _PAGE_USER _PAGE_URE -#define _PAGE_WRITE (_PAGE_UWE | _PAGE_SWE) -#define _PAGE_DIRTY _PAGE_D -#define _PAGE_ACCESSED _PAGE_A -#define _PAGE_NO_CACHE _PAGE_CI -#define _PAGE_SHARED _PAGE_U_SHARED -#define _PAGE_READ (_PAGE_URE | _PAGE_SRE) - -#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY) -#define _PAGE_BASE (_PAGE_PRESENT | _PAGE_ACCESSED) -#define _PAGE_ALL (_PAGE_PRESENT | _PAGE_ACCESSED) -#define _KERNPG_TABLE \ - (_PAGE_BASE | _PAGE_SRE | _PAGE_SWE | _PAGE_ACCESSED | _PAGE_DIRTY) - -#define PAGE_NONE __pgprot(_PAGE_ALL) -#define PAGE_READONLY __pgprot(_PAGE_ALL | _PAGE_URE | _PAGE_SRE) -#define PAGE_READONLY_X __pgprot(_PAGE_ALL | _PAGE_URE | _PAGE_SRE | _PAGE_EXEC) -#define PAGE_SHARED \ - __pgprot(_PAGE_ALL | _PAGE_URE | _PAGE_SRE | _PAGE_UWE | _PAGE_SWE \ - | _PAGE_SHARED) -#define PAGE_SHARED_X \ - __pgprot(_PAGE_ALL | _PAGE_URE | _PAGE_SRE | _PAGE_UWE | _PAGE_SWE \ - | _PAGE_SHARED | _PAGE_EXEC) -#define PAGE_COPY __pgprot(_PAGE_ALL | _PAGE_URE | _PAGE_SRE) -#define PAGE_COPY_X __pgprot(_PAGE_ALL | _PAGE_URE | _PAGE_SRE | _PAGE_EXEC) - -#define PAGE_KERNEL \ - __pgprot(_PAGE_ALL | _PAGE_SRE | _PAGE_SWE \ - | _PAGE_SHARED | _PAGE_DIRTY | _PAGE_EXEC) -#define PAGE_KERNEL_RO \ - __pgprot(_PAGE_ALL | _PAGE_SRE \ - | _PAGE_SHARED | _PAGE_DIRTY | _PAGE_EXEC) -#define PAGE_KERNEL_NOCACHE \ - __pgprot(_PAGE_ALL | _PAGE_SRE | _PAGE_SWE \ - | _PAGE_SHARED | _PAGE_DIRTY | _PAGE_EXEC | _PAGE_CI) - -#define __P000 PAGE_NONE -#define __P001 PAGE_READONLY_X -#define __P010 PAGE_COPY -#define __P011 PAGE_COPY_X -#define __P100 PAGE_READONLY -#define __P101 PAGE_READONLY_X -#define __P110 PAGE_COPY -#define __P111 PAGE_COPY_X - -#define __S000 PAGE_NONE -#define __S001 PAGE_READONLY_X -#define __S010 PAGE_SHARED -#define __S011 PAGE_SHARED_X -#define __S100 PAGE_READONLY -#define __S101 PAGE_READONLY_X -#define __S110 PAGE_SHARED -#define __S111 PAGE_SHARED_X - -/* zero page used for uninitialized stuff */ -extern unsigned long empty_zero_page[2048]; -#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page)) - -/* number of bits that fit into a memory pointer */ -#define BITS_PER_PTR (8*sizeof(unsigned long)) - -/* to align the pointer to a pointer address */ -#define PTR_MASK (~(sizeof(void *)-1)) - -/* sizeof(void*)==1<>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK) - -/* to set the page-dir */ -#define SET_PAGE_DIR(tsk, pgdir) - -#define pte_none(x) (!pte_val(x)) -#define pte_present(x) (pte_val(x) & _PAGE_PRESENT) -#define pte_clear(mm, addr, xp) do { pte_val(*(xp)) = 0; } while (0) - -#define pmd_none(x) (!pmd_val(x)) -#define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK)) != _KERNPG_TABLE) -#define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT) -#define pmd_clear(xp) do { pmd_val(*(xp)) = 0; } while (0) - -/* - * The following only work if pte_present() is true. - * Undefined behaviour if not.. - */ - -static inline int pte_read(pte_t pte) { return pte_val(pte) & _PAGE_READ; } -static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_WRITE; } -static inline int pte_exec(pte_t pte) { return pte_val(pte) & _PAGE_EXEC; } -static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; } -static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } -static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; } -static inline int pte_special(pte_t pte) { return 0; } -static inline pte_t pte_mkspecial(pte_t pte) { return pte; } - -static inline pte_t pte_wrprotect(pte_t pte) -{ - pte_val(pte) &= ~(_PAGE_WRITE); - return pte; -} - -static inline pte_t pte_rdprotect(pte_t pte) -{ - pte_val(pte) &= ~(_PAGE_READ); - return pte; -} - -static inline pte_t pte_exprotect(pte_t pte) -{ - pte_val(pte) &= ~(_PAGE_EXEC); - return pte; -} - -static inline pte_t pte_mkclean(pte_t pte) -{ - pte_val(pte) &= ~(_PAGE_DIRTY); - return pte; -} - -static inline pte_t pte_mkold(pte_t pte) -{ - pte_val(pte) &= ~(_PAGE_ACCESSED); - return pte; -} - -static inline pte_t pte_mkwrite(pte_t pte) -{ - pte_val(pte) |= _PAGE_WRITE; - return pte; -} - -static inline pte_t pte_mkread(pte_t pte) -{ - pte_val(pte) |= _PAGE_READ; - return pte; -} - -static inline pte_t pte_mkexec(pte_t pte) -{ - pte_val(pte) |= _PAGE_EXEC; - return pte; -} - -static inline pte_t pte_mkdirty(pte_t pte) -{ - pte_val(pte) |= _PAGE_DIRTY; - return pte; -} - -static inline pte_t pte_mkyoung(pte_t pte) -{ - pte_val(pte) |= _PAGE_ACCESSED; - return pte; -} - -/* - * Conversion functions: convert a page and protection to a page entry, - * and a page entry and page directory to the page they refer to. - */ - -/* What actually goes as arguments to the various functions is less than - * obvious, but a rule of thumb is that struct page's goes as struct page *, - * really physical DRAM addresses are unsigned long's, and DRAM "virtual" - * addresses (the 0xc0xxxxxx's) goes as void *'s. - */ - -static inline pte_t __mk_pte(void *page, pgprot_t pgprot) -{ - pte_t pte; - /* the PTE needs a physical address */ - pte_val(pte) = __pa(page) | pgprot_val(pgprot); - return pte; -} - -#define mk_pte(page, pgprot) __mk_pte(page_address(page), (pgprot)) - -#define mk_pte_phys(physpage, pgprot) \ -({ \ - pte_t __pte; \ - \ - pte_val(__pte) = (physpage) + pgprot_val(pgprot); \ - __pte; \ -}) - -static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) -{ - pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); - return pte; -} - - -/* - * pte_val refers to a page in the 0x0xxxxxxx physical DRAM interval - * __pte_page(pte_val) refers to the "virtual" DRAM interval - * pte_pagenr refers to the page-number counted starting from the virtual - * DRAM start - */ - -static inline unsigned long __pte_page(pte_t pte) -{ - /* the PTE contains a physical address */ - return (unsigned long)__va(pte_val(pte) & PAGE_MASK); -} - -#define pte_pagenr(pte) ((__pte_page(pte) - PAGE_OFFSET) >> PAGE_SHIFT) - -/* permanent address of a page */ - -#define __page_address(page) (PAGE_OFFSET + (((page) - mem_map) << PAGE_SHIFT)) -#define pte_page(pte) (mem_map+pte_pagenr(pte)) - -/* - * only the pte's themselves need to point to physical DRAM (see above) - * the pagetable links are purely handled within the kernel SW and thus - * don't need the __pa and __va transformations. - */ -static inline void pmd_set(pmd_t *pmdp, pte_t *ptep) -{ - pmd_val(*pmdp) = _KERNPG_TABLE | (unsigned long) ptep; -} - -#define pmd_page(pmd) (pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT)) -#define pmd_page_kernel(pmd) ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK)) - -/* to find an entry in a page-table-directory. */ -#define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) - -#define __pgd_offset(address) pgd_index(address) - -#define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address)) - -/* to find an entry in a kernel page-table-directory */ -#define pgd_offset_k(address) pgd_offset(&init_mm, address) - -#define __pmd_offset(address) \ - (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1)) - -/* - * the pte page can be thought of an array like this: pte_t[PTRS_PER_PTE] - * - * this macro returns the index of the entry in the pte page which would - * control the given virtual address - */ -#define __pte_offset(address) \ - (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) -#define pte_offset_kernel(dir, address) \ - ((pte_t *) pmd_page_kernel(*(dir)) + __pte_offset(address)) -#define pte_offset_map(dir, address) \ - ((pte_t *)page_address(pmd_page(*(dir))) + __pte_offset(address)) -#define pte_offset_map_nested(dir, address) \ - pte_offset_map(dir, address) - -#define pte_unmap(pte) do { } while (0) -#define pte_unmap_nested(pte) do { } while (0) -#define pte_pfn(x) ((unsigned long)(((x).pte)) >> PAGE_SHIFT) -#define pfn_pte(pfn, prot) __pte((((pfn) << PAGE_SHIFT)) | pgprot_val(prot)) - -#define pte_ERROR(e) \ - printk(KERN_ERR "%s:%d: bad pte %p(%08lx).\n", \ - __FILE__, __LINE__, &(e), pte_val(e)) -#define pgd_ERROR(e) \ - printk(KERN_ERR "%s:%d: bad pgd %p(%08lx).\n", \ - __FILE__, __LINE__, &(e), pgd_val(e)) - -extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; /* defined in head.S */ - -/* - * or32 doesn't have any external MMU info: the kernel page - * tables contain all the necessary information. - * - * Actually I am not sure on what this could be used for. - */ -static inline void update_mmu_cache(struct vm_area_struct *vma, - unsigned long address, pte_t *pte) -{ -} - -/* __PHX__ FIXME, SWAP, this probably doesn't work */ - -/* Encode and de-code a swap entry (must be !pte_none(e) && !pte_present(e)) */ -/* Since the PAGE_PRESENT bit is bit 4, we can use the bits above */ - -#define __swp_type(x) (((x).val >> 5) & 0x7f) -#define __swp_offset(x) ((x).val >> 12) -#define __swp_entry(type, offset) \ - ((swp_entry_t) { ((type) << 5) | ((offset) << 12) }) -#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) -#define __swp_entry_to_pte(x) ((pte_t) { (x).val }) - -/* Encode and decode a nonlinear file mapping entry */ - -#define PTE_FILE_MAX_BITS 26 -#define pte_to_pgoff(x) (pte_val(x) >> 6) -#define pgoff_to_pte(x) __pte(((x) << 6) | _PAGE_FILE) - -#define kern_addr_valid(addr) (1) - -#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \ - remap_pfn_range(vma, vaddr, pfn, size, prot) - -#include - -/* - * No page table caches to initialise - */ -#define pgtable_cache_init() do { } while (0) -#define io_remap_page_range remap_page_range - -typedef pte_t *pte_addr_t; - -#endif /* __ASSEMBLY__ */ -#endif /* __ASM_OPENRISC_PGTABLE_H */ diff --git a/trunk/arch/openrisc/include/asm/processor.h b/trunk/arch/openrisc/include/asm/processor.h deleted file mode 100644 index bb54c97b9783..000000000000 --- a/trunk/arch/openrisc/include/asm/processor.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * OpenRISC implementation: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * et al. - * - * 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 __ASM_OPENRISC_PROCESSOR_H -#define __ASM_OPENRISC_PROCESSOR_H - -#include -#include -#include - -#define STACK_TOP TASK_SIZE -#define STACK_TOP_MAX STACK_TOP -/* Kernel and user SR register setting */ -#define KERNEL_SR (SPR_SR_DME | SPR_SR_IME | SPR_SR_ICE \ - | SPR_SR_DCE | SPR_SR_SM) -#define USER_SR (SPR_SR_DME | SPR_SR_IME | SPR_SR_ICE \ - | SPR_SR_DCE | SPR_SR_IEE | SPR_SR_TEE) -/* - * Default implementation of macro that returns current - * instruction pointer ("program counter"). - */ -#define current_text_addr() ({ __label__ _l; _l: &&_l; }) - -/* - * User space process size. This is hardcoded into a few places, - * so don't change it unless you know what you are doing. - */ - -#define TASK_SIZE (0x80000000UL) - -/* This decides where the kernel will search for a free chunk of vm - * space during mmap's. - */ -#define TASK_UNMAPPED_BASE (TASK_SIZE / 8 * 3) - -#ifndef __ASSEMBLY__ - -struct task_struct; - -struct thread_struct { -}; - -/* - * At user->kernel entry, the pt_regs struct is stacked on the top of the - * kernel-stack. This macro allows us to find those regs for a task. - * Notice that subsequent pt_regs stackings, like recursive interrupts - * occurring while we're in the kernel, won't affect this - only the first - * user->kernel transition registers are reached by this (i.e. not regs - * for running signal handler) - */ -#define user_regs(thread_info) (((struct pt_regs *)((unsigned long)(thread_info) + THREAD_SIZE - STACK_FRAME_OVERHEAD)) - 1) - -/* - * Dito but for the currently running task - */ - -#define task_pt_regs(task) user_regs(task_thread_info(task)) -#define current_regs() user_regs(current_thread_info()) - -extern inline void prepare_to_copy(struct task_struct *tsk) -{ -} - -#define INIT_SP (sizeof(init_stack) + (unsigned long) &init_stack) - -#define INIT_THREAD { } - - -#define KSTK_EIP(tsk) (task_pt_regs(tsk)->pc); -#define KSTK_ESP(tsk) (task_pt_regs(tsk)->sp); - - -extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); - -void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp); -void release_thread(struct task_struct *); -unsigned long get_wchan(struct task_struct *p); - -/* - * Free current thread data structures etc.. - */ - -extern inline void exit_thread(void) -{ - /* Nothing needs to be done. */ -} - -/* - * Return saved PC of a blocked thread. For now, this is the "user" PC - */ -extern unsigned long thread_saved_pc(struct task_struct *t); - -#define init_stack (init_thread_union.stack) - -#define cpu_relax() do { } while (0) - -#endif /* __ASSEMBLY__ */ -#endif /* __ASM_OPENRISC_PROCESSOR_H */ diff --git a/trunk/arch/openrisc/include/asm/prom.h b/trunk/arch/openrisc/include/asm/prom.h deleted file mode 100644 index e1f3fe26606c..000000000000 --- a/trunk/arch/openrisc/include/asm/prom.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * OpenRISC implementation: - * Copyright (C) 2010-2011 Jonas Bonn - * et al. - * - * 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/of.h gets to determine #include ordering */ - -#ifndef _ASM_OPENRISC_PROM_H -#define _ASM_OPENRISC_PROM_H -#ifdef __KERNEL__ -#ifndef __ASSEMBLY__ - -#include -#include -#include -#include -#include -#include -#include -#include -#define HAVE_ARCH_DEVTREE_FIXUPS - -/* Other Prototypes */ -extern int early_uartlite_console(void); - -/* Parse the ibm,dma-window property of an OF node into the busno, phys and - * size parameters. - */ -void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop, - unsigned long *busno, unsigned long *phys, unsigned long *size); - -extern void kdump_move_device_tree(void); - -/* CPU OF node matching */ -struct device_node *of_get_cpu_node(int cpu, unsigned int *thread); - -/* Get the MAC address */ -extern const void *of_get_mac_address(struct device_node *np); - -/** - * of_irq_map_pci - Resolve the interrupt for a PCI device - * @pdev: the device whose interrupt is to be resolved - * @out_irq: structure of_irq filled by this function - * - * This function resolves the PCI interrupt for a given PCI device. If a - * device-node exists for a given pci_dev, it will use normal OF tree - * walking. If not, it will implement standard swizzling and walk up the - * PCI tree until an device-node is found, at which point it will finish - * resolving using the OF tree walking. - */ -struct pci_dev; -extern int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq); - -/* This routine is here to provide compatibility with how powerpc - * handles IRQ mapping for OF device nodes. We precompute and permanently - * register them in the platform_device objects, whereas powerpc computes them - * on request. - */ -static inline void irq_dispose_mapping(unsigned int virq) -{ -} - -#endif /* __ASSEMBLY__ */ -#endif /* __KERNEL__ */ -#endif /* _ASM_OPENRISC_PROM_H */ diff --git a/trunk/arch/openrisc/include/asm/ptrace.h b/trunk/arch/openrisc/include/asm/ptrace.h deleted file mode 100644 index 054537c5f9c9..000000000000 --- a/trunk/arch/openrisc/include/asm/ptrace.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * OpenRISC implementation: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * et al. - * - * 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 __ASM_OPENRISC_PTRACE_H -#define __ASM_OPENRISC_PTRACE_H - -#include - -#ifndef __ASSEMBLY__ -/* - * This is the layout of the regset returned by the GETREGSET ptrace call - */ -struct user_regs_struct { - /* GPR R0-R31... */ - unsigned long gpr[32]; - unsigned long pc; - unsigned long sr; - unsigned long pad1; - unsigned long pad2; -}; -#endif - -#ifdef __KERNEL__ - -/* - * Make kernel PTrace/register structures opaque to userspace... userspace can - * access thread state via the regset mechanism. This allows us a bit of - * flexibility in how we order the registers on the stack, permitting some - * optimizations like packing call-clobbered registers together so that - * they share a cacheline (not done yet, though... future optimization). - */ - -#ifndef __ASSEMBLY__ -/* - * This struct describes how the registers are laid out on the kernel stack - * during a syscall or other kernel entry. - * - * This structure should always be cacheline aligned on the stack. - * FIXME: I don't think that's the case right now. The alignment is - * taken care of elsewhere... head.S, process.c, etc. - */ - -struct pt_regs { - union { - struct { - /* Named registers */ - long sr; /* Stored in place of r0 */ - long sp; /* r1 */ - }; - struct { - /* Old style */ - long offset[2]; - long gprs[30]; - }; - struct { - /* New style */ - long gpr[32]; - }; - }; - long pc; - long orig_gpr11; /* For restarting system calls */ - long syscallno; /* Syscall number (used by strace) */ - long dummy; /* Cheap alignment fix */ -}; -#endif /* __ASSEMBLY__ */ - -/* TODO: Rename this to REDZONE because that's what it is */ -#define STACK_FRAME_OVERHEAD 128 /* size of minimum stack frame */ - -#define instruction_pointer(regs) ((regs)->pc) -#define user_mode(regs) (((regs)->sr & SPR_SR_SM) == 0) -#define user_stack_pointer(regs) ((unsigned long)(regs)->sp) -#define profile_pc(regs) instruction_pointer(regs) - -/* - * Offsets used by 'ptrace' system call interface. - */ -#define PT_SR 0 -#define PT_SP 4 -#define PT_GPR2 8 -#define PT_GPR3 12 -#define PT_GPR4 16 -#define PT_GPR5 20 -#define PT_GPR6 24 -#define PT_GPR7 28 -#define PT_GPR8 32 -#define PT_GPR9 36 -#define PT_GPR10 40 -#define PT_GPR11 44 -#define PT_GPR12 48 -#define PT_GPR13 52 -#define PT_GPR14 56 -#define PT_GPR15 60 -#define PT_GPR16 64 -#define PT_GPR17 68 -#define PT_GPR18 72 -#define PT_GPR19 76 -#define PT_GPR20 80 -#define PT_GPR21 84 -#define PT_GPR22 88 -#define PT_GPR23 92 -#define PT_GPR24 96 -#define PT_GPR25 100 -#define PT_GPR26 104 -#define PT_GPR27 108 -#define PT_GPR28 112 -#define PT_GPR29 116 -#define PT_GPR30 120 -#define PT_GPR31 124 -#define PT_PC 128 -#define PT_ORIG_GPR11 132 -#define PT_SYSCALLNO 136 - -#endif /* __KERNEL__ */ - -#endif /* __ASM_OPENRISC_PTRACE_H */ diff --git a/trunk/arch/openrisc/include/asm/serial.h b/trunk/arch/openrisc/include/asm/serial.h deleted file mode 100644 index 270a45241639..000000000000 --- a/trunk/arch/openrisc/include/asm/serial.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * OpenRISC implementation: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * et al. - * - * 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 __ASM_OPENRISC_SERIAL_H -#define __ASM_OPENRISC_SERIAL_H - -#ifdef __KERNEL__ - -#include - -/* There's a generic version of this file, but it assumes a 1.8MHz UART clk... - * this, on the other hand, assumes the UART clock is tied to the system - * clock... 8250_early.c (early 8250 serial console) actually uses this, so - * it needs to be correct to get the early console working. - */ - -#define BASE_BAUD (cpuinfo.clock_frequency/16) - -#endif /* __KERNEL__ */ - -#endif /* __ASM_OPENRISC_SERIAL_H */ diff --git a/trunk/arch/openrisc/include/asm/sigcontext.h b/trunk/arch/openrisc/include/asm/sigcontext.h deleted file mode 100644 index 54a5c50132e3..000000000000 --- a/trunk/arch/openrisc/include/asm/sigcontext.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * OpenRISC implementation: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * et al. - * - * 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 __ASM_OPENRISC_SIGCONTEXT_H -#define __ASM_OPENRISC_SIGCONTEXT_H - -#include - -/* This struct is saved by setup_frame in signal.c, to keep the current - context while a signal handler is executed. It's restored by sys_sigreturn. - - To keep things simple, we use pt_regs here even though normally you just - specify the list of regs to save. Then we can use copy_from_user on the - entire regs instead of a bunch of get_user's as well... -*/ - -struct sigcontext { - struct pt_regs regs; /* needs to be first */ - unsigned long oldmask; - unsigned long usp; /* usp before stacking this gunk on it */ -}; - -#endif /* __ASM_OPENRISC_SIGCONTEXT_H */ diff --git a/trunk/arch/openrisc/include/asm/spinlock.h b/trunk/arch/openrisc/include/asm/spinlock.h deleted file mode 100644 index fd00a3a24123..000000000000 --- a/trunk/arch/openrisc/include/asm/spinlock.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * OpenRISC implementation: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * et al. - * - * 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 __ASM_OPENRISC_SPINLOCK_H -#define __ASM_OPENRISC_SPINLOCK_H - -#error "or32 doesn't do SMP yet" - -#endif diff --git a/trunk/arch/openrisc/include/asm/spr.h b/trunk/arch/openrisc/include/asm/spr.h deleted file mode 100644 index 1cccb42dd477..000000000000 --- a/trunk/arch/openrisc/include/asm/spr.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * OpenRISC implementation: - * Copyright (C) 2010-2011 Jonas Bonn - * - * 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 __ASM_OPENRISC_SPR_H -#define __ASM_OPENRISC_SPR_H - -#define mtspr(_spr, _val) __asm__ __volatile__ ( \ - "l.mtspr r0,%1,%0" \ - : : "K" (_spr), "r" (_val)) -#define mtspr_off(_spr, _off, _val) __asm__ __volatile__ ( \ - "l.mtspr %0,%1,%2" \ - : : "r" (_off), "r" (_val), "K" (_spr)) - -static inline unsigned long mfspr(unsigned long add) -{ - unsigned long ret; - __asm__ __volatile__ ("l.mfspr %0,r0,%1" : "=r" (ret) : "K" (add)); - return ret; -} - -static inline unsigned long mfspr_off(unsigned long add, unsigned long offset) -{ - unsigned long ret; - __asm__ __volatile__ ("l.mfspr %0,%1,%2" : "=r" (ret) - : "r" (offset), "K" (add)); - return ret; -} - -#endif diff --git a/trunk/arch/openrisc/include/asm/spr_defs.h b/trunk/arch/openrisc/include/asm/spr_defs.h deleted file mode 100644 index 5dbc668865c4..000000000000 --- a/trunk/arch/openrisc/include/asm/spr_defs.h +++ /dev/null @@ -1,604 +0,0 @@ -/* - * OpenRISC Linux - * - * SPR Definitions - * - * Copyright (C) 2000 Damjan Lampret - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2008, 2010 Embecosm Limited - * Copyright (C) 2010-2011 Jonas Bonn - * et al. - * - * 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 file is part of OpenRISC 1000 Architectural Simulator. - */ - -#ifndef SPR_DEFS__H -#define SPR_DEFS__H - -/* Definition of special-purpose registers (SPRs). */ - -#define MAX_GRPS (32) -#define MAX_SPRS_PER_GRP_BITS (11) -#define MAX_SPRS_PER_GRP (1 << MAX_SPRS_PER_GRP_BITS) -#define MAX_SPRS (0x10000) - -/* Base addresses for the groups */ -#define SPRGROUP_SYS (0 << MAX_SPRS_PER_GRP_BITS) -#define SPRGROUP_DMMU (1 << MAX_SPRS_PER_GRP_BITS) -#define SPRGROUP_IMMU (2 << MAX_SPRS_PER_GRP_BITS) -#define SPRGROUP_DC (3 << MAX_SPRS_PER_GRP_BITS) -#define SPRGROUP_IC (4 << MAX_SPRS_PER_GRP_BITS) -#define SPRGROUP_MAC (5 << MAX_SPRS_PER_GRP_BITS) -#define SPRGROUP_D (6 << MAX_SPRS_PER_GRP_BITS) -#define SPRGROUP_PC (7 << MAX_SPRS_PER_GRP_BITS) -#define SPRGROUP_PM (8 << MAX_SPRS_PER_GRP_BITS) -#define SPRGROUP_PIC (9 << MAX_SPRS_PER_GRP_BITS) -#define SPRGROUP_TT (10 << MAX_SPRS_PER_GRP_BITS) -#define SPRGROUP_FP (11 << MAX_SPRS_PER_GRP_BITS) - -/* System control and status group */ -#define SPR_VR (SPRGROUP_SYS + 0) -#define SPR_UPR (SPRGROUP_SYS + 1) -#define SPR_CPUCFGR (SPRGROUP_SYS + 2) -#define SPR_DMMUCFGR (SPRGROUP_SYS + 3) -#define SPR_IMMUCFGR (SPRGROUP_SYS + 4) -#define SPR_DCCFGR (SPRGROUP_SYS + 5) -#define SPR_ICCFGR (SPRGROUP_SYS + 6) -#define SPR_DCFGR (SPRGROUP_SYS + 7) -#define SPR_PCCFGR (SPRGROUP_SYS + 8) -#define SPR_NPC (SPRGROUP_SYS + 16) /* CZ 21/06/01 */ -#define SPR_SR (SPRGROUP_SYS + 17) /* CZ 21/06/01 */ -#define SPR_PPC (SPRGROUP_SYS + 18) /* CZ 21/06/01 */ -#define SPR_FPCSR (SPRGROUP_SYS + 20) /* CZ 21/06/01 */ -#define SPR_EPCR_BASE (SPRGROUP_SYS + 32) /* CZ 21/06/01 */ -#define SPR_EPCR_LAST (SPRGROUP_SYS + 47) /* CZ 21/06/01 */ -#define SPR_EEAR_BASE (SPRGROUP_SYS + 48) -#define SPR_EEAR_LAST (SPRGROUP_SYS + 63) -#define SPR_ESR_BASE (SPRGROUP_SYS + 64) -#define SPR_ESR_LAST (SPRGROUP_SYS + 79) -#define SPR_GPR_BASE (SPRGROUP_SYS + 1024) - -/* Data MMU group */ -#define SPR_DMMUCR (SPRGROUP_DMMU + 0) -#define SPR_DTLBEIR (SPRGROUP_DMMU + 2) -#define SPR_DTLBMR_BASE(WAY) (SPRGROUP_DMMU + 0x200 + (WAY) * 0x100) -#define SPR_DTLBMR_LAST(WAY) (SPRGROUP_DMMU + 0x27f + (WAY) * 0x100) -#define SPR_DTLBTR_BASE(WAY) (SPRGROUP_DMMU + 0x280 + (WAY) * 0x100) -#define SPR_DTLBTR_LAST(WAY) (SPRGROUP_DMMU + 0x2ff + (WAY) * 0x100) - -/* Instruction MMU group */ -#define SPR_IMMUCR (SPRGROUP_IMMU + 0) -#define SPR_ITLBEIR (SPRGROUP_IMMU + 2) -#define SPR_ITLBMR_BASE(WAY) (SPRGROUP_IMMU + 0x200 + (WAY) * 0x100) -#define SPR_ITLBMR_LAST(WAY) (SPRGROUP_IMMU + 0x27f + (WAY) * 0x100) -#define SPR_ITLBTR_BASE(WAY) (SPRGROUP_IMMU + 0x280 + (WAY) * 0x100) -#define SPR_ITLBTR_LAST(WAY) (SPRGROUP_IMMU + 0x2ff + (WAY) * 0x100) - -/* Data cache group */ -#define SPR_DCCR (SPRGROUP_DC + 0) -#define SPR_DCBPR (SPRGROUP_DC + 1) -#define SPR_DCBFR (SPRGROUP_DC + 2) -#define SPR_DCBIR (SPRGROUP_DC + 3) -#define SPR_DCBWR (SPRGROUP_DC + 4) -#define SPR_DCBLR (SPRGROUP_DC + 5) -#define SPR_DCR_BASE(WAY) (SPRGROUP_DC + 0x200 + (WAY) * 0x200) -#define SPR_DCR_LAST(WAY) (SPRGROUP_DC + 0x3ff + (WAY) * 0x200) - -/* Instruction cache group */ -#define SPR_ICCR (SPRGROUP_IC + 0) -#define SPR_ICBPR (SPRGROUP_IC + 1) -#define SPR_ICBIR (SPRGROUP_IC + 2) -#define SPR_ICBLR (SPRGROUP_IC + 3) -#define SPR_ICR_BASE(WAY) (SPRGROUP_IC + 0x200 + (WAY) * 0x200) -#define SPR_ICR_LAST(WAY) (SPRGROUP_IC + 0x3ff + (WAY) * 0x200) - -/* MAC group */ -#define SPR_MACLO (SPRGROUP_MAC + 1) -#define SPR_MACHI (SPRGROUP_MAC + 2) - -/* Debug group */ -#define SPR_DVR(N) (SPRGROUP_D + (N)) -#define SPR_DCR(N) (SPRGROUP_D + 8 + (N)) -#define SPR_DMR1 (SPRGROUP_D + 16) -#define SPR_DMR2 (SPRGROUP_D + 17) -#define SPR_DWCR0 (SPRGROUP_D + 18) -#define SPR_DWCR1 (SPRGROUP_D + 19) -#define SPR_DSR (SPRGROUP_D + 20) -#define SPR_DRR (SPRGROUP_D + 21) - -/* Performance counters group */ -#define SPR_PCCR(N) (SPRGROUP_PC + (N)) -#define SPR_PCMR(N) (SPRGROUP_PC + 8 + (N)) - -/* Power management group */ -#define SPR_PMR (SPRGROUP_PM + 0) - -/* PIC group */ -#define SPR_PICMR (SPRGROUP_PIC + 0) -#define SPR_PICPR (SPRGROUP_PIC + 1) -#define SPR_PICSR (SPRGROUP_PIC + 2) - -/* Tick Timer group */ -#define SPR_TTMR (SPRGROUP_TT + 0) -#define SPR_TTCR (SPRGROUP_TT + 1) - -/* - * Bit definitions for the Version Register - * - */ -#define SPR_VR_VER 0xff000000 /* Processor version */ -#define SPR_VR_CFG 0x00ff0000 /* Processor configuration */ -#define SPR_VR_RES 0x0000ffc0 /* Reserved */ -#define SPR_VR_REV 0x0000003f /* Processor revision */ - -#define SPR_VR_VER_OFF 24 -#define SPR_VR_CFG_OFF 16 -#define SPR_VR_REV_OFF 0 - -/* - * Bit definitions for the Unit Present Register - * - */ -#define SPR_UPR_UP 0x00000001 /* UPR present */ -#define SPR_UPR_DCP 0x00000002 /* Data cache present */ -#define SPR_UPR_ICP 0x00000004 /* Instruction cache present */ -#define SPR_UPR_DMP 0x00000008 /* Data MMU present */ -#define SPR_UPR_IMP 0x00000010 /* Instruction MMU present */ -#define SPR_UPR_MP 0x00000020 /* MAC present */ -#define SPR_UPR_DUP 0x00000040 /* Debug unit present */ -#define SPR_UPR_PCUP 0x00000080 /* Performance counters unit present */ -#define SPR_UPR_PMP 0x00000100 /* Power management present */ -#define SPR_UPR_PICP 0x00000200 /* PIC present */ -#define SPR_UPR_TTP 0x00000400 /* Tick timer present */ -#define SPR_UPR_RES 0x00fe0000 /* Reserved */ -#define SPR_UPR_CUP 0xff000000 /* Context units present */ - -/* - * JPB: Bit definitions for the CPU configuration register - * - */ -#define SPR_CPUCFGR_NSGF 0x0000000f /* Number of shadow GPR files */ -#define SPR_CPUCFGR_CGF 0x00000010 /* Custom GPR file */ -#define SPR_CPUCFGR_OB32S 0x00000020 /* ORBIS32 supported */ -#define SPR_CPUCFGR_OB64S 0x00000040 /* ORBIS64 supported */ -#define SPR_CPUCFGR_OF32S 0x00000080 /* ORFPX32 supported */ -#define SPR_CPUCFGR_OF64S 0x00000100 /* ORFPX64 supported */ -#define SPR_CPUCFGR_OV64S 0x00000200 /* ORVDX64 supported */ -#define SPR_CPUCFGR_RES 0xfffffc00 /* Reserved */ - -/* - * JPB: Bit definitions for the Debug configuration register and other - * constants. - * - */ - -#define SPR_DCFGR_NDP 0x00000007 /* Number of matchpoints mask */ -#define SPR_DCFGR_NDP1 0x00000000 /* One matchpoint supported */ -#define SPR_DCFGR_NDP2 0x00000001 /* Two matchpoints supported */ -#define SPR_DCFGR_NDP3 0x00000002 /* Three matchpoints supported */ -#define SPR_DCFGR_NDP4 0x00000003 /* Four matchpoints supported */ -#define SPR_DCFGR_NDP5 0x00000004 /* Five matchpoints supported */ -#define SPR_DCFGR_NDP6 0x00000005 /* Six matchpoints supported */ -#define SPR_DCFGR_NDP7 0x00000006 /* Seven matchpoints supported */ -#define SPR_DCFGR_NDP8 0x00000007 /* Eight matchpoints supported */ -#define SPR_DCFGR_WPCI 0x00000008 /* Watchpoint counters implemented */ - -#define MATCHPOINTS_TO_NDP(n) (1 == n ? SPR_DCFGR_NDP1 : \ - 2 == n ? SPR_DCFGR_NDP2 : \ - 3 == n ? SPR_DCFGR_NDP3 : \ - 4 == n ? SPR_DCFGR_NDP4 : \ - 5 == n ? SPR_DCFGR_NDP5 : \ - 6 == n ? SPR_DCFGR_NDP6 : \ - 7 == n ? SPR_DCFGR_NDP7 : SPR_DCFGR_NDP8) -#define MAX_MATCHPOINTS 8 -#define MAX_WATCHPOINTS (MAX_MATCHPOINTS + 2) - -/* - * Bit definitions for the Supervision Register - * - */ -#define SPR_SR_SM 0x00000001 /* Supervisor Mode */ -#define SPR_SR_TEE 0x00000002 /* Tick timer Exception Enable */ -#define SPR_SR_IEE 0x00000004 /* Interrupt Exception Enable */ -#define SPR_SR_DCE 0x00000008 /* Data Cache Enable */ -#define SPR_SR_ICE 0x00000010 /* Instruction Cache Enable */ -#define SPR_SR_DME 0x00000020 /* Data MMU Enable */ -#define SPR_SR_IME 0x00000040 /* Instruction MMU Enable */ -#define SPR_SR_LEE 0x00000080 /* Little Endian Enable */ -#define SPR_SR_CE 0x00000100 /* CID Enable */ -#define SPR_SR_F 0x00000200 /* Condition Flag */ -#define SPR_SR_CY 0x00000400 /* Carry flag */ -#define SPR_SR_OV 0x00000800 /* Overflow flag */ -#define SPR_SR_OVE 0x00001000 /* Overflow flag Exception */ -#define SPR_SR_DSX 0x00002000 /* Delay Slot Exception */ -#define SPR_SR_EPH 0x00004000 /* Exception Prefix High */ -#define SPR_SR_FO 0x00008000 /* Fixed one */ -#define SPR_SR_SUMRA 0x00010000 /* Supervisor SPR read access */ -#define SPR_SR_RES 0x0ffe0000 /* Reserved */ -#define SPR_SR_CID 0xf0000000 /* Context ID */ - -/* - * Bit definitions for the Data MMU Control Register - * - */ -#define SPR_DMMUCR_P2S 0x0000003e /* Level 2 Page Size */ -#define SPR_DMMUCR_P1S 0x000007c0 /* Level 1 Page Size */ -#define SPR_DMMUCR_VADDR_WIDTH 0x0000f800 /* Virtual ADDR Width */ -#define SPR_DMMUCR_PADDR_WIDTH 0x000f0000 /* Physical ADDR Width */ - -/* - * Bit definitions for the Instruction MMU Control Register - * - */ -#define SPR_IMMUCR_P2S 0x0000003e /* Level 2 Page Size */ -#define SPR_IMMUCR_P1S 0x000007c0 /* Level 1 Page Size */ -#define SPR_IMMUCR_VADDR_WIDTH 0x0000f800 /* Virtual ADDR Width */ -#define SPR_IMMUCR_PADDR_WIDTH 0x000f0000 /* Physical ADDR Width */ - -/* - * Bit definitions for the Data TLB Match Register - * - */ -#define SPR_DTLBMR_V 0x00000001 /* Valid */ -#define SPR_DTLBMR_PL1 0x00000002 /* Page Level 1 (if 0 then PL2) */ -#define SPR_DTLBMR_CID 0x0000003c /* Context ID */ -#define SPR_DTLBMR_LRU 0x000000c0 /* Least Recently Used */ -#define SPR_DTLBMR_VPN 0xfffff000 /* Virtual Page Number */ - -/* - * Bit definitions for the Data TLB Translate Register - * - */ -#define SPR_DTLBTR_CC 0x00000001 /* Cache Coherency */ -#define SPR_DTLBTR_CI 0x00000002 /* Cache Inhibit */ -#define SPR_DTLBTR_WBC 0x00000004 /* Write-Back Cache */ -#define SPR_DTLBTR_WOM 0x00000008 /* Weakly-Ordered Memory */ -#define SPR_DTLBTR_A 0x00000010 /* Accessed */ -#define SPR_DTLBTR_D 0x00000020 /* Dirty */ -#define SPR_DTLBTR_URE 0x00000040 /* User Read Enable */ -#define SPR_DTLBTR_UWE 0x00000080 /* User Write Enable */ -#define SPR_DTLBTR_SRE 0x00000100 /* Supervisor Read Enable */ -#define SPR_DTLBTR_SWE 0x00000200 /* Supervisor Write Enable */ -#define SPR_DTLBTR_PPN 0xfffff000 /* Physical Page Number */ - -/* - * Bit definitions for the Instruction TLB Match Register - * - */ -#define SPR_ITLBMR_V 0x00000001 /* Valid */ -#define SPR_ITLBMR_PL1 0x00000002 /* Page Level 1 (if 0 then PL2) */ -#define SPR_ITLBMR_CID 0x0000003c /* Context ID */ -#define SPR_ITLBMR_LRU 0x000000c0 /* Least Recently Used */ -#define SPR_ITLBMR_VPN 0xfffff000 /* Virtual Page Number */ - -/* - * Bit definitions for the Instruction TLB Translate Register - * - */ -#define SPR_ITLBTR_CC 0x00000001 /* Cache Coherency */ -#define SPR_ITLBTR_CI 0x00000002 /* Cache Inhibit */ -#define SPR_ITLBTR_WBC 0x00000004 /* Write-Back Cache */ -#define SPR_ITLBTR_WOM 0x00000008 /* Weakly-Ordered Memory */ -#define SPR_ITLBTR_A 0x00000010 /* Accessed */ -#define SPR_ITLBTR_D 0x00000020 /* Dirty */ -#define SPR_ITLBTR_SXE 0x00000040 /* User Read Enable */ -#define SPR_ITLBTR_UXE 0x00000080 /* User Write Enable */ -#define SPR_ITLBTR_PPN 0xfffff000 /* Physical Page Number */ - -/* - * Bit definitions for Data Cache Control register - * - */ -#define SPR_DCCR_EW 0x000000ff /* Enable ways */ - -/* - * Bit definitions for Insn Cache Control register - * - */ -#define SPR_ICCR_EW 0x000000ff /* Enable ways */ - -/* - * Bit definitions for Data Cache Configuration Register - * - */ - -#define SPR_DCCFGR_NCW 0x00000007 -#define SPR_DCCFGR_NCS 0x00000078 -#define SPR_DCCFGR_CBS 0x00000080 -#define SPR_DCCFGR_CWS 0x00000100 -#define SPR_DCCFGR_CCRI 0x00000200 -#define SPR_DCCFGR_CBIRI 0x00000400 -#define SPR_DCCFGR_CBPRI 0x00000800 -#define SPR_DCCFGR_CBLRI 0x00001000 -#define SPR_DCCFGR_CBFRI 0x00002000 -#define SPR_DCCFGR_CBWBRI 0x00004000 - -#define SPR_DCCFGR_NCW_OFF 0 -#define SPR_DCCFGR_NCS_OFF 3 -#define SPR_DCCFGR_CBS_OFF 7 - -/* - * Bit definitions for Instruction Cache Configuration Register - * - */ -#define SPR_ICCFGR_NCW 0x00000007 -#define SPR_ICCFGR_NCS 0x00000078 -#define SPR_ICCFGR_CBS 0x00000080 -#define SPR_ICCFGR_CCRI 0x00000200 -#define SPR_ICCFGR_CBIRI 0x00000400 -#define SPR_ICCFGR_CBPRI 0x00000800 -#define SPR_ICCFGR_CBLRI 0x00001000 - -#define SPR_ICCFGR_NCW_OFF 0 -#define SPR_ICCFGR_NCS_OFF 3 -#define SPR_ICCFGR_CBS_OFF 7 - -/* - * Bit definitions for Data MMU Configuration Register - * - */ - -#define SPR_DMMUCFGR_NTW 0x00000003 -#define SPR_DMMUCFGR_NTS 0x0000001C -#define SPR_DMMUCFGR_NAE 0x000000E0 -#define SPR_DMMUCFGR_CRI 0x00000100 -#define SPR_DMMUCFGR_PRI 0x00000200 -#define SPR_DMMUCFGR_TEIRI 0x00000400 -#define SPR_DMMUCFGR_HTR 0x00000800 - -#define SPR_DMMUCFGR_NTW_OFF 0 -#define SPR_DMMUCFGR_NTS_OFF 2 - -/* - * Bit definitions for Instruction MMU Configuration Register - * - */ - -#define SPR_IMMUCFGR_NTW 0x00000003 -#define SPR_IMMUCFGR_NTS 0x0000001C -#define SPR_IMMUCFGR_NAE 0x000000E0 -#define SPR_IMMUCFGR_CRI 0x00000100 -#define SPR_IMMUCFGR_PRI 0x00000200 -#define SPR_IMMUCFGR_TEIRI 0x00000400 -#define SPR_IMMUCFGR_HTR 0x00000800 - -#define SPR_IMMUCFGR_NTW_OFF 0 -#define SPR_IMMUCFGR_NTS_OFF 2 - -/* - * Bit definitions for Debug Control registers - * - */ -#define SPR_DCR_DP 0x00000001 /* DVR/DCR present */ -#define SPR_DCR_CC 0x0000000e /* Compare condition */ -#define SPR_DCR_SC 0x00000010 /* Signed compare */ -#define SPR_DCR_CT 0x000000e0 /* Compare to */ - -/* Bit results with SPR_DCR_CC mask */ -#define SPR_DCR_CC_MASKED 0x00000000 -#define SPR_DCR_CC_EQUAL 0x00000002 -#define SPR_DCR_CC_LESS 0x00000004 -#define SPR_DCR_CC_LESSE 0x00000006 -#define SPR_DCR_CC_GREAT 0x00000008 -#define SPR_DCR_CC_GREATE 0x0000000a -#define SPR_DCR_CC_NEQUAL 0x0000000c - -/* Bit results with SPR_DCR_CT mask */ -#define SPR_DCR_CT_DISABLED 0x00000000 -#define SPR_DCR_CT_IFEA 0x00000020 -#define SPR_DCR_CT_LEA 0x00000040 -#define SPR_DCR_CT_SEA 0x00000060 -#define SPR_DCR_CT_LD 0x00000080 -#define SPR_DCR_CT_SD 0x000000a0 -#define SPR_DCR_CT_LSEA 0x000000c0 -#define SPR_DCR_CT_LSD 0x000000e0 -/* SPR_DCR_CT_LSD doesn't seem to be implemented anywhere in or1ksim. 2004-1-30 HP */ - -/* - * Bit definitions for Debug Mode 1 register - * - */ -#define SPR_DMR1_CW 0x000fffff /* Chain register pair data */ -#define SPR_DMR1_CW0_AND 0x00000001 -#define SPR_DMR1_CW0_OR 0x00000002 -#define SPR_DMR1_CW0 (SPR_DMR1_CW0_AND | SPR_DMR1_CW0_OR) -#define SPR_DMR1_CW1_AND 0x00000004 -#define SPR_DMR1_CW1_OR 0x00000008 -#define SPR_DMR1_CW1 (SPR_DMR1_CW1_AND | SPR_DMR1_CW1_OR) -#define SPR_DMR1_CW2_AND 0x00000010 -#define SPR_DMR1_CW2_OR 0x00000020 -#define SPR_DMR1_CW2 (SPR_DMR1_CW2_AND | SPR_DMR1_CW2_OR) -#define SPR_DMR1_CW3_AND 0x00000040 -#define SPR_DMR1_CW3_OR 0x00000080 -#define SPR_DMR1_CW3 (SPR_DMR1_CW3_AND | SPR_DMR1_CW3_OR) -#define SPR_DMR1_CW4_AND 0x00000100 -#define SPR_DMR1_CW4_OR 0x00000200 -#define SPR_DMR1_CW4 (SPR_DMR1_CW4_AND | SPR_DMR1_CW4_OR) -#define SPR_DMR1_CW5_AND 0x00000400 -#define SPR_DMR1_CW5_OR 0x00000800 -#define SPR_DMR1_CW5 (SPR_DMR1_CW5_AND | SPR_DMR1_CW5_OR) -#define SPR_DMR1_CW6_AND 0x00001000 -#define SPR_DMR1_CW6_OR 0x00002000 -#define SPR_DMR1_CW6 (SPR_DMR1_CW6_AND | SPR_DMR1_CW6_OR) -#define SPR_DMR1_CW7_AND 0x00004000 -#define SPR_DMR1_CW7_OR 0x00008000 -#define SPR_DMR1_CW7 (SPR_DMR1_CW7_AND | SPR_DMR1_CW7_OR) -#define SPR_DMR1_CW8_AND 0x00010000 -#define SPR_DMR1_CW8_OR 0x00020000 -#define SPR_DMR1_CW8 (SPR_DMR1_CW8_AND | SPR_DMR1_CW8_OR) -#define SPR_DMR1_CW9_AND 0x00040000 -#define SPR_DMR1_CW9_OR 0x00080000 -#define SPR_DMR1_CW9 (SPR_DMR1_CW9_AND | SPR_DMR1_CW9_OR) -#define SPR_DMR1_RES1 0x00300000 /* Reserved */ -#define SPR_DMR1_ST 0x00400000 /* Single-step trace*/ -#define SPR_DMR1_BT 0x00800000 /* Branch trace */ -#define SPR_DMR1_RES2 0xff000000 /* Reserved */ - -/* - * Bit definitions for Debug Mode 2 register. AWTC and WGB corrected by JPB - * - */ -#define SPR_DMR2_WCE0 0x00000001 /* Watchpoint counter 0 enable */ -#define SPR_DMR2_WCE1 0x00000002 /* Watchpoint counter 0 enable */ -#define SPR_DMR2_AWTC 0x00000ffc /* Assign watchpoints to counters */ -#define SPR_DMR2_AWTC_OFF 2 /* Bit offset to AWTC field */ -#define SPR_DMR2_WGB 0x003ff000 /* Watchpoints generating breakpoint */ -#define SPR_DMR2_WGB_OFF 12 /* Bit offset to WGB field */ -#define SPR_DMR2_WBS 0xffc00000 /* JPB: Watchpoint status */ -#define SPR_DMR2_WBS_OFF 22 /* Bit offset to WBS field */ - -/* - * Bit definitions for Debug watchpoint counter registers - * - */ -#define SPR_DWCR_COUNT 0x0000ffff /* Count */ -#define SPR_DWCR_MATCH 0xffff0000 /* Match */ -#define SPR_DWCR_MATCH_OFF 16 /* Match bit offset */ - -/* - * Bit definitions for Debug stop register - * - */ -#define SPR_DSR_RSTE 0x00000001 /* Reset exception */ -#define SPR_DSR_BUSEE 0x00000002 /* Bus error exception */ -#define SPR_DSR_DPFE 0x00000004 /* Data Page Fault exception */ -#define SPR_DSR_IPFE 0x00000008 /* Insn Page Fault exception */ -#define SPR_DSR_TTE 0x00000010 /* Tick Timer exception */ -#define SPR_DSR_AE 0x00000020 /* Alignment exception */ -#define SPR_DSR_IIE 0x00000040 /* Illegal Instruction exception */ -#define SPR_DSR_IE 0x00000080 /* Interrupt exception */ -#define SPR_DSR_DME 0x00000100 /* DTLB miss exception */ -#define SPR_DSR_IME 0x00000200 /* ITLB miss exception */ -#define SPR_DSR_RE 0x00000400 /* Range exception */ -#define SPR_DSR_SCE 0x00000800 /* System call exception */ -#define SPR_DSR_FPE 0x00001000 /* Floating Point Exception */ -#define SPR_DSR_TE 0x00002000 /* Trap exception */ - -/* - * Bit definitions for Debug reason register - * - */ -#define SPR_DRR_RSTE 0x00000001 /* Reset exception */ -#define SPR_DRR_BUSEE 0x00000002 /* Bus error exception */ -#define SPR_DRR_DPFE 0x00000004 /* Data Page Fault exception */ -#define SPR_DRR_IPFE 0x00000008 /* Insn Page Fault exception */ -#define SPR_DRR_TTE 0x00000010 /* Tick Timer exception */ -#define SPR_DRR_AE 0x00000020 /* Alignment exception */ -#define SPR_DRR_IIE 0x00000040 /* Illegal Instruction exception */ -#define SPR_DRR_IE 0x00000080 /* Interrupt exception */ -#define SPR_DRR_DME 0x00000100 /* DTLB miss exception */ -#define SPR_DRR_IME 0x00000200 /* ITLB miss exception */ -#define SPR_DRR_RE 0x00000400 /* Range exception */ -#define SPR_DRR_SCE 0x00000800 /* System call exception */ -#define SPR_DRR_FPE 0x00001000 /* Floating Point Exception */ -#define SPR_DRR_TE 0x00002000 /* Trap exception */ - -/* - * Bit definitions for Performance counters mode registers - * - */ -#define SPR_PCMR_CP 0x00000001 /* Counter present */ -#define SPR_PCMR_UMRA 0x00000002 /* User mode read access */ -#define SPR_PCMR_CISM 0x00000004 /* Count in supervisor mode */ -#define SPR_PCMR_CIUM 0x00000008 /* Count in user mode */ -#define SPR_PCMR_LA 0x00000010 /* Load access event */ -#define SPR_PCMR_SA 0x00000020 /* Store access event */ -#define SPR_PCMR_IF 0x00000040 /* Instruction fetch event*/ -#define SPR_PCMR_DCM 0x00000080 /* Data cache miss event */ -#define SPR_PCMR_ICM 0x00000100 /* Insn cache miss event */ -#define SPR_PCMR_IFS 0x00000200 /* Insn fetch stall event */ -#define SPR_PCMR_LSUS 0x00000400 /* LSU stall event */ -#define SPR_PCMR_BS 0x00000800 /* Branch stall event */ -#define SPR_PCMR_DTLBM 0x00001000 /* DTLB miss event */ -#define SPR_PCMR_ITLBM 0x00002000 /* ITLB miss event */ -#define SPR_PCMR_DDS 0x00004000 /* Data dependency stall event */ -#define SPR_PCMR_WPE 0x03ff8000 /* Watchpoint events */ - -/* - * Bit definitions for the Power management register - * - */ -#define SPR_PMR_SDF 0x0000000f /* Slow down factor */ -#define SPR_PMR_DME 0x00000010 /* Doze mode enable */ -#define SPR_PMR_SME 0x00000020 /* Sleep mode enable */ -#define SPR_PMR_DCGE 0x00000040 /* Dynamic clock gating enable */ -#define SPR_PMR_SUME 0x00000080 /* Suspend mode enable */ - -/* - * Bit definitions for PICMR - * - */ -#define SPR_PICMR_IUM 0xfffffffc /* Interrupt unmask */ - -/* - * Bit definitions for PICPR - * - */ -#define SPR_PICPR_IPRIO 0xfffffffc /* Interrupt priority */ - -/* - * Bit definitions for PICSR - * - */ -#define SPR_PICSR_IS 0xffffffff /* Interrupt status */ - -/* - * Bit definitions for Tick Timer Control Register - * - */ - -#define SPR_TTCR_CNT 0xffffffff /* Count, time period */ -#define SPR_TTMR_TP 0x0fffffff /* Time period */ -#define SPR_TTMR_IP 0x10000000 /* Interrupt Pending */ -#define SPR_TTMR_IE 0x20000000 /* Interrupt Enable */ -#define SPR_TTMR_DI 0x00000000 /* Disabled */ -#define SPR_TTMR_RT 0x40000000 /* Restart tick */ -#define SPR_TTMR_SR 0x80000000 /* Single run */ -#define SPR_TTMR_CR 0xc0000000 /* Continuous run */ -#define SPR_TTMR_M 0xc0000000 /* Tick mode */ - -/* - * Bit definitions for the FP Control Status Register - * - */ -#define SPR_FPCSR_FPEE 0x00000001 /* Floating Point Exception Enable */ -#define SPR_FPCSR_RM 0x00000006 /* Rounding Mode */ -#define SPR_FPCSR_OVF 0x00000008 /* Overflow Flag */ -#define SPR_FPCSR_UNF 0x00000010 /* Underflow Flag */ -#define SPR_FPCSR_SNF 0x00000020 /* SNAN Flag */ -#define SPR_FPCSR_QNF 0x00000040 /* QNAN Flag */ -#define SPR_FPCSR_ZF 0x00000080 /* Zero Flag */ -#define SPR_FPCSR_IXF 0x00000100 /* Inexact Flag */ -#define SPR_FPCSR_IVF 0x00000200 /* Invalid Flag */ -#define SPR_FPCSR_INF 0x00000400 /* Infinity Flag */ -#define SPR_FPCSR_DZF 0x00000800 /* Divide By Zero Flag */ -#define SPR_FPCSR_ALLF (SPR_FPCSR_OVF | SPR_FPCSR_UNF | SPR_FPCSR_SNF | \ - SPR_FPCSR_QNF | SPR_FPCSR_ZF | SPR_FPCSR_IXF | \ - SPR_FPCSR_IVF | SPR_FPCSR_INF | SPR_FPCSR_DZF) - -#define FPCSR_RM_RN (0<<1) -#define FPCSR_RM_RZ (1<<1) -#define FPCSR_RM_RIP (2<<1) -#define FPCSR_RM_RIN (3<<1) - -/* - * l.nop constants - * - */ -#define NOP_NOP 0x0000 /* Normal nop instruction */ -#define NOP_EXIT 0x0001 /* End of simulation */ -#define NOP_REPORT 0x0002 /* Simple report */ -/*#define NOP_PRINTF 0x0003 Simprintf instruction (obsolete)*/ -#define NOP_PUTC 0x0004 /* JPB: Simputc instruction */ -#define NOP_CNT_RESET 0x0005 /* Reset statistics counters */ -#define NOP_GET_TICKS 0x0006 /* JPB: Get # ticks running */ -#define NOP_GET_PS 0x0007 /* JPB: Get picosecs/cycle */ -#define NOP_REPORT_FIRST 0x0400 /* Report with number */ -#define NOP_REPORT_LAST 0x03ff /* Report with number */ - -#endif /* SPR_DEFS__H */ diff --git a/trunk/arch/openrisc/include/asm/syscall.h b/trunk/arch/openrisc/include/asm/syscall.h deleted file mode 100644 index 9f0337055d26..000000000000 --- a/trunk/arch/openrisc/include/asm/syscall.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * OpenRISC implementation: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * et al. - * - * 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 __ASM_OPENRISC_SYSCALL_H__ -#define __ASM_OPENRISC_SYSCALL_H__ - -#include -#include - -static inline int -syscall_get_nr(struct task_struct *task, struct pt_regs *regs) -{ - return regs->syscallno ? regs->syscallno : -1; -} - -static inline void -syscall_rollback(struct task_struct *task, struct pt_regs *regs) -{ - regs->gpr[11] = regs->orig_gpr11; -} - -static inline long -syscall_get_error(struct task_struct *task, struct pt_regs *regs) -{ - return IS_ERR_VALUE(regs->gpr[11]) ? regs->gpr[11] : 0; -} - -static inline long -syscall_get_return_value(struct task_struct *task, struct pt_regs *regs) -{ - return regs->gpr[11]; -} - -static inline void -syscall_set_return_value(struct task_struct *task, struct pt_regs *regs, - int error, long val) -{ - if (error) - regs->gpr[11] = -error; - else - regs->gpr[11] = val; -} - -static inline void -syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, - unsigned int i, unsigned int n, unsigned long *args) -{ - BUG_ON(i + n > 6); - - memcpy(args, ®s->gpr[3 + i], n * sizeof(args[0])); -} - -static inline void -syscall_set_arguments(struct task_struct *task, struct pt_regs *regs, - unsigned int i, unsigned int n, const unsigned long *args) -{ - BUG_ON(i + n > 6); - - memcpy(®s->gpr[3 + i], args, n * sizeof(args[0])); -} - -#endif diff --git a/trunk/arch/openrisc/include/asm/syscalls.h b/trunk/arch/openrisc/include/asm/syscalls.h deleted file mode 100644 index 84a978af44d7..000000000000 --- a/trunk/arch/openrisc/include/asm/syscalls.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * OpenRISC implementation: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * et al. - * - * 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 __ASM_OPENRISC_SYSCALLS_H -#define __ASM_OPENRISC_SYSCALLS_H - -asmlinkage long sys_or1k_atomic(unsigned long type, unsigned long *v1, - unsigned long *v2); - -#include - -#endif /* __ASM_OPENRISC_SYSCALLS_H */ diff --git a/trunk/arch/openrisc/include/asm/system.h b/trunk/arch/openrisc/include/asm/system.h deleted file mode 100644 index cf658882186b..000000000000 --- a/trunk/arch/openrisc/include/asm/system.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * OpenRISC implementation: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * et al. - * - * 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 __ASM_OPENRISC_SYSTEM_H -#define __ASM_OPENRISC_SYSTEM_H - -#ifdef __KERNEL__ -#ifndef __ASSEMBLY__ - -#include -#include - -/* We probably need this definition, but the generic system.h provides it - * and it's not used on our arch anyway... - */ -/*#define nop() __asm__ __volatile__ ("l.nop"::)*/ - -#endif /* __ASSEMBLY__ */ -#endif /* __KERNEL__ */ -#endif /* __ASM_OPENRISC_SYSTEM_H */ diff --git a/trunk/arch/openrisc/include/asm/thread_info.h b/trunk/arch/openrisc/include/asm/thread_info.h deleted file mode 100644 index 07a8bc080ef2..000000000000 --- a/trunk/arch/openrisc/include/asm/thread_info.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * OpenRISC implementation: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * et al. - * - * 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 _ASM_THREAD_INFO_H -#define _ASM_THREAD_INFO_H - -#ifdef __KERNEL__ - -#ifndef __ASSEMBLY__ -#include -#include -#endif - - -/* THREAD_SIZE is the size of the task_struct/kernel_stack combo. - * normally, the stack is found by doing something like p + THREAD_SIZE - * in or32, a page is 8192 bytes, which seems like a sane size - */ - -#define THREAD_SIZE_ORDER 0 -#define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER) - -/* - * low level task data that entry.S needs immediate access to - * - this struct should fit entirely inside of one cache line - * - this struct shares the supervisor stack pages - * - if the contents of this structure are changed, the assembly constants - * must also be changed - */ -#ifndef __ASSEMBLY__ - -typedef unsigned long mm_segment_t; - -struct thread_info { - struct task_struct *task; /* main task structure */ - struct exec_domain *exec_domain; /* execution domain */ - unsigned long flags; /* low level flags */ - __u32 cpu; /* current CPU */ - __s32 preempt_count; /* 0 => preemptable, <0 => BUG */ - - mm_segment_t addr_limit; /* thread address space: - 0-0x7FFFFFFF for user-thead - 0-0xFFFFFFFF for kernel-thread - */ - struct restart_block restart_block; - __u8 supervisor_stack[0]; - - /* saved context data */ - unsigned long ksp; -}; -#endif - -/* - * macros/functions for gaining access to the thread information structure - * - * preempt_count needs to be 1 initially, until the scheduler is functional. - */ -#ifndef __ASSEMBLY__ -#define INIT_THREAD_INFO(tsk) \ -{ \ - .task = &tsk, \ - .exec_domain = &default_exec_domain, \ - .flags = 0, \ - .cpu = 0, \ - .preempt_count = 1, \ - .addr_limit = KERNEL_DS, \ - .restart_block = { \ - .fn = do_no_restart_syscall, \ - }, \ - .ksp = 0, \ -} - -#define init_thread_info (init_thread_union.thread_info) - -/* how to get the thread information struct from C */ -register struct thread_info *current_thread_info_reg asm("r10"); -#define current_thread_info() (current_thread_info_reg) - -#define get_thread_info(ti) get_task_struct((ti)->task) -#define put_thread_info(ti) put_task_struct((ti)->task) - -#endif /* !__ASSEMBLY__ */ - -/* - * thread information flags - * these are process state flags that various assembly files may need to - * access - * - pending work-to-be-done flags are in LSW - * - other flags in MSW - */ -#define TIF_SYSCALL_TRACE 0 /* syscall trace active */ -#define TIF_NOTIFY_RESUME 1 /* resumption notification requested */ -#define TIF_SIGPENDING 2 /* signal pending */ -#define TIF_NEED_RESCHED 3 /* rescheduling necessary */ -#define TIF_SINGLESTEP 4 /* restore singlestep on return to user - * mode - */ -#define TIF_SYSCALL_TRACEPOINT 8 /* for ftrace syscall instrumentation */ -#define TIF_RESTORE_SIGMASK 9 -#define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling * TIF_NEED_RESCHED - */ -#define TIF_MEMDIE 17 - -#define _TIF_SYSCALL_TRACE (1< - * - * 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 __ASM_OPENRISC_TIMEX_H -#define __ASM_OPENRISC_TIMEX_H - -#define get_cycles get_cycles - -#include -#include -#include - -static inline cycles_t get_cycles(void) -{ - return mfspr(SPR_TTCR); -} - -/* This isn't really used any more */ -#define CLOCK_TICK_RATE 1000 - -#define ARCH_HAS_READ_CURRENT_TIMER - -#endif diff --git a/trunk/arch/openrisc/include/asm/tlb.h b/trunk/arch/openrisc/include/asm/tlb.h deleted file mode 100644 index fa4376a4515d..000000000000 --- a/trunk/arch/openrisc/include/asm/tlb.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * OpenRISC implementation: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * et al. - * - * 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 __ASM_OPENRISC_TLB_H__ -#define __ASM_OPENRISC_TLB_H__ - -/* - * or32 doesn't need any special per-pte or - * per-vma handling.. - */ -#define tlb_start_vma(tlb, vma) do { } while (0) -#define tlb_end_vma(tlb, vma) do { } while (0) -#define __tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0) - -#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm) -#include -#include - -#endif /* __ASM_OPENRISC_TLB_H__ */ diff --git a/trunk/arch/openrisc/include/asm/tlbflush.h b/trunk/arch/openrisc/include/asm/tlbflush.h deleted file mode 100644 index 6a2accd6cb67..000000000000 --- a/trunk/arch/openrisc/include/asm/tlbflush.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * OpenRISC implementation: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * et al. - * - * 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 __ASM_OPENRISC_TLBFLUSH_H -#define __ASM_OPENRISC_TLBFLUSH_H - -#include -#include -#include -#include -#include -#include - -/* - * - flush_tlb() flushes the current mm struct TLBs - * - flush_tlb_all() flushes all processes TLBs - * - flush_tlb_mm(mm) flushes the specified mm context TLB's - * - flush_tlb_page(vma, vmaddr) flushes one page - * - flush_tlb_range(mm, start, end) flushes a range of pages - */ - -void flush_tlb_all(void); -void flush_tlb_mm(struct mm_struct *mm); -void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr); -void flush_tlb_range(struct vm_area_struct *vma, - unsigned long start, - unsigned long end); - -static inline void flush_tlb(void) -{ - flush_tlb_mm(current->mm); -} - -static inline void flush_tlb_kernel_range(unsigned long start, - unsigned long end) -{ - flush_tlb_range(NULL, start, end); -} - -#endif /* __ASM_OPENRISC_TLBFLUSH_H */ diff --git a/trunk/arch/openrisc/include/asm/uaccess.h b/trunk/arch/openrisc/include/asm/uaccess.h deleted file mode 100644 index c310e45b538e..000000000000 --- a/trunk/arch/openrisc/include/asm/uaccess.h +++ /dev/null @@ -1,355 +0,0 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * OpenRISC implementation: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * et al. - * - * 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 __ASM_OPENRISC_UACCESS_H -#define __ASM_OPENRISC_UACCESS_H - -/* - * User space memory access functions - */ -#include -#include -#include -#include -#include -#include - -#define VERIFY_READ 0 -#define VERIFY_WRITE 1 - -/* - * The fs value determines whether argument validity checking should be - * performed or not. If get_fs() == USER_DS, checking is performed, with - * get_fs() == KERNEL_DS, checking is bypassed. - * - * For historical reasons, these macros are grossly misnamed. - */ - -/* addr_limit is the maximum accessible address for the task. we misuse - * the KERNEL_DS and USER_DS values to both assign and compare the - * addr_limit values through the equally misnamed get/set_fs macros. - * (see above) - */ - -#define KERNEL_DS (~0UL) -#define get_ds() (KERNEL_DS) - -#define USER_DS (TASK_SIZE) -#define get_fs() (current_thread_info()->addr_limit) -#define set_fs(x) (current_thread_info()->addr_limit = (x)) - -#define segment_eq(a, b) ((a) == (b)) - -/* Ensure that the range from addr to addr+size is all within the process' - * address space - */ -#define __range_ok(addr, size) (size <= get_fs() && addr <= (get_fs()-size)) - -/* Ensure that addr is below task's addr_limit */ -#define __addr_ok(addr) ((unsigned long) addr < get_fs()) - -#define access_ok(type, addr, size) \ - __range_ok((unsigned long)addr, (unsigned long)size) - -/* - * The exception table consists of pairs of addresses: the first is the - * address of an instruction that is allowed to fault, and the second is - * the address at which the program should continue. No registers are - * modified, so it is entirely up to the continuation code to figure out - * what to do. - * - * All the routines below use bits of fixup code that are out of line - * with the main instruction path. This means when everything is well, - * we don't even have to jump over them. Further, they do not intrude - * on our cache or tlb entries. - */ - -struct exception_table_entry { - unsigned long insn, fixup; -}; - -/* Returns 0 if exception not found and fixup otherwise. */ -extern unsigned long search_exception_table(unsigned long); -extern void sort_exception_table(void); - -/* - * These are the main single-value transfer routines. They automatically - * use the right size if we just have the right pointer type. - * - * This gets kind of ugly. We want to return _two_ values in "get_user()" - * and yet we don't want to do any pointers, because that is too much - * of a performance impact. Thus we have a few rather ugly macros here, - * and hide all the uglyness from the user. - * - * The "__xxx" versions of the user access functions are versions that - * do not verify the address space, that must have been done previously - * with a separate "access_ok()" call (this is used when we do multiple - * accesses to the same area of user memory). - * - * As we use the same address space for kernel and user data on the - * PowerPC, we can just do these as direct assignments. (Of course, the - * exception handling means that it's no longer "just"...) - */ -#define get_user(x, ptr) \ - __get_user_check((x), (ptr), sizeof(*(ptr))) -#define put_user(x, ptr) \ - __put_user_check((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr))) - -#define __get_user(x, ptr) \ - __get_user_nocheck((x), (ptr), sizeof(*(ptr))) -#define __put_user(x, ptr) \ - __put_user_nocheck((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr))) - -extern long __put_user_bad(void); - -#define __put_user_nocheck(x, ptr, size) \ -({ \ - long __pu_err; \ - __put_user_size((x), (ptr), (size), __pu_err); \ - __pu_err; \ -}) - -#define __put_user_check(x, ptr, size) \ -({ \ - long __pu_err = -EFAULT; \ - __typeof__(*(ptr)) *__pu_addr = (ptr); \ - if (access_ok(VERIFY_WRITE, __pu_addr, size)) \ - __put_user_size((x), __pu_addr, (size), __pu_err); \ - __pu_err; \ -}) - -#define __put_user_size(x, ptr, size, retval) \ -do { \ - retval = 0; \ - switch (size) { \ - case 1: __put_user_asm(x, ptr, retval, "l.sb"); break; \ - case 2: __put_user_asm(x, ptr, retval, "l.sh"); break; \ - case 4: __put_user_asm(x, ptr, retval, "l.sw"); break; \ - case 8: __put_user_asm2(x, ptr, retval); break; \ - default: __put_user_bad(); \ - } \ -} while (0) - -struct __large_struct { - unsigned long buf[100]; -}; -#define __m(x) (*(struct __large_struct *)(x)) - -/* - * We don't tell gcc that we are accessing memory, but this is OK - * because we do not write to any memory gcc knows about, so there - * are no aliasing issues. - */ -#define __put_user_asm(x, addr, err, op) \ - __asm__ __volatile__( \ - "1: "op" 0(%2),%1\n" \ - "2:\n" \ - ".section .fixup,\"ax\"\n" \ - "3: l.addi %0,r0,%3\n" \ - " l.j 2b\n" \ - " l.nop\n" \ - ".previous\n" \ - ".section __ex_table,\"a\"\n" \ - " .align 2\n" \ - " .long 1b,3b\n" \ - ".previous" \ - : "=r"(err) \ - : "r"(x), "r"(addr), "i"(-EFAULT), "0"(err)) - -#define __put_user_asm2(x, addr, err) \ - __asm__ __volatile__( \ - "1: l.sw 0(%2),%1\n" \ - "2: l.sw 4(%2),%H1\n" \ - "3:\n" \ - ".section .fixup,\"ax\"\n" \ - "4: l.addi %0,r0,%3\n" \ - " l.j 3b\n" \ - " l.nop\n" \ - ".previous\n" \ - ".section __ex_table,\"a\"\n" \ - " .align 2\n" \ - " .long 1b,4b\n" \ - " .long 2b,4b\n" \ - ".previous" \ - : "=r"(err) \ - : "r"(x), "r"(addr), "i"(-EFAULT), "0"(err)) - -#define __get_user_nocheck(x, ptr, size) \ -({ \ - long __gu_err, __gu_val; \ - __get_user_size(__gu_val, (ptr), (size), __gu_err); \ - (x) = (__typeof__(*(ptr)))__gu_val; \ - __gu_err; \ -}) - -#define __get_user_check(x, ptr, size) \ -({ \ - long __gu_err = -EFAULT, __gu_val = 0; \ - const __typeof__(*(ptr)) * __gu_addr = (ptr); \ - if (access_ok(VERIFY_READ, __gu_addr, size)) \ - __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \ - (x) = (__typeof__(*(ptr)))__gu_val; \ - __gu_err; \ -}) - -extern long __get_user_bad(void); - -#define __get_user_size(x, ptr, size, retval) \ -do { \ - retval = 0; \ - switch (size) { \ - case 1: __get_user_asm(x, ptr, retval, "l.lbz"); break; \ - case 2: __get_user_asm(x, ptr, retval, "l.lhz"); break; \ - case 4: __get_user_asm(x, ptr, retval, "l.lwz"); break; \ - case 8: __get_user_asm2(x, ptr, retval); \ - default: (x) = __get_user_bad(); \ - } \ -} while (0) - -#define __get_user_asm(x, addr, err, op) \ - __asm__ __volatile__( \ - "1: "op" %1,0(%2)\n" \ - "2:\n" \ - ".section .fixup,\"ax\"\n" \ - "3: l.addi %0,r0,%3\n" \ - " l.addi %1,r0,0\n" \ - " l.j 2b\n" \ - " l.nop\n" \ - ".previous\n" \ - ".section __ex_table,\"a\"\n" \ - " .align 2\n" \ - " .long 1b,3b\n" \ - ".previous" \ - : "=r"(err), "=r"(x) \ - : "r"(addr), "i"(-EFAULT), "0"(err)) - -#define __get_user_asm2(x, addr, err) \ - __asm__ __volatile__( \ - "1: l.lwz %1,0(%2)\n" \ - "2: l.lwz %H1,4(%2)\n" \ - "3:\n" \ - ".section .fixup,\"ax\"\n" \ - "4: l.addi %0,r0,%3\n" \ - " l.addi %1,r0,0\n" \ - " l.addi %H1,r0,0\n" \ - " l.j 3b\n" \ - " l.nop\n" \ - ".previous\n" \ - ".section __ex_table,\"a\"\n" \ - " .align 2\n" \ - " .long 1b,4b\n" \ - " .long 2b,4b\n" \ - ".previous" \ - : "=r"(err), "=&r"(x) \ - : "r"(addr), "i"(-EFAULT), "0"(err)) - -/* more complex routines */ - -extern unsigned long __must_check -__copy_tofrom_user(void *to, const void *from, unsigned long size); - -#define __copy_from_user(to, from, size) \ - __copy_tofrom_user(to, from, size) -#define __copy_to_user(to, from, size) \ - __copy_tofrom_user(to, from, size) - -#define __copy_to_user_inatomic __copy_to_user -#define __copy_from_user_inatomic __copy_from_user - -static inline unsigned long -copy_from_user(void *to, const void *from, unsigned long n) -{ - unsigned long over; - - if (access_ok(VERIFY_READ, from, n)) - return __copy_tofrom_user(to, from, n); - if ((unsigned long)from < TASK_SIZE) { - over = (unsigned long)from + n - TASK_SIZE; - return __copy_tofrom_user(to, from, n - over) + over; - } - return n; -} - -static inline unsigned long -copy_to_user(void *to, const void *from, unsigned long n) -{ - unsigned long over; - - if (access_ok(VERIFY_WRITE, to, n)) - return __copy_tofrom_user(to, from, n); - if ((unsigned long)to < TASK_SIZE) { - over = (unsigned long)to + n - TASK_SIZE; - return __copy_tofrom_user(to, from, n - over) + over; - } - return n; -} - -extern unsigned long __clear_user(void *addr, unsigned long size); - -static inline __must_check unsigned long -clear_user(void *addr, unsigned long size) -{ - - if (access_ok(VERIFY_WRITE, addr, size)) - return __clear_user(addr, size); - if ((unsigned long)addr < TASK_SIZE) { - unsigned long over = (unsigned long)addr + size - TASK_SIZE; - return __clear_user(addr, size - over) + over; - } - return size; -} - -extern int __strncpy_from_user(char *dst, const char *src, long count); - -static inline long strncpy_from_user(char *dst, const char *src, long count) -{ - if (access_ok(VERIFY_READ, src, 1)) - return __strncpy_from_user(dst, src, count); - return -EFAULT; -} - -/* - * Return the size of a string (including the ending 0) - * - * Return 0 for error - */ - -extern int __strnlen_user(const char *str, long len, unsigned long top); - -/* - * Returns the length of the string at str (including the null byte), - * or 0 if we hit a page we can't access, - * or something > len if we didn't find a null byte. - * - * The `top' parameter to __strnlen_user is to make sure that - * we can never overflow from the user area into kernel space. - */ -static inline long strnlen_user(const char __user *str, long len) -{ - unsigned long top = (unsigned long)get_fs(); - unsigned long res = 0; - - if (__addr_ok(str)) - res = __strnlen_user(str, len, top); - - return res; -} - -#define strlen_user(str) strnlen_user(str, TASK_SIZE-1) - -#endif /* __ASM_OPENRISC_UACCESS_H */ diff --git a/trunk/arch/openrisc/include/asm/unaligned.h b/trunk/arch/openrisc/include/asm/unaligned.h deleted file mode 100644 index 1141cbd6fd72..000000000000 --- a/trunk/arch/openrisc/include/asm/unaligned.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * OpenRISC implementation: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * et al. - * - * 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 __ASM_OPENRISC_UNALIGNED_H -#define __ASM_OPENRISC_UNALIGNED_H - -/* - * This is copied from the generic implementation and the C-struct - * variant replaced with the memmove variant. The GCC compiler - * for the OR32 arch optimizes too aggressively for the C-struct - * variant to work, so use the memmove variant instead. - * - * It may be worth considering implementing the unaligned access - * exception handler and allowing unaligned accesses (access_ok.h)... - * not sure if it would be much of a performance win without further - * investigation. - */ -#include - -#if defined(__LITTLE_ENDIAN) -# include -# include -# include -# define get_unaligned __get_unaligned_le -# define put_unaligned __put_unaligned_le -#elif defined(__BIG_ENDIAN) -# include -# include -# include -# define get_unaligned __get_unaligned_be -# define put_unaligned __put_unaligned_be -#else -# error need to define endianess -#endif - -#endif /* __ASM_OPENRISC_UNALIGNED_H */ diff --git a/trunk/arch/openrisc/include/asm/unistd.h b/trunk/arch/openrisc/include/asm/unistd.h deleted file mode 100644 index 89af3ab5c2e9..000000000000 --- a/trunk/arch/openrisc/include/asm/unistd.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * OpenRISC implementation: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * et al. - * - * 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. - */ - -#if !defined(__ASM_OPENRISC_UNISTD_H) || defined(__SYSCALL) -#define __ASM_OPENRISC_UNISTD_H - -#define __ARCH_HAVE_MMU - -#define sys_mmap2 sys_mmap_pgoff - -#include - -#define __NR_or1k_atomic __NR_arch_specific_syscall -__SYSCALL(__NR_or1k_atomic, sys_or1k_atomic) - -#endif /* __ASM_OPENRISC_UNISTD_H */ diff --git a/trunk/arch/openrisc/kernel/Makefile b/trunk/arch/openrisc/kernel/Makefile deleted file mode 100644 index 9a4c2706d795..000000000000 --- a/trunk/arch/openrisc/kernel/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# -# Makefile for the linux kernel. -# - -extra-y := head.o vmlinux.lds init_task.o - -obj-y := setup.o idle.o or32_ksyms.o process.o dma.o \ - traps.o time.o irq.o entry.o ptrace.o signal.o sys_or32.o \ - sys_call_table.o - -obj-$(CONFIG_MODULES) += module.o -obj-$(CONFIG_OF) += prom.o - -clean: diff --git a/trunk/arch/openrisc/kernel/asm-offsets.c b/trunk/arch/openrisc/kernel/asm-offsets.c deleted file mode 100644 index 1a242a0d7583..000000000000 --- a/trunk/arch/openrisc/kernel/asm-offsets.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * OpenRISC asm-offsets.c - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * Modifications for the OpenRISC architecture: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * - * 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 used to generate definitions needed by - * assembly language modules. - * - * We use the technique used in the OSF Mach kernel code: - * generate asm statements containing #defines, - * compile this file to assembler, and then extract the - * #defines from the assembly-language output. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DEFINE(sym, val) \ - asm volatile("\n->" #sym " %0 " #val : : "i" (val)) - -#define BLANK() asm volatile("\n->" : : ) - -int main(void) -{ - /* offsets into the task_struct */ - DEFINE(TASK_STATE, offsetof(struct task_struct, state)); - DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags)); - DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace)); - DEFINE(TASK_THREAD, offsetof(struct task_struct, thread)); - DEFINE(TASK_MM, offsetof(struct task_struct, mm)); - DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm)); - - /* offsets into thread_info */ - DEFINE(TI_TASK, offsetof(struct thread_info, task)); - DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); - DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count)); - DEFINE(TI_KSP, offsetof(struct thread_info, ksp)); - - DEFINE(PT_SIZE, sizeof(struct pt_regs)); - - /* Interrupt register frame */ - DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD); - DEFINE(INT_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs)); - - DEFINE(NUM_USER_SEGMENTS, TASK_SIZE >> 28); - return 0; -} diff --git a/trunk/arch/openrisc/kernel/dma.c b/trunk/arch/openrisc/kernel/dma.c deleted file mode 100644 index 968d3ee477e3..000000000000 --- a/trunk/arch/openrisc/kernel/dma.c +++ /dev/null @@ -1,191 +0,0 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * Modifications for the OpenRISC architecture: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * - * 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. - * - * DMA mapping callbacks... - * As alloc_coherent is the only DMA callback being used currently, that's - * the only thing implemented properly. The rest need looking into... - */ - -#include -#include - -#include -#include -#include - -static int page_set_nocache(pte_t *pte, unsigned long addr, - unsigned long next, struct mm_walk *walk) -{ - unsigned long cl; - - pte_val(*pte) |= _PAGE_CI; - - /* - * Flush the page out of the TLB so that the new page flags get - * picked up next time there's an access - */ - flush_tlb_page(NULL, addr); - - /* Flush page out of dcache */ - for (cl = __pa(addr); cl < __pa(next); cl += cpuinfo.dcache_block_size) - mtspr(SPR_DCBFR, cl); - - return 0; -} - -static int page_clear_nocache(pte_t *pte, unsigned long addr, - unsigned long next, struct mm_walk *walk) -{ - pte_val(*pte) &= ~_PAGE_CI; - - /* - * Flush the page out of the TLB so that the new page flags get - * picked up next time there's an access - */ - flush_tlb_page(NULL, addr); - - return 0; -} - -/* - * Alloc "coherent" memory, which for OpenRISC means simply uncached. - * - * This function effectively just calls __get_free_pages, sets the - * cache-inhibit bit on those pages, and makes sure that the pages are - * flushed out of the cache before they are used. - * - */ -void *or1k_dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t gfp) -{ - unsigned long va; - void *page; - struct mm_walk walk = { - .pte_entry = page_set_nocache, - .mm = &init_mm - }; - - page = alloc_pages_exact(size, gfp); - if (!page) - return NULL; - - /* This gives us the real physical address of the first page. */ - *dma_handle = __pa(page); - - va = (unsigned long)page; - - /* - * We need to iterate through the pages, clearing the dcache for - * them and setting the cache-inhibit bit. - */ - if (walk_page_range(va, va + size, &walk)) { - free_pages_exact(page, size); - return NULL; - } - - return (void *)va; -} - -void or1k_dma_free_coherent(struct device *dev, size_t size, void *vaddr, - dma_addr_t dma_handle) -{ - unsigned long va = (unsigned long)vaddr; - struct mm_walk walk = { - .pte_entry = page_clear_nocache, - .mm = &init_mm - }; - - /* walk_page_range shouldn't be able to fail here */ - WARN_ON(walk_page_range(va, va + size, &walk)); - - free_pages_exact(vaddr, size); -} - -dma_addr_t or1k_map_page(struct device *dev, struct page *page, - unsigned long offset, size_t size, - enum dma_data_direction dir, - struct dma_attrs *attrs) -{ - unsigned long cl; - dma_addr_t addr = page_to_phys(page) + offset; - - switch (dir) { - case DMA_TO_DEVICE: - /* Flush the dcache for the requested range */ - for (cl = addr; cl < addr + size; - cl += cpuinfo.dcache_block_size) - mtspr(SPR_DCBFR, cl); - break; - case DMA_FROM_DEVICE: - /* Invalidate the dcache for the requested range */ - for (cl = addr; cl < addr + size; - cl += cpuinfo.dcache_block_size) - mtspr(SPR_DCBIR, cl); - break; - default: - /* - * NOTE: If dir == DMA_BIDIRECTIONAL then there's no need to - * flush nor invalidate the cache here as the area will need - * to be manually synced anyway. - */ - break; - } - - return addr; -} - -void or1k_unmap_page(struct device *dev, dma_addr_t dma_handle, - size_t size, enum dma_data_direction dir, - struct dma_attrs *attrs) -{ - /* Nothing special to do here... */ -} - -void or1k_sync_single_for_cpu(struct device *dev, - dma_addr_t dma_handle, size_t size, - enum dma_data_direction dir) -{ - unsigned long cl; - dma_addr_t addr = dma_handle; - - /* Invalidate the dcache for the requested range */ - for (cl = addr; cl < addr + size; cl += cpuinfo.dcache_block_size) - mtspr(SPR_DCBIR, cl); -} - -void or1k_sync_single_for_device(struct device *dev, - dma_addr_t dma_handle, size_t size, - enum dma_data_direction dir) -{ - unsigned long cl; - dma_addr_t addr = dma_handle; - - /* Flush the dcache for the requested range */ - for (cl = addr; cl < addr + size; cl += cpuinfo.dcache_block_size) - mtspr(SPR_DCBFR, cl); -} - -/* Number of entries preallocated for DMA-API debugging */ -#define PREALLOC_DMA_DEBUG_ENTRIES (1 << 16) - -static int __init dma_init(void) -{ - dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES); - - return 0; -} - -fs_initcall(dma_init); diff --git a/trunk/arch/openrisc/kernel/entry.S b/trunk/arch/openrisc/kernel/entry.S deleted file mode 100644 index d5f9c35a583f..000000000000 --- a/trunk/arch/openrisc/kernel/entry.S +++ /dev/null @@ -1,1128 +0,0 @@ -/* - * OpenRISC entry.S - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * Modifications for the OpenRISC architecture: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2005 Gyorgy Jeney - * Copyright (C) 2010-2011 Jonas Bonn - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DISABLE_INTERRUPTS(t1,t2) \ - l.mfspr t2,r0,SPR_SR ;\ - l.movhi t1,hi(~(SPR_SR_IEE|SPR_SR_TEE)) ;\ - l.ori t1,t1,lo(~(SPR_SR_IEE|SPR_SR_TEE)) ;\ - l.and t2,t2,t1 ;\ - l.mtspr r0,t2,SPR_SR - -#define ENABLE_INTERRUPTS(t1) \ - l.mfspr t1,r0,SPR_SR ;\ - l.ori t1,t1,lo(SPR_SR_IEE|SPR_SR_TEE) ;\ - l.mtspr r0,t1,SPR_SR - -/* =========================================================[ macros ]=== */ - -/* - * We need to disable interrupts at beginning of RESTORE_ALL - * since interrupt might come in after we've loaded EPC return address - * and overwrite EPC with address somewhere in RESTORE_ALL - * which is of course wrong! - */ - -#define RESTORE_ALL \ - DISABLE_INTERRUPTS(r3,r4) ;\ - l.lwz r3,PT_PC(r1) ;\ - l.mtspr r0,r3,SPR_EPCR_BASE ;\ - l.lwz r3,PT_SR(r1) ;\ - l.mtspr r0,r3,SPR_ESR_BASE ;\ - l.lwz r2,PT_GPR2(r1) ;\ - l.lwz r3,PT_GPR3(r1) ;\ - l.lwz r4,PT_GPR4(r1) ;\ - l.lwz r5,PT_GPR5(r1) ;\ - l.lwz r6,PT_GPR6(r1) ;\ - l.lwz r7,PT_GPR7(r1) ;\ - l.lwz r8,PT_GPR8(r1) ;\ - l.lwz r9,PT_GPR9(r1) ;\ - l.lwz r10,PT_GPR10(r1) ;\ - l.lwz r11,PT_GPR11(r1) ;\ - l.lwz r12,PT_GPR12(r1) ;\ - l.lwz r13,PT_GPR13(r1) ;\ - l.lwz r14,PT_GPR14(r1) ;\ - l.lwz r15,PT_GPR15(r1) ;\ - l.lwz r16,PT_GPR16(r1) ;\ - l.lwz r17,PT_GPR17(r1) ;\ - l.lwz r18,PT_GPR18(r1) ;\ - l.lwz r19,PT_GPR19(r1) ;\ - l.lwz r20,PT_GPR20(r1) ;\ - l.lwz r21,PT_GPR21(r1) ;\ - l.lwz r22,PT_GPR22(r1) ;\ - l.lwz r23,PT_GPR23(r1) ;\ - l.lwz r24,PT_GPR24(r1) ;\ - l.lwz r25,PT_GPR25(r1) ;\ - l.lwz r26,PT_GPR26(r1) ;\ - l.lwz r27,PT_GPR27(r1) ;\ - l.lwz r28,PT_GPR28(r1) ;\ - l.lwz r29,PT_GPR29(r1) ;\ - l.lwz r30,PT_GPR30(r1) ;\ - l.lwz r31,PT_GPR31(r1) ;\ - l.lwz r1,PT_SP(r1) ;\ - l.rfe - - -#define EXCEPTION_ENTRY(handler) \ - .global handler ;\ -handler: ;\ - /* r1, EPCR, ESR a already saved */ ;\ - l.sw PT_GPR2(r1),r2 ;\ - l.sw PT_GPR3(r1),r3 ;\ - l.sw PT_ORIG_GPR11(r1),r11 ;\ - /* r4 already save */ ;\ - l.sw PT_GPR5(r1),r5 ;\ - l.sw PT_GPR6(r1),r6 ;\ - l.sw PT_GPR7(r1),r7 ;\ - l.sw PT_GPR8(r1),r8 ;\ - l.sw PT_GPR9(r1),r9 ;\ - /* r10 already saved */ ;\ - l.sw PT_GPR11(r1),r11 ;\ - /* r12 already saved */ ;\ - l.sw PT_GPR13(r1),r13 ;\ - l.sw PT_GPR14(r1),r14 ;\ - l.sw PT_GPR15(r1),r15 ;\ - l.sw PT_GPR16(r1),r16 ;\ - l.sw PT_GPR17(r1),r17 ;\ - l.sw PT_GPR18(r1),r18 ;\ - l.sw PT_GPR19(r1),r19 ;\ - l.sw PT_GPR20(r1),r20 ;\ - l.sw PT_GPR21(r1),r21 ;\ - l.sw PT_GPR22(r1),r22 ;\ - l.sw PT_GPR23(r1),r23 ;\ - l.sw PT_GPR24(r1),r24 ;\ - l.sw PT_GPR25(r1),r25 ;\ - l.sw PT_GPR26(r1),r26 ;\ - l.sw PT_GPR27(r1),r27 ;\ - l.sw PT_GPR28(r1),r28 ;\ - l.sw PT_GPR29(r1),r29 ;\ - /* r30 already save */ ;\ -/* l.sw PT_GPR30(r1),r30*/ ;\ - l.sw PT_GPR31(r1),r31 ;\ - l.sw PT_SYSCALLNO(r1),r0 - -#define UNHANDLED_EXCEPTION(handler,vector) \ - .global handler ;\ -handler: ;\ - /* r1, EPCR, ESR already saved */ ;\ - l.sw PT_GPR2(r1),r2 ;\ - l.sw PT_GPR3(r1),r3 ;\ - l.sw PT_ORIG_GPR11(r1),r11 ;\ - l.sw PT_GPR5(r1),r5 ;\ - l.sw PT_GPR6(r1),r6 ;\ - l.sw PT_GPR7(r1),r7 ;\ - l.sw PT_GPR8(r1),r8 ;\ - l.sw PT_GPR9(r1),r9 ;\ - /* r10 already saved */ ;\ - l.sw PT_GPR11(r1),r11 ;\ - /* r12 already saved */ ;\ - l.sw PT_GPR13(r1),r13 ;\ - l.sw PT_GPR14(r1),r14 ;\ - l.sw PT_GPR15(r1),r15 ;\ - l.sw PT_GPR16(r1),r16 ;\ - l.sw PT_GPR17(r1),r17 ;\ - l.sw PT_GPR18(r1),r18 ;\ - l.sw PT_GPR19(r1),r19 ;\ - l.sw PT_GPR20(r1),r20 ;\ - l.sw PT_GPR21(r1),r21 ;\ - l.sw PT_GPR22(r1),r22 ;\ - l.sw PT_GPR23(r1),r23 ;\ - l.sw PT_GPR24(r1),r24 ;\ - l.sw PT_GPR25(r1),r25 ;\ - l.sw PT_GPR26(r1),r26 ;\ - l.sw PT_GPR27(r1),r27 ;\ - l.sw PT_GPR28(r1),r28 ;\ - l.sw PT_GPR29(r1),r29 ;\ - /* r31 already saved */ ;\ - l.sw PT_GPR30(r1),r30 ;\ -/* l.sw PT_GPR31(r1),r31 */ ;\ - l.sw PT_SYSCALLNO(r1),r0 ;\ - l.addi r3,r1,0 ;\ - /* r4 is exception EA */ ;\ - l.addi r5,r0,vector ;\ - l.jal unhandled_exception ;\ - l.nop ;\ - l.j _ret_from_exception ;\ - l.nop - -/* - * NOTE: one should never assume that SPR_EPC, SPR_ESR, SPR_EEAR - * contain the same values as when exception we're handling - * occured. in fact they never do. if you need them use - * values saved on stack (for SPR_EPC, SPR_ESR) or content - * of r4 (for SPR_EEAR). for details look at EXCEPTION_HANDLE() - * in 'arch/or32/kernel/head.S' - */ - -/* =====================================================[ exceptions] === */ - -/* ---[ 0x100: RESET exception ]----------------------------------------- */ - -EXCEPTION_ENTRY(_tng_kernel_start) - l.jal _start - l.andi r0,r0,0 - -/* ---[ 0x200: BUS exception ]------------------------------------------- */ - -EXCEPTION_ENTRY(_bus_fault_handler) - /* r4: EA of fault (set by EXCEPTION_HANDLE) */ - l.jal do_bus_fault - l.addi r3,r1,0 /* pt_regs */ - - l.j _ret_from_exception - l.nop - -/* ---[ 0x300: Data Page Fault exception ]------------------------------- */ - -EXCEPTION_ENTRY(_data_page_fault_handler) - /* set up parameters for do_page_fault */ - l.addi r3,r1,0 // pt_regs - /* r4 set be EXCEPTION_HANDLE */ // effective address of fault - l.ori r5,r0,0x300 // exception vector - - /* - * __PHX__: TODO - * - * all this can be written much simpler. look at - * DTLB miss handler in the CONFIG_GUARD_PROTECTED_CORE part - */ -#ifdef CONFIG_OPENRISC_NO_SPR_SR_DSX - l.lwz r6,PT_PC(r3) // address of an offending insn - l.lwz r6,0(r6) // instruction that caused pf - - l.srli r6,r6,26 // check opcode for jump insn - l.sfeqi r6,0 // l.j - l.bf 8f - l.sfeqi r6,1 // l.jal - l.bf 8f - l.sfeqi r6,3 // l.bnf - l.bf 8f - l.sfeqi r6,4 // l.bf - l.bf 8f - l.sfeqi r6,0x11 // l.jr - l.bf 8f - l.sfeqi r6,0x12 // l.jalr - l.bf 8f - - l.nop - - l.j 9f - l.nop -8: - - l.lwz r6,PT_PC(r3) // address of an offending insn - l.addi r6,r6,4 - l.lwz r6,0(r6) // instruction that caused pf - l.srli r6,r6,26 // get opcode -9: - -#else - - l.mfspr r6,r0,SPR_SR // SR -// l.lwz r6,PT_SR(r3) // ESR - l.andi r6,r6,SPR_SR_DSX // check for delay slot exception - l.sfeqi r6,0x1 // exception happened in delay slot - l.bnf 7f - l.lwz r6,PT_PC(r3) // address of an offending insn - - l.addi r6,r6,4 // offending insn is in delay slot -7: - l.lwz r6,0(r6) // instruction that caused pf - l.srli r6,r6,26 // check opcode for write access -#endif - - l.sfgeui r6,0x34 // check opcode for write access - l.bnf 1f - l.sfleui r6,0x37 - l.bnf 1f - l.ori r6,r0,0x1 // write access - l.j 2f - l.nop -1: l.ori r6,r0,0x0 // !write access -2: - - /* call fault.c handler in or32/mm/fault.c */ - l.jal do_page_fault - l.nop - l.j _ret_from_exception - l.nop - -/* ---[ 0x400: Insn Page Fault exception ]------------------------------- */ - -EXCEPTION_ENTRY(_insn_page_fault_handler) - /* set up parameters for do_page_fault */ - l.addi r3,r1,0 // pt_regs - /* r4 set be EXCEPTION_HANDLE */ // effective address of fault - l.ori r5,r0,0x400 // exception vector - l.ori r6,r0,0x0 // !write access - - /* call fault.c handler in or32/mm/fault.c */ - l.jal do_page_fault - l.nop - l.j _ret_from_exception - l.nop - - -/* ---[ 0x500: Timer exception ]----------------------------------------- */ - -EXCEPTION_ENTRY(_timer_handler) - l.jal timer_interrupt - l.addi r3,r1,0 /* pt_regs */ - - l.j _ret_from_intr - l.nop - -/* ---[ 0x600: Aligment exception ]-------------------------------------- */ - -EXCEPTION_ENTRY(_alignment_handler) - /* r4: EA of fault (set by EXCEPTION_HANDLE) */ - l.jal do_unaligned_access - l.addi r3,r1,0 /* pt_regs */ - - l.j _ret_from_exception - l.nop - -#if 0 -EXCEPTION_ENTRY(_aligment_handler) -// l.mfspr r2,r0,SPR_EEAR_BASE /* Load the efective addres */ - l.addi r2,r4,0 -// l.mfspr r5,r0,SPR_EPCR_BASE /* Load the insn address */ - l.lwz r5,PT_PC(r1) - - l.lwz r3,0(r5) /* Load insn */ - l.srli r4,r3,26 /* Shift left to get the insn opcode */ - - l.sfeqi r4,0x00 /* Check if the load/store insn is in delay slot */ - l.bf jmp - l.sfeqi r4,0x01 - l.bf jmp - l.sfeqi r4,0x03 - l.bf jmp - l.sfeqi r4,0x04 - l.bf jmp - l.sfeqi r4,0x11 - l.bf jr - l.sfeqi r4,0x12 - l.bf jr - l.nop - l.j 1f - l.addi r5,r5,4 /* Increment PC to get return insn address */ - -jmp: - l.slli r4,r3,6 /* Get the signed extended jump length */ - l.srai r4,r4,4 - - l.lwz r3,4(r5) /* Load the real load/store insn */ - - l.add r5,r5,r4 /* Calculate jump target address */ - - l.j 1f - l.srli r4,r3,26 /* Shift left to get the insn opcode */ - -jr: - l.slli r4,r3,9 /* Shift to get the reg nb */ - l.andi r4,r4,0x7c - - l.lwz r3,4(r5) /* Load the real load/store insn */ - - l.add r4,r4,r1 /* Load the jump register value from the stack */ - l.lwz r5,0(r4) - - l.srli r4,r3,26 /* Shift left to get the insn opcode */ - - -1: -// l.mtspr r0,r5,SPR_EPCR_BASE - l.sw PT_PC(r1),r5 - - l.sfeqi r4,0x26 - l.bf lhs - l.sfeqi r4,0x25 - l.bf lhz - l.sfeqi r4,0x22 - l.bf lws - l.sfeqi r4,0x21 - l.bf lwz - l.sfeqi r4,0x37 - l.bf sh - l.sfeqi r4,0x35 - l.bf sw - l.nop - -1: l.j 1b /* I don't know what to do */ - l.nop - -lhs: l.lbs r5,0(r2) - l.slli r5,r5,8 - l.lbz r6,1(r2) - l.or r5,r5,r6 - l.srli r4,r3,19 - l.andi r4,r4,0x7c - l.add r4,r4,r1 - l.j align_end - l.sw 0(r4),r5 - -lhz: l.lbz r5,0(r2) - l.slli r5,r5,8 - l.lbz r6,1(r2) - l.or r5,r5,r6 - l.srli r4,r3,19 - l.andi r4,r4,0x7c - l.add r4,r4,r1 - l.j align_end - l.sw 0(r4),r5 - -lws: l.lbs r5,0(r2) - l.slli r5,r5,24 - l.lbz r6,1(r2) - l.slli r6,r6,16 - l.or r5,r5,r6 - l.lbz r6,2(r2) - l.slli r6,r6,8 - l.or r5,r5,r6 - l.lbz r6,3(r2) - l.or r5,r5,r6 - l.srli r4,r3,19 - l.andi r4,r4,0x7c - l.add r4,r4,r1 - l.j align_end - l.sw 0(r4),r5 - -lwz: l.lbz r5,0(r2) - l.slli r5,r5,24 - l.lbz r6,1(r2) - l.slli r6,r6,16 - l.or r5,r5,r6 - l.lbz r6,2(r2) - l.slli r6,r6,8 - l.or r5,r5,r6 - l.lbz r6,3(r2) - l.or r5,r5,r6 - l.srli r4,r3,19 - l.andi r4,r4,0x7c - l.add r4,r4,r1 - l.j align_end - l.sw 0(r4),r5 - -sh: - l.srli r4,r3,9 - l.andi r4,r4,0x7c - l.add r4,r4,r1 - l.lwz r5,0(r4) - l.sb 1(r2),r5 - l.srli r5,r5,8 - l.j align_end - l.sb 0(r2),r5 - -sw: - l.srli r4,r3,9 - l.andi r4,r4,0x7c - l.add r4,r4,r1 - l.lwz r5,0(r4) - l.sb 3(r2),r5 - l.srli r5,r5,8 - l.sb 2(r2),r5 - l.srli r5,r5,8 - l.sb 1(r2),r5 - l.srli r5,r5,8 - l.j align_end - l.sb 0(r2),r5 - -align_end: - l.j _ret_from_intr - l.nop -#endif - -/* ---[ 0x700: Illegal insn exception ]---------------------------------- */ - -EXCEPTION_ENTRY(_illegal_instruction_handler) - /* r4: EA of fault (set by EXCEPTION_HANDLE) */ - l.jal do_illegal_instruction - l.addi r3,r1,0 /* pt_regs */ - - l.j _ret_from_exception - l.nop - -/* ---[ 0x800: External interrupt exception ]---------------------------- */ - -EXCEPTION_ENTRY(_external_irq_handler) -#ifdef CONFIG_OPENRISC_ESR_EXCEPTION_BUG_CHECK - l.lwz r4,PT_SR(r1) // were interrupts enabled ? - l.andi r4,r4,SPR_SR_IEE - l.sfeqi r4,0 - l.bnf 1f // ext irq enabled, all ok. - l.nop - - l.addi r1,r1,-0x8 - l.movhi r3,hi(42f) - l.ori r3,r3,lo(42f) - l.sw 0x0(r1),r3 - l.jal printk - l.sw 0x4(r1),r4 - l.addi r1,r1,0x8 - - .section .rodata, "a" -42: - .string "\n\rESR interrupt bug: in _external_irq_handler (ESR %x)\n\r" - .align 4 - .previous - - l.ori r4,r4,SPR_SR_IEE // fix the bug -// l.sw PT_SR(r1),r4 -1: -#endif - l.addi r3,r1,0 - l.movhi r8,hi(do_IRQ) - l.ori r8,r8,lo(do_IRQ) - l.jalr r8 - l.nop - l.j _ret_from_intr - l.nop - -/* ---[ 0x900: DTLB miss exception ]------------------------------------- */ - - -/* ---[ 0xa00: ITLB miss exception ]------------------------------------- */ - - -/* ---[ 0xb00: Range exception ]----------------------------------------- */ - -UNHANDLED_EXCEPTION(_vector_0xb00,0xb00) - -/* ---[ 0xc00: Syscall exception ]--------------------------------------- */ - -/* - * Syscalls are a special type of exception in that they are - * _explicitly_ invoked by userspace and can therefore be - * held to conform to the same ABI as normal functions with - * respect to whether registers are preserved across the call - * or not. - */ - -/* Upon syscall entry we just save the callee-saved registers - * and not the call-clobbered ones. - */ - -_string_syscall_return: - .string "syscall return %ld \n\r\0" - .align 4 - -ENTRY(_sys_call_handler) - /* syscalls run with interrupts enabled */ - ENABLE_INTERRUPTS(r29) // enable interrupts, r29 is temp - - /* r1, EPCR, ESR a already saved */ - l.sw PT_GPR2(r1),r2 - /* r3-r8 must be saved because syscall restart relies - * on us being able to restart the syscall args... technically - * they should be clobbered, otherwise - */ - l.sw PT_GPR3(r1),r3 - /* r4 already saved */ - /* r4 holds the EEAR address of the fault, load the original r4 */ - l.lwz r4,PT_GPR4(r1) - l.sw PT_GPR5(r1),r5 - l.sw PT_GPR6(r1),r6 - l.sw PT_GPR7(r1),r7 - l.sw PT_GPR8(r1),r8 - l.sw PT_GPR9(r1),r9 - /* r10 already saved */ - l.sw PT_GPR11(r1),r11 - l.sw PT_ORIG_GPR11(r1),r11 - /* r12,r13 already saved */ - - /* r14-r28 (even) aren't touched by the syscall fast path below - * so we don't need to save them. However, the functions that return - * to userspace via a call to switch() DO need to save these because - * switch() effectively clobbers them... saving these registers for - * such functions is handled in their syscall wrappers (see fork, vfork, - * and clone, below). - - /* r30 is the only register we clobber in the fast path */ - /* r30 already saved */ -/* l.sw PT_GPR30(r1),r30 */ - /* This is used by do_signal to determine whether to check for - * syscall restart or not */ - l.sw PT_SYSCALLNO(r1),r11 - -_syscall_check_trace_enter: - /* If TIF_SYSCALL_TRACE is set, then we want to do syscall tracing */ - l.lwz r30,TI_FLAGS(r10) - l.andi r30,r30,_TIF_SYSCALL_TRACE - l.sfne r30,r0 - l.bf _syscall_trace_enter - l.nop - -_syscall_check: - /* Ensure that the syscall number is reasonable */ - l.sfgeui r11,__NR_syscalls - l.bf _syscall_badsys - l.nop - -_syscall_call: - l.movhi r29,hi(sys_call_table) - l.ori r29,r29,lo(sys_call_table) - l.slli r11,r11,2 - l.add r29,r29,r11 - l.lwz r29,0(r29) - - l.jalr r29 - l.nop - -_syscall_return: - /* All syscalls return here... just pay attention to ret_from_fork - * which does it in a round-about way. - */ - l.sw PT_GPR11(r1),r11 // save return value - -#if 0 -_syscall_debug: - l.movhi r3,hi(_string_syscall_return) - l.ori r3,r3,lo(_string_syscall_return) - l.ori r27,r0,1 - l.sw -4(r1),r27 - l.sw -8(r1),r11 - l.addi r1,r1,-8 - l.movhi r27,hi(printk) - l.ori r27,r27,lo(printk) - l.jalr r27 - l.nop - l.addi r1,r1,8 -#endif - -_syscall_check_trace_leave: - /* r30 is a callee-saved register so this should still hold the - * _TIF_SYSCALL_TRACE flag from _syscall_check_trace_enter above... - * _syscall_trace_leave expects syscall result to be in pt_regs->r11. - */ - l.sfne r30,r0 - l.bf _syscall_trace_leave - l.nop - -/* This is where the exception-return code begins... interrupts need to be - * disabled the rest of the way here because we can't afford to miss any - * interrupts that set NEED_RESCHED or SIGNALPENDING... really true? */ - -_syscall_check_work: - /* Here we need to disable interrupts */ - DISABLE_INTERRUPTS(r27,r29) - l.lwz r30,TI_FLAGS(r10) - l.andi r30,r30,_TIF_WORK_MASK - l.sfne r30,r0 - - l.bnf _syscall_resume_userspace - l.nop - - /* Work pending follows a different return path, so we need to - * make sure that all the call-saved registers get into pt_regs - * before branching... - */ - l.sw PT_GPR14(r1),r14 - l.sw PT_GPR16(r1),r16 - l.sw PT_GPR18(r1),r18 - l.sw PT_GPR20(r1),r20 - l.sw PT_GPR22(r1),r22 - l.sw PT_GPR24(r1),r24 - l.sw PT_GPR26(r1),r26 - l.sw PT_GPR28(r1),r28 - - /* _work_pending needs to be called with interrupts disabled */ - l.j _work_pending - l.nop - -_syscall_resume_userspace: -// ENABLE_INTERRUPTS(r29) - - -/* This is the hot path for returning to userspace from a syscall. If there's - * work to be done and the branch to _work_pending was taken above, then the - * return to userspace will be done via the normal exception return path... - * that path restores _all_ registers and will overwrite the "clobbered" - * registers with whatever garbage is in pt_regs -- that's OK because those - * registers are clobbered anyway and because the extra work is insignificant - * in the context of the extra work that _work_pending is doing. - -/* Once again, syscalls are special and only guarantee to preserve the - * same registers as a normal function call */ - -/* The assumption here is that the registers r14-r28 (even) are untouched and - * don't need to be restored... be sure that that's really the case! - */ - -/* This is still too much... we should only be restoring what we actually - * clobbered... we should even be using 'scratch' (odd) regs above so that - * we don't need to restore anything, hardly... - */ - - l.lwz r2,PT_GPR2(r1) - - /* Restore args */ - /* r3-r8 are technically clobbered, but syscall restart needs these - * to be restored... - */ - l.lwz r3,PT_GPR3(r1) - l.lwz r4,PT_GPR4(r1) - l.lwz r5,PT_GPR5(r1) - l.lwz r6,PT_GPR6(r1) - l.lwz r7,PT_GPR7(r1) - l.lwz r8,PT_GPR8(r1) - - l.lwz r9,PT_GPR9(r1) - l.lwz r10,PT_GPR10(r1) - l.lwz r11,PT_GPR11(r1) - - /* r30 is the only register we clobber in the fast path */ - l.lwz r30,PT_GPR30(r1) - - /* Here we use r13-r19 (odd) as scratch regs */ - l.lwz r13,PT_PC(r1) - l.lwz r15,PT_SR(r1) - l.lwz r1,PT_SP(r1) - /* Interrupts need to be disabled for setting EPCR and ESR - * so that another interrupt doesn't come in here and clobber - * them before we can use them for our l.rfe */ - DISABLE_INTERRUPTS(r17,r19) - l.mtspr r0,r13,SPR_EPCR_BASE - l.mtspr r0,r15,SPR_ESR_BASE - l.rfe - -/* End of hot path! - * Keep the below tracing and error handling out of the hot path... -*/ - -_syscall_trace_enter: - /* Here we pass pt_regs to do_syscall_trace_enter. Make sure - * that function is really getting all the info it needs as - * pt_regs isn't a complete set of userspace regs, just the - * ones relevant to the syscall... - * - * Note use of delay slot for setting argument. - */ - l.jal do_syscall_trace_enter - l.addi r3,r1,0 - - /* Restore arguments (not preserved across do_syscall_trace_enter) - * so that we can do the syscall for real and return to the syscall - * hot path. - */ - l.lwz r11,PT_SYSCALLNO(r1) - l.lwz r3,PT_GPR3(r1) - l.lwz r4,PT_GPR4(r1) - l.lwz r5,PT_GPR5(r1) - l.lwz r6,PT_GPR6(r1) - l.lwz r7,PT_GPR7(r1) - - l.j _syscall_check - l.lwz r8,PT_GPR8(r1) - -_syscall_trace_leave: - l.jal do_syscall_trace_leave - l.addi r3,r1,0 - - l.j _syscall_check_work - l.nop - -_syscall_badsys: - /* Here we effectively pretend to have executed an imaginary - * syscall that returns -ENOSYS and then return to the regular - * syscall hot path. - * Note that "return value" is set in the delay slot... - */ - l.j _syscall_return - l.addi r11,r0,-ENOSYS - -/******* END SYSCALL HANDLING *******/ - -/* ---[ 0xd00: Trap exception ]------------------------------------------ */ - -UNHANDLED_EXCEPTION(_vector_0xd00,0xd00) - -/* ---[ 0xe00: Trap exception ]------------------------------------------ */ - -EXCEPTION_ENTRY(_trap_handler) - /* r4: EA of fault (set by EXCEPTION_HANDLE) */ - l.jal do_trap - l.addi r3,r1,0 /* pt_regs */ - - l.j _ret_from_exception - l.nop - -/* ---[ 0xf00: Reserved exception ]-------------------------------------- */ - -UNHANDLED_EXCEPTION(_vector_0xf00,0xf00) - -/* ---[ 0x1000: Reserved exception ]------------------------------------- */ - -UNHANDLED_EXCEPTION(_vector_0x1000,0x1000) - -/* ---[ 0x1100: Reserved exception ]------------------------------------- */ - -UNHANDLED_EXCEPTION(_vector_0x1100,0x1100) - -/* ---[ 0x1200: Reserved exception ]------------------------------------- */ - -UNHANDLED_EXCEPTION(_vector_0x1200,0x1200) - -/* ---[ 0x1300: Reserved exception ]------------------------------------- */ - -UNHANDLED_EXCEPTION(_vector_0x1300,0x1300) - -/* ---[ 0x1400: Reserved exception ]------------------------------------- */ - -UNHANDLED_EXCEPTION(_vector_0x1400,0x1400) - -/* ---[ 0x1500: Reserved exception ]------------------------------------- */ - -UNHANDLED_EXCEPTION(_vector_0x1500,0x1500) - -/* ---[ 0x1600: Reserved exception ]------------------------------------- */ - -UNHANDLED_EXCEPTION(_vector_0x1600,0x1600) - -/* ---[ 0x1700: Reserved exception ]------------------------------------- */ - -UNHANDLED_EXCEPTION(_vector_0x1700,0x1700) - -/* ---[ 0x1800: Reserved exception ]------------------------------------- */ - -UNHANDLED_EXCEPTION(_vector_0x1800,0x1800) - -/* ---[ 0x1900: Reserved exception ]------------------------------------- */ - -UNHANDLED_EXCEPTION(_vector_0x1900,0x1900) - -/* ---[ 0x1a00: Reserved exception ]------------------------------------- */ - -UNHANDLED_EXCEPTION(_vector_0x1a00,0x1a00) - -/* ---[ 0x1b00: Reserved exception ]------------------------------------- */ - -UNHANDLED_EXCEPTION(_vector_0x1b00,0x1b00) - -/* ---[ 0x1c00: Reserved exception ]------------------------------------- */ - -UNHANDLED_EXCEPTION(_vector_0x1c00,0x1c00) - -/* ---[ 0x1d00: Reserved exception ]------------------------------------- */ - -UNHANDLED_EXCEPTION(_vector_0x1d00,0x1d00) - -/* ---[ 0x1e00: Reserved exception ]------------------------------------- */ - -UNHANDLED_EXCEPTION(_vector_0x1e00,0x1e00) - -/* ---[ 0x1f00: Reserved exception ]------------------------------------- */ - -UNHANDLED_EXCEPTION(_vector_0x1f00,0x1f00) - -/* ========================================================[ return ] === */ - -_work_pending: - /* - * if (current_thread_info->flags & _TIF_NEED_RESCHED) - * schedule(); - */ - l.lwz r5,TI_FLAGS(r10) - l.andi r3,r5,_TIF_NEED_RESCHED - l.sfnei r3,0 - l.bnf _work_notifysig - l.nop - l.jal schedule - l.nop - l.j _resume_userspace - l.nop - -/* Handle pending signals and notify-resume requests. - * do_notify_resume must be passed the latest pushed pt_regs, not - * necessarily the "userspace" ones. Also, pt_regs->syscallno - * must be set so that the syscall restart functionality works. - */ -_work_notifysig: - l.jal do_notify_resume - l.ori r3,r1,0 /* pt_regs */ - -_resume_userspace: - DISABLE_INTERRUPTS(r3,r4) - l.lwz r3,TI_FLAGS(r10) - l.andi r3,r3,_TIF_WORK_MASK - l.sfnei r3,0 - l.bf _work_pending - l.nop - -_restore_all: - RESTORE_ALL - /* This returns to userspace code */ - - -ENTRY(_ret_from_intr) -ENTRY(_ret_from_exception) - l.lwz r4,PT_SR(r1) - l.andi r3,r4,SPR_SR_SM - l.sfeqi r3,0 - l.bnf _restore_all - l.nop - l.j _resume_userspace - l.nop - -ENTRY(ret_from_fork) - l.jal schedule_tail - l.nop - - /* _syscall_returns expect r11 to contain return value */ - l.lwz r11,PT_GPR11(r1) - - /* The syscall fast path return expects call-saved registers - * r12-r28 to be untouched, so we restore them here as they - * will have been effectively clobbered when arriving here - * via the call to switch() - */ - l.lwz r12,PT_GPR12(r1) - l.lwz r14,PT_GPR14(r1) - l.lwz r16,PT_GPR16(r1) - l.lwz r18,PT_GPR18(r1) - l.lwz r20,PT_GPR20(r1) - l.lwz r22,PT_GPR22(r1) - l.lwz r24,PT_GPR24(r1) - l.lwz r26,PT_GPR26(r1) - l.lwz r28,PT_GPR28(r1) - - l.j _syscall_return - l.nop - -/* Since syscalls don't save call-clobbered registers, the args to - * kernel_thread_helper will need to be passed through callee-saved - * registers and copied to the parameter registers when the thread - * begins running. - * - * See arch/openrisc/kernel/process.c: - * The args are passed as follows: - * arg1 (r3) : passed in r20 - * arg2 (r4) : passed in r22 - */ - -ENTRY(_kernel_thread_helper) - l.or r3,r20,r0 - l.or r4,r22,r0 - l.movhi r31,hi(kernel_thread_helper) - l.ori r31,r31,lo(kernel_thread_helper) - l.jr r31 - l.nop - - -/* ========================================================[ switch ] === */ - -/* - * This routine switches between two different tasks. The process - * state of one is saved on its kernel stack. Then the state - * of the other is restored from its kernel stack. The memory - * management hardware is updated to the second process's state. - * Finally, we can return to the second process, via the 'return'. - * - * Note: there are two ways to get to the "going out" portion - * of this code; either by coming in via the entry (_switch) - * or via "fork" which must set up an environment equivalent - * to the "_switch" path. If you change this (or in particular, the - * SAVE_REGS macro), you'll have to change the fork code also. - */ - - -/* _switch MUST never lay on page boundry, cause it runs from - * effective addresses and beeing interrupted by iTLB miss would kill it. - * dTLB miss seams to never accour in the bad place since data accesses - * are from task structures which are always page aligned. - * - * The problem happens in RESTORE_ALL_NO_R11 where we first set the EPCR - * register, then load the previous register values and only at the end call - * the l.rfe instruction. If get TLB miss in beetwen the EPCR register gets - * garbled and we end up calling l.rfe with the wrong EPCR. (same probably - * holds for ESR) - * - * To avoid this problems it is sufficient to align _switch to - * some nice round number smaller than it's size... - */ - -/* ABI rules apply here... we either enter _switch via schedule() or via - * an imaginary call to which we shall return at return_from_fork. Either - * way, we are a function call and only need to preserve the callee-saved - * registers when we return. As such, we don't need to save the registers - * on the stack that we won't be returning as they were... - */ - - .align 0x400 -ENTRY(_switch) - /* We don't store SR as _switch only gets called in a context where - * the SR will be the same going in and coming out... */ - - /* Set up new pt_regs struct for saving task state */ - l.addi r1,r1,-(INT_FRAME_SIZE) - - /* No need to store r1/PT_SP as it goes into KSP below */ - l.sw PT_GPR2(r1),r2 - l.sw PT_GPR9(r1),r9 - /* This is wrong, r12 shouldn't be here... but GCC is broken for the time being - * and expects r12 to be callee-saved... */ - l.sw PT_GPR12(r1),r12 - l.sw PT_GPR14(r1),r14 - l.sw PT_GPR16(r1),r16 - l.sw PT_GPR18(r1),r18 - l.sw PT_GPR20(r1),r20 - l.sw PT_GPR22(r1),r22 - l.sw PT_GPR24(r1),r24 - l.sw PT_GPR26(r1),r26 - l.sw PT_GPR28(r1),r28 - l.sw PT_GPR30(r1),r30 - - l.addi r11,r10,0 /* Save old 'current' to 'last' return value*/ - - /* We use thread_info->ksp for storing the address of the above - * structure so that we can get back to it later... we don't want - * to lose the value of thread_info->ksp, though, so store it as - * pt_regs->sp so that we can easily restore it when we are made - * live again... - */ - - /* Save the old value of thread_info->ksp as pt_regs->sp */ - l.lwz r29,TI_KSP(r10) - l.sw PT_SP(r1),r29 - - /* Swap kernel stack pointers */ - l.sw TI_KSP(r10),r1 /* Save old stack pointer */ - l.or r10,r4,r0 /* Set up new current_thread_info */ - l.lwz r1,TI_KSP(r10) /* Load new stack pointer */ - - /* Restore the old value of thread_info->ksp */ - l.lwz r29,PT_SP(r1) - l.sw TI_KSP(r10),r29 - - /* ...and restore the registers, except r11 because the return value - * has already been set above. - */ - l.lwz r2,PT_GPR2(r1) - l.lwz r9,PT_GPR9(r1) - /* No need to restore r10 */ - /* ...and do not restore r11 */ - - /* This is wrong, r12 shouldn't be here... but GCC is broken for the time being - * and expects r12 to be callee-saved... */ - l.lwz r12,PT_GPR12(r1) - l.lwz r14,PT_GPR14(r1) - l.lwz r16,PT_GPR16(r1) - l.lwz r18,PT_GPR18(r1) - l.lwz r20,PT_GPR20(r1) - l.lwz r22,PT_GPR22(r1) - l.lwz r24,PT_GPR24(r1) - l.lwz r26,PT_GPR26(r1) - l.lwz r28,PT_GPR28(r1) - l.lwz r30,PT_GPR30(r1) - - /* Unwind stack to pre-switch state */ - l.addi r1,r1,(INT_FRAME_SIZE) - - /* Return via the link-register back to where we 'came from', where that can be - * either schedule() or return_from_fork()... */ - l.jr r9 - l.nop - -/* ==================================================================== */ - -/* These all use the delay slot for setting the argument register, so the - * jump is always happening after the l.addi instruction. - * - * These are all just wrappers that don't touch the link-register r9, so the - * return from the "real" syscall function will return back to the syscall - * code that did the l.jal that brought us here. - */ - -/* fork requires that we save all the callee-saved registers because they - * are all effectively clobbered by the call to _switch. Here we store - * all the registers that aren't touched by the syscall fast path and thus - * weren't saved there. - */ - -_fork_save_extra_regs_and_call: - l.sw PT_GPR14(r1),r14 - l.sw PT_GPR16(r1),r16 - l.sw PT_GPR18(r1),r18 - l.sw PT_GPR20(r1),r20 - l.sw PT_GPR22(r1),r22 - l.sw PT_GPR24(r1),r24 - l.sw PT_GPR26(r1),r26 - l.jr r29 - l.sw PT_GPR28(r1),r28 - -ENTRY(sys_clone) - l.movhi r29,hi(_sys_clone) - l.ori r29,r29,lo(_sys_clone) - l.j _fork_save_extra_regs_and_call - l.addi r7,r1,0 - -ENTRY(sys_fork) - l.movhi r29,hi(_sys_fork) - l.ori r29,r29,lo(_sys_fork) - l.j _fork_save_extra_regs_and_call - l.addi r3,r1,0 - -ENTRY(sys_execve) - l.j _sys_execve - l.addi r6,r1,0 - -ENTRY(sys_sigaltstack) - l.j _sys_sigaltstack - l.addi r5,r1,0 - -ENTRY(sys_rt_sigreturn) - l.j _sys_rt_sigreturn - l.addi r3,r1,0 - -/* This is a catch-all syscall for atomic instructions for the OpenRISC 1000. - * The functions takes a variable number of parameters depending on which - * particular flavour of atomic you want... parameter 1 is a flag identifying - * the atomic in question. Currently, this function implements the - * following variants: - * - * XCHG: - * @flag: 1 - * @ptr1: - * @ptr2: - * Atomically exchange the values in pointers 1 and 2. - * - */ - -ENTRY(sys_or1k_atomic) - /* FIXME: This ignores r3 and always does an XCHG */ - DISABLE_INTERRUPTS(r17,r19) - l.lwz r30,0(r4) - l.lwz r28,0(r5) - l.sw 0(r4),r28 - l.sw 0(r5),r30 - ENABLE_INTERRUPTS(r17) - l.jr r9 - l.or r11,r0,r0 - -/* ============================================================[ EOF ]=== */ diff --git a/trunk/arch/openrisc/kernel/head.S b/trunk/arch/openrisc/kernel/head.S deleted file mode 100644 index c75018d22644..000000000000 --- a/trunk/arch/openrisc/kernel/head.S +++ /dev/null @@ -1,1607 +0,0 @@ -/* - * OpenRISC head.S - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * Modifications for the OpenRISC architecture: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define tophys(rd,rs) \ - l.movhi rd,hi(-KERNELBASE) ;\ - l.add rd,rd,rs - -#define CLEAR_GPR(gpr) \ - l.or gpr,r0,r0 - -#define LOAD_SYMBOL_2_GPR(gpr,symbol) \ - l.movhi gpr,hi(symbol) ;\ - l.ori gpr,gpr,lo(symbol) - - -#define UART_BASE_ADD 0x90000000 - -#define EXCEPTION_SR (SPR_SR_DME | SPR_SR_IME | SPR_SR_DCE | SPR_SR_ICE | SPR_SR_SM) -#define SYSCALL_SR (SPR_SR_DME | SPR_SR_IME | SPR_SR_DCE | SPR_SR_ICE | SPR_SR_IEE | SPR_SR_TEE | SPR_SR_SM) - -/* ============================================[ tmp store locations ]=== */ - -/* - * emergency_print temporary stores - */ -#define EMERGENCY_PRINT_STORE_GPR4 l.sw 0x20(r0),r4 -#define EMERGENCY_PRINT_LOAD_GPR4 l.lwz r4,0x20(r0) - -#define EMERGENCY_PRINT_STORE_GPR5 l.sw 0x24(r0),r5 -#define EMERGENCY_PRINT_LOAD_GPR5 l.lwz r5,0x24(r0) - -#define EMERGENCY_PRINT_STORE_GPR6 l.sw 0x28(r0),r6 -#define EMERGENCY_PRINT_LOAD_GPR6 l.lwz r6,0x28(r0) - -#define EMERGENCY_PRINT_STORE_GPR7 l.sw 0x2c(r0),r7 -#define EMERGENCY_PRINT_LOAD_GPR7 l.lwz r7,0x2c(r0) - -#define EMERGENCY_PRINT_STORE_GPR8 l.sw 0x30(r0),r8 -#define EMERGENCY_PRINT_LOAD_GPR8 l.lwz r8,0x30(r0) - -#define EMERGENCY_PRINT_STORE_GPR9 l.sw 0x34(r0),r9 -#define EMERGENCY_PRINT_LOAD_GPR9 l.lwz r9,0x34(r0) - - -/* - * TLB miss handlers temorary stores - */ -#define EXCEPTION_STORE_GPR9 l.sw 0x10(r0),r9 -#define EXCEPTION_LOAD_GPR9 l.lwz r9,0x10(r0) - -#define EXCEPTION_STORE_GPR2 l.sw 0x64(r0),r2 -#define EXCEPTION_LOAD_GPR2 l.lwz r2,0x64(r0) - -#define EXCEPTION_STORE_GPR3 l.sw 0x68(r0),r3 -#define EXCEPTION_LOAD_GPR3 l.lwz r3,0x68(r0) - -#define EXCEPTION_STORE_GPR4 l.sw 0x6c(r0),r4 -#define EXCEPTION_LOAD_GPR4 l.lwz r4,0x6c(r0) - -#define EXCEPTION_STORE_GPR5 l.sw 0x70(r0),r5 -#define EXCEPTION_LOAD_GPR5 l.lwz r5,0x70(r0) - -#define EXCEPTION_STORE_GPR6 l.sw 0x74(r0),r6 -#define EXCEPTION_LOAD_GPR6 l.lwz r6,0x74(r0) - - -/* - * EXCEPTION_HANDLE temporary stores - */ - -#define EXCEPTION_T_STORE_GPR30 l.sw 0x78(r0),r30 -#define EXCEPTION_T_LOAD_GPR30(reg) l.lwz reg,0x78(r0) - -#define EXCEPTION_T_STORE_GPR10 l.sw 0x7c(r0),r10 -#define EXCEPTION_T_LOAD_GPR10(reg) l.lwz reg,0x7c(r0) - -#define EXCEPTION_T_STORE_SP l.sw 0x80(r0),r1 -#define EXCEPTION_T_LOAD_SP(reg) l.lwz reg,0x80(r0) - -/* - * For UNHANLDED_EXCEPTION - */ - -#define EXCEPTION_T_STORE_GPR31 l.sw 0x84(r0),r31 -#define EXCEPTION_T_LOAD_GPR31(reg) l.lwz reg,0x84(r0) - -/* =========================================================[ macros ]=== */ - - -#define GET_CURRENT_PGD(reg,t1) \ - LOAD_SYMBOL_2_GPR(reg,current_pgd) ;\ - tophys (t1,reg) ;\ - l.lwz reg,0(t1) - - -/* - * DSCR: this is a common hook for handling exceptions. it will save - * the needed registers, set up stack and pointer to current - * then jump to the handler while enabling MMU - * - * PRMS: handler - a function to jump to. it has to save the - * remaining registers to kernel stack, call - * appropriate arch-independant exception handler - * and finaly jump to ret_from_except - * - * PREQ: unchanged state from the time exception happened - * - * POST: SAVED the following registers original value - * to the new created exception frame pointed to by r1 - * - * r1 - ksp pointing to the new (exception) frame - * r4 - EEAR exception EA - * r10 - current pointing to current_thread_info struct - * r12 - syscall 0, since we didn't come from syscall - * r13 - temp it actually contains new SR, not needed anymore - * r31 - handler address of the handler we'll jump to - * - * handler has to save remaining registers to the exception - * ksp frame *before* tainting them! - * - * NOTE: this function is not reentrant per se. reentrancy is guaranteed - * by processor disabling all exceptions/interrupts when exception - * accours. - * - * OPTM: no need to make it so wasteful to extract ksp when in user mode - */ - -#define EXCEPTION_HANDLE(handler) \ - EXCEPTION_T_STORE_GPR30 ;\ - l.mfspr r30,r0,SPR_ESR_BASE ;\ - l.andi r30,r30,SPR_SR_SM ;\ - l.sfeqi r30,0 ;\ - EXCEPTION_T_STORE_GPR10 ;\ - l.bnf 2f /* kernel_mode */ ;\ - EXCEPTION_T_STORE_SP /* delay slot */ ;\ -1: /* user_mode: */ ;\ - LOAD_SYMBOL_2_GPR(r1,current_thread_info_set) ;\ - tophys (r30,r1) ;\ - /* r10: current_thread_info */ ;\ - l.lwz r10,0(r30) ;\ - tophys (r30,r10) ;\ - l.lwz r1,(TI_KSP)(r30) ;\ - /* fall through */ ;\ -2: /* kernel_mode: */ ;\ - /* create new stack frame, save only needed gprs */ ;\ - /* r1: KSP, r10: current, r4: EEAR, r31: __pa(KSP) */ ;\ - /* r12: temp, syscall indicator */ ;\ - l.addi r1,r1,-(INT_FRAME_SIZE) ;\ - /* r1 is KSP, r30 is __pa(KSP) */ ;\ - tophys (r30,r1) ;\ - l.sw PT_GPR12(r30),r12 ;\ - l.mfspr r12,r0,SPR_EPCR_BASE ;\ - l.sw PT_PC(r30),r12 ;\ - l.mfspr r12,r0,SPR_ESR_BASE ;\ - l.sw PT_SR(r30),r12 ;\ - /* save r30 */ ;\ - EXCEPTION_T_LOAD_GPR30(r12) ;\ - l.sw PT_GPR30(r30),r12 ;\ - /* save r10 as was prior to exception */ ;\ - EXCEPTION_T_LOAD_GPR10(r12) ;\ - l.sw PT_GPR10(r30),r12 ;\ - /* save PT_SP as was prior to exception */ ;\ - EXCEPTION_T_LOAD_SP(r12) ;\ - l.sw PT_SP(r30),r12 ;\ - /* save exception r4, set r4 = EA */ ;\ - l.sw PT_GPR4(r30),r4 ;\ - l.mfspr r4,r0,SPR_EEAR_BASE ;\ - /* r12 == 1 if we come from syscall */ ;\ - CLEAR_GPR(r12) ;\ - /* ----- turn on MMU ----- */ ;\ - l.ori r30,r0,(EXCEPTION_SR) ;\ - l.mtspr r0,r30,SPR_ESR_BASE ;\ - /* r30: EA address of handler */ ;\ - LOAD_SYMBOL_2_GPR(r30,handler) ;\ - l.mtspr r0,r30,SPR_EPCR_BASE ;\ - l.rfe - -/* - * this doesn't work - * - * - * #ifdef CONFIG_JUMP_UPON_UNHANDLED_EXCEPTION - * #define UNHANDLED_EXCEPTION(handler) \ - * l.ori r3,r0,0x1 ;\ - * l.mtspr r0,r3,SPR_SR ;\ - * l.movhi r3,hi(0xf0000100) ;\ - * l.ori r3,r3,lo(0xf0000100) ;\ - * l.jr r3 ;\ - * l.nop 1 - * - * #endif - */ - -/* DSCR: this is the same as EXCEPTION_HANDLE(), we are just - * a bit more carefull (if we have a PT_SP or current pointer - * corruption) and set them up from 'current_set' - * - */ -#define UNHANDLED_EXCEPTION(handler) \ - EXCEPTION_T_STORE_GPR31 ;\ - EXCEPTION_T_STORE_GPR10 ;\ - EXCEPTION_T_STORE_SP ;\ - /* temporary store r3, r9 into r1, r10 */ ;\ - l.addi r1,r3,0x0 ;\ - l.addi r10,r9,0x0 ;\ - /* the string referenced by r3 must be low enough */ ;\ - l.jal _emergency_print ;\ - l.ori r3,r0,lo(_string_unhandled_exception) ;\ - l.mfspr r3,r0,SPR_NPC ;\ - l.jal _emergency_print_nr ;\ - l.andi r3,r3,0x1f00 ;\ - /* the string referenced by r3 must be low enough */ ;\ - l.jal _emergency_print ;\ - l.ori r3,r0,lo(_string_epc_prefix) ;\ - l.jal _emergency_print_nr ;\ - l.mfspr r3,r0,SPR_EPCR_BASE ;\ - l.jal _emergency_print ;\ - l.ori r3,r0,lo(_string_nl) ;\ - /* end of printing */ ;\ - l.addi r3,r1,0x0 ;\ - l.addi r9,r10,0x0 ;\ - /* extract current, ksp from current_set */ ;\ - LOAD_SYMBOL_2_GPR(r1,_unhandled_stack_top) ;\ - LOAD_SYMBOL_2_GPR(r10,init_thread_union) ;\ - /* create new stack frame, save only needed gprs */ ;\ - /* r1: KSP, r10: current, r31: __pa(KSP) */ ;\ - /* r12: temp, syscall indicator, r13 temp */ ;\ - l.addi r1,r1,-(INT_FRAME_SIZE) ;\ - /* r1 is KSP, r31 is __pa(KSP) */ ;\ - tophys (r31,r1) ;\ - l.sw PT_GPR12(r31),r12 ;\ - l.mfspr r12,r0,SPR_EPCR_BASE ;\ - l.sw PT_PC(r31),r12 ;\ - l.mfspr r12,r0,SPR_ESR_BASE ;\ - l.sw PT_SR(r31),r12 ;\ - /* save r31 */ ;\ - EXCEPTION_T_LOAD_GPR31(r12) ;\ - l.sw PT_GPR31(r31),r12 ;\ - /* save r10 as was prior to exception */ ;\ - EXCEPTION_T_LOAD_GPR10(r12) ;\ - l.sw PT_GPR10(r31),r12 ;\ - /* save PT_SP as was prior to exception */ ;\ - EXCEPTION_T_LOAD_SP(r12) ;\ - l.sw PT_SP(r31),r12 ;\ - l.sw PT_GPR13(r31),r13 ;\ - /* --> */ ;\ - /* save exception r4, set r4 = EA */ ;\ - l.sw PT_GPR4(r31),r4 ;\ - l.mfspr r4,r0,SPR_EEAR_BASE ;\ - /* r12 == 1 if we come from syscall */ ;\ - CLEAR_GPR(r12) ;\ - /* ----- play a MMU trick ----- */ ;\ - l.ori r31,r0,(EXCEPTION_SR) ;\ - l.mtspr r0,r31,SPR_ESR_BASE ;\ - /* r31: EA address of handler */ ;\ - LOAD_SYMBOL_2_GPR(r31,handler) ;\ - l.mtspr r0,r31,SPR_EPCR_BASE ;\ - l.rfe - -/* =====================================================[ exceptions] === */ - -/* ---[ 0x100: RESET exception ]----------------------------------------- */ - .org 0x100 - /* Jump to .init code at _start which lives in the .head section - * and will be discarded after boot. - */ - LOAD_SYMBOL_2_GPR(r4, _start) - tophys (r3,r4) /* MMU disabled */ - l.jr r3 - l.nop - -/* ---[ 0x200: BUS exception ]------------------------------------------- */ - .org 0x200 -_dispatch_bus_fault: - EXCEPTION_HANDLE(_bus_fault_handler) - -/* ---[ 0x300: Data Page Fault exception ]------------------------------- */ - .org 0x300 -_dispatch_do_dpage_fault: -// totaly disable timer interrupt -// l.mtspr r0,r0,SPR_TTMR -// DEBUG_TLB_PROBE(0x300) -// EXCEPTION_DEBUG_VALUE_ER_ENABLED(0x300) - EXCEPTION_HANDLE(_data_page_fault_handler) - -/* ---[ 0x400: Insn Page Fault exception ]------------------------------- */ - .org 0x400 -_dispatch_do_ipage_fault: -// totaly disable timer interrupt -// l.mtspr r0,r0,SPR_TTMR -// DEBUG_TLB_PROBE(0x400) -// EXCEPTION_DEBUG_VALUE_ER_ENABLED(0x400) - EXCEPTION_HANDLE(_insn_page_fault_handler) - -/* ---[ 0x500: Timer exception ]----------------------------------------- */ - .org 0x500 - EXCEPTION_HANDLE(_timer_handler) - -/* ---[ 0x600: Aligment exception ]-------------------------------------- */ - .org 0x600 - EXCEPTION_HANDLE(_alignment_handler) - -/* ---[ 0x700: Illegal insn exception ]---------------------------------- */ - .org 0x700 - EXCEPTION_HANDLE(_illegal_instruction_handler) - -/* ---[ 0x800: External interrupt exception ]---------------------------- */ - .org 0x800 - EXCEPTION_HANDLE(_external_irq_handler) - -/* ---[ 0x900: DTLB miss exception ]------------------------------------- */ - .org 0x900 - l.j boot_dtlb_miss_handler - l.nop - -/* ---[ 0xa00: ITLB miss exception ]------------------------------------- */ - .org 0xa00 - l.j boot_itlb_miss_handler - l.nop - -/* ---[ 0xb00: Range exception ]----------------------------------------- */ - .org 0xb00 - UNHANDLED_EXCEPTION(_vector_0xb00) - -/* ---[ 0xc00: Syscall exception ]--------------------------------------- */ - .org 0xc00 - EXCEPTION_HANDLE(_sys_call_handler) - -/* ---[ 0xd00: Trap exception ]------------------------------------------ */ - .org 0xd00 - UNHANDLED_EXCEPTION(_vector_0xd00) - -/* ---[ 0xe00: Trap exception ]------------------------------------------ */ - .org 0xe00 -// UNHANDLED_EXCEPTION(_vector_0xe00) - EXCEPTION_HANDLE(_trap_handler) - -/* ---[ 0xf00: Reserved exception ]-------------------------------------- */ - .org 0xf00 - UNHANDLED_EXCEPTION(_vector_0xf00) - -/* ---[ 0x1000: Reserved exception ]------------------------------------- */ - .org 0x1000 - UNHANDLED_EXCEPTION(_vector_0x1000) - -/* ---[ 0x1100: Reserved exception ]------------------------------------- */ - .org 0x1100 - UNHANDLED_EXCEPTION(_vector_0x1100) - -/* ---[ 0x1200: Reserved exception ]------------------------------------- */ - .org 0x1200 - UNHANDLED_EXCEPTION(_vector_0x1200) - -/* ---[ 0x1300: Reserved exception ]------------------------------------- */ - .org 0x1300 - UNHANDLED_EXCEPTION(_vector_0x1300) - -/* ---[ 0x1400: Reserved exception ]------------------------------------- */ - .org 0x1400 - UNHANDLED_EXCEPTION(_vector_0x1400) - -/* ---[ 0x1500: Reserved exception ]------------------------------------- */ - .org 0x1500 - UNHANDLED_EXCEPTION(_vector_0x1500) - -/* ---[ 0x1600: Reserved exception ]------------------------------------- */ - .org 0x1600 - UNHANDLED_EXCEPTION(_vector_0x1600) - -/* ---[ 0x1700: Reserved exception ]------------------------------------- */ - .org 0x1700 - UNHANDLED_EXCEPTION(_vector_0x1700) - -/* ---[ 0x1800: Reserved exception ]------------------------------------- */ - .org 0x1800 - UNHANDLED_EXCEPTION(_vector_0x1800) - -/* ---[ 0x1900: Reserved exception ]------------------------------------- */ - .org 0x1900 - UNHANDLED_EXCEPTION(_vector_0x1900) - -/* ---[ 0x1a00: Reserved exception ]------------------------------------- */ - .org 0x1a00 - UNHANDLED_EXCEPTION(_vector_0x1a00) - -/* ---[ 0x1b00: Reserved exception ]------------------------------------- */ - .org 0x1b00 - UNHANDLED_EXCEPTION(_vector_0x1b00) - -/* ---[ 0x1c00: Reserved exception ]------------------------------------- */ - .org 0x1c00 - UNHANDLED_EXCEPTION(_vector_0x1c00) - -/* ---[ 0x1d00: Reserved exception ]------------------------------------- */ - .org 0x1d00 - UNHANDLED_EXCEPTION(_vector_0x1d00) - -/* ---[ 0x1e00: Reserved exception ]------------------------------------- */ - .org 0x1e00 - UNHANDLED_EXCEPTION(_vector_0x1e00) - -/* ---[ 0x1f00: Reserved exception ]------------------------------------- */ - .org 0x1f00 - UNHANDLED_EXCEPTION(_vector_0x1f00) - - .org 0x2000 -/* ===================================================[ kernel start ]=== */ - -/* .text*/ - -/* This early stuff belongs in HEAD, but some of the functions below definitely - * don't... */ - - __HEAD - .global _start -_start: - /* - * ensure a deterministic start - */ - - l.ori r3,r0,0x1 - l.mtspr r0,r3,SPR_SR - - CLEAR_GPR(r1) - CLEAR_GPR(r2) - CLEAR_GPR(r3) - CLEAR_GPR(r4) - CLEAR_GPR(r5) - CLEAR_GPR(r6) - CLEAR_GPR(r7) - CLEAR_GPR(r8) - CLEAR_GPR(r9) - CLEAR_GPR(r10) - CLEAR_GPR(r11) - CLEAR_GPR(r12) - CLEAR_GPR(r13) - CLEAR_GPR(r14) - CLEAR_GPR(r15) - CLEAR_GPR(r16) - CLEAR_GPR(r17) - CLEAR_GPR(r18) - CLEAR_GPR(r19) - CLEAR_GPR(r20) - CLEAR_GPR(r21) - CLEAR_GPR(r22) - CLEAR_GPR(r23) - CLEAR_GPR(r24) - CLEAR_GPR(r25) - CLEAR_GPR(r26) - CLEAR_GPR(r27) - CLEAR_GPR(r28) - CLEAR_GPR(r29) - CLEAR_GPR(r30) - CLEAR_GPR(r31) - - /* - * set up initial ksp and current - */ - LOAD_SYMBOL_2_GPR(r1,init_thread_union+0x2000) // setup kernel stack - LOAD_SYMBOL_2_GPR(r10,init_thread_union) // setup current - tophys (r31,r10) - l.sw TI_KSP(r31), r1 - - l.ori r4,r0,0x0 - - - /* - * .data contains initialized data, - * .bss contains uninitialized data - clear it up - */ -clear_bss: - LOAD_SYMBOL_2_GPR(r24, __bss_start) - LOAD_SYMBOL_2_GPR(r26, _end) - tophys(r28,r24) - tophys(r30,r26) - CLEAR_GPR(r24) - CLEAR_GPR(r26) -1: - l.sw (0)(r28),r0 - l.sfltu r28,r30 - l.bf 1b - l.addi r28,r28,4 - -enable_ic: - l.jal _ic_enable - l.nop - -enable_dc: - l.jal _dc_enable - l.nop - -flush_tlb: - /* - * I N V A L I D A T E T L B e n t r i e s - */ - LOAD_SYMBOL_2_GPR(r5,SPR_DTLBMR_BASE(0)) - LOAD_SYMBOL_2_GPR(r6,SPR_ITLBMR_BASE(0)) - l.addi r7,r0,128 /* Maximum number of sets */ -1: - l.mtspr r5,r0,0x0 - l.mtspr r6,r0,0x0 - - l.addi r5,r5,1 - l.addi r6,r6,1 - l.sfeq r7,r0 - l.bnf 1b - l.addi r7,r7,-1 - - -/* The MMU needs to be enabled before or32_early_setup is called */ - -enable_mmu: - /* - * enable dmmu & immu - * SR[5] = 0, SR[6] = 0, 6th and 7th bit of SR set to 0 - */ - l.mfspr r30,r0,SPR_SR - l.movhi r28,hi(SPR_SR_DME | SPR_SR_IME) - l.ori r28,r28,lo(SPR_SR_DME | SPR_SR_IME) - l.or r30,r30,r28 - l.mtspr r0,r30,SPR_SR - l.nop - l.nop - l.nop - l.nop - l.nop - l.nop - l.nop - l.nop - l.nop - l.nop - l.nop - l.nop - l.nop - l.nop - l.nop - l.nop - - // reset the simulation counters - l.nop 5 - - LOAD_SYMBOL_2_GPR(r24, or32_early_setup) - l.jalr r24 - l.nop - -clear_regs: - /* - * clear all GPRS to increase determinism - */ - CLEAR_GPR(r2) - CLEAR_GPR(r3) - CLEAR_GPR(r4) - CLEAR_GPR(r5) - CLEAR_GPR(r6) - CLEAR_GPR(r7) - CLEAR_GPR(r8) - CLEAR_GPR(r9) - CLEAR_GPR(r11) - CLEAR_GPR(r12) - CLEAR_GPR(r13) - CLEAR_GPR(r14) - CLEAR_GPR(r15) - CLEAR_GPR(r16) - CLEAR_GPR(r17) - CLEAR_GPR(r18) - CLEAR_GPR(r19) - CLEAR_GPR(r20) - CLEAR_GPR(r21) - CLEAR_GPR(r22) - CLEAR_GPR(r23) - CLEAR_GPR(r24) - CLEAR_GPR(r25) - CLEAR_GPR(r26) - CLEAR_GPR(r27) - CLEAR_GPR(r28) - CLEAR_GPR(r29) - CLEAR_GPR(r30) - CLEAR_GPR(r31) - -jump_start_kernel: - /* - * jump to kernel entry (start_kernel) - */ - LOAD_SYMBOL_2_GPR(r30, start_kernel) - l.jr r30 - l.nop - -/* ========================================[ cache ]=== */ - - /* aligment here so we don't change memory offsets with - * memory controler defined - */ - .align 0x2000 - -_ic_enable: - /* Check if IC present and skip enabling otherwise */ - l.mfspr r24,r0,SPR_UPR - l.andi r26,r24,SPR_UPR_ICP - l.sfeq r26,r0 - l.bf 9f - l.nop - - /* Disable IC */ - l.mfspr r6,r0,SPR_SR - l.addi r5,r0,-1 - l.xori r5,r5,SPR_SR_ICE - l.and r5,r6,r5 - l.mtspr r0,r5,SPR_SR - - /* Establish cache block size - If BS=0, 16; - If BS=1, 32; - r14 contain block size - */ - l.mfspr r24,r0,SPR_ICCFGR - l.andi r26,r24,SPR_ICCFGR_CBS - l.srli r28,r26,7 - l.ori r30,r0,16 - l.sll r14,r30,r28 - - /* Establish number of cache sets - r16 contains number of cache sets - r28 contains log(# of cache sets) - */ - l.andi r26,r24,SPR_ICCFGR_NCS - l.srli r28,r26,3 - l.ori r30,r0,1 - l.sll r16,r30,r28 - - /* Invalidate IC */ - l.addi r6,r0,0 - l.sll r5,r14,r28 -// l.mul r5,r14,r16 -// l.trap 1 -// l.addi r5,r0,IC_SIZE -1: - l.mtspr r0,r6,SPR_ICBIR - l.sfne r6,r5 - l.bf 1b - l.add r6,r6,r14 - // l.addi r6,r6,IC_LINE - - /* Enable IC */ - l.mfspr r6,r0,SPR_SR - l.ori r6,r6,SPR_SR_ICE - l.mtspr r0,r6,SPR_SR - l.nop - l.nop - l.nop - l.nop - l.nop - l.nop - l.nop - l.nop - l.nop - l.nop -9: - l.jr r9 - l.nop - -_dc_enable: - /* Check if DC present and skip enabling otherwise */ - l.mfspr r24,r0,SPR_UPR - l.andi r26,r24,SPR_UPR_DCP - l.sfeq r26,r0 - l.bf 9f - l.nop - - /* Disable DC */ - l.mfspr r6,r0,SPR_SR - l.addi r5,r0,-1 - l.xori r5,r5,SPR_SR_DCE - l.and r5,r6,r5 - l.mtspr r0,r5,SPR_SR - - /* Establish cache block size - If BS=0, 16; - If BS=1, 32; - r14 contain block size - */ - l.mfspr r24,r0,SPR_DCCFGR - l.andi r26,r24,SPR_DCCFGR_CBS - l.srli r28,r26,7 - l.ori r30,r0,16 - l.sll r14,r30,r28 - - /* Establish number of cache sets - r16 contains number of cache sets - r28 contains log(# of cache sets) - */ - l.andi r26,r24,SPR_DCCFGR_NCS - l.srli r28,r26,3 - l.ori r30,r0,1 - l.sll r16,r30,r28 - - /* Invalidate DC */ - l.addi r6,r0,0 - l.sll r5,r14,r28 -1: - l.mtspr r0,r6,SPR_DCBIR - l.sfne r6,r5 - l.bf 1b - l.add r6,r6,r14 - - /* Enable DC */ - l.mfspr r6,r0,SPR_SR - l.ori r6,r6,SPR_SR_DCE - l.mtspr r0,r6,SPR_SR -9: - l.jr r9 - l.nop - -/* ===============================================[ page table masks ]=== */ - -/* bit 4 is used in hardware as write back cache bit. we never use this bit - * explicitly, so we can reuse it as _PAGE_FILE bit and mask it out when - * writing into hardware pte's - */ - -#define DTLB_UP_CONVERT_MASK 0x3fa -#define ITLB_UP_CONVERT_MASK 0x3a - -/* for SMP we'd have (this is a bit subtle, CC must be always set - * for SMP, but since we have _PAGE_PRESENT bit always defined - * we can just modify the mask) - */ -#define DTLB_SMP_CONVERT_MASK 0x3fb -#define ITLB_SMP_CONVERT_MASK 0x3b - -/* ---[ boot dtlb miss handler ]----------------------------------------- */ - -boot_dtlb_miss_handler: - -/* mask for DTLB_MR register: - (0) sets V (valid) bit, - * - (31-12) sets bits belonging to VPN (31-12) - */ -#define DTLB_MR_MASK 0xfffff001 - -/* mask for DTLB_TR register: - (2) sets CI (cache inhibit) bit, - * - (4) sets A (access) bit, - * - (5) sets D (dirty) bit, - * - (8) sets SRE (superuser read) bit - * - (9) sets SWE (superuser write) bit - * - (31-12) sets bits belonging to VPN (31-12) - */ -#define DTLB_TR_MASK 0xfffff332 - -/* These are for masking out the VPN/PPN value from the MR/TR registers... - * it's not the same as the PFN */ -#define VPN_MASK 0xfffff000 -#define PPN_MASK 0xfffff000 - - - EXCEPTION_STORE_GPR6 - -#if 0 - l.mfspr r6,r0,SPR_ESR_BASE // - l.andi r6,r6,SPR_SR_SM // are we in kernel mode ? - l.sfeqi r6,0 // r6 == 0x1 --> SM - l.bf exit_with_no_dtranslation // - l.nop -#endif - - /* this could be optimized by moving storing of - * non r6 registers here, and jumping r6 restore - * if not in supervisor mode - */ - - EXCEPTION_STORE_GPR2 - EXCEPTION_STORE_GPR3 - EXCEPTION_STORE_GPR4 - EXCEPTION_STORE_GPR5 - - l.mfspr r4,r0,SPR_EEAR_BASE // get the offending EA - -immediate_translation: - CLEAR_GPR(r6) - - l.srli r3,r4,0xd // r3 <- r4 / 8192 (sets are relative to page size (8Kb) NOT VPN size (4Kb) - - l.mfspr r6, r0, SPR_DMMUCFGR - l.andi r6, r6, SPR_DMMUCFGR_NTS - l.srli r6, r6, SPR_DMMUCFGR_NTS_OFF - l.ori r5, r0, 0x1 - l.sll r5, r5, r6 // r5 = number DMMU sets - l.addi r6, r5, -1 // r6 = nsets mask - l.and r2, r3, r6 // r2 <- r3 % NSETS_MASK - - l.or r6,r6,r4 // r6 <- r4 - l.ori r6,r6,~(VPN_MASK) // r6 <- VPN :VPN .xfff - clear up lo(r6) to 0x**** *fff - l.movhi r5,hi(DTLB_MR_MASK) // r5 <- ffff:0000.x000 - l.ori r5,r5,lo(DTLB_MR_MASK) // r5 <- ffff:1111.x001 - apply DTLB_MR_MASK - l.and r5,r5,r6 // r5 <- VPN :VPN .x001 - we have DTLBMR entry - l.mtspr r2,r5,SPR_DTLBMR_BASE(0) // set DTLBMR - - /* set up DTLB with no translation for EA <= 0xbfffffff */ - LOAD_SYMBOL_2_GPR(r6,0xbfffffff) - l.sfgeu r6,r4 // flag if r6 >= r4 (if 0xbfffffff >= EA) - l.bf 1f // goto out - l.and r3,r4,r4 // delay slot :: 24 <- r4 (if flag==1) - - tophys(r3,r4) // r3 <- PA -1: - l.ori r3,r3,~(PPN_MASK) // r3 <- PPN :PPN .xfff - clear up lo(r6) to 0x**** *fff - l.movhi r5,hi(DTLB_TR_MASK) // r5 <- ffff:0000.x000 - l.ori r5,r5,lo(DTLB_TR_MASK) // r5 <- ffff:1111.x330 - apply DTLB_MR_MASK - l.and r5,r5,r3 // r5 <- PPN :PPN .x330 - we have DTLBTR entry - l.mtspr r2,r5,SPR_DTLBTR_BASE(0) // set DTLBTR - - EXCEPTION_LOAD_GPR6 - EXCEPTION_LOAD_GPR5 - EXCEPTION_LOAD_GPR4 - EXCEPTION_LOAD_GPR3 - EXCEPTION_LOAD_GPR2 - - l.rfe // SR <- ESR, PC <- EPC - -exit_with_no_dtranslation: - /* EA out of memory or not in supervisor mode */ - EXCEPTION_LOAD_GPR6 - EXCEPTION_LOAD_GPR4 - l.j _dispatch_bus_fault - -/* ---[ boot itlb miss handler ]----------------------------------------- */ - -boot_itlb_miss_handler: - -/* mask for ITLB_MR register: - sets V (valid) bit, - * - sets bits belonging to VPN (15-12) - */ -#define ITLB_MR_MASK 0xfffff001 - -/* mask for ITLB_TR register: - sets A (access) bit, - * - sets SXE (superuser execute) bit - * - sets bits belonging to VPN (15-12) - */ -#define ITLB_TR_MASK 0xfffff050 - -/* -#define VPN_MASK 0xffffe000 -#define PPN_MASK 0xffffe000 -*/ - - - - EXCEPTION_STORE_GPR2 - EXCEPTION_STORE_GPR3 - EXCEPTION_STORE_GPR4 - EXCEPTION_STORE_GPR5 - EXCEPTION_STORE_GPR6 - -#if 0 - l.mfspr r6,r0,SPR_ESR_BASE // - l.andi r6,r6,SPR_SR_SM // are we in kernel mode ? - l.sfeqi r6,0 // r6 == 0x1 --> SM - l.bf exit_with_no_itranslation - l.nop -#endif - - - l.mfspr r4,r0,SPR_EEAR_BASE // get the offending EA - -earlyearly: - CLEAR_GPR(r6) - - l.srli r3,r4,0xd // r3 <- r4 / 8192 (sets are relative to page size (8Kb) NOT VPN size (4Kb) - - l.mfspr r6, r0, SPR_IMMUCFGR - l.andi r6, r6, SPR_IMMUCFGR_NTS - l.srli r6, r6, SPR_IMMUCFGR_NTS_OFF - l.ori r5, r0, 0x1 - l.sll r5, r5, r6 // r5 = number IMMU sets from IMMUCFGR - l.addi r6, r5, -1 // r6 = nsets mask - l.and r2, r3, r6 // r2 <- r3 % NSETS_MASK - - l.or r6,r6,r4 // r6 <- r4 - l.ori r6,r6,~(VPN_MASK) // r6 <- VPN :VPN .xfff - clear up lo(r6) to 0x**** *fff - l.movhi r5,hi(ITLB_MR_MASK) // r5 <- ffff:0000.x000 - l.ori r5,r5,lo(ITLB_MR_MASK) // r5 <- ffff:1111.x001 - apply ITLB_MR_MASK - l.and r5,r5,r6 // r5 <- VPN :VPN .x001 - we have ITLBMR entry - l.mtspr r2,r5,SPR_ITLBMR_BASE(0) // set ITLBMR - - /* - * set up ITLB with no translation for EA <= 0x0fffffff - * - * we need this for head.S mapping (EA = PA). if we move all functions - * which run with mmu enabled into entry.S, we might be able to eliminate this. - * - */ - LOAD_SYMBOL_2_GPR(r6,0x0fffffff) - l.sfgeu r6,r4 // flag if r6 >= r4 (if 0xb0ffffff >= EA) - l.bf 1f // goto out - l.and r3,r4,r4 // delay slot :: 24 <- r4 (if flag==1) - - tophys(r3,r4) // r3 <- PA -1: - l.ori r3,r3,~(PPN_MASK) // r3 <- PPN :PPN .xfff - clear up lo(r6) to 0x**** *fff - l.movhi r5,hi(ITLB_TR_MASK) // r5 <- ffff:0000.x000 - l.ori r5,r5,lo(ITLB_TR_MASK) // r5 <- ffff:1111.x050 - apply ITLB_MR_MASK - l.and r5,r5,r3 // r5 <- PPN :PPN .x050 - we have ITLBTR entry - l.mtspr r2,r5,SPR_ITLBTR_BASE(0) // set ITLBTR - - EXCEPTION_LOAD_GPR6 - EXCEPTION_LOAD_GPR5 - EXCEPTION_LOAD_GPR4 - EXCEPTION_LOAD_GPR3 - EXCEPTION_LOAD_GPR2 - - l.rfe // SR <- ESR, PC <- EPC - -exit_with_no_itranslation: - EXCEPTION_LOAD_GPR4 - EXCEPTION_LOAD_GPR6 - l.j _dispatch_bus_fault - l.nop - -/* ====================================================================== */ -/* - * Stuff below here shouldn't go into .head section... maybe this stuff - * can be moved to entry.S ??? - */ - -/* ==============================================[ DTLB miss handler ]=== */ - -/* - * Comments: - * Exception handlers are entered with MMU off so the following handler - * needs to use physical addressing - * - */ - - .text -ENTRY(dtlb_miss_handler) - EXCEPTION_STORE_GPR2 - EXCEPTION_STORE_GPR3 - EXCEPTION_STORE_GPR4 - EXCEPTION_STORE_GPR5 - EXCEPTION_STORE_GPR6 - /* - * get EA of the miss - */ - l.mfspr r2,r0,SPR_EEAR_BASE - /* - * pmd = (pmd_t *)(current_pgd + pgd_index(daddr)); - */ - GET_CURRENT_PGD(r3,r5) // r3 is current_pgd, r5 is temp - l.srli r4,r2,0x18 // >> PAGE_SHIFT + (PAGE_SHIFT - 2) - l.slli r4,r4,0x2 // to get address << 2 - l.add r5,r4,r3 // r4 is pgd_index(daddr) - /* - * if (pmd_none(*pmd)) - * goto pmd_none: - */ - tophys (r4,r5) - l.lwz r3,0x0(r4) // get *pmd value - l.sfne r3,r0 - l.bnf d_pmd_none - l.andi r3,r3,~PAGE_MASK //0x1fff // ~PAGE_MASK - /* - * if (pmd_bad(*pmd)) - * pmd_clear(pmd) - * goto pmd_bad: - */ -// l.sfeq r3,r0 // check *pmd value -// l.bf d_pmd_good - l.addi r3,r0,0xffffe000 // PAGE_MASK -// l.j d_pmd_bad -// l.sw 0x0(r4),r0 // clear pmd -d_pmd_good: - /* - * pte = *pte_offset(pmd, daddr); - */ - l.lwz r4,0x0(r4) // get **pmd value - l.and r4,r4,r3 // & PAGE_MASK - l.srli r5,r2,0xd // >> PAGE_SHIFT, r2 == EEAR - l.andi r3,r5,0x7ff // (1UL << PAGE_SHIFT - 2) - 1 - l.slli r3,r3,0x2 // to get address << 2 - l.add r3,r3,r4 - l.lwz r2,0x0(r3) // this is pte at last - /* - * if (!pte_present(pte)) - */ - l.andi r4,r2,0x1 - l.sfne r4,r0 // is pte present - l.bnf d_pte_not_present - l.addi r3,r0,0xffffe3fa // PAGE_MASK | DTLB_UP_CONVERT_MASK - /* - * fill DTLB TR register - */ - l.and r4,r2,r3 // apply the mask - // Determine number of DMMU sets - l.mfspr r6, r0, SPR_DMMUCFGR - l.andi r6, r6, SPR_DMMUCFGR_NTS - l.srli r6, r6, SPR_DMMUCFGR_NTS_OFF - l.ori r3, r0, 0x1 - l.sll r3, r3, r6 // r3 = number DMMU sets DMMUCFGR - l.addi r6, r3, -1 // r6 = nsets mask - l.and r5, r5, r6 // calc offset: & (NUM_TLB_ENTRIES-1) - //NUM_TLB_ENTRIES - l.mtspr r5,r4,SPR_DTLBTR_BASE(0) - /* - * fill DTLB MR register - */ - l.mfspr r2,r0,SPR_EEAR_BASE - l.addi r3,r0,0xffffe000 // PAGE_MASK - l.and r4,r2,r3 // apply PAGE_MASK to EA (__PHX__ do we really need this?) - l.ori r4,r4,0x1 // set hardware valid bit: DTBL_MR entry - l.mtspr r5,r4,SPR_DTLBMR_BASE(0) - - EXCEPTION_LOAD_GPR2 - EXCEPTION_LOAD_GPR3 - EXCEPTION_LOAD_GPR4 - EXCEPTION_LOAD_GPR5 - EXCEPTION_LOAD_GPR6 - l.rfe -d_pmd_bad: - l.nop 1 - EXCEPTION_LOAD_GPR2 - EXCEPTION_LOAD_GPR3 - EXCEPTION_LOAD_GPR4 - EXCEPTION_LOAD_GPR5 - EXCEPTION_LOAD_GPR6 - l.rfe -d_pmd_none: -d_pte_not_present: - EXCEPTION_LOAD_GPR2 - EXCEPTION_LOAD_GPR3 - EXCEPTION_LOAD_GPR4 - EXCEPTION_LOAD_GPR5 - EXCEPTION_LOAD_GPR6 - l.j _dispatch_do_dpage_fault - l.nop - -/* ==============================================[ ITLB miss handler ]=== */ -ENTRY(itlb_miss_handler) - EXCEPTION_STORE_GPR2 - EXCEPTION_STORE_GPR3 - EXCEPTION_STORE_GPR4 - EXCEPTION_STORE_GPR5 - EXCEPTION_STORE_GPR6 - /* - * get EA of the miss - */ - l.mfspr r2,r0,SPR_EEAR_BASE - - /* - * pmd = (pmd_t *)(current_pgd + pgd_index(daddr)); - * - */ - GET_CURRENT_PGD(r3,r5) // r3 is current_pgd, r5 is temp - l.srli r4,r2,0x18 // >> PAGE_SHIFT + (PAGE_SHIFT - 2) - l.slli r4,r4,0x2 // to get address << 2 - l.add r5,r4,r3 // r4 is pgd_index(daddr) - /* - * if (pmd_none(*pmd)) - * goto pmd_none: - */ - tophys (r4,r5) - l.lwz r3,0x0(r4) // get *pmd value - l.sfne r3,r0 - l.bnf i_pmd_none - l.andi r3,r3,0x1fff // ~PAGE_MASK - /* - * if (pmd_bad(*pmd)) - * pmd_clear(pmd) - * goto pmd_bad: - */ - -// l.sfeq r3,r0 // check *pmd value -// l.bf i_pmd_good - l.addi r3,r0,0xffffe000 // PAGE_MASK -// l.j i_pmd_bad -// l.sw 0x0(r4),r0 // clear pmd - -i_pmd_good: - /* - * pte = *pte_offset(pmd, iaddr); - * - */ - l.lwz r4,0x0(r4) // get **pmd value - l.and r4,r4,r3 // & PAGE_MASK - l.srli r5,r2,0xd // >> PAGE_SHIFT, r2 == EEAR - l.andi r3,r5,0x7ff // (1UL << PAGE_SHIFT - 2) - 1 - l.slli r3,r3,0x2 // to get address << 2 - l.add r3,r3,r4 - l.lwz r2,0x0(r3) // this is pte at last - /* - * if (!pte_present(pte)) - * - */ - l.andi r4,r2,0x1 - l.sfne r4,r0 // is pte present - l.bnf i_pte_not_present - l.addi r3,r0,0xffffe03a // PAGE_MASK | ITLB_UP_CONVERT_MASK - /* - * fill ITLB TR register - */ - l.and r4,r2,r3 // apply the mask - l.andi r3,r2,0x7c0 // _PAGE_EXEC | _PAGE_SRE | _PAGE_SWE | _PAGE_URE | _PAGE_UWE -// l.andi r3,r2,0x400 // _PAGE_EXEC - l.sfeq r3,r0 - l.bf itlb_tr_fill //_workaround - // Determine number of IMMU sets - l.mfspr r6, r0, SPR_IMMUCFGR - l.andi r6, r6, SPR_IMMUCFGR_NTS - l.srli r6, r6, SPR_IMMUCFGR_NTS_OFF - l.ori r3, r0, 0x1 - l.sll r3, r3, r6 // r3 = number IMMU sets IMMUCFGR - l.addi r6, r3, -1 // r6 = nsets mask - l.and r5, r5, r6 // calc offset: & (NUM_TLB_ENTRIES-1) - -/* - * __PHX__ :: fixme - * we should not just blindly set executable flags, - * but it does help with ping. the clean way would be to find out - * (and fix it) why stack doesn't have execution permissions - */ - -itlb_tr_fill_workaround: - l.ori r4,r4,0xc0 // | (SPR_ITLBTR_UXE | ITLBTR_SXE) -itlb_tr_fill: - l.mtspr r5,r4,SPR_ITLBTR_BASE(0) - /* - * fill DTLB MR register - */ - l.mfspr r2,r0,SPR_EEAR_BASE - l.addi r3,r0,0xffffe000 // PAGE_MASK - l.and r4,r2,r3 // apply PAGE_MASK to EA (__PHX__ do we really need this?) - l.ori r4,r4,0x1 // set hardware valid bit: DTBL_MR entry - l.mtspr r5,r4,SPR_ITLBMR_BASE(0) - - EXCEPTION_LOAD_GPR2 - EXCEPTION_LOAD_GPR3 - EXCEPTION_LOAD_GPR4 - EXCEPTION_LOAD_GPR5 - EXCEPTION_LOAD_GPR6 - l.rfe - -i_pmd_bad: - l.nop 1 - EXCEPTION_LOAD_GPR2 - EXCEPTION_LOAD_GPR3 - EXCEPTION_LOAD_GPR4 - EXCEPTION_LOAD_GPR5 - EXCEPTION_LOAD_GPR6 - l.rfe -i_pmd_none: -i_pte_not_present: - EXCEPTION_LOAD_GPR2 - EXCEPTION_LOAD_GPR3 - EXCEPTION_LOAD_GPR4 - EXCEPTION_LOAD_GPR5 - EXCEPTION_LOAD_GPR6 - l.j _dispatch_do_ipage_fault - l.nop - -/* ==============================================[ boot tlb handlers ]=== */ - - -/* =================================================[ debugging aids ]=== */ - - .align 64 -_immu_trampoline: - .space 64 -_immu_trampoline_top: - -#define TRAMP_SLOT_0 (0x0) -#define TRAMP_SLOT_1 (0x4) -#define TRAMP_SLOT_2 (0x8) -#define TRAMP_SLOT_3 (0xc) -#define TRAMP_SLOT_4 (0x10) -#define TRAMP_SLOT_5 (0x14) -#define TRAMP_FRAME_SIZE (0x18) - -ENTRY(_immu_trampoline_workaround) - // r2 EEA - // r6 is physical EEA - tophys(r6,r2) - - LOAD_SYMBOL_2_GPR(r5,_immu_trampoline) - tophys (r3,r5) // r3 is trampoline (physical) - - LOAD_SYMBOL_2_GPR(r4,0x15000000) - l.sw TRAMP_SLOT_0(r3),r4 - l.sw TRAMP_SLOT_1(r3),r4 - l.sw TRAMP_SLOT_4(r3),r4 - l.sw TRAMP_SLOT_5(r3),r4 - - // EPC = EEA - 0x4 - l.lwz r4,0x0(r6) // load op @ EEA + 0x0 (fc address) - l.sw TRAMP_SLOT_3(r3),r4 // store it to _immu_trampoline_data - l.lwz r4,-0x4(r6) // load op @ EEA - 0x4 (f8 address) - l.sw TRAMP_SLOT_2(r3),r4 // store it to _immu_trampoline_data - - l.srli r5,r4,26 // check opcode for write access - l.sfeqi r5,0 // l.j - l.bf 0f - l.sfeqi r5,0x11 // l.jr - l.bf 1f - l.sfeqi r5,1 // l.jal - l.bf 2f - l.sfeqi r5,0x12 // l.jalr - l.bf 3f - l.sfeqi r5,3 // l.bnf - l.bf 4f - l.sfeqi r5,4 // l.bf - l.bf 5f -99: - l.nop - l.j 99b // should never happen - l.nop 1 - - // r2 is EEA - // r3 is trampoline address (physical) - // r4 is instruction - // r6 is physical(EEA) - // - // r5 - -2: // l.jal - - /* 19 20 aa aa l.movhi r9,0xaaaa - * a9 29 bb bb l.ori r9,0xbbbb - * - * where 0xaaaabbbb is EEA + 0x4 shifted right 2 - */ - - l.addi r6,r2,0x4 // this is 0xaaaabbbb - - // l.movhi r9,0xaaaa - l.ori r5,r0,0x1920 // 0x1920 == l.movhi r9 - l.sh (TRAMP_SLOT_0+0x0)(r3),r5 - l.srli r5,r6,16 - l.sh (TRAMP_SLOT_0+0x2)(r3),r5 - - // l.ori r9,0xbbbb - l.ori r5,r0,0xa929 // 0xa929 == l.ori r9 - l.sh (TRAMP_SLOT_1+0x0)(r3),r5 - l.andi r5,r6,0xffff - l.sh (TRAMP_SLOT_1+0x2)(r3),r5 - - /* falthrough, need to set up new jump offset */ - - -0: // l.j - l.slli r6,r4,6 // original offset shifted left 6 - 2 -// l.srli r6,r6,6 // original offset shifted right 2 - - l.slli r4,r2,4 // old jump position: EEA shifted left 4 -// l.srli r4,r4,6 // old jump position: shifted right 2 - - l.addi r5,r3,0xc // new jump position (physical) - l.slli r5,r5,4 // new jump position: shifted left 4 - - // calculate new jump offset - // new_off = old_off + (old_jump - new_jump) - - l.sub r5,r4,r5 // old_jump - new_jump - l.add r5,r6,r5 // orig_off + (old_jump - new_jump) - l.srli r5,r5,6 // new offset shifted right 2 - - // r5 is new jump offset - // l.j has opcode 0x0... - l.sw TRAMP_SLOT_2(r3),r5 // write it back - - l.j trampoline_out - l.nop - -/* ----------------------------- */ - -3: // l.jalr - - /* 19 20 aa aa l.movhi r9,0xaaaa - * a9 29 bb bb l.ori r9,0xbbbb - * - * where 0xaaaabbbb is EEA + 0x4 shifted right 2 - */ - - l.addi r6,r2,0x4 // this is 0xaaaabbbb - - // l.movhi r9,0xaaaa - l.ori r5,r0,0x1920 // 0x1920 == l.movhi r9 - l.sh (TRAMP_SLOT_0+0x0)(r3),r5 - l.srli r5,r6,16 - l.sh (TRAMP_SLOT_0+0x2)(r3),r5 - - // l.ori r9,0xbbbb - l.ori r5,r0,0xa929 // 0xa929 == l.ori r9 - l.sh (TRAMP_SLOT_1+0x0)(r3),r5 - l.andi r5,r6,0xffff - l.sh (TRAMP_SLOT_1+0x2)(r3),r5 - - l.lhz r5,(TRAMP_SLOT_2+0x0)(r3) // load hi part of jump instruction - l.andi r5,r5,0x3ff // clear out opcode part - l.ori r5,r5,0x4400 // opcode changed from l.jalr -> l.jr - l.sh (TRAMP_SLOT_2+0x0)(r3),r5 // write it back - - /* falthrough */ - -1: // l.jr - l.j trampoline_out - l.nop - -/* ----------------------------- */ - -4: // l.bnf -5: // l.bf - l.slli r6,r4,6 // original offset shifted left 6 - 2 -// l.srli r6,r6,6 // original offset shifted right 2 - - l.slli r4,r2,4 // old jump position: EEA shifted left 4 -// l.srli r4,r4,6 // old jump position: shifted right 2 - - l.addi r5,r3,0xc // new jump position (physical) - l.slli r5,r5,4 // new jump position: shifted left 4 - - // calculate new jump offset - // new_off = old_off + (old_jump - new_jump) - - l.add r6,r6,r4 // (orig_off + old_jump) - l.sub r6,r6,r5 // (orig_off + old_jump) - new_jump - l.srli r6,r6,6 // new offset shifted right 2 - - // r6 is new jump offset - l.lwz r4,(TRAMP_SLOT_2+0x0)(r3) // load jump instruction - l.srli r4,r4,16 - l.andi r4,r4,0xfc00 // get opcode part - l.slli r4,r4,16 - l.or r6,r4,r6 // l.b(n)f new offset - l.sw TRAMP_SLOT_2(r3),r6 // write it back - - /* we need to add l.j to EEA + 0x8 */ - tophys (r4,r2) // may not be needed (due to shifts down_ - l.addi r4,r4,(0x8 - 0x8) // jump target = r2 + 0x8 (compensate for 0x8) - // jump position = r5 + 0x8 (0x8 compensated) - l.sub r4,r4,r5 // jump offset = target - new_position + 0x8 - - l.slli r4,r4,4 // the amount of info in imediate of jump - l.srli r4,r4,6 // jump instruction with offset - l.sw TRAMP_SLOT_4(r3),r4 // write it to 4th slot - - /* fallthrough */ - -trampoline_out: - // set up new EPC to point to our trampoline code - LOAD_SYMBOL_2_GPR(r5,_immu_trampoline) - l.mtspr r0,r5,SPR_EPCR_BASE - - // immu_trampoline is (4x) CACHE_LINE aligned - // and only 6 instructions long, - // so we need to invalidate only 2 lines - - /* Establish cache block size - If BS=0, 16; - If BS=1, 32; - r14 contain block size - */ - l.mfspr r21,r0,SPR_ICCFGR - l.andi r21,r21,SPR_ICCFGR_CBS - l.srli r21,r21,7 - l.ori r23,r0,16 - l.sll r14,r23,r21 - - l.mtspr r0,r5,SPR_ICBIR - l.add r5,r5,r14 - l.mtspr r0,r5,SPR_ICBIR - - l.jr r9 - l.nop - - -/* - * DSCR: prints a string referenced by r3. - * - * PRMS: r3 - address of the first character of null - * terminated string to be printed - * - * PREQ: UART at UART_BASE_ADD has to be initialized - * - * POST: caller should be aware that r3, r9 are changed - */ -ENTRY(_emergency_print) - EMERGENCY_PRINT_STORE_GPR4 - EMERGENCY_PRINT_STORE_GPR5 - EMERGENCY_PRINT_STORE_GPR6 - EMERGENCY_PRINT_STORE_GPR7 -2: - l.lbz r7,0(r3) - l.sfeq r7,r0 - l.bf 9f - l.nop - -// putc: - l.movhi r4,hi(UART_BASE_ADD) - - l.addi r6,r0,0x20 -1: l.lbz r5,5(r4) - l.andi r5,r5,0x20 - l.sfeq r5,r6 - l.bnf 1b - l.nop - - l.sb 0(r4),r7 - - l.addi r6,r0,0x60 -1: l.lbz r5,5(r4) - l.andi r5,r5,0x60 - l.sfeq r5,r6 - l.bnf 1b - l.nop - - /* next character */ - l.j 2b - l.addi r3,r3,0x1 - -9: - EMERGENCY_PRINT_LOAD_GPR7 - EMERGENCY_PRINT_LOAD_GPR6 - EMERGENCY_PRINT_LOAD_GPR5 - EMERGENCY_PRINT_LOAD_GPR4 - l.jr r9 - l.nop - -ENTRY(_emergency_print_nr) - EMERGENCY_PRINT_STORE_GPR4 - EMERGENCY_PRINT_STORE_GPR5 - EMERGENCY_PRINT_STORE_GPR6 - EMERGENCY_PRINT_STORE_GPR7 - EMERGENCY_PRINT_STORE_GPR8 - - l.addi r8,r0,32 // shift register - -1: /* remove leading zeros */ - l.addi r8,r8,-0x4 - l.srl r7,r3,r8 - l.andi r7,r7,0xf - - /* don't skip the last zero if number == 0x0 */ - l.sfeqi r8,0x4 - l.bf 2f - l.nop - - l.sfeq r7,r0 - l.bf 1b - l.nop - -2: - l.srl r7,r3,r8 - - l.andi r7,r7,0xf - l.sflts r8,r0 - l.bf 9f - - l.sfgtui r7,0x9 - l.bnf 8f - l.nop - l.addi r7,r7,0x27 - -8: - l.addi r7,r7,0x30 -// putc: - l.movhi r4,hi(UART_BASE_ADD) - - l.addi r6,r0,0x20 -1: l.lbz r5,5(r4) - l.andi r5,r5,0x20 - l.sfeq r5,r6 - l.bnf 1b - l.nop - - l.sb 0(r4),r7 - - l.addi r6,r0,0x60 -1: l.lbz r5,5(r4) - l.andi r5,r5,0x60 - l.sfeq r5,r6 - l.bnf 1b - l.nop - - /* next character */ - l.j 2b - l.addi r8,r8,-0x4 - -9: - EMERGENCY_PRINT_LOAD_GPR8 - EMERGENCY_PRINT_LOAD_GPR7 - EMERGENCY_PRINT_LOAD_GPR6 - EMERGENCY_PRINT_LOAD_GPR5 - EMERGENCY_PRINT_LOAD_GPR4 - l.jr r9 - l.nop - - -/* - * This should be used for debugging only. - * It messes up the Linux early serial output - * somehow, so use it sparingly and essentially - * only if you need to debug something that goes wrong - * before Linux gets the early serial going. - * - * Furthermore, you'll have to make sure you set the - * UART_DEVISOR correctly according to the system - * clock rate. - * - * - */ - - - -#define SYS_CLK 20000000 -//#define SYS_CLK 1843200 -#define OR32_CONSOLE_BAUD 115200 -#define UART_DIVISOR SYS_CLK/(16*OR32_CONSOLE_BAUD) - -ENTRY(_early_uart_init) - l.movhi r3,hi(UART_BASE_ADD) - - l.addi r4,r0,0x7 - l.sb 0x2(r3),r4 - - l.addi r4,r0,0x0 - l.sb 0x1(r3),r4 - - l.addi r4,r0,0x3 - l.sb 0x3(r3),r4 - - l.lbz r5,3(r3) - l.ori r4,r5,0x80 - l.sb 0x3(r3),r4 - l.addi r4,r0,((UART_DIVISOR>>8) & 0x000000ff) - l.sb UART_DLM(r3),r4 - l.addi r4,r0,((UART_DIVISOR) & 0x000000ff) - l.sb UART_DLL(r3),r4 - l.sb 0x3(r3),r5 - - l.jr r9 - l.nop - -_string_copying_linux: - .string "\n\n\n\n\n\rCopying Linux... \0" - -_string_ok_booting: - .string "Ok, booting the kernel.\n\r\0" - -_string_unhandled_exception: - .string "\n\rRunarunaround: Unhandled exception 0x\0" - -_string_epc_prefix: - .string ": EPC=0x\0" - -_string_nl: - .string "\n\r\0" - - .global _string_esr_irq_bug -_string_esr_irq_bug: - .string "\n\rESR external interrupt bug, for details look into entry.S\n\r\0" - - - -/* ========================================[ page aligned structures ]=== */ - -/* - * .data section should be page aligned - * (look into arch/or32/kernel/vmlinux.lds) - */ - .section .data,"aw" - .align 8192 - .global empty_zero_page -empty_zero_page: - .space 8192 - - .global swapper_pg_dir -swapper_pg_dir: - .space 8192 - - .global _unhandled_stack -_unhandled_stack: - .space 8192 -_unhandled_stack_top: - -/* ============================================================[ EOF ]=== */ diff --git a/trunk/arch/openrisc/kernel/idle.c b/trunk/arch/openrisc/kernel/idle.c deleted file mode 100644 index d5bc5f813e89..000000000000 --- a/trunk/arch/openrisc/kernel/idle.c +++ /dev/null @@ -1,77 +0,0 @@ -/* - * OpenRISC idle.c - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * Modifications for the OpenRISC architecture: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * - * 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. - * - * Idle daemon for or32. Idle daemon will handle any action - * that needs to be taken when the system becomes idle. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -void (*powersave) (void) = NULL; - -static inline void pm_idle(void) -{ - barrier(); -} - -void cpu_idle(void) -{ - set_thread_flag(TIF_POLLING_NRFLAG); - - /* endless idle loop with no priority at all */ - while (1) { - tick_nohz_stop_sched_tick(1); - - while (!need_resched()) { - check_pgt_cache(); - rmb(); - - clear_thread_flag(TIF_POLLING_NRFLAG); - - local_irq_disable(); - /* Don't trace irqs off for idle */ - stop_critical_timings(); - if (!need_resched() && powersave != NULL) - powersave(); - start_critical_timings(); - local_irq_enable(); - set_thread_flag(TIF_POLLING_NRFLAG); - } - - tick_nohz_restart_sched_tick(); - preempt_enable_no_resched(); - schedule(); - preempt_disable(); - } -} diff --git a/trunk/arch/openrisc/kernel/init_task.c b/trunk/arch/openrisc/kernel/init_task.c deleted file mode 100644 index 45744a384927..000000000000 --- a/trunk/arch/openrisc/kernel/init_task.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * OpenRISC init_task.c - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * Modifications for the OpenRISC architecture: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include - -static struct signal_struct init_signals = INIT_SIGNALS(init_signals); -static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); - -/* - * Initial thread structure. - * - * We need to make sure that this is THREAD_SIZE aligned due to the - * way process stacks are handled. This is done by having a special - * "init_task" linker map entry.. - */ -union thread_union init_thread_union __init_task_data = { - INIT_THREAD_INFO(init_task) -}; - -/* - * Initial task structure. - * - * All other task structs will be allocated on slabs in fork.c - */ -struct task_struct init_task = INIT_TASK(init_task); -EXPORT_SYMBOL(init_task); diff --git a/trunk/arch/openrisc/kernel/irq.c b/trunk/arch/openrisc/kernel/irq.c deleted file mode 100644 index 59b302338331..000000000000 --- a/trunk/arch/openrisc/kernel/irq.c +++ /dev/null @@ -1,172 +0,0 @@ -/* - * OpenRISC irq.c - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * Modifications for the OpenRISC architecture: - * Copyright (C) 2010-2011 Jonas Bonn - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* read interrupt enabled status */ -unsigned long arch_local_save_flags(void) -{ - return mfspr(SPR_SR) & (SPR_SR_IEE|SPR_SR_TEE); -} -EXPORT_SYMBOL(arch_local_save_flags); - -/* set interrupt enabled status */ -void arch_local_irq_restore(unsigned long flags) -{ - mtspr(SPR_SR, ((mfspr(SPR_SR) & ~(SPR_SR_IEE|SPR_SR_TEE)) | flags)); -} -EXPORT_SYMBOL(arch_local_irq_restore); - - -/* OR1K PIC implementation */ - -/* We're a couple of cycles faster than the generic implementations with - * these 'fast' versions. - */ - -static void or1k_pic_mask(struct irq_data *data) -{ - mtspr(SPR_PICMR, mfspr(SPR_PICMR) & ~(1UL << data->irq)); -} - -static void or1k_pic_unmask(struct irq_data *data) -{ - mtspr(SPR_PICMR, mfspr(SPR_PICMR) | (1UL << data->irq)); -} - -static void or1k_pic_ack(struct irq_data *data) -{ - /* EDGE-triggered interrupts need to be ack'ed in order to clear - * the latch. - * LEVER-triggered interrupts do not need to be ack'ed; however, - * ack'ing the interrupt has no ill-effect and is quicker than - * trying to figure out what type it is... - */ - - /* The OpenRISC 1000 spec says to write a 1 to the bit to ack the - * interrupt, but the OR1200 does this backwards and requires a 0 - * to be written... - */ - -#ifdef CONFIG_OR1K_1200 - /* There are two oddities with the OR1200 PIC implementation: - * i) LEVEL-triggered interrupts are latched and need to be cleared - * ii) the interrupt latch is cleared by writing a 0 to the bit, - * as opposed to a 1 as mandated by the spec - */ - - mtspr(SPR_PICSR, mfspr(SPR_PICSR) & ~(1UL << data->irq)); -#else - WARN(1, "Interrupt handling possibily broken\n"); - mtspr(SPR_PICSR, (1UL << irq)); -#endif -} - -static void or1k_pic_mask_ack(struct irq_data *data) -{ - /* Comments for pic_ack apply here, too */ - -#ifdef CONFIG_OR1K_1200 - mtspr(SPR_PICSR, mfspr(SPR_PICSR) & ~(1UL << data->irq)); -#else - WARN(1, "Interrupt handling possibily broken\n"); - mtspr(SPR_PICSR, (1UL << irq)); -#endif -} - -static int or1k_pic_set_type(struct irq_data *data, unsigned int flow_type) -{ - /* There's nothing to do in the PIC configuration when changing - * flow type. Level and edge-triggered interrupts are both - * supported, but it's PIC-implementation specific which type - * is handled. */ - - return irq_setup_alt_chip(data, flow_type); -} - -static inline int pic_get_irq(int first) -{ - int irq; - - irq = ffs(mfspr(SPR_PICSR) >> first); - - return irq ? irq + first - 1 : NO_IRQ; -} - -static void __init or1k_irq_init(void) -{ - struct irq_chip_generic *gc; - struct irq_chip_type *ct; - - /* Disable all interrupts until explicitly requested */ - mtspr(SPR_PICMR, (0UL)); - - gc = irq_alloc_generic_chip("or1k-PIC", 1, 0, 0, handle_level_irq); - ct = gc->chip_types; - - ct->chip.irq_unmask = or1k_pic_unmask; - ct->chip.irq_mask = or1k_pic_mask; - ct->chip.irq_ack = or1k_pic_ack; - ct->chip.irq_mask_ack = or1k_pic_mask_ack; - ct->chip.irq_set_type = or1k_pic_set_type; - - /* The OR1K PIC can handle both level and edge trigged - * interrupts in roughly the same manner - */ -#if 0 - /* FIXME: chip.type??? */ - ct->chip.type = IRQ_TYPE_EDGE_BOTH | IRQ_TYPE_LEVEL_MASK; -#endif - - irq_setup_generic_chip(gc, IRQ_MSK(NR_IRQS), 0, - IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE); -} - -void __init init_IRQ(void) -{ - or1k_irq_init(); -} - -void __irq_entry do_IRQ(struct pt_regs *regs) -{ - int irq = -1; - struct pt_regs *old_regs = set_irq_regs(regs); - - irq_enter(); - - while ((irq = pic_get_irq(irq + 1)) != NO_IRQ) - generic_handle_irq(irq); - - irq_exit(); - set_irq_regs(old_regs); -} - -unsigned int irq_create_of_mapping(struct device_node *controller, - const u32 *intspec, unsigned int intsize) -{ - return intspec[0]; -} -EXPORT_SYMBOL_GPL(irq_create_of_mapping); diff --git a/trunk/arch/openrisc/kernel/module.c b/trunk/arch/openrisc/kernel/module.c deleted file mode 100644 index 10ff50f0202a..000000000000 --- a/trunk/arch/openrisc/kernel/module.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - * OpenRISC module.c - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * Modifications for the OpenRISC architecture: - * Copyright (C) 2010-2011 Jonas Bonn - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include - -int apply_relocate_add(Elf32_Shdr *sechdrs, - const char *strtab, - unsigned int symindex, - unsigned int relsec, - struct module *me) -{ - unsigned int i; - Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr; - Elf32_Sym *sym; - uint32_t *location; - uint32_t value; - - pr_debug("Applying relocate section %u to %u\n", relsec, - sechdrs[relsec].sh_info); - for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { - /* This is where to make the change */ - location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr - + rel[i].r_offset; - - /* This is the symbol it is referring to. Note that all - undefined symbols have been resolved. */ - sym = (Elf32_Sym *)sechdrs[symindex].sh_addr - + ELF32_R_SYM(rel[i].r_info); - value = sym->st_value + rel[i].r_addend; - - switch (ELF32_R_TYPE(rel[i].r_info)) { - case R_OR32_32: - *location = value; - break; - case R_OR32_CONST: - location = (uint16_t *)location + 1; - *((uint16_t *)location) = (uint16_t) (value); - break; - case R_OR32_CONSTH: - location = (uint16_t *)location + 1; - *((uint16_t *)location) = (uint16_t) (value >> 16); - break; - case R_OR32_JUMPTARG: - value -= (uint32_t)location; - value >>= 2; - value &= 0x03ffffff; - value |= *location & 0xfc000000; - *location = value; - break; - default: - pr_err("module %s: Unknown relocation: %u\n", - me->name, ELF32_R_TYPE(rel[i].r_info)); - break; - } - } - - return 0; -} diff --git a/trunk/arch/openrisc/kernel/or32_ksyms.c b/trunk/arch/openrisc/kernel/or32_ksyms.c deleted file mode 100644 index 83ccf7c0c58d..000000000000 --- a/trunk/arch/openrisc/kernel/or32_ksyms.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * OpenRISC or32_ksyms.c - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * Modifications for the OpenRISC architecture: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#define DECLARE_EXPORT(name) extern void name(void); EXPORT_SYMBOL(name) - -/* compiler generated symbols */ -DECLARE_EXPORT(__udivsi3); -DECLARE_EXPORT(__divsi3); -DECLARE_EXPORT(__umodsi3); -DECLARE_EXPORT(__modsi3); -DECLARE_EXPORT(__muldi3); -DECLARE_EXPORT(__ashrdi3); -DECLARE_EXPORT(__ashldi3); -DECLARE_EXPORT(__lshrdi3); - -EXPORT_SYMBOL(__copy_tofrom_user); diff --git a/trunk/arch/openrisc/kernel/process.c b/trunk/arch/openrisc/kernel/process.c deleted file mode 100644 index e4209af879ec..000000000000 --- a/trunk/arch/openrisc/kernel/process.c +++ /dev/null @@ -1,311 +0,0 @@ -/* - * OpenRISC process.c - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * Modifications for the OpenRISC architecture: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * - * 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 file handles the architecture-dependent parts of process handling... - */ - -#define __KERNEL_SYSCALLS__ -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -/* - * Pointer to Current thread info structure. - * - * Used at user space -> kernel transitions. - */ -struct thread_info *current_thread_info_set[NR_CPUS] = { &init_thread_info, }; - -void machine_restart(void) -{ - printk(KERN_INFO "*** MACHINE RESTART ***\n"); - __asm__("l.nop 1"); -} - -/* - * Similar to machine_power_off, but don't shut off power. Add code - * here to freeze the system for e.g. post-mortem debug purpose when - * possible. This halt has nothing to do with the idle halt. - */ -void machine_halt(void) -{ - printk(KERN_INFO "*** MACHINE HALT ***\n"); - __asm__("l.nop 1"); -} - -/* If or when software power-off is implemented, add code here. */ -void machine_power_off(void) -{ - printk(KERN_INFO "*** MACHINE POWER OFF ***\n"); - __asm__("l.nop 1"); -} - -void (*pm_power_off) (void) = machine_power_off; - -/* - * When a process does an "exec", machine state like FPU and debug - * registers need to be reset. This is a hook function for that. - * Currently we don't have any such state to reset, so this is empty. - */ -void flush_thread(void) -{ -} - -void show_regs(struct pt_regs *regs) -{ - extern void show_registers(struct pt_regs *regs); - - /* __PHX__ cleanup this mess */ - show_registers(regs); -} - -unsigned long thread_saved_pc(struct task_struct *t) -{ - return (unsigned long)user_regs(t->stack)->pc; -} - -void release_thread(struct task_struct *dead_task) -{ -} - -/* - * Copy the thread-specific (arch specific) info from the current - * process to the new one p - */ -extern asmlinkage void ret_from_fork(void); - -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 pt_regs *kregs; - unsigned long sp = (unsigned long)task_stack_page(p) + THREAD_SIZE; - struct thread_info *ti; - unsigned long top_of_kernel_stack; - - top_of_kernel_stack = sp; - - p->set_child_tid = p->clear_child_tid = NULL; - - /* Copy registers */ - /* redzone */ - sp -= STACK_FRAME_OVERHEAD; - sp -= sizeof(struct pt_regs); - childregs = (struct pt_regs *)sp; - - /* Copy parent registers */ - *childregs = *regs; - - if ((childregs->sr & SPR_SR_SM) == 1) { - /* for kernel thread, set `current_thread_info' - * and stackptr in new task - */ - childregs->sp = (unsigned long)task_stack_page(p) + THREAD_SIZE; - childregs->gpr[10] = (unsigned long)task_thread_info(p); - } else { - childregs->sp = usp; - } - - childregs->gpr[11] = 0; /* Result from fork() */ - - /* - * The way this works is that at some point in the future - * some task will call _switch to switch to the new task. - * That will pop off the stack frame created below and start - * the new task running at ret_from_fork. The new task will - * do some house keeping and then return from the fork or clone - * system call, using the stack frame created above. - */ - /* redzone */ - sp -= STACK_FRAME_OVERHEAD; - sp -= sizeof(struct pt_regs); - kregs = (struct pt_regs *)sp; - - ti = task_thread_info(p); - ti->ksp = sp; - - /* kregs->sp must store the location of the 'pre-switch' kernel stack - * pointer... for a newly forked process, this is simply the top of - * the kernel stack. - */ - kregs->sp = top_of_kernel_stack; - kregs->gpr[3] = (unsigned long)current; /* arg to schedule_tail */ - kregs->gpr[10] = (unsigned long)task_thread_info(p); - kregs->gpr[9] = (unsigned long)ret_from_fork; - - return 0; -} - -/* - * Set up a thread for executing a new program - */ -void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp) -{ - unsigned long sr = regs->sr & ~SPR_SR_SM; - - set_fs(USER_DS); - memset(regs->gpr, 0, sizeof(regs->gpr)); - - regs->pc = pc; - regs->sr = sr; - regs->sp = sp; - -/* printk("start thread, ksp = %lx\n", current_thread_info()->ksp);*/ -} - -/* Fill in the fpu structure for a core dump. */ -int dump_fpu(struct pt_regs *regs, elf_fpregset_t * fpu) -{ - /* TODO */ - return 0; -} - -extern struct thread_info *_switch(struct thread_info *old_ti, - struct thread_info *new_ti); - -struct task_struct *__switch_to(struct task_struct *old, - struct task_struct *new) -{ - struct task_struct *last; - struct thread_info *new_ti, *old_ti; - unsigned long flags; - - local_irq_save(flags); - - /* current_set is an array of saved current pointers - * (one for each cpu). we need them at user->kernel transition, - * while we save them at kernel->user transition - */ - new_ti = new->stack; - old_ti = old->stack; - - current_thread_info_set[smp_processor_id()] = new_ti; - last = (_switch(old_ti, new_ti))->task; - - local_irq_restore(flags); - - return last; -} - -/* - * Write out registers in core dump format, as defined by the - * struct user_regs_struct - */ -void dump_elf_thread(elf_greg_t *dest, struct pt_regs* regs) -{ - dest[0] = 0; /* r0 */ - memcpy(dest+1, regs->gpr+1, 31*sizeof(unsigned long)); - dest[32] = regs->pc; - dest[33] = regs->sr; - dest[34] = 0; - dest[35] = 0; -} - -extern void _kernel_thread_helper(void); - -void __noreturn kernel_thread_helper(int (*fn) (void *), void *arg) -{ - do_exit(fn(arg)); -} - -/* - * Create a kernel thread. - */ -int kernel_thread(int (*fn) (void *), void *arg, unsigned long flags) -{ - struct pt_regs regs; - - memset(®s, 0, sizeof(regs)); - - regs.gpr[20] = (unsigned long)fn; - regs.gpr[22] = (unsigned long)arg; - regs.sr = mfspr(SPR_SR); - regs.pc = (unsigned long)_kernel_thread_helper; - - return do_fork(flags | CLONE_VM | CLONE_UNTRACED, - 0, ®s, 0, NULL, NULL); -} - -/* - * sys_execve() executes a new program. - */ -asmlinkage long _sys_execve(const char __user *name, - const char __user * const __user *argv, - const char __user * const __user *envp, - struct pt_regs *regs) -{ - int error; - char *filename; - - filename = getname(name); - error = PTR_ERR(filename); - - if (IS_ERR(filename)) - goto out; - - error = do_execve(filename, argv, envp, regs); - putname(filename); - -out: - return error; -} - -unsigned long get_wchan(struct task_struct *p) -{ - /* TODO */ - - return 0; -} - -int kernel_execve(const char *filename, char *const argv[], char *const envp[]) -{ - register long __res asm("r11") = __NR_execve; - register long __a asm("r3") = (long)(filename); - register long __b asm("r4") = (long)(argv); - register long __c asm("r5") = (long)(envp); - __asm__ volatile ("l.sys 1" - : "=r" (__res), "=r"(__a), "=r"(__b), "=r"(__c) - : "0"(__res), "1"(__a), "2"(__b), "3"(__c) - : "r6", "r7", "r8", "r12", "r13", "r15", - "r17", "r19", "r21", "r23", "r25", "r27", - "r29", "r31"); - __asm__ volatile ("l.nop"); - return __res; -} diff --git a/trunk/arch/openrisc/kernel/prom.c b/trunk/arch/openrisc/kernel/prom.c deleted file mode 100644 index 1bb58ba89afa..000000000000 --- a/trunk/arch/openrisc/kernel/prom.c +++ /dev/null @@ -1,108 +0,0 @@ -/* - * OpenRISC prom.c - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * Modifications for the OpenRISC architecture: - * Copyright (C) 2010-2011 Jonas Bonn - * - * 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. - * - * Architecture specific procedures for creating, accessing and - * interpreting the device tree. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern char cmd_line[COMMAND_LINE_SIZE]; - -void __init early_init_dt_add_memory_arch(u64 base, u64 size) -{ - size &= PAGE_MASK; - memblock_add(base, size); -} - -void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) -{ - return __va(memblock_alloc(size, align)); -} - -void __init early_init_devtree(void *params) -{ - void *alloc; - - /* Setup flat device-tree pointer */ - initial_boot_params = params; - - - /* Retrieve various informations from the /chosen node of the - * device-tree, including the platform type, initrd location and - * size, TCE reserve, and more ... - */ - of_scan_flat_dt(early_init_dt_scan_chosen, cmd_line); - - /* Scan memory nodes and rebuild MEMBLOCKs */ - memblock_init(); - of_scan_flat_dt(early_init_dt_scan_root, NULL); - of_scan_flat_dt(early_init_dt_scan_memory, NULL); - - /* Save command line for /proc/cmdline and then parse parameters */ - strlcpy(boot_command_line, cmd_line, COMMAND_LINE_SIZE); - - memblock_analyze(); - - /* We must copy the flattend device tree from init memory to regular - * memory because the device tree references the strings in it - * directly. - */ - - alloc = __va(memblock_alloc(initial_boot_params->totalsize, PAGE_SIZE)); - - memcpy(alloc, initial_boot_params, initial_boot_params->totalsize); - - initial_boot_params = alloc; -} - -#ifdef CONFIG_BLK_DEV_INITRD -void __init early_init_dt_setup_initrd_arch(unsigned long start, - unsigned long end) -{ - initrd_start = (unsigned long)__va(start); - initrd_end = (unsigned long)__va(end); - initrd_below_start_ok = 1; -} -#endif diff --git a/trunk/arch/openrisc/kernel/ptrace.c b/trunk/arch/openrisc/kernel/ptrace.c deleted file mode 100644 index 656b94beab89..000000000000 --- a/trunk/arch/openrisc/kernel/ptrace.c +++ /dev/null @@ -1,211 +0,0 @@ -/* - * OpenRISC ptrace.c - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * Modifications for the OpenRISC architecture: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2005 Gyorgy Jeney - * Copyright (C) 2010-2011 Jonas Bonn - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -/* - * Copy the thread state to a regset that can be interpreted by userspace. - * - * It doesn't matter what our internal pt_regs structure looks like. The - * important thing is that we export a consistent view of the thread state - * to userspace. As such, we need to make sure that the regset remains - * ABI compatible as defined by the struct user_regs_struct: - * - * (Each item is a 32-bit word) - * r0 = 0 (exported for clarity) - * 31 GPRS r1-r31 - * PC (Program counter) - * SR (Supervision register) - */ -static int genregs_get(struct task_struct *target, - const struct user_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user * ubuf) -{ - const struct pt_regs *regs = task_pt_regs(target); - int ret; - - /* r0 */ - ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, 0, 4); - - if (!ret) - ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, - regs->gpr+1, 4, 4*32); - if (!ret) - ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, - ®s->pc, 4*32, 4*33); - if (!ret) - ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, - ®s->sr, 4*33, 4*34); - if (!ret) - ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, - 4*34, -1); - - return ret; -} - -/* - * Set the thread state from a regset passed in via ptrace - */ -static int genregs_set(struct task_struct *target, - const struct user_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user * ubuf) -{ - struct pt_regs *regs = task_pt_regs(target); - int ret; - - /* ignore r0 */ - ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 0, 4); - /* r1 - r31 */ - if (!ret) - ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, - regs->gpr+1, 4, 4*32); - /* PC */ - if (!ret) - ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, - ®s->pc, 4*32, 4*33); - /* - * Skip SR and padding... userspace isn't allowed to changes bits in - * the Supervision register - */ - if (!ret) - ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, - 4*33, -1); - - return ret; -} - -/* - * Define the register sets available on OpenRISC under Linux - */ -enum or1k_regset { - REGSET_GENERAL, -}; - -static const struct user_regset or1k_regsets[] = { - [REGSET_GENERAL] = { - .core_note_type = NT_PRSTATUS, - .n = ELF_NGREG, - .size = sizeof(long), - .align = sizeof(long), - .get = genregs_get, - .set = genregs_set, - }, -}; - -static const struct user_regset_view user_or1k_native_view = { - .name = "or1k", - .e_machine = EM_OPENRISC, - .regsets = or1k_regsets, - .n = ARRAY_SIZE(or1k_regsets), -}; - -const struct user_regset_view *task_user_regset_view(struct task_struct *task) -{ - return &user_or1k_native_view; -} - -/* - * does not yet catch signals sent when the child dies. - * in exit.c or in signal.c. - */ - - -/* - * Called by kernel/ptrace.c when detaching.. - * - * Make sure the single step bit is not set. - */ -void ptrace_disable(struct task_struct *child) -{ - pr_debug("ptrace_disable(): TODO\n"); - - user_disable_single_step(child); - clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); -} - -long arch_ptrace(struct task_struct *child, long request, unsigned long addr, - unsigned long data) -{ - int ret; - - switch (request) { - default: - ret = ptrace_request(child, request, addr, data); - break; - } - - return ret; -} - -/* - * Notification of system call entry/exit - * - triggered by current->work.syscall_trace - */ -asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) -{ - long ret = 0; - - if (test_thread_flag(TIF_SYSCALL_TRACE) && - tracehook_report_syscall_entry(regs)) - /* - * Tracing decided this syscall should not happen. - * We'll return a bogus call number to get an ENOSYS - * error, but leave the original number in . - */ - ret = -1L; - - /* Are these regs right??? */ - if (unlikely(current->audit_context)) - audit_syscall_entry(audit_arch(), regs->syscallno, - regs->gpr[3], regs->gpr[4], - regs->gpr[5], regs->gpr[6]); - - return ret ? : regs->syscallno; -} - -asmlinkage void do_syscall_trace_leave(struct pt_regs *regs) -{ - int step; - - if (unlikely(current->audit_context)) - audit_syscall_exit(AUDITSC_RESULT(regs->gpr[11]), - regs->gpr[11]); - - step = test_thread_flag(TIF_SINGLESTEP); - if (step || test_thread_flag(TIF_SYSCALL_TRACE)) - tracehook_report_syscall_exit(regs, step); -} diff --git a/trunk/arch/openrisc/kernel/setup.c b/trunk/arch/openrisc/kernel/setup.c deleted file mode 100644 index 1422f747f52b..000000000000 --- a/trunk/arch/openrisc/kernel/setup.c +++ /dev/null @@ -1,381 +0,0 @@ -/* - * OpenRISC setup.c - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * Modifications for the OpenRISC architecture: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * - * 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 file handles the architecture-dependent parts of initialization - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "vmlinux.h" - -char __initdata cmd_line[COMMAND_LINE_SIZE] = CONFIG_CMDLINE; - -static unsigned long __init setup_memory(void) -{ - unsigned long bootmap_size; - unsigned long ram_start_pfn; - unsigned long free_ram_start_pfn; - unsigned long ram_end_pfn; - phys_addr_t memory_start, memory_end; - struct memblock_region *region; - - memory_end = memory_start = 0; - - /* Find main memory where is the kernel */ - for_each_memblock(memory, region) { - memory_start = region->base; - memory_end = region->base + region->size; - printk(KERN_INFO "%s: Memory: 0x%x-0x%x\n", __func__, - memory_start, memory_end); - } - - if (!memory_end) { - panic("No memory!"); - } - - ram_start_pfn = PFN_UP(memory_start); - /* free_ram_start_pfn is first page after kernel */ - free_ram_start_pfn = PFN_UP(__pa(&_end)); - ram_end_pfn = PFN_DOWN(memblock_end_of_DRAM()); - - max_pfn = ram_end_pfn; - - /* - * initialize the boot-time allocator (with low memory only). - * - * This makes the memory from the end of the kernel to the end of - * RAM usable. - * init_bootmem sets the global values min_low_pfn, max_low_pfn. - */ - bootmap_size = init_bootmem(free_ram_start_pfn, - ram_end_pfn - ram_start_pfn); - free_bootmem(PFN_PHYS(free_ram_start_pfn), - (ram_end_pfn - free_ram_start_pfn) << PAGE_SHIFT); - reserve_bootmem(PFN_PHYS(free_ram_start_pfn), bootmap_size, - BOOTMEM_DEFAULT); - - for_each_memblock(reserved, region) { - printk(KERN_INFO "Reserved - 0x%08x-0x%08x\n", - (u32) region->base, (u32) region->size); - reserve_bootmem(region->base, region->size, BOOTMEM_DEFAULT); - } - - return ram_end_pfn; -} - -struct cpuinfo cpuinfo; - -static void print_cpuinfo(void) -{ - unsigned long upr = mfspr(SPR_UPR); - unsigned long vr = mfspr(SPR_VR); - unsigned int version; - unsigned int revision; - - version = (vr & SPR_VR_VER) >> 24; - revision = (vr & SPR_VR_REV); - - printk(KERN_INFO "CPU: OpenRISC-%x (revision %d) @%d MHz\n", - version, revision, cpuinfo.clock_frequency / 1000000); - - if (!(upr & SPR_UPR_UP)) { - printk(KERN_INFO - "-- no UPR register... unable to detect configuration\n"); - return; - } - - if (upr & SPR_UPR_DCP) - printk(KERN_INFO - "-- dcache: %4d bytes total, %2d bytes/line, %d way(s)\n", - cpuinfo.dcache_size, cpuinfo.dcache_block_size, 1); - else - printk(KERN_INFO "-- dcache disabled\n"); - if (upr & SPR_UPR_ICP) - printk(KERN_INFO - "-- icache: %4d bytes total, %2d bytes/line, %d way(s)\n", - cpuinfo.icache_size, cpuinfo.icache_block_size, 1); - else - printk(KERN_INFO "-- icache disabled\n"); - - if (upr & SPR_UPR_DMP) - printk(KERN_INFO "-- dmmu: %4d entries, %lu way(s)\n", - 1 << ((mfspr(SPR_DMMUCFGR) & SPR_DMMUCFGR_NTS) >> 2), - 1 + (mfspr(SPR_DMMUCFGR) & SPR_DMMUCFGR_NTW)); - if (upr & SPR_UPR_IMP) - printk(KERN_INFO "-- immu: %4d entries, %lu way(s)\n", - 1 << ((mfspr(SPR_IMMUCFGR) & SPR_IMMUCFGR_NTS) >> 2), - 1 + (mfspr(SPR_IMMUCFGR) & SPR_IMMUCFGR_NTW)); - - printk(KERN_INFO "-- additional features:\n"); - if (upr & SPR_UPR_DUP) - printk(KERN_INFO "-- debug unit\n"); - if (upr & SPR_UPR_PCUP) - printk(KERN_INFO "-- performance counters\n"); - if (upr & SPR_UPR_PMP) - printk(KERN_INFO "-- power management\n"); - if (upr & SPR_UPR_PICP) - printk(KERN_INFO "-- PIC\n"); - if (upr & SPR_UPR_TTP) - printk(KERN_INFO "-- timer\n"); - if (upr & SPR_UPR_CUP) - printk(KERN_INFO "-- custom unit(s)\n"); -} - -void __init setup_cpuinfo(void) -{ - struct device_node *cpu; - unsigned long iccfgr, dccfgr; - unsigned long cache_set_size, cache_ways; - - cpu = of_find_compatible_node(NULL, NULL, "opencores,or1200-rtlsvn481"); - if (!cpu) - panic("No compatible CPU found in device tree...\n"); - - iccfgr = mfspr(SPR_ICCFGR); - cache_ways = 1 << (iccfgr & SPR_ICCFGR_NCW); - cache_set_size = 1 << ((iccfgr & SPR_ICCFGR_NCS) >> 3); - cpuinfo.icache_block_size = 16 << ((iccfgr & SPR_ICCFGR_CBS) >> 7); - cpuinfo.icache_size = - cache_set_size * cache_ways * cpuinfo.icache_block_size; - - dccfgr = mfspr(SPR_DCCFGR); - cache_ways = 1 << (dccfgr & SPR_DCCFGR_NCW); - cache_set_size = 1 << ((dccfgr & SPR_DCCFGR_NCS) >> 3); - cpuinfo.dcache_block_size = 16 << ((dccfgr & SPR_DCCFGR_CBS) >> 7); - cpuinfo.dcache_size = - cache_set_size * cache_ways * cpuinfo.dcache_block_size; - - if (of_property_read_u32(cpu, "clock-frequency", - &cpuinfo.clock_frequency)) { - printk(KERN_WARNING - "Device tree missing CPU 'clock-frequency' parameter." - "Assuming frequency 25MHZ" - "This is probably not what you want."); - } - - of_node_put(cpu); - - print_cpuinfo(); -} - -/** - * or32_early_setup - * - * Handles the pointer to the device tree that this kernel is to use - * for establishing the available platform devices. - * - * For now, this is limited to using the built-in device tree. In the future, - * it is intended that this function will take a pointer to the device tree - * that is potentially built-in, but potentially also passed in by the - * bootloader, or discovered by some equally clever means... - */ - -void __init or32_early_setup(void) -{ - - early_init_devtree(__dtb_start); - - printk(KERN_INFO "Compiled-in FDT at 0x%p\n", __dtb_start); -} - -static int __init openrisc_device_probe(void) -{ - of_platform_populate(NULL, NULL, NULL, NULL); - - return 0; -} - -device_initcall(openrisc_device_probe); - -static inline unsigned long extract_value_bits(unsigned long reg, - short bit_nr, short width) -{ - return (reg >> bit_nr) & (0 << width); -} - -static inline unsigned long extract_value(unsigned long reg, unsigned long mask) -{ - while (!(mask & 0x1)) { - reg = reg >> 1; - mask = mask >> 1; - } - return mask & reg; -} - -void __init detect_unit_config(unsigned long upr, unsigned long mask, - char *text, void (*func) (void)) -{ - if (text != NULL) - printk("%s", text); - - if (upr & mask) { - if (func != NULL) - func(); - else - printk("present\n"); - } else - printk("not present\n"); -} - -/* - * calibrate_delay - * - * Lightweight calibrate_delay implementation that calculates loops_per_jiffy - * from the clock frequency passed in via the device tree - * - */ - -void __cpuinit calibrate_delay(void) -{ - const int *val; - struct device_node *cpu = NULL; - cpu = of_find_compatible_node(NULL, NULL, "opencores,or1200-rtlsvn481"); - val = of_get_property(cpu, "clock-frequency", NULL); - if (!val) - panic("no cpu 'clock-frequency' parameter in device tree"); - loops_per_jiffy = *val / HZ; - pr_cont("%lu.%02lu BogoMIPS (lpj=%lu)\n", - loops_per_jiffy / (500000 / HZ), - (loops_per_jiffy / (5000 / HZ)) % 100, loops_per_jiffy); -} - -void __init setup_arch(char **cmdline_p) -{ - unsigned long max_low_pfn; - - unflatten_device_tree(); - - setup_cpuinfo(); - - /* process 1's initial memory region is the kernel code/data */ - init_mm.start_code = (unsigned long)&_stext; - init_mm.end_code = (unsigned long)&_etext; - init_mm.end_data = (unsigned long)&_edata; - init_mm.brk = (unsigned long)&_end; - -#ifdef CONFIG_BLK_DEV_INITRD - initrd_start = (unsigned long)&__initrd_start; - initrd_end = (unsigned long)&__initrd_end; - if (initrd_start == initrd_end) { - initrd_start = 0; - initrd_end = 0; - } - initrd_below_start_ok = 1; -#endif - - /* setup bootmem allocator */ - max_low_pfn = setup_memory(); - - /* paging_init() sets up the MMU and marks all pages as reserved */ - paging_init(); - -#if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE) - if (!conswitchp) - conswitchp = &dummy_con; -#endif - - *cmdline_p = cmd_line; - - printk(KERN_INFO "OpenRISC Linux -- http://openrisc.net\n"); -} - -static int show_cpuinfo(struct seq_file *m, void *v) -{ - unsigned long vr; - int version, revision; - - vr = mfspr(SPR_VR); - version = (vr & SPR_VR_VER) >> 24; - revision = vr & SPR_VR_REV; - - return seq_printf(m, - "cpu\t\t: OpenRISC-%x\n" - "revision\t: %d\n" - "frequency\t: %ld\n" - "dcache size\t: %d bytes\n" - "dcache block size\t: %d bytes\n" - "icache size\t: %d bytes\n" - "icache block size\t: %d bytes\n" - "immu\t\t: %d entries, %lu ways\n" - "dmmu\t\t: %d entries, %lu ways\n" - "bogomips\t: %lu.%02lu\n", - version, - revision, - loops_per_jiffy * HZ, - cpuinfo.dcache_size, - cpuinfo.dcache_block_size, - cpuinfo.icache_size, - cpuinfo.icache_block_size, - 1 << ((mfspr(SPR_DMMUCFGR) & SPR_DMMUCFGR_NTS) >> 2), - 1 + (mfspr(SPR_DMMUCFGR) & SPR_DMMUCFGR_NTW), - 1 << ((mfspr(SPR_IMMUCFGR) & SPR_IMMUCFGR_NTS) >> 2), - 1 + (mfspr(SPR_IMMUCFGR) & SPR_IMMUCFGR_NTW), - (loops_per_jiffy * HZ) / 500000, - ((loops_per_jiffy * HZ) / 5000) % 100); -} - -static void *c_start(struct seq_file *m, loff_t * pos) -{ - /* We only have one CPU... */ - return *pos < 1 ? (void *)1 : NULL; -} - -static void *c_next(struct seq_file *m, void *v, loff_t * pos) -{ - ++*pos; - return NULL; -} - -static void c_stop(struct seq_file *m, void *v) -{ -} - -const struct seq_operations cpuinfo_op = { - .start = c_start, - .next = c_next, - .stop = c_stop, - .show = show_cpuinfo, -}; diff --git a/trunk/arch/openrisc/kernel/signal.c b/trunk/arch/openrisc/kernel/signal.c deleted file mode 100644 index 5f759c76834e..000000000000 --- a/trunk/arch/openrisc/kernel/signal.c +++ /dev/null @@ -1,396 +0,0 @@ -/* - * OpenRISC signal.c - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * Modifications for the OpenRISC architecture: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define DEBUG_SIG 0 - -#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) - -asmlinkage long -_sys_sigaltstack(const stack_t *uss, stack_t *uoss, struct pt_regs *regs) -{ - return do_sigaltstack(uss, uoss, regs->sp); -} - -struct rt_sigframe { - struct siginfo *pinfo; - void *puc; - struct siginfo info; - struct ucontext uc; - unsigned char retcode[16]; /* trampoline code */ -}; - -static int restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) -{ - unsigned int err = 0; - unsigned long old_usp; - - /* Alwys make any pending restarted system call return -EINTR */ - current_thread_info()->restart_block.fn = do_no_restart_syscall; - - /* restore the regs from &sc->regs (same as sc, since regs is first) - * (sc is already checked for VERIFY_READ since the sigframe was - * checked in sys_sigreturn previously) - */ - - if (__copy_from_user(regs, sc, sizeof(struct pt_regs))) - goto badframe; - - /* make sure the SM-bit is cleared so user-mode cannot fool us */ - regs->sr &= ~SPR_SR_SM; - - /* restore the old USP as it was before we stacked the sc etc. - * (we cannot just pop the sigcontext since we aligned the sp and - * stuff after pushing it) - */ - - err |= __get_user(old_usp, &sc->usp); - - regs->sp = old_usp; - - /* TODO: the other ports use regs->orig_XX to disable syscall checks - * after this completes, but we don't use that mechanism. maybe we can - * use it now ? - */ - - return err; - -badframe: - return 1; -} - -asmlinkage long _sys_rt_sigreturn(struct pt_regs *regs) -{ - struct rt_sigframe *frame = (struct rt_sigframe __user *)regs->sp; - sigset_t set; - stack_t st; - - /* - * Since we stacked the signal on a dword boundary, - * then frame should be dword aligned here. If it's - * not, then the user is trying to mess with us. - */ - if (((long)frame) & 3) - goto badframe; - - if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) - goto badframe; - if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) - goto badframe; - - sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) - goto badframe; - - if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) - goto badframe; - /* It is more difficult to avoid calling this function than to - call it and ignore errors. */ - do_sigaltstack(&st, NULL, regs->sp); - - return regs->gpr[11]; - -badframe: - force_sig(SIGSEGV, current); - return 0; -} - -/* - * Set up a signal frame. - */ - -static int setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, - unsigned long mask) -{ - int err = 0; - unsigned long usp = regs->sp; - - /* copy the regs. they are first in sc so we can use sc directly */ - - err |= __copy_to_user(sc, regs, sizeof(struct pt_regs)); - - /* then some other stuff */ - - err |= __put_user(mask, &sc->oldmask); - - err |= __put_user(usp, &sc->usp); - - return err; -} - -static inline unsigned long align_sigframe(unsigned long sp) -{ - return sp & ~3UL; -} - -/* - * Work out where the signal frame should go. It's either on the user stack - * or the alternate stack. - */ - -static inline void __user *get_sigframe(struct k_sigaction *ka, - struct pt_regs *regs, size_t frame_size) -{ - unsigned long sp = regs->sp; - int onsigstack = on_sig_stack(sp); - - /* redzone */ - sp -= STACK_FRAME_OVERHEAD; - - /* This is the X/Open sanctioned signal stack switching. */ - if ((ka->sa.sa_flags & SA_ONSTACK) && !onsigstack) { - if (current->sas_ss_size) - sp = current->sas_ss_sp + current->sas_ss_size; - } - - sp = align_sigframe(sp - frame_size); - - /* - * If we are on the alternate signal stack and would overflow it, don't. - * Return an always-bogus address instead so we will die with SIGSEGV. - */ - if (onsigstack && !likely(on_sig_stack(sp))) - return (void __user *)-1L; - - return (void __user *)sp; -} - -/* grab and setup a signal frame. - * - * basically we stack a lot of state info, and arrange for the - * user-mode program to return to the kernel using either a - * trampoline which performs the syscall sigreturn, or a provided - * user-mode trampoline. - */ -static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, - sigset_t *set, struct pt_regs *regs) -{ - struct rt_sigframe *frame; - unsigned long return_ip; - int err = 0; - - frame = get_sigframe(ka, regs, sizeof(*frame)); - - if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) - goto give_sigsegv; - - err |= __put_user(&frame->info, &frame->pinfo); - err |= __put_user(&frame->uc, &frame->puc); - - if (ka->sa.sa_flags & SA_SIGINFO) - err |= copy_siginfo_to_user(&frame->info, info); - if (err) - goto give_sigsegv; - - /* Clear all the bits of the ucontext we don't use. */ - err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext)); - err |= __put_user(0, &frame->uc.uc_flags); - err |= __put_user(NULL, &frame->uc.uc_link); - err |= __put_user((void *)current->sas_ss_sp, - &frame->uc.uc_stack.ss_sp); - err |= __put_user(sas_ss_flags(regs->sp), &frame->uc.uc_stack.ss_flags); - err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); - err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]); - - err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); - - if (err) - goto give_sigsegv; - - /* trampoline - the desired return ip is the retcode itself */ - return_ip = (unsigned long)&frame->retcode; - /* This is l.ori r11,r0,__NR_sigreturn, l.sys 1 */ - err |= __put_user(0xa960, (short *)(frame->retcode + 0)); - err |= __put_user(__NR_rt_sigreturn, (short *)(frame->retcode + 2)); - err |= __put_user(0x20000001, (unsigned long *)(frame->retcode + 4)); - err |= __put_user(0x15000000, (unsigned long *)(frame->retcode + 8)); - - if (err) - goto give_sigsegv; - - /* TODO what is the current->exec_domain stuff and invmap ? */ - - /* Set up registers for signal handler */ - regs->pc = (unsigned long)ka->sa.sa_handler; /* what we enter NOW */ - regs->gpr[9] = (unsigned long)return_ip; /* what we enter LATER */ - regs->gpr[3] = (unsigned long)sig; /* arg 1: signo */ - regs->gpr[4] = (unsigned long)&frame->info; /* arg 2: (siginfo_t*) */ - regs->gpr[5] = (unsigned long)&frame->uc; /* arg 3: ucontext */ - - /* actually move the usp to reflect the stacked frame */ - regs->sp = (unsigned long)frame; - - return; - -give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); -} - -static inline void -handle_signal(unsigned long sig, - siginfo_t *info, struct k_sigaction *ka, - sigset_t *oldset, struct pt_regs *regs) -{ - setup_rt_frame(sig, ka, info, oldset, regs); - - if (ka->sa.sa_flags & SA_ONESHOT) - ka->sa.sa_handler = SIG_DFL; - - 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, sig); - recalc_sigpending(); - - spin_unlock_irq(¤t->sighand->siglock); -} - -/* - * Note that 'init' is a special process: it doesn't get signals it doesn't - * want to handle. Thus you cannot kill init even with a SIGKILL even by - * mistake. - * - * Also note that the regs structure given here as an argument, is the latest - * pushed pt_regs. It may or may not be the same as the first pushed registers - * when the initial usermode->kernelmode transition took place. Therefore - * we can use user_mode(regs) to see if we came directly from kernel or user - * mode below. - */ - -void do_signal(struct pt_regs *regs) -{ - siginfo_t info; - int signr; - struct k_sigaction ka; - - /* - * We want the common case to go fast, which - * is why we may in certain cases get here from - * kernel mode. Just return without doing anything - * if so. - */ - if (!user_mode(regs)) - return; - - signr = get_signal_to_deliver(&info, &ka, regs, NULL); - - /* If we are coming out of a syscall then we need - * to check if the syscall was interrupted and wants to be - * restarted after handling the signal. If so, the original - * syscall number is put back into r11 and the PC rewound to - * point at the l.sys instruction that resulted in the - * original syscall. Syscall results other than the four - * below mean that the syscall executed to completion and no - * restart is necessary. - */ - if (regs->syscallno) { - int restart = 0; - - switch (regs->gpr[11]) { - case -ERESTART_RESTARTBLOCK: - case -ERESTARTNOHAND: - /* Restart if there is no signal handler */ - restart = (signr <= 0); - break; - case -ERESTARTSYS: - /* Restart if there no signal handler or - * SA_RESTART flag is set */ - restart = (signr <= 0 || (ka.sa.sa_flags & SA_RESTART)); - break; - case -ERESTARTNOINTR: - /* Always restart */ - restart = 1; - break; - } - - if (restart) { - if (regs->gpr[11] == -ERESTART_RESTARTBLOCK) - regs->gpr[11] = __NR_restart_syscall; - else - regs->gpr[11] = regs->orig_gpr11; - regs->pc -= 4; - } else { - regs->gpr[11] = -EINTR; - } - } - - if (signr <= 0) { - /* no signal to deliver so we just put the saved sigmask - * back */ - if (test_thread_flag(TIF_RESTORE_SIGMASK)) { - clear_thread_flag(TIF_RESTORE_SIGMASK); - sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); - } - - } else { /* signr > 0 */ - sigset_t *oldset; - - if (current_thread_info()->flags & _TIF_RESTORE_SIGMASK) - oldset = ¤t->saved_sigmask; - else - oldset = ¤t->blocked; - - /* Whee! Actually deliver the signal. */ - handle_signal(signr, &info, &ka, oldset, regs); - /* a signal was successfully delivered; the saved - * sigmask will have been stored in the signal frame, - * and will be restored by sigreturn, so we can simply - * clear the TIF_RESTORE_SIGMASK flag */ - if (test_thread_flag(TIF_RESTORE_SIGMASK)) - clear_thread_flag(TIF_RESTORE_SIGMASK); - - tracehook_signal_handler(signr, &info, &ka, regs, - test_thread_flag(TIF_SINGLESTEP)); - } - - return; -} - -asmlinkage void do_notify_resume(struct pt_regs *regs) -{ - if (current_thread_info()->flags & _TIF_SIGPENDING) - do_signal(regs); - - if (current_thread_info()->flags & _TIF_NOTIFY_RESUME) { - clear_thread_flag(TIF_NOTIFY_RESUME); - tracehook_notify_resume(regs); - if (current->replacement_session_keyring) - key_replace_session_keyring(); - } -} diff --git a/trunk/arch/openrisc/kernel/sys_call_table.c b/trunk/arch/openrisc/kernel/sys_call_table.c deleted file mode 100644 index e1f8ce8c72a8..000000000000 --- a/trunk/arch/openrisc/kernel/sys_call_table.c +++ /dev/null @@ -1,28 +0,0 @@ -/* - * OpenRISC sys_call_table.c - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * Modifications for the OpenRISC architecture: - * Copyright (C) 2010-2011 Jonas Bonn - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include - -#include - -#undef __SYSCALL -#define __SYSCALL(nr, call) [nr] = (call), - -void *sys_call_table[__NR_syscalls] = { -#include -}; diff --git a/trunk/arch/openrisc/kernel/sys_or32.c b/trunk/arch/openrisc/kernel/sys_or32.c deleted file mode 100644 index 57060084c0cc..000000000000 --- a/trunk/arch/openrisc/kernel/sys_or32.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * OpenRISC sys_or32.c - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * Modifications for the OpenRISC architecture: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * - * 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 file contains various random system calls that - * have a non-standard calling sequence on some platforms. - * Since we don't have to do any backwards compatibility, our - * versions are done in the most "normal" way possible. - */ - -#include -#include -#include - -#include - -/* These are secondary entry points as the primary entry points are defined in - * entry.S where we add the 'regs' parameter value - */ - -asmlinkage long _sys_clone(unsigned long clone_flags, unsigned long newsp, - int __user *parent_tid, int __user *child_tid, - struct pt_regs *regs) -{ - long ret; - - /* FIXME: Is alignment necessary? */ - /* newsp = ALIGN(newsp, 4); */ - - if (!newsp) - newsp = regs->sp; - - ret = do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid); - - return ret; -} - -asmlinkage int _sys_fork(struct pt_regs *regs) -{ -#ifdef CONFIG_MMU - return do_fork(SIGCHLD, regs->sp, regs, 0, NULL, NULL); -#else - return -EINVAL; -#endif -} diff --git a/trunk/arch/openrisc/kernel/time.c b/trunk/arch/openrisc/kernel/time.c deleted file mode 100644 index bd946ef1623d..000000000000 --- a/trunk/arch/openrisc/kernel/time.c +++ /dev/null @@ -1,181 +0,0 @@ -/* - * OpenRISC time.c - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * Modifications for the OpenRISC architecture: - * Copyright (C) 2010-2011 Jonas Bonn - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -static int openrisc_timer_set_next_event(unsigned long delta, - struct clock_event_device *dev) -{ - u32 c; - - /* Read 32-bit counter value, add delta, mask off the low 28 bits. - * We're guaranteed delta won't be bigger than 28 bits because the - * generic timekeeping code ensures that for us. - */ - c = mfspr(SPR_TTCR); - c += delta; - c &= SPR_TTMR_TP; - - /* Set counter and enable interrupt. - * Keep timer in continuous mode always. - */ - mtspr(SPR_TTMR, SPR_TTMR_CR | SPR_TTMR_IE | c); - - return 0; -} - -static void openrisc_timer_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) -{ - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - pr_debug(KERN_INFO "%s: periodic\n", __func__); - BUG(); - break; - case CLOCK_EVT_MODE_ONESHOT: - pr_debug(KERN_INFO "%s: oneshot\n", __func__); - break; - case CLOCK_EVT_MODE_UNUSED: - pr_debug(KERN_INFO "%s: unused\n", __func__); - break; - case CLOCK_EVT_MODE_SHUTDOWN: - pr_debug(KERN_INFO "%s: shutdown\n", __func__); - break; - case CLOCK_EVT_MODE_RESUME: - pr_debug(KERN_INFO "%s: resume\n", __func__); - break; - } -} - -/* This is the clock event device based on the OR1K tick timer. - * As the timer is being used as a continuous clock-source (required for HR - * timers) we cannot enable the PERIODIC feature. The tick timer can run using - * one-shot events, so no problem. - */ - -static struct clock_event_device clockevent_openrisc_timer = { - .name = "openrisc_timer_clockevent", - .features = CLOCK_EVT_FEAT_ONESHOT, - .rating = 300, - .set_next_event = openrisc_timer_set_next_event, - .set_mode = openrisc_timer_set_mode, -}; - -static inline void timer_ack(void) -{ - /* Clear the IP bit and disable further interrupts */ - /* This can be done very simply... we just need to keep the timer - running, so just maintain the CR bits while clearing the rest - of the register - */ - mtspr(SPR_TTMR, SPR_TTMR_CR); -} - -/* - * The timer interrupt is mostly handled in generic code nowadays... this - * function just acknowledges the interrupt and fires the event handler that - * has been set on the clockevent device by the generic time management code. - * - * This function needs to be called by the timer exception handler and that's - * all the exception handler needs to do. - */ - -irqreturn_t __irq_entry timer_interrupt(struct pt_regs *regs) -{ - struct pt_regs *old_regs = set_irq_regs(regs); - struct clock_event_device *evt = &clockevent_openrisc_timer; - - timer_ack(); - - /* - * update_process_times() expects us to have called irq_enter(). - */ - irq_enter(); - evt->event_handler(evt); - irq_exit(); - - set_irq_regs(old_regs); - - return IRQ_HANDLED; -} - -static __init void openrisc_clockevent_init(void) -{ - clockevents_calc_mult_shift(&clockevent_openrisc_timer, - cpuinfo.clock_frequency, 4); - - /* We only have 28 bits */ - clockevent_openrisc_timer.max_delta_ns = - clockevent_delta2ns((u32) 0x0fffffff, &clockevent_openrisc_timer); - clockevent_openrisc_timer.min_delta_ns = - clockevent_delta2ns(1, &clockevent_openrisc_timer); - clockevent_openrisc_timer.cpumask = cpumask_of(0); - clockevents_register_device(&clockevent_openrisc_timer); -} - -/** - * Clocksource: Based on OpenRISC timer/counter - * - * This sets up the OpenRISC Tick Timer as a clock source. The tick timer - * is 32 bits wide and runs at the CPU clock frequency. - */ - -static cycle_t openrisc_timer_read(struct clocksource *cs) -{ - return (cycle_t) mfspr(SPR_TTCR); -} - -static struct clocksource openrisc_timer = { - .name = "openrisc_timer", - .rating = 200, - .read = openrisc_timer_read, - .mask = CLOCKSOURCE_MASK(32), - .flags = CLOCK_SOURCE_IS_CONTINUOUS, -}; - -static int __init openrisc_timer_init(void) -{ - if (clocksource_register_hz(&openrisc_timer, cpuinfo.clock_frequency)) - panic("failed to register clocksource"); - - /* Enable the incrementer: 'continuous' mode with interrupt disabled */ - mtspr(SPR_TTMR, SPR_TTMR_CR); - - return 0; -} - -void __init time_init(void) -{ - u32 upr; - - upr = mfspr(SPR_UPR); - if (!(upr & SPR_UPR_TTP)) - panic("Linux not supported on devices without tick timer"); - - openrisc_timer_init(); - openrisc_clockevent_init(); -} diff --git a/trunk/arch/openrisc/kernel/traps.c b/trunk/arch/openrisc/kernel/traps.c deleted file mode 100644 index a4ec44a052b2..000000000000 --- a/trunk/arch/openrisc/kernel/traps.c +++ /dev/null @@ -1,366 +0,0 @@ -/* - * OpenRISC traps.c - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * Modifications for the OpenRISC architecture: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * - * 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. - * - * Here we handle the break vectors not used by the system call - * mechanism, as well as some general stack/register dumping - * things. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -extern char _etext, _stext; - -int kstack_depth_to_print = 0x180; - -static inline int valid_stack_ptr(struct thread_info *tinfo, void *p) -{ - return p > (void *)tinfo && p < (void *)tinfo + THREAD_SIZE - 3; -} - -void show_trace(struct task_struct *task, unsigned long *stack) -{ - struct thread_info *context; - unsigned long addr; - - context = (struct thread_info *) - ((unsigned long)stack & (~(THREAD_SIZE - 1))); - - while (valid_stack_ptr(context, stack)) { - addr = *stack++; - if (__kernel_text_address(addr)) { - printk(" [<%08lx>]", addr); - print_symbol(" %s", addr); - printk("\n"); - } - } - printk(" =======================\n"); -} - -/* displays a short stack trace */ -void show_stack(struct task_struct *task, unsigned long *esp) -{ - unsigned long addr, *stack; - int i; - - if (esp == NULL) - esp = (unsigned long *)&esp; - - stack = esp; - - printk("Stack dump [0x%08lx]:\n", (unsigned long)esp); - for (i = 0; i < kstack_depth_to_print; i++) { - if (kstack_end(stack)) - break; - if (__get_user(addr, stack)) { - /* This message matches "failing address" marked - s390 in ksymoops, so lines containing it will - not be filtered out by ksymoops. */ - printk("Failing address 0x%lx\n", (unsigned long)stack); - break; - } - stack++; - - printk("sp + %02d: 0x%08lx\n", i * 4, addr); - } - printk("\n"); - - show_trace(task, esp); - - return; -} - -void show_trace_task(struct task_struct *tsk) -{ - /* - * TODO: SysRq-T trace dump... - */ -} - -/* - * The architecture-independent backtrace generator - */ -void dump_stack(void) -{ - unsigned long stack; - - show_stack(current, &stack); -} - -void show_registers(struct pt_regs *regs) -{ - int i; - int in_kernel = 1; - unsigned long esp; - - esp = (unsigned long)(®s->sp); - if (user_mode(regs)) - in_kernel = 0; - - printk("CPU #: %d\n" - " PC: %08lx SR: %08lx SP: %08lx\n", - smp_processor_id(), regs->pc, regs->sr, regs->sp); - printk("GPR00: %08lx GPR01: %08lx GPR02: %08lx GPR03: %08lx\n", - 0L, regs->gpr[1], regs->gpr[2], regs->gpr[3]); - printk("GPR04: %08lx GPR05: %08lx GPR06: %08lx GPR07: %08lx\n", - regs->gpr[4], regs->gpr[5], regs->gpr[6], regs->gpr[7]); - printk("GPR08: %08lx GPR09: %08lx GPR10: %08lx GPR11: %08lx\n", - regs->gpr[8], regs->gpr[9], regs->gpr[10], regs->gpr[11]); - printk("GPR12: %08lx GPR13: %08lx GPR14: %08lx GPR15: %08lx\n", - regs->gpr[12], regs->gpr[13], regs->gpr[14], regs->gpr[15]); - printk("GPR16: %08lx GPR17: %08lx GPR18: %08lx GPR19: %08lx\n", - regs->gpr[16], regs->gpr[17], regs->gpr[18], regs->gpr[19]); - printk("GPR20: %08lx GPR21: %08lx GPR22: %08lx GPR23: %08lx\n", - regs->gpr[20], regs->gpr[21], regs->gpr[22], regs->gpr[23]); - printk("GPR24: %08lx GPR25: %08lx GPR26: %08lx GPR27: %08lx\n", - regs->gpr[24], regs->gpr[25], regs->gpr[26], regs->gpr[27]); - printk("GPR28: %08lx GPR29: %08lx GPR30: %08lx GPR31: %08lx\n", - regs->gpr[28], regs->gpr[29], regs->gpr[30], regs->gpr[31]); - printk(" RES: %08lx oGPR11: %08lx syscallno: %08lx\n", - regs->gpr[11], regs->orig_gpr11, regs->syscallno); - - printk("Process %s (pid: %d, stackpage=%08lx)\n", - current->comm, current->pid, (unsigned long)current); - /* - * When in-kernel, we also print out the stack and code at the - * time of the fault.. - */ - if (in_kernel) { - - printk("\nStack: "); - show_stack(NULL, (unsigned long *)esp); - - printk("\nCode: "); - if (regs->pc < PAGE_OFFSET) - goto bad; - - for (i = -24; i < 24; i++) { - unsigned char c; - if (__get_user(c, &((unsigned char *)regs->pc)[i])) { -bad: - printk(" Bad PC value."); - break; - } - - if (i == 0) - printk("(%02x) ", c); - else - printk("%02x ", c); - } - } - printk("\n"); -} - -void nommu_dump_state(struct pt_regs *regs, - unsigned long ea, unsigned long vector) -{ - int i; - unsigned long addr, stack = regs->sp; - - printk("\n\r[nommu_dump_state] :: ea %lx, vector %lx\n\r", ea, vector); - - printk("CPU #: %d\n" - " PC: %08lx SR: %08lx SP: %08lx\n", - 0, regs->pc, regs->sr, regs->sp); - printk("GPR00: %08lx GPR01: %08lx GPR02: %08lx GPR03: %08lx\n", - 0L, regs->gpr[1], regs->gpr[2], regs->gpr[3]); - printk("GPR04: %08lx GPR05: %08lx GPR06: %08lx GPR07: %08lx\n", - regs->gpr[4], regs->gpr[5], regs->gpr[6], regs->gpr[7]); - printk("GPR08: %08lx GPR09: %08lx GPR10: %08lx GPR11: %08lx\n", - regs->gpr[8], regs->gpr[9], regs->gpr[10], regs->gpr[11]); - printk("GPR12: %08lx GPR13: %08lx GPR14: %08lx GPR15: %08lx\n", - regs->gpr[12], regs->gpr[13], regs->gpr[14], regs->gpr[15]); - printk("GPR16: %08lx GPR17: %08lx GPR18: %08lx GPR19: %08lx\n", - regs->gpr[16], regs->gpr[17], regs->gpr[18], regs->gpr[19]); - printk("GPR20: %08lx GPR21: %08lx GPR22: %08lx GPR23: %08lx\n", - regs->gpr[20], regs->gpr[21], regs->gpr[22], regs->gpr[23]); - printk("GPR24: %08lx GPR25: %08lx GPR26: %08lx GPR27: %08lx\n", - regs->gpr[24], regs->gpr[25], regs->gpr[26], regs->gpr[27]); - printk("GPR28: %08lx GPR29: %08lx GPR30: %08lx GPR31: %08lx\n", - regs->gpr[28], regs->gpr[29], regs->gpr[30], regs->gpr[31]); - printk(" RES: %08lx oGPR11: %08lx syscallno: %08lx\n", - regs->gpr[11], regs->orig_gpr11, regs->syscallno); - - printk("Process %s (pid: %d, stackpage=%08lx)\n", - ((struct task_struct *)(__pa(current)))->comm, - ((struct task_struct *)(__pa(current)))->pid, - (unsigned long)current); - - printk("\nStack: "); - printk("Stack dump [0x%08lx]:\n", (unsigned long)stack); - for (i = 0; i < kstack_depth_to_print; i++) { - if (((long)stack & (THREAD_SIZE - 1)) == 0) - break; - stack++; - - printk("%lx :: sp + %02d: 0x%08lx\n", stack, i * 4, - *((unsigned long *)(__pa(stack)))); - } - printk("\n"); - - printk("Call Trace: "); - i = 1; - while (((long)stack & (THREAD_SIZE - 1)) != 0) { - addr = *((unsigned long *)__pa(stack)); - stack++; - - if (kernel_text_address(addr)) { - if (i && ((i % 6) == 0)) - printk("\n "); - printk(" [<%08lx>]", addr); - i++; - } - } - printk("\n"); - - printk("\nCode: "); - - for (i = -24; i < 24; i++) { - unsigned char c; - c = ((unsigned char *)(__pa(regs->pc)))[i]; - - if (i == 0) - printk("(%02x) ", c); - else - printk("%02x ", c); - } - printk("\n"); -} - -/* This is normally the 'Oops' routine */ -void die(const char *str, struct pt_regs *regs, long err) -{ - - console_verbose(); - printk("\n%s#: %04lx\n", str, err & 0xffff); - show_registers(regs); -#ifdef CONFIG_JUMP_UPON_UNHANDLED_EXCEPTION - printk("\n\nUNHANDLED_EXCEPTION: entering infinite loop\n"); - - /* shut down interrupts */ - local_irq_disable(); - - __asm__ __volatile__("l.nop 1"); - do {} while (1); -#endif - do_exit(SIGSEGV); -} - -/* This is normally the 'Oops' routine */ -void die_if_kernel(const char *str, struct pt_regs *regs, long err) -{ - if (user_mode(regs)) - return; - - die(str, regs, err); -} - -void unhandled_exception(struct pt_regs *regs, int ea, int vector) -{ - printk("Unable to handle exception at EA =0x%x, vector 0x%x", - ea, vector); - die("Oops", regs, 9); -} - -void __init trap_init(void) -{ - /* Nothing needs to be done */ -} - -asmlinkage void do_trap(struct pt_regs *regs, unsigned long address) -{ - siginfo_t info; - memset(&info, 0, sizeof(info)); - info.si_signo = SIGTRAP; - info.si_code = TRAP_TRACE; - info.si_addr = (void *)address; - force_sig_info(SIGTRAP, &info, current); - - regs->pc += 4; -} - -asmlinkage void do_unaligned_access(struct pt_regs *regs, unsigned long address) -{ - siginfo_t info; - - if (user_mode(regs)) { - /* Send a SIGSEGV */ - info.si_signo = SIGSEGV; - info.si_errno = 0; - /* info.si_code has been set above */ - info.si_addr = (void *)address; - force_sig_info(SIGSEGV, &info, current); - } else { - printk("KERNEL: Unaligned Access 0x%.8lx\n", address); - show_registers(regs); - die("Die:", regs, address); - } - -} - -asmlinkage void do_bus_fault(struct pt_regs *regs, unsigned long address) -{ - siginfo_t info; - - if (user_mode(regs)) { - /* Send a SIGBUS */ - info.si_signo = SIGBUS; - info.si_errno = 0; - info.si_code = BUS_ADRERR; - info.si_addr = (void *)address; - force_sig_info(SIGBUS, &info, current); - } else { /* Kernel mode */ - printk("KERNEL: Bus error (SIGBUS) 0x%.8lx\n", address); - show_registers(regs); - die("Die:", regs, address); - } -} - -asmlinkage void do_illegal_instruction(struct pt_regs *regs, - unsigned long address) -{ - siginfo_t info; - - if (user_mode(regs)) { - /* Send a SIGILL */ - info.si_signo = SIGILL; - info.si_errno = 0; - info.si_code = ILL_ILLOPC; - info.si_addr = (void *)address; - force_sig_info(SIGBUS, &info, current); - } else { /* Kernel mode */ - printk("KERNEL: Illegal instruction (SIGILL) 0x%.8lx\n", - address); - show_registers(regs); - die("Die:", regs, address); - } -} diff --git a/trunk/arch/openrisc/kernel/vmlinux.h b/trunk/arch/openrisc/kernel/vmlinux.h deleted file mode 100644 index ee842a2d3f36..000000000000 --- a/trunk/arch/openrisc/kernel/vmlinux.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __OPENRISC_VMLINUX_H_ -#define __OPENRISC_VMLINUX_H_ - -extern char _stext, _etext, _edata, _end; -#ifdef CONFIG_BLK_DEV_INITRD -extern char __initrd_start, __initrd_end; -extern char __initramfs_start; -#endif - -extern u32 __dtb_start[]; - -#endif diff --git a/trunk/arch/openrisc/kernel/vmlinux.lds.S b/trunk/arch/openrisc/kernel/vmlinux.lds.S deleted file mode 100644 index 2d69a853b742..000000000000 --- a/trunk/arch/openrisc/kernel/vmlinux.lds.S +++ /dev/null @@ -1,115 +0,0 @@ -/* - * OpenRISC vmlinux.lds.S - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * Modifications for the OpenRISC architecture: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * - * 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. - * - * ld script for OpenRISC architecture - */ - -/* TODO - * - clean up __offset & stuff - * - change all 8192 aligment to PAGE !!! - * - recheck if all aligments are really needed - */ - -# define LOAD_OFFSET PAGE_OFFSET -# define LOAD_BASE PAGE_OFFSET - -#include -#include -#include - -OUTPUT_FORMAT("elf32-or32", "elf32-or32", "elf32-or32") -jiffies = jiffies_64 + 4; - -SECTIONS -{ - /* Read-only sections, merged into text segment: */ - . = LOAD_BASE ; - - /* _s_kernel_ro must be page aligned */ - . = ALIGN(PAGE_SIZE); - _s_kernel_ro = .; - - .text : AT(ADDR(.text) - LOAD_OFFSET) - { - _stext = .; - TEXT_TEXT - SCHED_TEXT - LOCK_TEXT - KPROBES_TEXT - IRQENTRY_TEXT - *(.fixup) - *(.text.__*) - _etext = .; - } - /* TODO: Check if fixup and text.__* are really necessary - * fixup is definitely necessary - */ - - _sdata = .; - - /* Page alignment required for RO_DATA_SECTION */ - RO_DATA_SECTION(PAGE_SIZE) - _e_kernel_ro = .; - - /* Whatever comes after _e_kernel_ro had better be page-aligend, too */ - - /* 32 here is cacheline size... recheck this */ - RW_DATA_SECTION(32, PAGE_SIZE, PAGE_SIZE) - - _edata = .; - - EXCEPTION_TABLE(4) - NOTES - - /* Init code and data */ - . = ALIGN(PAGE_SIZE); - __init_begin = .; - - HEAD_TEXT_SECTION - - /* Page aligned */ - INIT_TEXT_SECTION(PAGE_SIZE) - - /* Align __setup_start on 16 byte boundary */ - INIT_DATA_SECTION(16) - - PERCPU_SECTION(L1_CACHE_BYTES) - - __init_end = .; - - . = ALIGN(PAGE_SIZE); - .initrd : AT(ADDR(.initrd) - LOAD_OFFSET) - { - __initrd_start = .; - *(.initrd) - __initrd_end = .; - FILL (0); - . = ALIGN (PAGE_SIZE); - } - - __vmlinux_end = .; /* last address of the physical file */ - - BSS_SECTION(0, 0, 0x20) - - _end = .; - - /* Throw in the debugging sections */ - STABS_DEBUG - DWARF_DEBUG - - /* Sections to be discarded -- must be last */ - DISCARDS -} diff --git a/trunk/arch/openrisc/lib/Makefile b/trunk/arch/openrisc/lib/Makefile deleted file mode 100644 index 966f65dbc6f0..000000000000 --- a/trunk/arch/openrisc/lib/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# -# Makefile for or32 specific library files.. -# - -obj-y = string.o delay.o diff --git a/trunk/arch/openrisc/lib/delay.c b/trunk/arch/openrisc/lib/delay.c deleted file mode 100644 index 01d9740ae6f3..000000000000 --- a/trunk/arch/openrisc/lib/delay.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * Modifications for the OpenRISC architecture: - * Copyright (C) 2010-2011 Jonas Bonn - * - * 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 - * - * Precise Delay Loops - */ - -#include -#include -#include -#include -#include -#include - -int __devinit read_current_timer(unsigned long *timer_value) -{ - *timer_value = mfspr(SPR_TTCR); - return 0; -} - -void __delay(unsigned long cycles) -{ - cycles_t target = get_cycles() + cycles; - - while (get_cycles() < target) - cpu_relax(); -} -EXPORT_SYMBOL(__delay); - -inline void __const_udelay(unsigned long xloops) -{ - unsigned long long loops; - - loops = xloops * loops_per_jiffy * HZ; - - __delay(loops >> 32); -} -EXPORT_SYMBOL(__const_udelay); - -void __udelay(unsigned long usecs) -{ - __const_udelay(usecs * 0x10C7UL); /* 2**32 / 1000000 (rounded up) */ -} -EXPORT_SYMBOL(__udelay); - -void __ndelay(unsigned long nsecs) -{ - __const_udelay(nsecs * 0x5UL); /* 2**32 / 1000000000 (rounded up) */ -} -EXPORT_SYMBOL(__ndelay); diff --git a/trunk/arch/openrisc/lib/string.S b/trunk/arch/openrisc/lib/string.S deleted file mode 100644 index 465f04bc7deb..000000000000 --- a/trunk/arch/openrisc/lib/string.S +++ /dev/null @@ -1,204 +0,0 @@ -/* - * OpenRISC string.S - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * Modifications for the OpenRISC architecture: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include - - /* - * this can be optimized by doing gcc inline assemlby with - * proper constraints (no need to save args registers...) - * - */ - - -/* - * - * int __copy_tofrom_user(void *to, const void *from, unsigned long size); - * - * NOTE: it returns number of bytes NOT copied !!! - * - */ - .global __copy_tofrom_user -__copy_tofrom_user: - l.addi r1,r1,-12 - l.sw 0(r1),r6 - l.sw 4(r1),r4 - l.sw 8(r1),r3 - - l.addi r11,r5,0 -2: l.sfeq r11,r0 - l.bf 1f - l.addi r11,r11,-1 -8: l.lbz r6,0(r4) -9: l.sb 0(r3),r6 - l.addi r3,r3,1 - l.j 2b - l.addi r4,r4,1 -1: - l.addi r11,r11,1 // r11 holds the return value - - l.lwz r6,0(r1) - l.lwz r4,4(r1) - l.lwz r3,8(r1) - l.jr r9 - l.addi r1,r1,12 - - .section .fixup, "ax" -99: - l.j 1b - l.nop - .previous - - .section __ex_table, "a" - .long 8b, 99b // read fault - .long 9b, 99b // write fault - .previous - -/* - * unsigned long clear_user(void *addr, unsigned long size) ; - * - * NOTE: it returns number of bytes NOT cleared !!! - */ - .global __clear_user -__clear_user: - l.addi r1,r1,-8 - l.sw 0(r1),r4 - l.sw 4(r1),r3 - -2: l.sfeq r4,r0 - l.bf 1f - l.addi r4,r4,-1 -9: l.sb 0(r3),r0 - l.j 2b - l.addi r3,r3,1 - -1: - l.addi r11,r4,1 - - l.lwz r4,0(r1) - l.lwz r3,4(r1) - l.jr r9 - l.addi r1,r1,8 - - .section .fixup, "ax" -99: - l.j 1b - l.nop - .previous - - .section __ex_table, "a" - .long 9b, 99b // write fault - .previous - -/* - * long strncpy_from_user(char *dst, const char *src, long count) - * - * - */ - .global __strncpy_from_user -__strncpy_from_user: - l.addi r1,r1,-16 - l.sw 0(r1),r6 - l.sw 4(r1),r5 - l.sw 8(r1),r4 - l.sw 12(r1),r3 - - l.addi r11,r5,0 -2: l.sfeq r5,r0 - l.bf 1f - l.addi r5,r5,-1 -8: l.lbz r6,0(r4) - l.sfeq r6,r0 - l.bf 1f -9: l.sb 0(r3),r6 - l.addi r3,r3,1 - l.j 2b - l.addi r4,r4,1 -1: - l.lwz r6,0(r1) - l.addi r5,r5,1 - l.sub r11,r11,r5 // r11 holds the return value - - l.lwz r6,0(r1) - l.lwz r5,4(r1) - l.lwz r4,8(r1) - l.lwz r3,12(r1) - l.jr r9 - l.addi r1,r1,16 - - .section .fixup, "ax" -99: - l.movhi r11,hi(-EFAULT) - l.ori r11,r11,lo(-EFAULT) - - l.lwz r6,0(r1) - l.lwz r5,4(r1) - l.lwz r4,8(r1) - l.lwz r3,12(r1) - l.jr r9 - l.addi r1,r1,16 - .previous - - .section __ex_table, "a" - .long 8b, 99b // read fault - .previous - -/* - * extern int __strnlen_user(const char *str, long len, unsigned long top); - * - * - * RTRN: - length of a string including NUL termination character - * - on page fault 0 - */ - - .global __strnlen_user -__strnlen_user: - l.addi r1,r1,-8 - l.sw 0(r1),r6 - l.sw 4(r1),r3 - - l.addi r11,r0,0 -2: l.sfeq r11,r4 - l.bf 1f - l.addi r11,r11,1 -8: l.lbz r6,0(r3) - l.sfeq r6,r0 - l.bf 1f - l.sfgeu r3,r5 // are we over the top ? - l.bf 99f - l.j 2b - l.addi r3,r3,1 - -1: - l.lwz r6,0(r1) - l.lwz r3,4(r1) - l.jr r9 - l.addi r1,r1,8 - - .section .fixup, "ax" -99: - l.addi r11,r0,0 - - l.lwz r6,0(r1) - l.lwz r3,4(r1) - l.jr r9 - l.addi r1,r1,8 - .previous - - .section __ex_table, "a" - .long 8b, 99b // read fault - .previous diff --git a/trunk/arch/openrisc/mm/Makefile b/trunk/arch/openrisc/mm/Makefile deleted file mode 100644 index 324ba2634529..000000000000 --- a/trunk/arch/openrisc/mm/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# -# Makefile for the linux openrisc-specific parts of the memory manager. -# - -obj-y := fault.o tlb.o init.o ioremap.o diff --git a/trunk/arch/openrisc/mm/fault.c b/trunk/arch/openrisc/mm/fault.c deleted file mode 100644 index a5dce82f864b..000000000000 --- a/trunk/arch/openrisc/mm/fault.c +++ /dev/null @@ -1,338 +0,0 @@ -/* - * OpenRISC fault.c - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * Modifications for the OpenRISC architecture: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include - -#include -#include -#include - -#define NUM_TLB_ENTRIES 64 -#define TLB_OFFSET(add) (((add) >> PAGE_SHIFT) & (NUM_TLB_ENTRIES-1)) - -unsigned long pte_misses; /* updated by do_page_fault() */ -unsigned long pte_errors; /* updated by do_page_fault() */ - -/* __PHX__ :: - check the vmalloc_fault in do_page_fault() - * - also look into include/asm-or32/mmu_context.h - */ -volatile pgd_t *current_pgd; - -extern void die(char *, struct pt_regs *, long); - -/* - * This routine handles page faults. It determines the address, - * and the problem, and then passes it off to one of the appropriate - * routines. - * - * If this routine detects a bad access, it returns 1, otherwise it - * returns 0. - */ - -asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long address, - unsigned long vector, int write_acc) -{ - struct task_struct *tsk; - struct mm_struct *mm; - struct vm_area_struct *vma; - siginfo_t info; - int fault; - - tsk = current; - - /* - * We fault-in kernel-space virtual memory on-demand. The - * 'reference' page table is init_mm.pgd. - * - * NOTE! We MUST NOT take any locks for this case. We may - * be in an interrupt or a critical region, and should - * only copy the information from the master page table, - * nothing more. - * - * NOTE2: This is done so that, when updating the vmalloc - * mappings we don't have to walk all processes pgdirs and - * add the high mappings all at once. Instead we do it as they - * are used. However vmalloc'ed page entries have the PAGE_GLOBAL - * bit set so sometimes the TLB can use a lingering entry. - * - * This verifies that the fault happens in kernel space - * and that the fault was not a protection error. - */ - - if (address >= VMALLOC_START && - (vector != 0x300 && vector != 0x400) && - !user_mode(regs)) - goto vmalloc_fault; - - /* If exceptions were enabled, we can reenable them here */ - if (user_mode(regs)) { - /* Exception was in userspace: reenable interrupts */ - local_irq_enable(); - } else { - /* If exception was in a syscall, then IRQ's may have - * been enabled or disabled. If they were enabled, - * reenable them. - */ - if (regs->sr && (SPR_SR_IEE | SPR_SR_TEE)) - local_irq_enable(); - } - - mm = tsk->mm; - info.si_code = SEGV_MAPERR; - - /* - * If we're in an interrupt or have no user - * context, we must not take the fault.. - */ - - if (in_interrupt() || !mm) - goto no_context; - - down_read(&mm->mmap_sem); - vma = find_vma(mm, address); - - if (!vma) - goto bad_area; - - if (vma->vm_start <= address) - goto good_area; - - if (!(vma->vm_flags & VM_GROWSDOWN)) - goto bad_area; - - if (user_mode(regs)) { - /* - * accessing the stack below usp is always a bug. - * we get page-aligned addresses so we can only check - * if we're within a page from usp, but that might be - * enough to catch brutal errors at least. - */ - if (address + PAGE_SIZE < regs->sp) - goto bad_area; - } - if (expand_stack(vma, address)) - goto bad_area; - - /* - * Ok, we have a good vm_area for this memory access, so - * we can handle it.. - */ - -good_area: - info.si_code = SEGV_ACCERR; - - /* first do some preliminary protection checks */ - - if (write_acc) { - if (!(vma->vm_flags & VM_WRITE)) - goto bad_area; - } else { - /* not present */ - if (!(vma->vm_flags & (VM_READ | VM_EXEC))) - goto bad_area; - } - - /* are we trying to execute nonexecutable area */ - if ((vector == 0x400) && !(vma->vm_page_prot.pgprot & _PAGE_EXEC)) - goto bad_area; - - /* - * If for any reason at all we couldn't handle the fault, - * make sure we exit gracefully rather than endlessly redo - * the fault. - */ - - fault = handle_mm_fault(mm, vma, address, write_acc); - if (unlikely(fault & VM_FAULT_ERROR)) { - if (fault & VM_FAULT_OOM) - goto out_of_memory; - else if (fault & VM_FAULT_SIGBUS) - goto do_sigbus; - BUG(); - } - /*RGD modeled on Cris */ - if (fault & VM_FAULT_MAJOR) - tsk->maj_flt++; - else - tsk->min_flt++; - - up_read(&mm->mmap_sem); - return; - - /* - * Something tried to access memory that isn't in our memory map.. - * Fix it, but check if it's kernel or user first.. - */ - -bad_area: - up_read(&mm->mmap_sem); - -bad_area_nosemaphore: - - /* User mode accesses just cause a SIGSEGV */ - - if (user_mode(regs)) { - info.si_signo = SIGSEGV; - info.si_errno = 0; - /* info.si_code has been set above */ - info.si_addr = (void *)address; - force_sig_info(SIGSEGV, &info, tsk); - return; - } - -no_context: - - /* Are we prepared to handle this kernel fault? - * - * (The kernel has valid exception-points in the source - * when it acesses user-memory. When it fails in one - * of those points, we find it in a table and do a jump - * to some fixup code that loads an appropriate error - * code) - */ - - { - const struct exception_table_entry *entry; - - __asm__ __volatile__("l.nop 42"); - - if ((entry = search_exception_tables(regs->pc)) != NULL) { - /* Adjust the instruction pointer in the stackframe */ - regs->pc = entry->fixup; - return; - } - } - - /* - * Oops. The kernel tried to access some bad page. We'll have to - * terminate things with extreme prejudice. - */ - - if ((unsigned long)(address) < PAGE_SIZE) - printk(KERN_ALERT - "Unable to handle kernel NULL pointer dereference"); - else - printk(KERN_ALERT "Unable to handle kernel access"); - printk(" at virtual address 0x%08lx\n", address); - - die("Oops", regs, write_acc); - - do_exit(SIGKILL); - - /* - * 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: - __asm__ __volatile__("l.nop 42"); - __asm__ __volatile__("l.nop 1"); - - up_read(&mm->mmap_sem); - printk("VM: killing process %s\n", tsk->comm); - if (user_mode(regs)) - do_exit(SIGKILL); - goto no_context; - -do_sigbus: - up_read(&mm->mmap_sem); - - /* - * Send a sigbus, regardless of whether we were in kernel - * or user mode. - */ - info.si_signo = SIGBUS; - info.si_errno = 0; - info.si_code = BUS_ADRERR; - info.si_addr = (void *)address; - force_sig_info(SIGBUS, &info, tsk); - - /* Kernel mode? Handle exceptions or die */ - if (!user_mode(regs)) - goto no_context; - return; - -vmalloc_fault: - { - /* - * Synchronize this task's top level page-table - * with the 'reference' page table. - * - * Use current_pgd instead of tsk->active_mm->pgd - * since the latter might be unavailable if this - * code is executed in a misfortunately run irq - * (like inside schedule() between switch_mm and - * switch_to...). - */ - - int offset = pgd_index(address); - pgd_t *pgd, *pgd_k; - pud_t *pud, *pud_k; - pmd_t *pmd, *pmd_k; - pte_t *pte_k; - -/* - phx_warn("do_page_fault(): vmalloc_fault will not work, " - "since current_pgd assign a proper value somewhere\n" - "anyhow we don't need this at the moment\n"); - - phx_mmu("vmalloc_fault"); -*/ - pgd = (pgd_t *)current_pgd + offset; - pgd_k = init_mm.pgd + offset; - - /* Since we're two-level, we don't need to do both - * set_pgd and set_pmd (they do the same thing). If - * we go three-level at some point, do the right thing - * with pgd_present and set_pgd here. - * - * Also, since the vmalloc area is global, we don't - * need to copy individual PTE's, it is enough to - * copy the pgd pointer into the pte page of the - * root task. If that is there, we'll find our pte if - * it exists. - */ - - pud = pud_offset(pgd, address); - pud_k = pud_offset(pgd_k, address); - if (!pud_present(*pud_k)) - goto no_context; - - pmd = pmd_offset(pud, address); - pmd_k = pmd_offset(pud_k, address); - - if (!pmd_present(*pmd_k)) - goto bad_area_nosemaphore; - - set_pmd(pmd, *pmd_k); - - /* Make sure the actual PTE exists as well to - * catch kernel vmalloc-area accesses to non-mapped - * addresses. If we don't do this, this will just - * silently loop forever. - */ - - pte_k = pte_offset_kernel(pmd_k, address); - if (!pte_present(*pte_k)) - goto no_context; - - return; - } -} diff --git a/trunk/arch/openrisc/mm/init.c b/trunk/arch/openrisc/mm/init.c deleted file mode 100644 index 359dcb20fe85..000000000000 --- a/trunk/arch/openrisc/mm/init.c +++ /dev/null @@ -1,283 +0,0 @@ -/* - * OpenRISC idle.c - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * Modifications for the OpenRISC architecture: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for initrd_* */ -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int mem_init_done; - -DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); - -static void __init zone_sizes_init(void) -{ - unsigned long zones_size[MAX_NR_ZONES]; - - /* Clear the zone sizes */ - memset(zones_size, 0, sizeof(zones_size)); - - /* - * We use only ZONE_NORMAL - */ - zones_size[ZONE_NORMAL] = max_low_pfn; - - free_area_init(zones_size); -} - -extern const char _s_kernel_ro[], _e_kernel_ro[]; - -/* - * Map all physical memory into kernel's address space. - * - * This is explicitly coded for two-level page tables, so if you need - * something else then this needs to change. - */ -static void __init map_ram(void) -{ - unsigned long v, p, e; - pgprot_t prot; - pgd_t *pge; - pud_t *pue; - pmd_t *pme; - pte_t *pte; - /* These mark extents of read-only kernel pages... - * ...from vmlinux.lds.S - */ - struct memblock_region *region; - - v = PAGE_OFFSET; - - for_each_memblock(memory, region) { - p = (u32) region->base & PAGE_MASK; - e = p + (u32) region->size; - - v = (u32) __va(p); - pge = pgd_offset_k(v); - - while (p < e) { - int j; - pue = pud_offset(pge, v); - pme = pmd_offset(pue, v); - - if ((u32) pue != (u32) pge || (u32) pme != (u32) pge) { - panic("%s: OR1K kernel hardcoded for " - "two-level page tables", - __func__); - } - - /* Alloc one page for holding PTE's... */ - pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); - set_pmd(pme, __pmd(_KERNPG_TABLE + __pa(pte))); - - /* Fill the newly allocated page with PTE'S */ - for (j = 0; p < e && j < PTRS_PER_PGD; - v += PAGE_SIZE, p += PAGE_SIZE, j++, pte++) { - if (v >= (u32) _e_kernel_ro || - v < (u32) _s_kernel_ro) - prot = PAGE_KERNEL; - else - prot = PAGE_KERNEL_RO; - - set_pte(pte, mk_pte_phys(p, prot)); - } - - pge++; - } - - printk(KERN_INFO "%s: Memory: 0x%x-0x%x\n", __func__, - region->base, region->base + region->size); - } -} - -void __init paging_init(void) -{ - extern void tlb_init(void); - - unsigned long end; - int i; - - printk(KERN_INFO "Setting up paging and PTEs.\n"); - - /* clear out the init_mm.pgd that will contain the kernel's mappings */ - - for (i = 0; i < PTRS_PER_PGD; i++) - swapper_pg_dir[i] = __pgd(0); - - /* make sure the current pgd table points to something sane - * (even if it is most probably not used until the next - * switch_mm) - */ - current_pgd = init_mm.pgd; - - end = (unsigned long)__va(max_low_pfn * PAGE_SIZE); - - map_ram(); - - zone_sizes_init(); - - /* self modifying code ;) */ - /* Since the old TLB miss handler has been running up until now, - * the kernel pages are still all RW, so we can still modify the - * text directly... after this change and a TLB flush, the kernel - * pages will become RO. - */ - { - extern unsigned long dtlb_miss_handler; - extern unsigned long itlb_miss_handler; - - unsigned long *dtlb_vector = __va(0x900); - unsigned long *itlb_vector = __va(0xa00); - - printk(KERN_INFO "dtlb_miss_handler %p\n", &dtlb_miss_handler); - *dtlb_vector = ((unsigned long)&dtlb_miss_handler - - (unsigned long)dtlb_vector) >> 2; - - printk(KERN_INFO "itlb_miss_handler %p\n", &itlb_miss_handler); - *itlb_vector = ((unsigned long)&itlb_miss_handler - - (unsigned long)itlb_vector) >> 2; - } - - /* Invalidate instruction caches after code modification */ - mtspr(SPR_ICBIR, 0x900); - mtspr(SPR_ICBIR, 0xa00); - - /* New TLB miss handlers and kernel page tables are in now place. - * Make sure that page flags get updated for all pages in TLB by - * flushing the TLB and forcing all TLB entries to be recreated - * from their page table flags. - */ - flush_tlb_all(); -} - -/* References to section boundaries */ - -extern char _stext, _etext, _edata, __bss_start, _end; -extern char __init_begin, __init_end; - -static int __init free_pages_init(void) -{ - int reservedpages, pfn; - - /* this will put all low memory onto the freelists */ - totalram_pages = free_all_bootmem(); - - reservedpages = 0; - for (pfn = 0; pfn < max_low_pfn; pfn++) { - /* - * Only count reserved RAM pages - */ - if (PageReserved(mem_map + pfn)) - reservedpages++; - } - - return reservedpages; -} - -static void __init set_max_mapnr_init(void) -{ - max_mapnr = num_physpages = max_low_pfn; -} - -void __init mem_init(void) -{ - int codesize, reservedpages, datasize, initsize; - - if (!mem_map) - BUG(); - - set_max_mapnr_init(); - - high_memory = (void *)__va(max_low_pfn * PAGE_SIZE); - - /* clear the zero-page */ - memset((void *)empty_zero_page, 0, PAGE_SIZE); - - reservedpages = free_pages_init(); - - codesize = (unsigned long)&_etext - (unsigned long)&_stext; - datasize = (unsigned long)&_edata - (unsigned long)&_etext; - initsize = (unsigned long)&__init_end - (unsigned long)&__init_begin; - - printk(KERN_INFO - "Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %ldk highmem)\n", - (unsigned long)nr_free_pages() << (PAGE_SHIFT - 10), - max_mapnr << (PAGE_SHIFT - 10), codesize >> 10, - reservedpages << (PAGE_SHIFT - 10), datasize >> 10, - initsize >> 10, (unsigned long)(0 << (PAGE_SHIFT - 10)) - ); - - printk("mem_init_done ...........................................\n"); - mem_init_done = 1; - return; -} - -#ifdef CONFIG_BLK_DEV_INITRD -void free_initrd_mem(unsigned long start, unsigned long end) -{ - printk(KERN_INFO "Freeing initrd memory: %ldk freed\n", - (end - start) >> 10); - - for (; start < end; start += PAGE_SIZE) { - ClearPageReserved(virt_to_page(start)); - init_page_count(virt_to_page(start)); - free_page(start); - totalram_pages++; - } -} -#endif - -void free_initmem(void) -{ - unsigned long addr; - - addr = (unsigned long)(&__init_begin); - for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) { - ClearPageReserved(virt_to_page(addr)); - init_page_count(virt_to_page(addr)); - free_page(addr); - totalram_pages++; - } - printk(KERN_INFO "Freeing unused kernel memory: %luk freed\n", - ((unsigned long)&__init_end - - (unsigned long)&__init_begin) >> 10); -} diff --git a/trunk/arch/openrisc/mm/ioremap.c b/trunk/arch/openrisc/mm/ioremap.c deleted file mode 100644 index 62b08ef392be..000000000000 --- a/trunk/arch/openrisc/mm/ioremap.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - * OpenRISC ioremap.c - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * Modifications for the OpenRISC architecture: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Jonas Bonn - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern int mem_init_done; - -static unsigned int fixmaps_used __initdata; - -/* - * Remap an arbitrary physical address space into the kernel virtual - * address space. Needed when the kernel wants to access high addresses - * directly. - * - * NOTE! We need to allow non-page-aligned mappings too: we will obviously - * have to convert them into an offset in a page-aligned mapping, but the - * caller shouldn't need to know that small detail. - */ -void __iomem *__init_refok -__ioremap(phys_addr_t addr, unsigned long size, pgprot_t prot) -{ - phys_addr_t p; - unsigned long v; - unsigned long offset, last_addr; - struct vm_struct *area = NULL; - - /* Don't allow wraparound or zero size */ - last_addr = addr + size - 1; - if (!size || last_addr < addr) - return NULL; - - /* - * Mappings have to be page-aligned - */ - offset = addr & ~PAGE_MASK; - p = addr & PAGE_MASK; - size = PAGE_ALIGN(last_addr + 1) - p; - - if (likely(mem_init_done)) { - area = get_vm_area(size, VM_IOREMAP); - if (!area) - return NULL; - v = (unsigned long)area->addr; - } else { - if ((fixmaps_used + (size >> PAGE_SHIFT)) > FIX_N_IOREMAPS) - return NULL; - v = fix_to_virt(FIX_IOREMAP_BEGIN + fixmaps_used); - fixmaps_used += (size >> PAGE_SHIFT); - } - - if (ioremap_page_range(v, v + size, p, prot)) { - if (likely(mem_init_done)) - vfree(area->addr); - else - fixmaps_used -= (size >> PAGE_SHIFT); - return NULL; - } - - return (void __iomem *)(offset + (char *)v); -} - -void iounmap(void *addr) -{ - /* If the page is from the fixmap pool then we just clear out - * the fixmap mapping. - */ - if (unlikely((unsigned long)addr > FIXADDR_START)) { - /* This is a bit broken... we don't really know - * how big the area is so it's difficult to know - * how many fixed pages to invalidate... - * just flush tlb and hope for the best... - * consider this a FIXME - * - * Really we should be clearing out one or more page - * table entries for these virtual addresses so that - * future references cause a page fault... for now, we - * rely on two things: - * i) this code never gets called on known boards - * ii) invalid accesses to the freed areas aren't made - */ - flush_tlb_all(); - return; - } - - return vfree((void *)(PAGE_MASK & (unsigned long)addr)); -} - -/** - * OK, this one's a bit tricky... ioremap can get called before memory is - * initialized (early serial console does this) and will want to alloc a page - * for its mapping. No userspace pages will ever get allocated before memory - * is initialized so this applies only to kernel pages. In the event that - * this is called before memory is initialized we allocate the page using - * the memblock infrastructure. - */ - -pte_t __init_refok *pte_alloc_one_kernel(struct mm_struct *mm, - unsigned long address) -{ - pte_t *pte; - - if (likely(mem_init_done)) { - pte = (pte_t *) __get_free_page(GFP_KERNEL | __GFP_REPEAT); - } else { - pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); -#if 0 - /* FIXME: use memblock... */ - pte = (pte_t *) __va(memblock_alloc(PAGE_SIZE, PAGE_SIZE)); -#endif - } - - if (pte) - clear_page(pte); - return pte; -} diff --git a/trunk/arch/openrisc/mm/tlb.c b/trunk/arch/openrisc/mm/tlb.c deleted file mode 100644 index 56b0b89624af..000000000000 --- a/trunk/arch/openrisc/mm/tlb.c +++ /dev/null @@ -1,193 +0,0 @@ -/* - * OpenRISC tlb.c - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * Modifications for the OpenRISC architecture: - * Copyright (C) 2003 Matjaz Breskvar - * Copyright (C) 2010-2011 Julius Baxter - * Copyright (C) 2010-2011 Jonas Bonn - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#define NO_CONTEXT -1 - -#define NUM_DTLB_SETS (1 << ((mfspr(SPR_IMMUCFGR) & SPR_IMMUCFGR_NTS) >> \ - SPR_DMMUCFGR_NTS_OFF)) -#define NUM_ITLB_SETS (1 << ((mfspr(SPR_IMMUCFGR) & SPR_IMMUCFGR_NTS) >> \ - SPR_IMMUCFGR_NTS_OFF)) -#define DTLB_OFFSET(addr) (((addr) >> PAGE_SHIFT) & (NUM_DTLB_SETS-1)) -#define ITLB_OFFSET(addr) (((addr) >> PAGE_SHIFT) & (NUM_ITLB_SETS-1)) -/* - * Invalidate all TLB entries. - * - * This comes down to setting the 'valid' bit for all xTLBMR registers to 0. - * Easiest way to accomplish this is to just zero out the xTLBMR register - * completely. - * - */ - -void flush_tlb_all(void) -{ - int i; - unsigned long num_tlb_sets; - - /* Determine number of sets for IMMU. */ - /* FIXME: Assumption is I & D nsets equal. */ - num_tlb_sets = NUM_ITLB_SETS; - - for (i = 0; i < num_tlb_sets; i++) { - mtspr_off(SPR_DTLBMR_BASE(0), i, 0); - mtspr_off(SPR_ITLBMR_BASE(0), i, 0); - } -} - -#define have_dtlbeir (mfspr(SPR_DMMUCFGR) & SPR_DMMUCFGR_TEIRI) -#define have_itlbeir (mfspr(SPR_IMMUCFGR) & SPR_IMMUCFGR_TEIRI) - -/* - * Invalidate a single page. This is what the xTLBEIR register is for. - * - * There's no point in checking the vma for PAGE_EXEC to determine whether it's - * the data or instruction TLB that should be flushed... that would take more - * than the few instructions that the following compiles down to! - * - * The case where we don't have the xTLBEIR register really only works for - * MMU's with a single way and is hard-coded that way. - */ - -#define flush_dtlb_page_eir(addr) mtspr(SPR_DTLBEIR, addr) -#define flush_dtlb_page_no_eir(addr) \ - mtspr_off(SPR_DTLBMR_BASE(0), DTLB_OFFSET(addr), 0); - -#define flush_itlb_page_eir(addr) mtspr(SPR_ITLBEIR, addr) -#define flush_itlb_page_no_eir(addr) \ - mtspr_off(SPR_ITLBMR_BASE(0), ITLB_OFFSET(addr), 0); - -void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) -{ - if (have_dtlbeir) - flush_dtlb_page_eir(addr); - else - flush_dtlb_page_no_eir(addr); - - if (have_itlbeir) - flush_itlb_page_eir(addr); - else - flush_itlb_page_no_eir(addr); -} - -void flush_tlb_range(struct vm_area_struct *vma, - unsigned long start, unsigned long end) -{ - int addr; - bool dtlbeir; - bool itlbeir; - - dtlbeir = have_dtlbeir; - itlbeir = have_itlbeir; - - for (addr = start; addr < end; addr += PAGE_SIZE) { - if (dtlbeir) - flush_dtlb_page_eir(addr); - else - flush_dtlb_page_no_eir(addr); - - if (itlbeir) - flush_itlb_page_eir(addr); - else - flush_itlb_page_no_eir(addr); - } -} - -/* - * Invalidate the selected mm context only. - * - * FIXME: Due to some bug here, we're flushing everything for now. - * This should be changed to loop over over mm and call flush_tlb_range. - */ - -void flush_tlb_mm(struct mm_struct *mm) -{ - - /* Was seeing bugs with the mm struct passed to us. Scrapped most of - this function. */ - /* Several architctures do this */ - flush_tlb_all(); -} - -/* called in schedule() just before actually doing the switch_to */ - -void switch_mm(struct mm_struct *prev, struct mm_struct *next, - struct task_struct *next_tsk) -{ - /* remember the pgd for the fault handlers - * this is similar to the pgd register in some other CPU's. - * we need our own copy of it because current and active_mm - * might be invalid at points where we still need to derefer - * the pgd. - */ - current_pgd = next->pgd; - - /* We don't have context support implemented, so flush all - * entries belonging to previous map - */ - - if (prev != next) - flush_tlb_mm(prev); - -} - -/* - * Initialize the context related info for a new mm_struct - * instance. - */ - -int init_new_context(struct task_struct *tsk, struct mm_struct *mm) -{ - mm->context = NO_CONTEXT; - return 0; -} - -/* called by __exit_mm to destroy the used MMU context if any before - * destroying the mm itself. this is only called when the last user of the mm - * drops it. - */ - -void destroy_context(struct mm_struct *mm) -{ - flush_tlb_mm(mm); - -} - -/* called once during VM initialization, from init.c */ - -void __init tlb_init(void) -{ - /* Do nothing... */ - /* invalidate the entire TLB */ - /* flush_tlb_all(); */ -} diff --git a/trunk/arch/parisc/kernel/module.c b/trunk/arch/parisc/kernel/module.c index 5e34ccf39a49..cedbbb8b18d9 100644 --- a/trunk/arch/parisc/kernel/module.c +++ b/trunk/arch/parisc/kernel/module.c @@ -540,6 +540,18 @@ static Elf_Addr get_stub(struct module *me, unsigned long value, long addend, return (Elf_Addr)stub; } +int apply_relocate(Elf_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *me) +{ + /* parisc should not need this ... */ + printk(KERN_ERR "module %s: RELOCATION unsupported\n", + me->name); + return -ENOEXEC; +} + #ifndef CONFIG_64BIT int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, diff --git a/trunk/arch/powerpc/include/asm/8253pit.h b/trunk/arch/powerpc/include/asm/8253pit.h new file mode 100644 index 000000000000..a71c9c1455a7 --- /dev/null +++ b/trunk/arch/powerpc/include/asm/8253pit.h @@ -0,0 +1,3 @@ +/* + * 8253/8254 Programmable Interval Timer + */ diff --git a/trunk/arch/powerpc/include/asm/cputable.h b/trunk/arch/powerpc/include/asm/cputable.h index e30442c539ce..c0d842cfd012 100644 --- a/trunk/arch/powerpc/include/asm/cputable.h +++ b/trunk/arch/powerpc/include/asm/cputable.h @@ -179,9 +179,8 @@ extern const char *powerpc_base_platform; #define LONG_ASM_CONST(x) 0 #endif -#define CPU_FTR_HVMODE LONG_ASM_CONST(0x0000000200000000) -#define CPU_FTR_ARCH_201 LONG_ASM_CONST(0x0000000400000000) -#define CPU_FTR_ARCH_206 LONG_ASM_CONST(0x0000000800000000) + +#define CPU_FTR_HVMODE_206 LONG_ASM_CONST(0x0000000800000000) #define CPU_FTR_CFAR LONG_ASM_CONST(0x0000001000000000) #define CPU_FTR_IABR LONG_ASM_CONST(0x0000002000000000) #define CPU_FTR_MMCRA LONG_ASM_CONST(0x0000004000000000) @@ -402,10 +401,9 @@ extern const char *powerpc_base_platform; CPU_FTR_MMCRA | CPU_FTR_CP_USE_DCBTZ | \ CPU_FTR_STCX_CHECKS_ADDRESS) #define CPU_FTRS_PPC970 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \ - CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | CPU_FTR_ARCH_201 | \ + CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \ CPU_FTR_ALTIVEC_COMP | CPU_FTR_CAN_NAP | CPU_FTR_MMCRA | \ - CPU_FTR_CP_USE_DCBTZ | CPU_FTR_STCX_CHECKS_ADDRESS | \ - CPU_FTR_HVMODE) + CPU_FTR_CP_USE_DCBTZ | CPU_FTR_STCX_CHECKS_ADDRESS) #define CPU_FTRS_POWER5 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \ CPU_FTR_MMCRA | CPU_FTR_SMT | \ @@ -419,13 +417,13 @@ extern const char *powerpc_base_platform; CPU_FTR_DSCR | CPU_FTR_UNALIGNED_LD_STD | \ CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_CFAR) #define CPU_FTRS_POWER7 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \ - CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | CPU_FTR_ARCH_206 |\ + CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | CPU_FTR_HVMODE_206 |\ CPU_FTR_MMCRA | CPU_FTR_SMT | \ CPU_FTR_COHERENT_ICACHE | \ CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \ CPU_FTR_DSCR | CPU_FTR_SAO | CPU_FTR_ASYM_SMT | \ CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \ - CPU_FTR_ICSWX | CPU_FTR_CFAR | CPU_FTR_HVMODE) + CPU_FTR_ICSWX | CPU_FTR_CFAR) #define CPU_FTRS_CELL (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \ CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \ diff --git a/trunk/arch/powerpc/include/asm/emulated_ops.h b/trunk/arch/powerpc/include/asm/emulated_ops.h index 2cc41c715d2b..45921672b97a 100644 --- a/trunk/arch/powerpc/include/asm/emulated_ops.h +++ b/trunk/arch/powerpc/include/asm/emulated_ops.h @@ -78,14 +78,14 @@ extern void ppc_warn_emulated_print(const char *type); #define PPC_WARN_EMULATED(type, regs) \ do { \ perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, \ - 1, regs, 0); \ + 1, 0, regs, 0); \ __PPC_WARN_EMULATED(type); \ } while (0) #define PPC_WARN_ALIGNMENT(type, regs) \ do { \ perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, \ - 1, regs, regs->dar); \ + 1, 0, regs, regs->dar); \ __PPC_WARN_EMULATED(type); \ } while (0) diff --git a/trunk/arch/powerpc/include/asm/exception-64s.h b/trunk/arch/powerpc/include/asm/exception-64s.h index 8057f4f6980f..f5dfe3411f64 100644 --- a/trunk/arch/powerpc/include/asm/exception-64s.h +++ b/trunk/arch/powerpc/include/asm/exception-64s.h @@ -61,22 +61,19 @@ #define EXC_HV H #define EXC_STD -#define __EXCEPTION_PROLOG_1(area, extra, vec) \ +#define EXCEPTION_PROLOG_1(area) \ GET_PACA(r13); \ std r9,area+EX_R9(r13); /* save r9 - r12 */ \ std r10,area+EX_R10(r13); \ + std r11,area+EX_R11(r13); \ + std r12,area+EX_R12(r13); \ BEGIN_FTR_SECTION_NESTED(66); \ mfspr r10,SPRN_CFAR; \ std r10,area+EX_CFAR(r13); \ END_FTR_SECTION_NESTED(CPU_FTR_CFAR, CPU_FTR_CFAR, 66); \ - mfcr r9; \ - extra(vec); \ - std r11,area+EX_R11(r13); \ - std r12,area+EX_R12(r13); \ - GET_SCRATCH0(r10); \ - std r10,area+EX_R13(r13) -#define EXCEPTION_PROLOG_1(area, extra, vec) \ - __EXCEPTION_PROLOG_1(area, extra, vec) + GET_SCRATCH0(r9); \ + std r9,area+EX_R13(r13); \ + mfcr r9 #define __EXCEPTION_PROLOG_PSERIES_1(label, h) \ ld r12,PACAKBASE(r13); /* get high part of &label */ \ @@ -88,65 +85,13 @@ mtspr SPRN_##h##SRR1,r10; \ h##rfid; \ b . /* prevent speculative execution */ -#define EXCEPTION_PROLOG_PSERIES_1(label, h) \ +#define EXCEPTION_PROLOG_PSERIES_1(label, h) \ __EXCEPTION_PROLOG_PSERIES_1(label, h) -#define EXCEPTION_PROLOG_PSERIES(area, label, h, extra, vec) \ - EXCEPTION_PROLOG_1(area, extra, vec); \ +#define EXCEPTION_PROLOG_PSERIES(area, label, h) \ + EXCEPTION_PROLOG_1(area); \ EXCEPTION_PROLOG_PSERIES_1(label, h); -#define __KVMTEST(n) \ - lbz r10,HSTATE_IN_GUEST(r13); \ - cmpwi r10,0; \ - bne do_kvm_##n - -#define __KVM_HANDLER(area, h, n) \ -do_kvm_##n: \ - ld r10,area+EX_R10(r13); \ - stw r9,HSTATE_SCRATCH1(r13); \ - ld r9,area+EX_R9(r13); \ - std r12,HSTATE_SCRATCH0(r13); \ - li r12,n; \ - b kvmppc_interrupt - -#define __KVM_HANDLER_SKIP(area, h, n) \ -do_kvm_##n: \ - cmpwi r10,KVM_GUEST_MODE_SKIP; \ - ld r10,area+EX_R10(r13); \ - beq 89f; \ - stw r9,HSTATE_SCRATCH1(r13); \ - ld r9,area+EX_R9(r13); \ - std r12,HSTATE_SCRATCH0(r13); \ - li r12,n; \ - b kvmppc_interrupt; \ -89: mtocrf 0x80,r9; \ - ld r9,area+EX_R9(r13); \ - b kvmppc_skip_##h##interrupt - -#ifdef CONFIG_KVM_BOOK3S_64_HANDLER -#define KVMTEST(n) __KVMTEST(n) -#define KVM_HANDLER(area, h, n) __KVM_HANDLER(area, h, n) -#define KVM_HANDLER_SKIP(area, h, n) __KVM_HANDLER_SKIP(area, h, n) - -#else -#define KVMTEST(n) -#define KVM_HANDLER(area, h, n) -#define KVM_HANDLER_SKIP(area, h, n) -#endif - -#ifdef CONFIG_KVM_BOOK3S_PR -#define KVMTEST_PR(n) __KVMTEST(n) -#define KVM_HANDLER_PR(area, h, n) __KVM_HANDLER(area, h, n) -#define KVM_HANDLER_PR_SKIP(area, h, n) __KVM_HANDLER_SKIP(area, h, n) - -#else -#define KVMTEST_PR(n) -#define KVM_HANDLER_PR(area, h, n) -#define KVM_HANDLER_PR_SKIP(area, h, n) -#endif - -#define NOTEST(n) - /* * The common exception prolog is used for all except a few exceptions * such as a segment miss on a kernel address. We have to be prepared @@ -219,58 +164,57 @@ do_kvm_##n: \ .globl label##_pSeries; \ label##_pSeries: \ HMT_MEDIUM; \ + DO_KVM vec; \ SET_SCRATCH0(r13); /* save r13 */ \ - EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common, \ - EXC_STD, KVMTEST_PR, vec) + EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common, EXC_STD) #define STD_EXCEPTION_HV(loc, vec, label) \ . = loc; \ .globl label##_hv; \ label##_hv: \ HMT_MEDIUM; \ - SET_SCRATCH0(r13); /* save r13 */ \ - EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common, \ - EXC_HV, KVMTEST, vec) + DO_KVM vec; \ + SET_SCRATCH0(r13); /* save r13 */ \ + EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common, EXC_HV) -#define __SOFTEN_TEST(h) \ - lbz r10,PACASOFTIRQEN(r13); \ - cmpwi r10,0; \ - beq masked_##h##interrupt -#define _SOFTEN_TEST(h) __SOFTEN_TEST(h) - -#define SOFTEN_TEST_PR(vec) \ - KVMTEST_PR(vec); \ - _SOFTEN_TEST(EXC_STD) - -#define SOFTEN_TEST_HV(vec) \ - KVMTEST(vec); \ - _SOFTEN_TEST(EXC_HV) - -#define SOFTEN_TEST_HV_201(vec) \ - KVMTEST(vec); \ - _SOFTEN_TEST(EXC_STD) - -#define __MASKABLE_EXCEPTION_PSERIES(vec, label, h, extra) \ +#define __MASKABLE_EXCEPTION_PSERIES(vec, label, h) \ HMT_MEDIUM; \ + DO_KVM vec; \ SET_SCRATCH0(r13); /* save r13 */ \ - __EXCEPTION_PROLOG_1(PACA_EXGEN, extra, vec); \ - EXCEPTION_PROLOG_PSERIES_1(label##_common, h); -#define _MASKABLE_EXCEPTION_PSERIES(vec, label, h, extra) \ - __MASKABLE_EXCEPTION_PSERIES(vec, label, h, extra) + GET_PACA(r13); \ + std r9,PACA_EXGEN+EX_R9(r13); /* save r9, r10 */ \ + std r10,PACA_EXGEN+EX_R10(r13); \ + lbz r10,PACASOFTIRQEN(r13); \ + mfcr r9; \ + cmpwi r10,0; \ + beq masked_##h##interrupt; \ + GET_SCRATCH0(r10); \ + std r10,PACA_EXGEN+EX_R13(r13); \ + std r11,PACA_EXGEN+EX_R11(r13); \ + std r12,PACA_EXGEN+EX_R12(r13); \ + ld r12,PACAKBASE(r13); /* get high part of &label */ \ + ld r10,PACAKMSR(r13); /* get MSR value for kernel */ \ + mfspr r11,SPRN_##h##SRR0; /* save SRR0 */ \ + LOAD_HANDLER(r12,label##_common) \ + mtspr SPRN_##h##SRR0,r12; \ + mfspr r12,SPRN_##h##SRR1; /* and SRR1 */ \ + mtspr SPRN_##h##SRR1,r10; \ + h##rfid; \ + b . /* prevent speculative execution */ +#define _MASKABLE_EXCEPTION_PSERIES(vec, label, h) \ + __MASKABLE_EXCEPTION_PSERIES(vec, label, h) #define MASKABLE_EXCEPTION_PSERIES(loc, vec, label) \ . = loc; \ .globl label##_pSeries; \ label##_pSeries: \ - _MASKABLE_EXCEPTION_PSERIES(vec, label, \ - EXC_STD, SOFTEN_TEST_PR) + _MASKABLE_EXCEPTION_PSERIES(vec, label, EXC_STD) #define MASKABLE_EXCEPTION_HV(loc, vec, label) \ . = loc; \ .globl label##_hv; \ label##_hv: \ - _MASKABLE_EXCEPTION_PSERIES(vec, label, \ - EXC_HV, SOFTEN_TEST_HV) + _MASKABLE_EXCEPTION_PSERIES(vec, label, EXC_HV) #ifdef CONFIG_PPC_ISERIES #define DISABLE_INTS \ diff --git a/trunk/arch/powerpc/include/asm/hvcall.h b/trunk/arch/powerpc/include/asm/hvcall.h index 1c324ff55ea8..fd8201dddd4b 100644 --- a/trunk/arch/powerpc/include/asm/hvcall.h +++ b/trunk/arch/powerpc/include/asm/hvcall.h @@ -29,10 +29,6 @@ #define H_LONG_BUSY_ORDER_100_SEC 9905 /* Long busy, hint that 100sec \ is a good time to retry */ #define H_LONG_BUSY_END_RANGE 9905 /* End of long busy range */ - -/* Internal value used in book3s_hv kvm support; not returned to guests */ -#define H_TOO_HARD 9999 - #define H_HARDWARE -1 /* Hardware error */ #define H_FUNCTION -2 /* Function not supported */ #define H_PRIVILEGE -3 /* Caller not privileged */ @@ -104,7 +100,6 @@ #define H_PAGE_SET_ACTIVE H_PAGE_STATE_CHANGE #define H_AVPN (1UL<<(63-32)) /* An avpn is provided as a sanity test */ #define H_ANDCOND (1UL<<(63-33)) -#define H_LOCAL (1UL<<(63-35)) #define H_ICACHE_INVALIDATE (1UL<<(63-40)) /* icbi, etc. (ignored for IO pages) */ #define H_ICACHE_SYNCHRONIZE (1UL<<(63-41)) /* dcbst, icbi, etc (ignored for IO pages */ #define H_COALESCE_CAND (1UL<<(63-42)) /* page is a good candidate for coalescing */ diff --git a/trunk/arch/powerpc/include/asm/hw_breakpoint.h b/trunk/arch/powerpc/include/asm/hw_breakpoint.h index 80fd4d2b4a62..1c33ec17ca36 100644 --- a/trunk/arch/powerpc/include/asm/hw_breakpoint.h +++ b/trunk/arch/powerpc/include/asm/hw_breakpoint.h @@ -57,7 +57,7 @@ void hw_breakpoint_pmu_read(struct perf_event *bp); extern void flush_ptrace_hw_breakpoint(struct task_struct *tsk); extern struct pmu perf_ops_bp; -extern void ptrace_triggered(struct perf_event *bp, +extern void ptrace_triggered(struct perf_event *bp, int nmi, struct perf_sample_data *data, struct pt_regs *regs); static inline void hw_breakpoint_disable(void) { diff --git a/trunk/arch/powerpc/include/asm/kvm.h b/trunk/arch/powerpc/include/asm/kvm.h index a4f6c85431f8..d2ca5ed3877b 100644 --- a/trunk/arch/powerpc/include/asm/kvm.h +++ b/trunk/arch/powerpc/include/asm/kvm.h @@ -22,10 +22,6 @@ #include -/* Select powerpc specific features in */ -#define __KVM_HAVE_SPAPR_TCE -#define __KVM_HAVE_PPC_SMT - struct kvm_regs { __u64 pc; __u64 cr; @@ -276,15 +272,4 @@ struct kvm_guest_debug_arch { #define KVM_INTERRUPT_UNSET -2U #define KVM_INTERRUPT_SET_LEVEL -3U -/* for KVM_CAP_SPAPR_TCE */ -struct kvm_create_spapr_tce { - __u64 liobn; - __u32 window_size; -}; - -/* for KVM_ALLOCATE_RMA */ -struct kvm_allocate_rma { - __u64 rma_size; -}; - #endif /* __LINUX_KVM_POWERPC_H */ diff --git a/trunk/arch/powerpc/include/asm/kvm_asm.h b/trunk/arch/powerpc/include/asm/kvm_asm.h index 7b1f0e0fc653..0951b17f4eb5 100644 --- a/trunk/arch/powerpc/include/asm/kvm_asm.h +++ b/trunk/arch/powerpc/include/asm/kvm_asm.h @@ -64,12 +64,8 @@ #define BOOK3S_INTERRUPT_PROGRAM 0x700 #define BOOK3S_INTERRUPT_FP_UNAVAIL 0x800 #define BOOK3S_INTERRUPT_DECREMENTER 0x900 -#define BOOK3S_INTERRUPT_HV_DECREMENTER 0x980 #define BOOK3S_INTERRUPT_SYSCALL 0xc00 #define BOOK3S_INTERRUPT_TRACE 0xd00 -#define BOOK3S_INTERRUPT_H_DATA_STORAGE 0xe00 -#define BOOK3S_INTERRUPT_H_INST_STORAGE 0xe20 -#define BOOK3S_INTERRUPT_H_EMUL_ASSIST 0xe40 #define BOOK3S_INTERRUPT_PERFMON 0xf00 #define BOOK3S_INTERRUPT_ALTIVEC 0xf20 #define BOOK3S_INTERRUPT_VSX 0xf40 diff --git a/trunk/arch/powerpc/include/asm/kvm_book3s.h b/trunk/arch/powerpc/include/asm/kvm_book3s.h index 98da010252a3..d62e703f1214 100644 --- a/trunk/arch/powerpc/include/asm/kvm_book3s.h +++ b/trunk/arch/powerpc/include/asm/kvm_book3s.h @@ -24,6 +24,20 @@ #include #include +struct kvmppc_slb { + u64 esid; + u64 vsid; + u64 orige; + u64 origv; + bool valid : 1; + bool Ks : 1; + bool Kp : 1; + bool nx : 1; + bool large : 1; /* PTEs are 16MB */ + bool tb : 1; /* 1TB segment */ + bool class : 1; +}; + struct kvmppc_bat { u64 raw; u32 bepi; @@ -53,22 +67,11 @@ struct kvmppc_sid_map { #define VSID_POOL_SIZE (SID_CONTEXTS * 16) #endif -struct hpte_cache { - struct hlist_node list_pte; - struct hlist_node list_pte_long; - struct hlist_node list_vpte; - struct hlist_node list_vpte_long; - struct rcu_head rcu_head; - u64 host_va; - u64 pfn; - ulong slot; - struct kvmppc_pte pte; -}; - struct kvmppc_vcpu_book3s { struct kvm_vcpu vcpu; struct kvmppc_book3s_shadow_vcpu *shadow_vcpu; struct kvmppc_sid_map sid_map[SID_MAP_NUM]; + struct kvmppc_slb slb[64]; struct { u64 esid; u64 vsid; @@ -78,6 +81,7 @@ struct kvmppc_vcpu_book3s { struct kvmppc_bat dbat[8]; u64 hid[6]; u64 gqr[8]; + int slb_nr; u64 sdr1; u64 hior; u64 msr_mask; @@ -89,13 +93,7 @@ struct kvmppc_vcpu_book3s { u64 vsid_max; #endif int context_id[SID_CONTEXTS]; - - struct hlist_head hpte_hash_pte[HPTEG_HASH_NUM_PTE]; - struct hlist_head hpte_hash_pte_long[HPTEG_HASH_NUM_PTE_LONG]; - struct hlist_head hpte_hash_vpte[HPTEG_HASH_NUM_VPTE]; - struct hlist_head hpte_hash_vpte_long[HPTEG_HASH_NUM_VPTE_LONG]; - int hpte_cache_count; - spinlock_t mmu_lock; + ulong prog_flags; /* flags to inject when giving a 700 trap */ }; #define CONTEXT_HOST 0 @@ -112,10 +110,8 @@ extern void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong ea, ulong ea_mask) extern void kvmppc_mmu_pte_vflush(struct kvm_vcpu *vcpu, u64 vp, u64 vp_mask); extern void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, ulong pa_start, ulong pa_end); extern void kvmppc_set_msr(struct kvm_vcpu *vcpu, u64 new_msr); -extern void kvmppc_set_pvr(struct kvm_vcpu *vcpu, u32 pvr); extern void kvmppc_mmu_book3s_64_init(struct kvm_vcpu *vcpu); extern void kvmppc_mmu_book3s_32_init(struct kvm_vcpu *vcpu); -extern void kvmppc_mmu_book3s_hv_init(struct kvm_vcpu *vcpu); extern int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte); extern int kvmppc_mmu_map_segment(struct kvm_vcpu *vcpu, ulong eaddr); extern void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu); @@ -127,22 +123,19 @@ extern int kvmppc_mmu_hpte_init(struct kvm_vcpu *vcpu); extern void kvmppc_mmu_invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte); extern int kvmppc_mmu_hpte_sysinit(void); extern void kvmppc_mmu_hpte_sysexit(void); -extern int kvmppc_mmu_hv_init(void); extern int kvmppc_ld(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr, bool data); extern int kvmppc_st(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr, bool data); extern void kvmppc_book3s_queue_irqprio(struct kvm_vcpu *vcpu, unsigned int vec); -extern void kvmppc_inject_interrupt(struct kvm_vcpu *vcpu, int vec, u64 flags); extern void kvmppc_set_bat(struct kvm_vcpu *vcpu, struct kvmppc_bat *bat, bool upper, u32 val); extern void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr); extern int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu); extern pfn_t kvmppc_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn); -extern void kvmppc_handler_lowmem_trampoline(void); -extern void kvmppc_handler_trampoline_enter(void); +extern ulong kvmppc_trampoline_lowmem; +extern ulong kvmppc_trampoline_enter; extern void kvmppc_rmcall(ulong srr0, ulong srr1); -extern void kvmppc_hv_entry_trampoline(void); extern void kvmppc_load_up_fpu(void); extern void kvmppc_load_up_altivec(void); extern void kvmppc_load_up_vsx(void); @@ -154,32 +147,15 @@ static inline struct kvmppc_vcpu_book3s *to_book3s(struct kvm_vcpu *vcpu) return container_of(vcpu, struct kvmppc_vcpu_book3s, vcpu); } -extern void kvm_return_point(void); - -/* Also add subarch specific defines */ - -#ifdef CONFIG_KVM_BOOK3S_32_HANDLER -#include -#endif -#ifdef CONFIG_KVM_BOOK3S_64_HANDLER -#include -#endif - -#ifdef CONFIG_KVM_BOOK3S_PR - -static inline unsigned long kvmppc_interrupt_offset(struct kvm_vcpu *vcpu) +static inline ulong dsisr(void) { - return to_book3s(vcpu)->hior; + ulong r; + asm ( "mfdsisr %0 " : "=r" (r) ); + return r; } -static inline void kvmppc_update_int_pending(struct kvm_vcpu *vcpu, - unsigned long pending_now, unsigned long old_pending) -{ - if (pending_now) - vcpu->arch.shared->int_pending = 1; - else if (old_pending) - vcpu->arch.shared->int_pending = 0; -} +extern void kvm_return_point(void); +static inline struct kvmppc_book3s_shadow_vcpu *to_svcpu(struct kvm_vcpu *vcpu); static inline void kvmppc_set_gpr(struct kvm_vcpu *vcpu, int num, ulong val) { @@ -268,120 +244,6 @@ static inline ulong kvmppc_get_fault_dar(struct kvm_vcpu *vcpu) return to_svcpu(vcpu)->fault_dar; } -static inline bool kvmppc_critical_section(struct kvm_vcpu *vcpu) -{ - ulong crit_raw = vcpu->arch.shared->critical; - ulong crit_r1 = kvmppc_get_gpr(vcpu, 1); - bool crit; - - /* Truncate crit indicators in 32 bit mode */ - if (!(vcpu->arch.shared->msr & MSR_SF)) { - crit_raw &= 0xffffffff; - crit_r1 &= 0xffffffff; - } - - /* Critical section when crit == r1 */ - crit = (crit_raw == crit_r1); - /* ... and we're in supervisor mode */ - crit = crit && !(vcpu->arch.shared->msr & MSR_PR); - - return crit; -} -#else /* CONFIG_KVM_BOOK3S_PR */ - -static inline unsigned long kvmppc_interrupt_offset(struct kvm_vcpu *vcpu) -{ - return 0; -} - -static inline void kvmppc_update_int_pending(struct kvm_vcpu *vcpu, - unsigned long pending_now, unsigned long old_pending) -{ -} - -static inline void kvmppc_set_gpr(struct kvm_vcpu *vcpu, int num, ulong val) -{ - vcpu->arch.gpr[num] = val; -} - -static inline ulong kvmppc_get_gpr(struct kvm_vcpu *vcpu, int num) -{ - return vcpu->arch.gpr[num]; -} - -static inline void kvmppc_set_cr(struct kvm_vcpu *vcpu, u32 val) -{ - vcpu->arch.cr = val; -} - -static inline u32 kvmppc_get_cr(struct kvm_vcpu *vcpu) -{ - return vcpu->arch.cr; -} - -static inline void kvmppc_set_xer(struct kvm_vcpu *vcpu, u32 val) -{ - vcpu->arch.xer = val; -} - -static inline u32 kvmppc_get_xer(struct kvm_vcpu *vcpu) -{ - return vcpu->arch.xer; -} - -static inline void kvmppc_set_ctr(struct kvm_vcpu *vcpu, ulong val) -{ - vcpu->arch.ctr = val; -} - -static inline ulong kvmppc_get_ctr(struct kvm_vcpu *vcpu) -{ - return vcpu->arch.ctr; -} - -static inline void kvmppc_set_lr(struct kvm_vcpu *vcpu, ulong val) -{ - vcpu->arch.lr = val; -} - -static inline ulong kvmppc_get_lr(struct kvm_vcpu *vcpu) -{ - return vcpu->arch.lr; -} - -static inline void kvmppc_set_pc(struct kvm_vcpu *vcpu, ulong val) -{ - vcpu->arch.pc = val; -} - -static inline ulong kvmppc_get_pc(struct kvm_vcpu *vcpu) -{ - return vcpu->arch.pc; -} - -static inline u32 kvmppc_get_last_inst(struct kvm_vcpu *vcpu) -{ - ulong pc = kvmppc_get_pc(vcpu); - - /* Load the instruction manually if it failed to do so in the - * exit path */ - if (vcpu->arch.last_inst == KVM_INST_FETCH_FAILED) - kvmppc_ld(vcpu, &pc, sizeof(u32), &vcpu->arch.last_inst, false); - - return vcpu->arch.last_inst; -} - -static inline ulong kvmppc_get_fault_dar(struct kvm_vcpu *vcpu) -{ - return vcpu->arch.fault_dar; -} - -static inline bool kvmppc_critical_section(struct kvm_vcpu *vcpu) -{ - return false; -} -#endif - /* Magic register values loaded into r3 and r4 before the 'sc' assembly * instruction for the OSI hypercalls */ #define OSI_SC_MAGIC_R3 0x113724FA @@ -389,4 +251,12 @@ static inline bool kvmppc_critical_section(struct kvm_vcpu *vcpu) #define INS_DCBZ 0x7c0007ec +/* Also add subarch specific defines */ + +#ifdef CONFIG_PPC_BOOK3S_32 +#include +#else +#include +#endif + #endif /* __ASM_KVM_BOOK3S_H__ */ diff --git a/trunk/arch/powerpc/include/asm/kvm_book3s_64.h b/trunk/arch/powerpc/include/asm/kvm_book3s_64.h index e43fe42b9875..4cadd612d575 100644 --- a/trunk/arch/powerpc/include/asm/kvm_book3s_64.h +++ b/trunk/arch/powerpc/include/asm/kvm_book3s_64.h @@ -20,13 +20,9 @@ #ifndef __ASM_KVM_BOOK3S_64_H__ #define __ASM_KVM_BOOK3S_64_H__ -#ifdef CONFIG_KVM_BOOK3S_PR static inline struct kvmppc_book3s_shadow_vcpu *to_svcpu(struct kvm_vcpu *vcpu) { return &get_paca()->shadow_vcpu; } -#endif - -#define SPAPR_TCE_SHIFT 12 #endif /* __ASM_KVM_BOOK3S_64_H__ */ diff --git a/trunk/arch/powerpc/include/asm/kvm_book3s_asm.h b/trunk/arch/powerpc/include/asm/kvm_book3s_asm.h index ef7b3688c3b6..d5a8a3861635 100644 --- a/trunk/arch/powerpc/include/asm/kvm_book3s_asm.h +++ b/trunk/arch/powerpc/include/asm/kvm_book3s_asm.h @@ -60,36 +60,6 @@ kvmppc_resume_\intno: #else /*__ASSEMBLY__ */ -/* - * This struct goes in the PACA on 64-bit processors. It is used - * to store host state that needs to be saved when we enter a guest - * and restored when we exit, but isn't specific to any particular - * guest or vcpu. It also has some scratch fields used by the guest - * exit code. - */ -struct kvmppc_host_state { - ulong host_r1; - ulong host_r2; - ulong host_msr; - ulong vmhandler; - ulong scratch0; - ulong scratch1; - u8 in_guest; - -#ifdef CONFIG_KVM_BOOK3S_64_HV - struct kvm_vcpu *kvm_vcpu; - struct kvmppc_vcore *kvm_vcore; - unsigned long xics_phys; - u64 dabr; - u64 host_mmcr[3]; - u32 host_pmc[8]; - u64 host_purr; - u64 host_spurr; - u64 host_dscr; - u64 dec_expires; -#endif -}; - struct kvmppc_book3s_shadow_vcpu { ulong gpr[14]; u32 cr; @@ -103,12 +73,17 @@ struct kvmppc_book3s_shadow_vcpu { ulong shadow_srr1; ulong fault_dar; + ulong host_r1; + ulong host_r2; + ulong handler; + ulong scratch0; + ulong scratch1; + ulong vmhandler; + u8 in_guest; + #ifdef CONFIG_PPC_BOOK3S_32 u32 sr[16]; /* Guest SRs */ - - struct kvmppc_host_state hstate; #endif - #ifdef CONFIG_PPC_BOOK3S_64 u8 slb_max; /* highest used guest slb entry */ struct { diff --git a/trunk/arch/powerpc/include/asm/kvm_booke.h b/trunk/arch/powerpc/include/asm/kvm_booke.h index a90e09188777..9c9ba3d59b1b 100644 --- a/trunk/arch/powerpc/include/asm/kvm_booke.h +++ b/trunk/arch/powerpc/include/asm/kvm_booke.h @@ -93,8 +93,4 @@ static inline ulong kvmppc_get_fault_dar(struct kvm_vcpu *vcpu) return vcpu->arch.fault_dear; } -static inline ulong kvmppc_get_msr(struct kvm_vcpu *vcpu) -{ - return vcpu->arch.shared->msr; -} #endif /* __ASM_KVM_BOOKE_H__ */ diff --git a/trunk/arch/powerpc/include/asm/kvm_e500.h b/trunk/arch/powerpc/include/asm/kvm_e500.h index adbfca9dd100..7a2a565f88c4 100644 --- a/trunk/arch/powerpc/include/asm/kvm_e500.h +++ b/trunk/arch/powerpc/include/asm/kvm_e500.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All rights reserved. + * Copyright (C) 2008 Freescale Semiconductor, Inc. All rights reserved. * * Author: Yu Liu, * @@ -29,25 +29,17 @@ struct tlbe{ u32 mas7; }; -#define E500_TLB_VALID 1 -#define E500_TLB_DIRTY 2 - -struct tlbe_priv { - pfn_t pfn; - unsigned int flags; /* E500_TLB_* */ -}; - -struct vcpu_id_table; - struct kvmppc_vcpu_e500 { /* Unmodified copy of the guest's TLB. */ - struct tlbe *gtlb_arch[E500_TLB_NUM]; + struct tlbe *guest_tlb[E500_TLB_NUM]; + /* TLB that's actually used when the guest is running. */ + struct tlbe *shadow_tlb[E500_TLB_NUM]; + /* Pages which are referenced in the shadow TLB. */ + struct page **shadow_pages[E500_TLB_NUM]; - /* KVM internal information associated with each guest TLB entry */ - struct tlbe_priv *gtlb_priv[E500_TLB_NUM]; - - unsigned int gtlb_size[E500_TLB_NUM]; - unsigned int gtlb_nv[E500_TLB_NUM]; + unsigned int guest_tlb_size[E500_TLB_NUM]; + unsigned int shadow_tlb_size[E500_TLB_NUM]; + unsigned int guest_tlb_nv[E500_TLB_NUM]; u32 host_pid[E500_PID_NUM]; u32 pid[E500_PID_NUM]; @@ -61,10 +53,6 @@ struct kvmppc_vcpu_e500 { u32 mas5; u32 mas6; u32 mas7; - - /* vcpu id table */ - struct vcpu_id_table *idt; - u32 l1csr0; u32 l1csr1; u32 hid0; diff --git a/trunk/arch/powerpc/include/asm/kvm_host.h b/trunk/arch/powerpc/include/asm/kvm_host.h index cc22b282d755..186f150b9b89 100644 --- a/trunk/arch/powerpc/include/asm/kvm_host.h +++ b/trunk/arch/powerpc/include/asm/kvm_host.h @@ -25,23 +25,15 @@ #include #include #include -#include -#include #include -#include -#include #include -#include -#define KVM_MAX_VCPUS NR_CPUS -#define KVM_MAX_VCORES NR_CPUS +#define KVM_MAX_VCPUS 1 #define KVM_MEMORY_SLOTS 32 /* memory slots that does not exposed to userspace */ #define KVM_PRIVATE_MEM_SLOTS 4 -#ifdef CONFIG_KVM_MMIO #define KVM_COALESCED_MMIO_PAGE_OFFSET 1 -#endif /* We don't currently support large pages. */ #define KVM_HPAGE_GFN_SHIFT(x) 0 @@ -65,10 +57,6 @@ struct kvm; struct kvm_run; struct kvm_vcpu; -struct lppaca; -struct slb_shadow; -struct dtl; - struct kvm_vm_stat { u32 remote_tlb_flush; }; @@ -145,74 +133,9 @@ struct kvmppc_exit_timing { }; }; -struct kvmppc_pginfo { - unsigned long pfn; - atomic_t refcnt; -}; - -struct kvmppc_spapr_tce_table { - struct list_head list; - struct kvm *kvm; - u64 liobn; - u32 window_size; - struct page *pages[0]; -}; - -struct kvmppc_rma_info { - void *base_virt; - unsigned long base_pfn; - unsigned long npages; - struct list_head list; - atomic_t use_count; -}; - struct kvm_arch { -#ifdef CONFIG_KVM_BOOK3S_64_HV - unsigned long hpt_virt; - unsigned long ram_npages; - unsigned long ram_psize; - unsigned long ram_porder; - struct kvmppc_pginfo *ram_pginfo; - unsigned int lpid; - unsigned int host_lpid; - unsigned long host_lpcr; - unsigned long sdr1; - unsigned long host_sdr1; - int tlbie_lock; - int n_rma_pages; - unsigned long lpcr; - unsigned long rmor; - struct kvmppc_rma_info *rma; - struct list_head spapr_tce_tables; - unsigned short last_vcpu[NR_CPUS]; - struct kvmppc_vcore *vcores[KVM_MAX_VCORES]; -#endif /* CONFIG_KVM_BOOK3S_64_HV */ }; -/* - * Struct for a virtual core. - * Note: entry_exit_count combines an entry count in the bottom 8 bits - * and an exit count in the next 8 bits. This is so that we can - * atomically increment the entry count iff the exit count is 0 - * without taking the lock. - */ -struct kvmppc_vcore { - int n_runnable; - int n_blocked; - int num_threads; - int entry_exit_count; - int n_woken; - int nap_count; - u16 pcpu; - u8 vcore_running; - u8 in_guest; - struct list_head runnable_threads; - spinlock_t lock; -}; - -#define VCORE_ENTRY_COUNT(vc) ((vc)->entry_exit_count & 0xff) -#define VCORE_EXIT_COUNT(vc) ((vc)->entry_exit_count >> 8) - struct kvmppc_pte { ulong eaddr; u64 vpage; @@ -240,18 +163,16 @@ struct kvmppc_mmu { bool (*is_dcbz32)(struct kvm_vcpu *vcpu); }; -struct kvmppc_slb { - u64 esid; - u64 vsid; - u64 orige; - u64 origv; - bool valid : 1; - bool Ks : 1; - bool Kp : 1; - bool nx : 1; - bool large : 1; /* PTEs are 16MB */ - bool tb : 1; /* 1TB segment */ - bool class : 1; +struct hpte_cache { + struct hlist_node list_pte; + struct hlist_node list_pte_long; + struct hlist_node list_vpte; + struct hlist_node list_vpte_long; + struct rcu_head rcu_head; + u64 host_va; + u64 pfn; + ulong slot; + struct kvmppc_pte pte; }; struct kvm_vcpu_arch { @@ -266,9 +187,6 @@ struct kvm_vcpu_arch { ulong highmem_handler; ulong rmcall; ulong host_paca_phys; - struct kvmppc_slb slb[64]; - int slb_max; /* 1 + index of last valid entry in slb[] */ - int slb_nr; /* total number of entries in SLB */ struct kvmppc_mmu mmu; #endif @@ -277,19 +195,13 @@ struct kvm_vcpu_arch { u64 fpr[32]; u64 fpscr; -#ifdef CONFIG_SPE - ulong evr[32]; - ulong spefscr; - ulong host_spefscr; - u64 acc; -#endif #ifdef CONFIG_ALTIVEC vector128 vr[32]; vector128 vscr; #endif #ifdef CONFIG_VSX - u64 vsr[64]; + u64 vsr[32]; #endif #ifdef CONFIG_PPC_BOOK3S @@ -297,27 +209,22 @@ struct kvm_vcpu_arch { u32 qpr[32]; #endif +#ifdef CONFIG_BOOKE ulong pc; ulong ctr; ulong lr; ulong xer; u32 cr; +#endif #ifdef CONFIG_PPC_BOOK3S + ulong shadow_msr; ulong hflags; ulong guest_owned_ext; - ulong purr; - ulong spurr; - ulong dscr; - ulong amr; - ulong uamor; - u32 ctrl; - ulong dabr; #endif u32 vrsave; /* also USPRG0 */ u32 mmucr; - ulong shadow_msr; ulong sprg4; ulong sprg5; ulong sprg6; @@ -342,7 +249,6 @@ struct kvm_vcpu_arch { u32 pvr; u32 shadow_pid; - u32 shadow_pid1; u32 pid; u32 swap_pid; @@ -352,9 +258,6 @@ struct kvm_vcpu_arch { u32 dbcr1; u32 dbsr; - u64 mmcr[3]; - u32 pmc[8]; - #ifdef CONFIG_KVM_EXIT_TIMING struct mutex exit_timing_lock; struct kvmppc_exit_timing timing_exit; @@ -369,12 +272,8 @@ struct kvm_vcpu_arch { struct dentry *debugfs_exit_timing; #endif -#ifdef CONFIG_PPC_BOOK3S - ulong fault_dar; - u32 fault_dsisr; -#endif - #ifdef CONFIG_BOOKE + u32 last_inst; ulong fault_dear; ulong fault_esr; ulong queued_dear; @@ -389,47 +288,25 @@ struct kvm_vcpu_arch { u8 dcr_is_write; u8 osi_needed; u8 osi_enabled; - u8 hcall_needed; u32 cpr0_cfgaddr; /* holds the last set cpr0_cfgaddr */ struct hrtimer dec_timer; struct tasklet_struct tasklet; u64 dec_jiffies; - u64 dec_expires; unsigned long pending_exceptions; - u16 last_cpu; - u8 ceded; - u8 prodded; - u32 last_inst; - - struct lppaca *vpa; - struct slb_shadow *slb_shadow; - struct dtl *dtl; - struct dtl *dtl_end; - - struct kvmppc_vcore *vcore; - int ret; - int trap; - int state; - int ptid; - wait_queue_head_t cpu_run; - struct kvm_vcpu_arch_shared *shared; unsigned long magic_page_pa; /* phys addr to map the magic page to */ unsigned long magic_page_ea; /* effect. addr to map the magic page to */ -#ifdef CONFIG_KVM_BOOK3S_64_HV - struct kvm_vcpu_arch_shared shregs; - - struct list_head run_list; - struct task_struct *run_task; - struct kvm_run *kvm_run; +#ifdef CONFIG_PPC_BOOK3S + struct hlist_head hpte_hash_pte[HPTEG_HASH_NUM_PTE]; + struct hlist_head hpte_hash_pte_long[HPTEG_HASH_NUM_PTE_LONG]; + struct hlist_head hpte_hash_vpte[HPTEG_HASH_NUM_VPTE]; + struct hlist_head hpte_hash_vpte_long[HPTEG_HASH_NUM_VPTE_LONG]; + int hpte_cache_count; + spinlock_t mmu_lock; #endif }; -#define KVMPPC_VCPU_BUSY_IN_HOST 0 -#define KVMPPC_VCPU_BLOCKED 1 -#define KVMPPC_VCPU_RUNNABLE 2 - #endif /* __POWERPC_KVM_HOST_H__ */ diff --git a/trunk/arch/powerpc/include/asm/kvm_ppc.h b/trunk/arch/powerpc/include/asm/kvm_ppc.h index d121f49d62b8..9345238edecf 100644 --- a/trunk/arch/powerpc/include/asm/kvm_ppc.h +++ b/trunk/arch/powerpc/include/asm/kvm_ppc.h @@ -33,9 +33,6 @@ #else #include #endif -#ifdef CONFIG_KVM_BOOK3S_64_HANDLER -#include -#endif enum emulation_result { EMULATE_DONE, /* no further processing */ @@ -45,7 +42,6 @@ enum emulation_result { EMULATE_AGAIN, /* something went wrong. go again */ }; -extern int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu); extern int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu); extern char kvmppc_handlers_start[]; extern unsigned long kvmppc_handler_len; @@ -113,27 +109,6 @@ extern void kvmppc_booke_exit(void); extern void kvmppc_core_destroy_mmu(struct kvm_vcpu *vcpu); extern int kvmppc_kvm_pv(struct kvm_vcpu *vcpu); -extern void kvmppc_map_magic(struct kvm_vcpu *vcpu); - -extern long kvmppc_alloc_hpt(struct kvm *kvm); -extern void kvmppc_free_hpt(struct kvm *kvm); -extern long kvmppc_prepare_vrma(struct kvm *kvm, - struct kvm_userspace_memory_region *mem); -extern void kvmppc_map_vrma(struct kvm *kvm, - struct kvm_userspace_memory_region *mem); -extern int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu); -extern long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm, - struct kvm_create_spapr_tce *args); -extern long kvm_vm_ioctl_allocate_rma(struct kvm *kvm, - struct kvm_allocate_rma *rma); -extern struct kvmppc_rma_info *kvm_alloc_rma(void); -extern void kvm_release_rma(struct kvmppc_rma_info *ri); -extern int kvmppc_core_init_vm(struct kvm *kvm); -extern void kvmppc_core_destroy_vm(struct kvm *kvm); -extern int kvmppc_core_prepare_memory_region(struct kvm *kvm, - struct kvm_userspace_memory_region *mem); -extern void kvmppc_core_commit_memory_region(struct kvm *kvm, - struct kvm_userspace_memory_region *mem); /* * Cuts out inst bits with ordering according to spec. @@ -176,20 +151,4 @@ int kvmppc_set_sregs_ivor(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs); void kvmppc_set_pid(struct kvm_vcpu *vcpu, u32 pid); -#ifdef CONFIG_KVM_BOOK3S_64_HV -static inline void kvmppc_set_xics_phys(int cpu, unsigned long addr) -{ - paca[cpu].kvm_hstate.xics_phys = addr; -} - -extern void kvm_rma_init(void); - -#else -static inline void kvmppc_set_xics_phys(int cpu, unsigned long addr) -{} - -static inline void kvm_rma_init(void) -{} -#endif - #endif /* __POWERPC_KVM_PPC_H__ */ diff --git a/trunk/arch/powerpc/include/asm/mmu-hash64.h b/trunk/arch/powerpc/include/asm/mmu-hash64.h index b445e0af4c2b..d865bd909c7d 100644 --- a/trunk/arch/powerpc/include/asm/mmu-hash64.h +++ b/trunk/arch/powerpc/include/asm/mmu-hash64.h @@ -90,19 +90,13 @@ extern char initial_stab[]; #define HPTE_R_PP0 ASM_CONST(0x8000000000000000) #define HPTE_R_TS ASM_CONST(0x4000000000000000) -#define HPTE_R_KEY_HI ASM_CONST(0x3000000000000000) #define HPTE_R_RPN_SHIFT 12 -#define HPTE_R_RPN ASM_CONST(0x0ffffffffffff000) +#define HPTE_R_RPN ASM_CONST(0x3ffffffffffff000) +#define HPTE_R_FLAGS ASM_CONST(0x00000000000003ff) #define HPTE_R_PP ASM_CONST(0x0000000000000003) #define HPTE_R_N ASM_CONST(0x0000000000000004) -#define HPTE_R_G ASM_CONST(0x0000000000000008) -#define HPTE_R_M ASM_CONST(0x0000000000000010) -#define HPTE_R_I ASM_CONST(0x0000000000000020) -#define HPTE_R_W ASM_CONST(0x0000000000000040) -#define HPTE_R_WIMG ASM_CONST(0x0000000000000078) #define HPTE_R_C ASM_CONST(0x0000000000000080) #define HPTE_R_R ASM_CONST(0x0000000000000100) -#define HPTE_R_KEY_LO ASM_CONST(0x0000000000000e00) #define HPTE_V_1TB_SEG ASM_CONST(0x4000000000000000) #define HPTE_V_VRMA_MASK ASM_CONST(0x4001ffffff000000) diff --git a/trunk/arch/powerpc/include/asm/paca.h b/trunk/arch/powerpc/include/asm/paca.h index a6da12859959..74126765106a 100644 --- a/trunk/arch/powerpc/include/asm/paca.h +++ b/trunk/arch/powerpc/include/asm/paca.h @@ -147,11 +147,8 @@ struct paca_struct { struct dtl_entry *dtl_curr; /* pointer corresponding to dtl_ridx */ #ifdef CONFIG_KVM_BOOK3S_HANDLER -#ifdef CONFIG_KVM_BOOK3S_PR /* We use this to store guest state in */ struct kvmppc_book3s_shadow_vcpu shadow_vcpu; -#endif - struct kvmppc_host_state kvm_hstate; #endif }; diff --git a/trunk/arch/powerpc/include/asm/ppc_asm.h b/trunk/arch/powerpc/include/asm/ppc_asm.h index 368f72f79808..1b422381fc16 100644 --- a/trunk/arch/powerpc/include/asm/ppc_asm.h +++ b/trunk/arch/powerpc/include/asm/ppc_asm.h @@ -150,22 +150,18 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR) #define REST_16VSRSU(n,b,base) REST_8VSRSU(n,b,base); REST_8VSRSU(n+8,b,base) #define REST_32VSRSU(n,b,base) REST_16VSRSU(n,b,base); REST_16VSRSU(n+16,b,base) -/* - * b = base register for addressing, o = base offset from register of 1st EVR - * n = first EVR, s = scratch - */ -#define SAVE_EVR(n,s,b,o) evmergehi s,s,n; stw s,o+4*(n)(b) -#define SAVE_2EVRS(n,s,b,o) SAVE_EVR(n,s,b,o); SAVE_EVR(n+1,s,b,o) -#define SAVE_4EVRS(n,s,b,o) SAVE_2EVRS(n,s,b,o); SAVE_2EVRS(n+2,s,b,o) -#define SAVE_8EVRS(n,s,b,o) SAVE_4EVRS(n,s,b,o); SAVE_4EVRS(n+4,s,b,o) -#define SAVE_16EVRS(n,s,b,o) SAVE_8EVRS(n,s,b,o); SAVE_8EVRS(n+8,s,b,o) -#define SAVE_32EVRS(n,s,b,o) SAVE_16EVRS(n,s,b,o); SAVE_16EVRS(n+16,s,b,o) -#define REST_EVR(n,s,b,o) lwz s,o+4*(n)(b); evmergelo n,s,n -#define REST_2EVRS(n,s,b,o) REST_EVR(n,s,b,o); REST_EVR(n+1,s,b,o) -#define REST_4EVRS(n,s,b,o) REST_2EVRS(n,s,b,o); REST_2EVRS(n+2,s,b,o) -#define REST_8EVRS(n,s,b,o) REST_4EVRS(n,s,b,o); REST_4EVRS(n+4,s,b,o) -#define REST_16EVRS(n,s,b,o) REST_8EVRS(n,s,b,o); REST_8EVRS(n+8,s,b,o) -#define REST_32EVRS(n,s,b,o) REST_16EVRS(n,s,b,o); REST_16EVRS(n+16,s,b,o) +#define SAVE_EVR(n,s,base) evmergehi s,s,n; stw s,THREAD_EVR0+4*(n)(base) +#define SAVE_2EVRS(n,s,base) SAVE_EVR(n,s,base); SAVE_EVR(n+1,s,base) +#define SAVE_4EVRS(n,s,base) SAVE_2EVRS(n,s,base); SAVE_2EVRS(n+2,s,base) +#define SAVE_8EVRS(n,s,base) SAVE_4EVRS(n,s,base); SAVE_4EVRS(n+4,s,base) +#define SAVE_16EVRS(n,s,base) SAVE_8EVRS(n,s,base); SAVE_8EVRS(n+8,s,base) +#define SAVE_32EVRS(n,s,base) SAVE_16EVRS(n,s,base); SAVE_16EVRS(n+16,s,base) +#define REST_EVR(n,s,base) lwz s,THREAD_EVR0+4*(n)(base); evmergelo n,s,n +#define REST_2EVRS(n,s,base) REST_EVR(n,s,base); REST_EVR(n+1,s,base) +#define REST_4EVRS(n,s,base) REST_2EVRS(n,s,base); REST_2EVRS(n+2,s,base) +#define REST_8EVRS(n,s,base) REST_4EVRS(n,s,base); REST_4EVRS(n+4,s,base) +#define REST_16EVRS(n,s,base) REST_8EVRS(n,s,base); REST_8EVRS(n+8,s,base) +#define REST_32EVRS(n,s,base) REST_16EVRS(n,s,base); REST_16EVRS(n+16,s,base) /* Macros to adjust thread priority for hardware multithreading */ #define HMT_VERY_LOW or 31,31,31 # very low priority diff --git a/trunk/arch/powerpc/include/asm/reg.h b/trunk/arch/powerpc/include/asm/reg.h index ddbe57ae8584..c5cae0dd176c 100644 --- a/trunk/arch/powerpc/include/asm/reg.h +++ b/trunk/arch/powerpc/include/asm/reg.h @@ -189,9 +189,6 @@ #define SPRN_CTR 0x009 /* Count Register */ #define SPRN_DSCR 0x11 #define SPRN_CFAR 0x1c /* Come From Address Register */ -#define SPRN_AMR 0x1d /* Authority Mask Register */ -#define SPRN_UAMOR 0x9d /* User Authority Mask Override Register */ -#define SPRN_AMOR 0x15d /* Authority Mask Override Register */ #define SPRN_ACOP 0x1F /* Available Coprocessor Register */ #define SPRN_CTRLF 0x088 #define SPRN_CTRLT 0x098 @@ -235,28 +232,22 @@ #define LPCR_VPM0 (1ul << (63-0)) #define LPCR_VPM1 (1ul << (63-1)) #define LPCR_ISL (1ul << (63-2)) -#define LPCR_VC_SH (63-2) #define LPCR_DPFD_SH (63-11) #define LPCR_VRMA_L (1ul << (63-12)) #define LPCR_VRMA_LP0 (1ul << (63-15)) #define LPCR_VRMA_LP1 (1ul << (63-16)) -#define LPCR_VRMASD_SH (63-16) #define LPCR_RMLS 0x1C000000 /* impl dependent rmo limit sel */ -#define LPCR_RMLS_SH (63-37) #define LPCR_ILE 0x02000000 /* !HV irqs set MSR:LE */ #define LPCR_PECE 0x00007000 /* powersave exit cause enable */ #define LPCR_PECE0 0x00004000 /* ext. exceptions can cause exit */ #define LPCR_PECE1 0x00002000 /* decrementer can cause exit */ #define LPCR_PECE2 0x00001000 /* machine check etc can cause exit */ #define LPCR_MER 0x00000800 /* Mediated External Exception */ -#define LPCR_LPES 0x0000000c #define LPCR_LPES0 0x00000008 /* LPAR Env selector 0 */ #define LPCR_LPES1 0x00000004 /* LPAR Env selector 1 */ -#define LPCR_LPES_SH 2 #define LPCR_RMI 0x00000002 /* real mode is cache inhibit */ #define LPCR_HDICE 0x00000001 /* Hyp Decr enable (HV,PR,EE) */ #define SPRN_LPID 0x13F /* Logical Partition Identifier */ -#define LPID_RSVD 0x3ff /* Reserved LPID for partn switching */ #define SPRN_HMER 0x150 /* Hardware m? error recovery */ #define SPRN_HMEER 0x151 /* Hardware m? enable error recovery */ #define SPRN_HEIR 0x153 /* Hypervisor Emulated Instruction Register */ @@ -307,7 +298,6 @@ #define SPRN_HASH1 0x3D2 /* Primary Hash Address Register */ #define SPRN_HASH2 0x3D3 /* Secondary Hash Address Resgister */ #define SPRN_HID0 0x3F0 /* Hardware Implementation Register 0 */ -#define HID0_HDICE_SH (63 - 23) /* 970 HDEC interrupt enable */ #define HID0_EMCP (1<<31) /* Enable Machine Check pin */ #define HID0_EBA (1<<29) /* Enable Bus Address Parity */ #define HID0_EBD (1<<28) /* Enable Bus Data Parity */ @@ -363,13 +353,6 @@ #define SPRN_IABR2 0x3FA /* 83xx */ #define SPRN_IBCR 0x135 /* 83xx Insn Breakpoint Control Reg */ #define SPRN_HID4 0x3F4 /* 970 HID4 */ -#define HID4_LPES0 (1ul << (63-0)) /* LPAR env. sel. bit 0 */ -#define HID4_RMLS2_SH (63 - 2) /* Real mode limit bottom 2 bits */ -#define HID4_LPID5_SH (63 - 6) /* partition ID bottom 4 bits */ -#define HID4_RMOR_SH (63 - 22) /* real mode offset (16 bits) */ -#define HID4_LPES1 (1 << (63-57)) /* LPAR env. sel. bit 1 */ -#define HID4_RMLS0_SH (63 - 58) /* Real mode limit top bit */ -#define HID4_LPID1_SH 0 /* partition ID top 2 bits */ #define SPRN_HID4_GEKKO 0x3F3 /* Gekko HID4 */ #define SPRN_HID5 0x3F6 /* 970 HID5 */ #define SPRN_HID6 0x3F9 /* BE HID 6 */ @@ -819,28 +802,28 @@ mfspr rX,SPRN_SPRG_PACA; \ FTR_SECTION_ELSE_NESTED(66); \ mfspr rX,SPRN_SPRG_HPACA; \ - ALT_FTR_SECTION_END_NESTED_IFCLR(CPU_FTR_HVMODE, 66) + ALT_FTR_SECTION_END_NESTED_IFCLR(CPU_FTR_HVMODE_206, 66) #define SET_PACA(rX) \ BEGIN_FTR_SECTION_NESTED(66); \ mtspr SPRN_SPRG_PACA,rX; \ FTR_SECTION_ELSE_NESTED(66); \ mtspr SPRN_SPRG_HPACA,rX; \ - ALT_FTR_SECTION_END_NESTED_IFCLR(CPU_FTR_HVMODE, 66) + ALT_FTR_SECTION_END_NESTED_IFCLR(CPU_FTR_HVMODE_206, 66) #define GET_SCRATCH0(rX) \ BEGIN_FTR_SECTION_NESTED(66); \ mfspr rX,SPRN_SPRG_SCRATCH0; \ FTR_SECTION_ELSE_NESTED(66); \ mfspr rX,SPRN_SPRG_HSCRATCH0; \ - ALT_FTR_SECTION_END_NESTED_IFCLR(CPU_FTR_HVMODE, 66) + ALT_FTR_SECTION_END_NESTED_IFCLR(CPU_FTR_HVMODE_206, 66) #define SET_SCRATCH0(rX) \ BEGIN_FTR_SECTION_NESTED(66); \ mtspr SPRN_SPRG_SCRATCH0,rX; \ FTR_SECTION_ELSE_NESTED(66); \ mtspr SPRN_SPRG_HSCRATCH0,rX; \ - ALT_FTR_SECTION_END_NESTED_IFCLR(CPU_FTR_HVMODE, 66) + ALT_FTR_SECTION_END_NESTED_IFCLR(CPU_FTR_HVMODE_206, 66) #else /* CONFIG_PPC_BOOK3S_64 */ #define GET_SCRATCH0(rX) mfspr rX,SPRN_SPRG_SCRATCH0 diff --git a/trunk/arch/powerpc/include/asm/reg_booke.h b/trunk/arch/powerpc/include/asm/reg_booke.h index 9ec0b39f9ddc..0f0ad9fa01c1 100644 --- a/trunk/arch/powerpc/include/asm/reg_booke.h +++ b/trunk/arch/powerpc/include/asm/reg_booke.h @@ -318,7 +318,6 @@ #define ESR_ILK 0x00100000 /* Instr. Cache Locking */ #define ESR_PUO 0x00040000 /* Unimplemented Operation exception */ #define ESR_BO 0x00020000 /* Byte Ordering */ -#define ESR_SPV 0x00000080 /* Signal Processing operation */ /* Bit definitions related to the DBCR0. */ #if defined(CONFIG_40x) diff --git a/trunk/arch/powerpc/kernel/asm-offsets.c b/trunk/arch/powerpc/kernel/asm-offsets.c index 54b935f2f5de..36e1c8a29be8 100644 --- a/trunk/arch/powerpc/kernel/asm-offsets.c +++ b/trunk/arch/powerpc/kernel/asm-offsets.c @@ -128,7 +128,6 @@ int main(void) DEFINE(ICACHEL1LINESPERPAGE, offsetof(struct ppc64_caches, ilines_per_page)); /* paca */ DEFINE(PACA_SIZE, sizeof(struct paca_struct)); - DEFINE(PACA_LOCK_TOKEN, offsetof(struct paca_struct, lock_token)); DEFINE(PACAPACAINDEX, offsetof(struct paca_struct, paca_index)); DEFINE(PACAPROCSTART, offsetof(struct paca_struct, cpu_start)); DEFINE(PACAKSAVE, offsetof(struct paca_struct, kstack)); @@ -188,9 +187,7 @@ int main(void) DEFINE(LPPACASRR1, offsetof(struct lppaca, saved_srr1)); DEFINE(LPPACAANYINT, offsetof(struct lppaca, int_dword.any_int)); DEFINE(LPPACADECRINT, offsetof(struct lppaca, int_dword.fields.decr_int)); - DEFINE(LPPACA_PMCINUSE, offsetof(struct lppaca, pmcregs_in_use)); DEFINE(LPPACA_DTLIDX, offsetof(struct lppaca, dtl_idx)); - DEFINE(LPPACA_YIELDCOUNT, offsetof(struct lppaca, yield_count)); DEFINE(PACA_DTL_RIDX, offsetof(struct paca_struct, dtl_ridx)); #endif /* CONFIG_PPC_STD_MMU_64 */ DEFINE(PACAEMERGSP, offsetof(struct paca_struct, emergency_sp)); @@ -201,6 +198,11 @@ int main(void) DEFINE(PACA_USER_TIME, offsetof(struct paca_struct, user_time)); DEFINE(PACA_SYSTEM_TIME, offsetof(struct paca_struct, system_time)); DEFINE(PACA_TRAP_SAVE, offsetof(struct paca_struct, trap_save)); +#ifdef CONFIG_KVM_BOOK3S_64_HANDLER + DEFINE(PACA_KVM_SVCPU, offsetof(struct paca_struct, shadow_vcpu)); + DEFINE(SVCPU_SLB, offsetof(struct kvmppc_book3s_shadow_vcpu, slb)); + DEFINE(SVCPU_SLB_MAX, offsetof(struct kvmppc_book3s_shadow_vcpu, slb_max)); +#endif #endif /* CONFIG_PPC64 */ /* RTAS */ @@ -395,160 +397,67 @@ int main(void) DEFINE(VCPU_HOST_PID, offsetof(struct kvm_vcpu, arch.host_pid)); DEFINE(VCPU_GPRS, offsetof(struct kvm_vcpu, arch.gpr)); DEFINE(VCPU_VRSAVE, offsetof(struct kvm_vcpu, arch.vrsave)); - DEFINE(VCPU_FPRS, offsetof(struct kvm_vcpu, arch.fpr)); - DEFINE(VCPU_FPSCR, offsetof(struct kvm_vcpu, arch.fpscr)); -#ifdef CONFIG_ALTIVEC - DEFINE(VCPU_VRS, offsetof(struct kvm_vcpu, arch.vr)); - DEFINE(VCPU_VSCR, offsetof(struct kvm_vcpu, arch.vscr)); -#endif -#ifdef CONFIG_VSX - DEFINE(VCPU_VSRS, offsetof(struct kvm_vcpu, arch.vsr)); -#endif - DEFINE(VCPU_XER, offsetof(struct kvm_vcpu, arch.xer)); - DEFINE(VCPU_CTR, offsetof(struct kvm_vcpu, arch.ctr)); - DEFINE(VCPU_LR, offsetof(struct kvm_vcpu, arch.lr)); - DEFINE(VCPU_CR, offsetof(struct kvm_vcpu, arch.cr)); - DEFINE(VCPU_PC, offsetof(struct kvm_vcpu, arch.pc)); -#ifdef CONFIG_KVM_BOOK3S_64_HV - DEFINE(VCPU_MSR, offsetof(struct kvm_vcpu, arch.shregs.msr)); - DEFINE(VCPU_SRR0, offsetof(struct kvm_vcpu, arch.shregs.srr0)); - DEFINE(VCPU_SRR1, offsetof(struct kvm_vcpu, arch.shregs.srr1)); - DEFINE(VCPU_SPRG0, offsetof(struct kvm_vcpu, arch.shregs.sprg0)); - DEFINE(VCPU_SPRG1, offsetof(struct kvm_vcpu, arch.shregs.sprg1)); - DEFINE(VCPU_SPRG2, offsetof(struct kvm_vcpu, arch.shregs.sprg2)); - DEFINE(VCPU_SPRG3, offsetof(struct kvm_vcpu, arch.shregs.sprg3)); -#endif DEFINE(VCPU_SPRG4, offsetof(struct kvm_vcpu, arch.sprg4)); DEFINE(VCPU_SPRG5, offsetof(struct kvm_vcpu, arch.sprg5)); DEFINE(VCPU_SPRG6, offsetof(struct kvm_vcpu, arch.sprg6)); DEFINE(VCPU_SPRG7, offsetof(struct kvm_vcpu, arch.sprg7)); DEFINE(VCPU_SHADOW_PID, offsetof(struct kvm_vcpu, arch.shadow_pid)); - DEFINE(VCPU_SHADOW_PID1, offsetof(struct kvm_vcpu, arch.shadow_pid1)); DEFINE(VCPU_SHARED, offsetof(struct kvm_vcpu, arch.shared)); DEFINE(VCPU_SHARED_MSR, offsetof(struct kvm_vcpu_arch_shared, msr)); - DEFINE(VCPU_SHADOW_MSR, offsetof(struct kvm_vcpu, arch.shadow_msr)); /* book3s */ -#ifdef CONFIG_KVM_BOOK3S_64_HV - DEFINE(KVM_LPID, offsetof(struct kvm, arch.lpid)); - DEFINE(KVM_SDR1, offsetof(struct kvm, arch.sdr1)); - DEFINE(KVM_HOST_LPID, offsetof(struct kvm, arch.host_lpid)); - DEFINE(KVM_HOST_LPCR, offsetof(struct kvm, arch.host_lpcr)); - DEFINE(KVM_HOST_SDR1, offsetof(struct kvm, arch.host_sdr1)); - DEFINE(KVM_TLBIE_LOCK, offsetof(struct kvm, arch.tlbie_lock)); - DEFINE(KVM_ONLINE_CPUS, offsetof(struct kvm, online_vcpus.counter)); - DEFINE(KVM_LAST_VCPU, offsetof(struct kvm, arch.last_vcpu)); - DEFINE(KVM_LPCR, offsetof(struct kvm, arch.lpcr)); - DEFINE(KVM_RMOR, offsetof(struct kvm, arch.rmor)); - DEFINE(VCPU_DSISR, offsetof(struct kvm_vcpu, arch.shregs.dsisr)); - DEFINE(VCPU_DAR, offsetof(struct kvm_vcpu, arch.shregs.dar)); -#endif #ifdef CONFIG_PPC_BOOK3S - DEFINE(VCPU_KVM, offsetof(struct kvm_vcpu, kvm)); - DEFINE(VCPU_VCPUID, offsetof(struct kvm_vcpu, vcpu_id)); DEFINE(VCPU_HOST_RETIP, offsetof(struct kvm_vcpu, arch.host_retip)); DEFINE(VCPU_HOST_MSR, offsetof(struct kvm_vcpu, arch.host_msr)); - DEFINE(VCPU_PURR, offsetof(struct kvm_vcpu, arch.purr)); - DEFINE(VCPU_SPURR, offsetof(struct kvm_vcpu, arch.spurr)); - DEFINE(VCPU_DSCR, offsetof(struct kvm_vcpu, arch.dscr)); - DEFINE(VCPU_AMR, offsetof(struct kvm_vcpu, arch.amr)); - DEFINE(VCPU_UAMOR, offsetof(struct kvm_vcpu, arch.uamor)); - DEFINE(VCPU_CTRL, offsetof(struct kvm_vcpu, arch.ctrl)); - DEFINE(VCPU_DABR, offsetof(struct kvm_vcpu, arch.dabr)); + DEFINE(VCPU_SHADOW_MSR, offsetof(struct kvm_vcpu, arch.shadow_msr)); DEFINE(VCPU_TRAMPOLINE_LOWMEM, offsetof(struct kvm_vcpu, arch.trampoline_lowmem)); DEFINE(VCPU_TRAMPOLINE_ENTER, offsetof(struct kvm_vcpu, arch.trampoline_enter)); DEFINE(VCPU_HIGHMEM_HANDLER, offsetof(struct kvm_vcpu, arch.highmem_handler)); DEFINE(VCPU_RMCALL, offsetof(struct kvm_vcpu, arch.rmcall)); DEFINE(VCPU_HFLAGS, offsetof(struct kvm_vcpu, arch.hflags)); - DEFINE(VCPU_DEC, offsetof(struct kvm_vcpu, arch.dec)); - DEFINE(VCPU_DEC_EXPIRES, offsetof(struct kvm_vcpu, arch.dec_expires)); - DEFINE(VCPU_PENDING_EXC, offsetof(struct kvm_vcpu, arch.pending_exceptions)); - DEFINE(VCPU_VPA, offsetof(struct kvm_vcpu, arch.vpa)); - DEFINE(VCPU_MMCR, offsetof(struct kvm_vcpu, arch.mmcr)); - DEFINE(VCPU_PMC, offsetof(struct kvm_vcpu, arch.pmc)); - DEFINE(VCPU_SLB, offsetof(struct kvm_vcpu, arch.slb)); - DEFINE(VCPU_SLB_MAX, offsetof(struct kvm_vcpu, arch.slb_max)); - DEFINE(VCPU_SLB_NR, offsetof(struct kvm_vcpu, arch.slb_nr)); - DEFINE(VCPU_LAST_CPU, offsetof(struct kvm_vcpu, arch.last_cpu)); - DEFINE(VCPU_FAULT_DSISR, offsetof(struct kvm_vcpu, arch.fault_dsisr)); - DEFINE(VCPU_FAULT_DAR, offsetof(struct kvm_vcpu, arch.fault_dar)); - DEFINE(VCPU_LAST_INST, offsetof(struct kvm_vcpu, arch.last_inst)); - DEFINE(VCPU_TRAP, offsetof(struct kvm_vcpu, arch.trap)); - DEFINE(VCPU_PTID, offsetof(struct kvm_vcpu, arch.ptid)); - DEFINE(VCORE_ENTRY_EXIT, offsetof(struct kvmppc_vcore, entry_exit_count)); - DEFINE(VCORE_NAP_COUNT, offsetof(struct kvmppc_vcore, nap_count)); - DEFINE(VCORE_IN_GUEST, offsetof(struct kvmppc_vcore, in_guest)); DEFINE(VCPU_SVCPU, offsetof(struct kvmppc_vcpu_book3s, shadow_vcpu) - offsetof(struct kvmppc_vcpu_book3s, vcpu)); - DEFINE(VCPU_SLB_E, offsetof(struct kvmppc_slb, orige)); - DEFINE(VCPU_SLB_V, offsetof(struct kvmppc_slb, origv)); - DEFINE(VCPU_SLB_SIZE, sizeof(struct kvmppc_slb)); - -#ifdef CONFIG_PPC_BOOK3S_64 -#ifdef CONFIG_KVM_BOOK3S_PR -# define SVCPU_FIELD(x, f) DEFINE(x, offsetof(struct paca_struct, shadow_vcpu.f)) -#else -# define SVCPU_FIELD(x, f) -#endif -# define HSTATE_FIELD(x, f) DEFINE(x, offsetof(struct paca_struct, kvm_hstate.f)) -#else /* 32-bit */ -# define SVCPU_FIELD(x, f) DEFINE(x, offsetof(struct kvmppc_book3s_shadow_vcpu, f)) -# define HSTATE_FIELD(x, f) DEFINE(x, offsetof(struct kvmppc_book3s_shadow_vcpu, hstate.f)) -#endif - - SVCPU_FIELD(SVCPU_CR, cr); - SVCPU_FIELD(SVCPU_XER, xer); - SVCPU_FIELD(SVCPU_CTR, ctr); - SVCPU_FIELD(SVCPU_LR, lr); - SVCPU_FIELD(SVCPU_PC, pc); - SVCPU_FIELD(SVCPU_R0, gpr[0]); - SVCPU_FIELD(SVCPU_R1, gpr[1]); - SVCPU_FIELD(SVCPU_R2, gpr[2]); - SVCPU_FIELD(SVCPU_R3, gpr[3]); - SVCPU_FIELD(SVCPU_R4, gpr[4]); - SVCPU_FIELD(SVCPU_R5, gpr[5]); - SVCPU_FIELD(SVCPU_R6, gpr[6]); - SVCPU_FIELD(SVCPU_R7, gpr[7]); - SVCPU_FIELD(SVCPU_R8, gpr[8]); - SVCPU_FIELD(SVCPU_R9, gpr[9]); - SVCPU_FIELD(SVCPU_R10, gpr[10]); - SVCPU_FIELD(SVCPU_R11, gpr[11]); - SVCPU_FIELD(SVCPU_R12, gpr[12]); - SVCPU_FIELD(SVCPU_R13, gpr[13]); - SVCPU_FIELD(SVCPU_FAULT_DSISR, fault_dsisr); - SVCPU_FIELD(SVCPU_FAULT_DAR, fault_dar); - SVCPU_FIELD(SVCPU_LAST_INST, last_inst); - SVCPU_FIELD(SVCPU_SHADOW_SRR1, shadow_srr1); + DEFINE(SVCPU_CR, offsetof(struct kvmppc_book3s_shadow_vcpu, cr)); + DEFINE(SVCPU_XER, offsetof(struct kvmppc_book3s_shadow_vcpu, xer)); + DEFINE(SVCPU_CTR, offsetof(struct kvmppc_book3s_shadow_vcpu, ctr)); + DEFINE(SVCPU_LR, offsetof(struct kvmppc_book3s_shadow_vcpu, lr)); + DEFINE(SVCPU_PC, offsetof(struct kvmppc_book3s_shadow_vcpu, pc)); + DEFINE(SVCPU_R0, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[0])); + DEFINE(SVCPU_R1, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[1])); + DEFINE(SVCPU_R2, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[2])); + DEFINE(SVCPU_R3, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[3])); + DEFINE(SVCPU_R4, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[4])); + DEFINE(SVCPU_R5, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[5])); + DEFINE(SVCPU_R6, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[6])); + DEFINE(SVCPU_R7, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[7])); + DEFINE(SVCPU_R8, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[8])); + DEFINE(SVCPU_R9, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[9])); + DEFINE(SVCPU_R10, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[10])); + DEFINE(SVCPU_R11, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[11])); + DEFINE(SVCPU_R12, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[12])); + DEFINE(SVCPU_R13, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[13])); + DEFINE(SVCPU_HOST_R1, offsetof(struct kvmppc_book3s_shadow_vcpu, host_r1)); + DEFINE(SVCPU_HOST_R2, offsetof(struct kvmppc_book3s_shadow_vcpu, host_r2)); + DEFINE(SVCPU_VMHANDLER, offsetof(struct kvmppc_book3s_shadow_vcpu, + vmhandler)); + DEFINE(SVCPU_SCRATCH0, offsetof(struct kvmppc_book3s_shadow_vcpu, + scratch0)); + DEFINE(SVCPU_SCRATCH1, offsetof(struct kvmppc_book3s_shadow_vcpu, + scratch1)); + DEFINE(SVCPU_IN_GUEST, offsetof(struct kvmppc_book3s_shadow_vcpu, + in_guest)); + DEFINE(SVCPU_FAULT_DSISR, offsetof(struct kvmppc_book3s_shadow_vcpu, + fault_dsisr)); + DEFINE(SVCPU_FAULT_DAR, offsetof(struct kvmppc_book3s_shadow_vcpu, + fault_dar)); + DEFINE(SVCPU_LAST_INST, offsetof(struct kvmppc_book3s_shadow_vcpu, + last_inst)); + DEFINE(SVCPU_SHADOW_SRR1, offsetof(struct kvmppc_book3s_shadow_vcpu, + shadow_srr1)); #ifdef CONFIG_PPC_BOOK3S_32 - SVCPU_FIELD(SVCPU_SR, sr); -#endif -#ifdef CONFIG_PPC64 - SVCPU_FIELD(SVCPU_SLB, slb); - SVCPU_FIELD(SVCPU_SLB_MAX, slb_max); + DEFINE(SVCPU_SR, offsetof(struct kvmppc_book3s_shadow_vcpu, sr)); #endif - - HSTATE_FIELD(HSTATE_HOST_R1, host_r1); - HSTATE_FIELD(HSTATE_HOST_R2, host_r2); - HSTATE_FIELD(HSTATE_HOST_MSR, host_msr); - HSTATE_FIELD(HSTATE_VMHANDLER, vmhandler); - HSTATE_FIELD(HSTATE_SCRATCH0, scratch0); - HSTATE_FIELD(HSTATE_SCRATCH1, scratch1); - HSTATE_FIELD(HSTATE_IN_GUEST, in_guest); - -#ifdef CONFIG_KVM_BOOK3S_64_HV - HSTATE_FIELD(HSTATE_KVM_VCPU, kvm_vcpu); - HSTATE_FIELD(HSTATE_KVM_VCORE, kvm_vcore); - HSTATE_FIELD(HSTATE_XICS_PHYS, xics_phys); - HSTATE_FIELD(HSTATE_MMCR, host_mmcr); - HSTATE_FIELD(HSTATE_PMC, host_pmc); - HSTATE_FIELD(HSTATE_PURR, host_purr); - HSTATE_FIELD(HSTATE_SPURR, host_spurr); - HSTATE_FIELD(HSTATE_DSCR, host_dscr); - HSTATE_FIELD(HSTATE_DABR, dabr); - HSTATE_FIELD(HSTATE_DECEXP, dec_expires); -#endif /* CONFIG_KVM_BOOK3S_64_HV */ - -#else /* CONFIG_PPC_BOOK3S */ +#else DEFINE(VCPU_CR, offsetof(struct kvm_vcpu, arch.cr)); DEFINE(VCPU_XER, offsetof(struct kvm_vcpu, arch.xer)); DEFINE(VCPU_LR, offsetof(struct kvm_vcpu, arch.lr)); @@ -558,7 +467,7 @@ int main(void) DEFINE(VCPU_FAULT_DEAR, offsetof(struct kvm_vcpu, arch.fault_dear)); DEFINE(VCPU_FAULT_ESR, offsetof(struct kvm_vcpu, arch.fault_esr)); #endif /* CONFIG_PPC_BOOK3S */ -#endif /* CONFIG_KVM */ +#endif #ifdef CONFIG_KVM_GUEST DEFINE(KVM_MAGIC_SCRATCH1, offsetof(struct kvm_vcpu_arch_shared, @@ -588,13 +497,6 @@ int main(void) DEFINE(TLBCAM_MAS7, offsetof(struct tlbcam, MAS7)); #endif -#if defined(CONFIG_KVM) && defined(CONFIG_SPE) - DEFINE(VCPU_EVR, offsetof(struct kvm_vcpu, arch.evr[0])); - DEFINE(VCPU_ACC, offsetof(struct kvm_vcpu, arch.acc)); - DEFINE(VCPU_SPEFSCR, offsetof(struct kvm_vcpu, arch.spefscr)); - DEFINE(VCPU_HOST_SPEFSCR, offsetof(struct kvm_vcpu, arch.host_spefscr)); -#endif - #ifdef CONFIG_KVM_EXIT_TIMING DEFINE(VCPU_TIMING_EXIT_TBU, offsetof(struct kvm_vcpu, arch.timing_exit.tv32.tbu)); diff --git a/trunk/arch/powerpc/kernel/cpu_setup_power7.S b/trunk/arch/powerpc/kernel/cpu_setup_power7.S index 76797c5105d6..4f9a93fcfe07 100644 --- a/trunk/arch/powerpc/kernel/cpu_setup_power7.S +++ b/trunk/arch/powerpc/kernel/cpu_setup_power7.S @@ -45,12 +45,12 @@ _GLOBAL(__restore_cpu_power7) blr __init_hvmode_206: - /* Disable CPU_FTR_HVMODE and exit if MSR:HV is not set */ + /* Disable CPU_FTR_HVMODE_206 and exit if MSR:HV is not set */ mfmsr r3 rldicl. r0,r3,4,63 bnelr ld r5,CPU_SPEC_FEATURES(r4) - LOAD_REG_IMMEDIATE(r6,CPU_FTR_HVMODE) + LOAD_REG_IMMEDIATE(r6,CPU_FTR_HVMODE_206) xor r5,r5,r6 std r5,CPU_SPEC_FEATURES(r4) blr @@ -61,23 +61,19 @@ __init_LPCR: * LPES = 0b01 (HSRR0/1 used for 0x500) * PECE = 0b111 * DPFD = 4 - * HDICE = 0 - * VC = 0b100 (VPM0=1, VPM1=0, ISL=0) - * VRMASD = 0b10000 (L=1, LP=00) * * Other bits untouched for now */ mfspr r3,SPRN_LPCR - li r5,1 - rldimi r3,r5, LPCR_LPES_SH, 64-LPCR_LPES_SH-2 + ori r3,r3,(LPCR_LPES0|LPCR_LPES1) + xori r3,r3, LPCR_LPES0 ori r3,r3,(LPCR_PECE0|LPCR_PECE1|LPCR_PECE2) + li r5,7 + sldi r5,r5,LPCR_DPFD_SH + andc r3,r3,r5 li r5,4 - rldimi r3,r5, LPCR_DPFD_SH, 64-LPCR_DPFD_SH-3 - clrrdi r3,r3,1 /* clear HDICE */ - li r5,4 - rldimi r3,r5, LPCR_VC_SH, 0 - li r5,0x10 - rldimi r3,r5, LPCR_VRMASD_SH, 64-LPCR_VRMASD_SH-5 + sldi r5,r5,LPCR_DPFD_SH + or r3,r3,r5 mtspr SPRN_LPCR,r3 isync blr diff --git a/trunk/arch/powerpc/kernel/cpu_setup_ppc970.S b/trunk/arch/powerpc/kernel/cpu_setup_ppc970.S index 12fac8df01c5..27f2507279d8 100644 --- a/trunk/arch/powerpc/kernel/cpu_setup_ppc970.S +++ b/trunk/arch/powerpc/kernel/cpu_setup_ppc970.S @@ -76,7 +76,7 @@ _GLOBAL(__setup_cpu_ppc970) /* Do nothing if not running in HV mode */ mfmsr r0 rldicl. r0,r0,4,63 - beq no_hv_mode + beqlr mfspr r0,SPRN_HID0 li r11,5 /* clear DOZE and SLEEP */ @@ -90,7 +90,7 @@ _GLOBAL(__setup_cpu_ppc970MP) /* Do nothing if not running in HV mode */ mfmsr r0 rldicl. r0,r0,4,63 - beq no_hv_mode + beqlr mfspr r0,SPRN_HID0 li r11,0x15 /* clear DOZE and SLEEP */ @@ -109,14 +109,6 @@ load_hids: sync isync - /* Try to set LPES = 01 in HID4 */ - mfspr r0,SPRN_HID4 - clrldi r0,r0,1 /* clear LPES0 */ - ori r0,r0,HID4_LPES1 /* set LPES1 */ - sync - mtspr SPRN_HID4,r0 - isync - /* Save away cpu state */ LOAD_REG_ADDR(r5,cpu_state_storage) @@ -125,21 +117,11 @@ load_hids: std r3,CS_HID0(r5) mfspr r3,SPRN_HID1 std r3,CS_HID1(r5) - mfspr r4,SPRN_HID4 - std r4,CS_HID4(r5) + mfspr r3,SPRN_HID4 + std r3,CS_HID4(r5) mfspr r3,SPRN_HID5 std r3,CS_HID5(r5) - /* See if we successfully set LPES1 to 1; if not we are in Apple mode */ - andi. r4,r4,HID4_LPES1 - bnelr - -no_hv_mode: - /* Disable CPU_FTR_HVMODE and exit, since we don't have HV mode */ - ld r5,CPU_SPEC_FEATURES(r4) - LOAD_REG_IMMEDIATE(r6,CPU_FTR_HVMODE) - andc r5,r5,r6 - std r5,CPU_SPEC_FEATURES(r4) blr /* Called with no MMU context (typically MSR:IR/DR off) to diff --git a/trunk/arch/powerpc/kernel/e500-pmu.c b/trunk/arch/powerpc/kernel/e500-pmu.c index cb2e2949c8d1..b150b510510f 100644 --- a/trunk/arch/powerpc/kernel/e500-pmu.c +++ b/trunk/arch/powerpc/kernel/e500-pmu.c @@ -75,11 +75,6 @@ static int e500_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = { [C(OP_WRITE)] = { -1, -1 }, [C(OP_PREFETCH)] = { -1, -1 }, }, - [C(NODE)] = { /* RESULT_ACCESS RESULT_MISS */ - [C(OP_READ)] = { -1, -1 }, - [C(OP_WRITE)] = { -1, -1 }, - [C(OP_PREFETCH)] = { -1, -1 }, - }, }; static int num_events = 128; diff --git a/trunk/arch/powerpc/kernel/exceptions-64s.S b/trunk/arch/powerpc/kernel/exceptions-64s.S index 41b02c792aa3..a85f4874cba7 100644 --- a/trunk/arch/powerpc/kernel/exceptions-64s.S +++ b/trunk/arch/powerpc/kernel/exceptions-64s.S @@ -40,6 +40,7 @@ __start_interrupts: .globl system_reset_pSeries; system_reset_pSeries: HMT_MEDIUM; + DO_KVM 0x100; SET_SCRATCH0(r13) #ifdef CONFIG_PPC_P7_NAP BEGIN_FTR_SECTION @@ -49,73 +50,82 @@ BEGIN_FTR_SECTION * state loss at this time. */ mfspr r13,SPRN_SRR1 - rlwinm. r13,r13,47-31,30,31 - beq 9f - - /* waking up from powersave (nap) state */ - cmpwi cr1,r13,2 + rlwinm r13,r13,47-31,30,31 + cmpwi cr0,r13,1 + bne 1f + b .power7_wakeup_noloss +1: cmpwi cr0,r13,2 + bne 1f + b .power7_wakeup_loss /* Total loss of HV state is fatal, we could try to use the * PIR to locate a PACA, then use an emergency stack etc... * but for now, let's just stay stuck here */ - bgt cr1,. - GET_PACA(r13) - -#ifdef CONFIG_KVM_BOOK3S_64_HV - lbz r0,PACAPROCSTART(r13) - cmpwi r0,0x80 - bne 1f - li r0,0 - stb r0,PACAPROCSTART(r13) - b kvm_start_guest -1: -#endif - - beq cr1,2f - b .power7_wakeup_noloss -2: b .power7_wakeup_loss -9: -END_FTR_SECTION_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206) +1: cmpwi cr0,r13,3 + beq . +END_FTR_SECTION_IFSET(CPU_FTR_HVMODE_206) #endif /* CONFIG_PPC_P7_NAP */ - EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common, EXC_STD, - NOTEST, 0x100) + EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common, EXC_STD) . = 0x200 -machine_check_pSeries_1: - /* This is moved out of line as it can be patched by FW, but - * some code path might still want to branch into the original - * vector - */ - b machine_check_pSeries +_machine_check_pSeries: + HMT_MEDIUM + DO_KVM 0x200 + SET_SCRATCH0(r13) + EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common, EXC_STD) . = 0x300 .globl data_access_pSeries data_access_pSeries: HMT_MEDIUM + DO_KVM 0x300 SET_SCRATCH0(r13) -#ifndef CONFIG_POWER4_ONLY BEGIN_FTR_SECTION - b data_access_check_stab -data_access_not_stab: -END_MMU_FTR_SECTION_IFCLR(MMU_FTR_SLB) -#endif - EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, data_access_common, EXC_STD, - KVMTEST_PR, 0x300) + GET_PACA(r13) + 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_pSeries + 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) + GET_SCRATCH0(r12) + std r10,PACA_EXGEN+EX_R10(r13) + std r11,PACA_EXGEN+EX_R9(r13) + std r12,PACA_EXGEN+EX_R13(r13) + EXCEPTION_PROLOG_PSERIES_1(data_access_common, EXC_STD) +FTR_SECTION_ELSE + EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, data_access_common, EXC_STD) +ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_SLB) . = 0x380 .globl data_access_slb_pSeries data_access_slb_pSeries: HMT_MEDIUM + DO_KVM 0x380 SET_SCRATCH0(r13) - EXCEPTION_PROLOG_1(PACA_EXSLB, KVMTEST_PR, 0x380) + GET_PACA(r13) std r3,PACA_EXSLB+EX_R3(r13) mfspr r3,SPRN_DAR + std r9,PACA_EXSLB+EX_R9(r13) /* save r9 - r12 */ + mfcr r9 #ifdef __DISABLED__ /* Keep that around for when we re-implement dynamic VSIDs */ cmpdi r3,0 bge slb_miss_user_pseries #endif /* __DISABLED__ */ - mfspr r12,SPRN_SRR1 + std r10,PACA_EXSLB+EX_R10(r13) + std r11,PACA_EXSLB+EX_R11(r13) + std r12,PACA_EXSLB+EX_R12(r13) + GET_SCRATCH0(r10) + std r10,PACA_EXSLB+EX_R13(r13) + mfspr r12,SPRN_SRR1 /* and SRR1 */ #ifndef CONFIG_RELOCATABLE b .slb_miss_realmode #else @@ -137,16 +147,24 @@ data_access_slb_pSeries: .globl instruction_access_slb_pSeries instruction_access_slb_pSeries: HMT_MEDIUM + DO_KVM 0x480 SET_SCRATCH0(r13) - EXCEPTION_PROLOG_1(PACA_EXSLB, KVMTEST_PR, 0x480) + GET_PACA(r13) std r3,PACA_EXSLB+EX_R3(r13) mfspr r3,SPRN_SRR0 /* SRR0 is faulting address */ + std r9,PACA_EXSLB+EX_R9(r13) /* save r9 - r12 */ + mfcr r9 #ifdef __DISABLED__ /* Keep that around for when we re-implement dynamic VSIDs */ cmpdi r3,0 bge slb_miss_user_pseries #endif /* __DISABLED__ */ - mfspr r12,SPRN_SRR1 + std r10,PACA_EXSLB+EX_R10(r13) + std r11,PACA_EXSLB+EX_R11(r13) + std r12,PACA_EXSLB+EX_R12(r13) + GET_SCRATCH0(r10) + std r10,PACA_EXSLB+EX_R13(r13) + mfspr r12,SPRN_SRR1 /* and SRR1 */ #ifndef CONFIG_RELOCATABLE b .slb_miss_realmode #else @@ -166,46 +184,26 @@ instruction_access_slb_pSeries: hardware_interrupt_pSeries: hardware_interrupt_hv: BEGIN_FTR_SECTION - _MASKABLE_EXCEPTION_PSERIES(0x502, hardware_interrupt, - EXC_HV, SOFTEN_TEST_HV) - KVM_HANDLER(PACA_EXGEN, EXC_HV, 0x502) + _MASKABLE_EXCEPTION_PSERIES(0x500, hardware_interrupt, EXC_STD) FTR_SECTION_ELSE - _MASKABLE_EXCEPTION_PSERIES(0x500, hardware_interrupt, - EXC_STD, SOFTEN_TEST_HV_201) - KVM_HANDLER(PACA_EXGEN, EXC_STD, 0x500) - ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206) + _MASKABLE_EXCEPTION_PSERIES(0x502, hardware_interrupt, EXC_HV) + ALT_FTR_SECTION_END_IFCLR(CPU_FTR_HVMODE_206) STD_EXCEPTION_PSERIES(0x600, 0x600, alignment) - KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0x600) - STD_EXCEPTION_PSERIES(0x700, 0x700, program_check) - KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0x700) - STD_EXCEPTION_PSERIES(0x800, 0x800, fp_unavailable) - KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0x800) MASKABLE_EXCEPTION_PSERIES(0x900, 0x900, decrementer) - MASKABLE_EXCEPTION_HV(0x980, 0x982, decrementer) + MASKABLE_EXCEPTION_HV(0x980, 0x980, decrementer) STD_EXCEPTION_PSERIES(0xa00, 0xa00, trap_0a) - KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xa00) - STD_EXCEPTION_PSERIES(0xb00, 0xb00, trap_0b) - KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xb00) . = 0xc00 .globl system_call_pSeries system_call_pSeries: HMT_MEDIUM -#ifdef CONFIG_KVM_BOOK3S_64_HANDLER - SET_SCRATCH0(r13) - GET_PACA(r13) - std r9,PACA_EXGEN+EX_R9(r13) - std r10,PACA_EXGEN+EX_R10(r13) - mfcr r9 - KVMTEST(0xc00) - GET_SCRATCH0(r13) -#endif + DO_KVM 0xc00 BEGIN_FTR_SECTION cmpdi r0,0x1ebe beq- 1f @@ -222,8 +220,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) rfid b . /* prevent speculative execution */ - KVM_HANDLER(PACA_EXGEN, EXC_STD, 0xc00) - /* Fast LE/BE switch system call */ 1: mfspr r12,SPRN_SRR1 xori r12,r12,MSR_LE @@ -232,7 +228,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) b . STD_EXCEPTION_PSERIES(0xd00, 0xd00, single_step) - KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xd00) /* At 0xe??? we have a bunch of hypervisor exceptions, we branch * out of line to handle them @@ -267,93 +262,30 @@ vsx_unavailable_pSeries_1: #ifdef CONFIG_CBE_RAS STD_EXCEPTION_HV(0x1200, 0x1202, cbe_system_error) - KVM_HANDLER_PR_SKIP(PACA_EXGEN, EXC_HV, 0x1202) #endif /* CONFIG_CBE_RAS */ - STD_EXCEPTION_PSERIES(0x1300, 0x1300, instruction_breakpoint) - KVM_HANDLER_PR_SKIP(PACA_EXGEN, EXC_STD, 0x1300) - #ifdef CONFIG_CBE_RAS STD_EXCEPTION_HV(0x1600, 0x1602, cbe_maintenance) - KVM_HANDLER_PR_SKIP(PACA_EXGEN, EXC_HV, 0x1602) #endif /* CONFIG_CBE_RAS */ - STD_EXCEPTION_PSERIES(0x1700, 0x1700, altivec_assist) - KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0x1700) - #ifdef CONFIG_CBE_RAS STD_EXCEPTION_HV(0x1800, 0x1802, cbe_thermal) - KVM_HANDLER_PR_SKIP(PACA_EXGEN, EXC_HV, 0x1802) #endif /* CONFIG_CBE_RAS */ . = 0x3000 /*** Out of line interrupts support ***/ - /* moved from 0x200 */ -machine_check_pSeries: - .globl machine_check_fwnmi -machine_check_fwnmi: - HMT_MEDIUM - SET_SCRATCH0(r13) /* save r13 */ - EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common, - EXC_STD, KVMTEST, 0x200) - KVM_HANDLER_SKIP(PACA_EXMC, EXC_STD, 0x200) - -#ifndef CONFIG_POWER4_ONLY - /* moved from 0x300 */ -data_access_check_stab: - GET_PACA(r13) - 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 -#ifdef CONFIG_KVM_BOOK3S_PR - lbz r9,HSTATE_IN_GUEST(r13) - rlwimi r10,r9,8,0x300 -#endif - mfcr r9 - cmpwi r10,0x2c - beq do_stab_bolted_pSeries - mtcrf 0x80,r9 - ld r9,PACA_EXSLB+EX_R9(r13) - ld r10,PACA_EXSLB+EX_R10(r13) - b data_access_not_stab -do_stab_bolted_pSeries: - std r11,PACA_EXSLB+EX_R11(r13) - std r12,PACA_EXSLB+EX_R12(r13) - GET_SCRATCH0(r10) - std r10,PACA_EXSLB+EX_R13(r13) - EXCEPTION_PROLOG_PSERIES_1(.do_stab_bolted, EXC_STD) -#endif /* CONFIG_POWER4_ONLY */ - - KVM_HANDLER_PR_SKIP(PACA_EXGEN, EXC_STD, 0x300) - KVM_HANDLER_PR_SKIP(PACA_EXSLB, EXC_STD, 0x380) - KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0x400) - KVM_HANDLER_PR(PACA_EXSLB, EXC_STD, 0x480) - KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0x900) - KVM_HANDLER(PACA_EXGEN, EXC_HV, 0x982) - - .align 7 /* moved from 0xe00 */ - STD_EXCEPTION_HV(., 0xe02, h_data_storage) - KVM_HANDLER_SKIP(PACA_EXGEN, EXC_HV, 0xe02) - STD_EXCEPTION_HV(., 0xe22, h_instr_storage) - KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe22) - STD_EXCEPTION_HV(., 0xe42, emulation_assist) - KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe42) - STD_EXCEPTION_HV(., 0xe62, hmi_exception) /* need to flush cache ? */ - KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe62) + STD_EXCEPTION_HV(., 0xe00, h_data_storage) + STD_EXCEPTION_HV(., 0xe20, h_instr_storage) + STD_EXCEPTION_HV(., 0xe40, emulation_assist) + STD_EXCEPTION_HV(., 0xe60, hmi_exception) /* need to flush cache ? */ /* moved from 0xf00 */ STD_EXCEPTION_PSERIES(., 0xf00, performance_monitor) - KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xf00) STD_EXCEPTION_PSERIES(., 0xf20, altivec_unavailable) - KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xf20) STD_EXCEPTION_PSERIES(., 0xf40, vsx_unavailable) - KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xf40) /* * An interrupt came in while soft-disabled; clear EE in SRR1, @@ -385,6 +317,14 @@ masked_Hinterrupt: hrfid b . + .align 7 +do_stab_bolted_pSeries: + std r11,PACA_EXSLB+EX_R11(r13) + std r12,PACA_EXSLB+EX_R12(r13) + GET_SCRATCH0(r10) + std r10,PACA_EXSLB+EX_R13(r13) + EXCEPTION_PROLOG_PSERIES_1(.do_stab_bolted, EXC_STD) + #ifdef CONFIG_PPC_PSERIES /* * Vectors for the FWNMI option. Share common code. @@ -394,8 +334,14 @@ masked_Hinterrupt: system_reset_fwnmi: HMT_MEDIUM SET_SCRATCH0(r13) /* save r13 */ - EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common, EXC_STD, - NOTEST, 0x100) + EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common, EXC_STD) + + .globl machine_check_fwnmi + .align 7 +machine_check_fwnmi: + HMT_MEDIUM + SET_SCRATCH0(r13) /* save r13 */ + EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common, EXC_STD) #endif /* CONFIG_PPC_PSERIES */ @@ -430,11 +376,7 @@ slb_miss_user_pseries: /* KVM's trampoline code needs to be close to the interrupt handlers */ #ifdef CONFIG_KVM_BOOK3S_64_HANDLER -#ifdef CONFIG_KVM_BOOK3S_PR #include "../kvm/book3s_rmhandlers.S" -#else -#include "../kvm/book3s_hv_rmhandlers.S" -#endif #endif .align 7 diff --git a/trunk/arch/powerpc/kernel/head_fsl_booke.S b/trunk/arch/powerpc/kernel/head_fsl_booke.S index fe37dd0dfd17..5ecf54cfa7d4 100644 --- a/trunk/arch/powerpc/kernel/head_fsl_booke.S +++ b/trunk/arch/powerpc/kernel/head_fsl_booke.S @@ -656,7 +656,7 @@ load_up_spe: cmpi 0,r4,0 beq 1f addi r4,r4,THREAD /* want THREAD of last_task_used_spe */ - SAVE_32EVRS(0,r10,r4,THREAD_EVR0) + SAVE_32EVRS(0,r10,r4) evxor evr10, evr10, evr10 /* clear out evr10 */ evmwumiaa evr10, evr10, evr10 /* evr10 <- ACC = 0 * 0 + ACC */ li r5,THREAD_ACC @@ -676,7 +676,7 @@ load_up_spe: stw r4,THREAD_USED_SPE(r5) evlddx evr4,r10,r5 evmra evr4,evr4 - REST_32EVRS(0,r10,r5,THREAD_EVR0) + REST_32EVRS(0,r10,r5) #ifndef CONFIG_SMP subi r4,r5,THREAD stw r4,last_task_used_spe@l(r3) @@ -787,11 +787,13 @@ _GLOBAL(giveup_spe) addi r3,r3,THREAD /* want THREAD of task */ lwz r5,PT_REGS(r3) cmpi 0,r5,0 - SAVE_32EVRS(0, r4, r3, THREAD_EVR0) + SAVE_32EVRS(0, r4, r3) evxor evr6, evr6, evr6 /* clear out evr6 */ evmwumiaa evr6, evr6, evr6 /* evr6 <- ACC = 0 * 0 + ACC */ li r4,THREAD_ACC evstddx evr6, r4, r3 /* save off accumulator */ + mfspr r6,SPRN_SPEFSCR + stw r6,THREAD_SPEFSCR(r3) /* save spefscr register value */ beq 1f lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5) lis r3,MSR_SPE@h diff --git a/trunk/arch/powerpc/kernel/idle_power7.S b/trunk/arch/powerpc/kernel/idle_power7.S index 3a70845a51c7..f8f0bc7f1d4f 100644 --- a/trunk/arch/powerpc/kernel/idle_power7.S +++ b/trunk/arch/powerpc/kernel/idle_power7.S @@ -73,6 +73,7 @@ _GLOBAL(power7_idle) b . _GLOBAL(power7_wakeup_loss) + GET_PACA(r13) ld r1,PACAR1(r13) REST_NVGPRS(r1) REST_GPR(2, r1) @@ -86,6 +87,7 @@ _GLOBAL(power7_wakeup_loss) rfid _GLOBAL(power7_wakeup_noloss) + GET_PACA(r13) ld r1,PACAR1(r13) ld r4,_MSR(r1) ld r5,_NIP(r1) diff --git a/trunk/arch/powerpc/kernel/module.c b/trunk/arch/powerpc/kernel/module.c index a1cd701b5753..49cee9df225b 100644 --- a/trunk/arch/powerpc/kernel/module.c +++ b/trunk/arch/powerpc/kernel/module.c @@ -31,6 +31,20 @@ LIST_HEAD(module_bug_list); +void *module_alloc(unsigned long size) +{ + if (size == 0) + return NULL; + + return vmalloc_exec(size); +} + +/* Free memory returned from module_alloc */ +void module_free(struct module *mod, void *module_region) +{ + vfree(module_region); +} + static const Elf_Shdr *find_section(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, const char *name) @@ -79,3 +93,7 @@ int module_finalize(const Elf_Ehdr *hdr, return 0; } + +void module_arch_cleanup(struct module *mod) +{ +} diff --git a/trunk/arch/powerpc/kernel/module_32.c b/trunk/arch/powerpc/kernel/module_32.c index 0b6d79617d7b..f832773fc28e 100644 --- a/trunk/arch/powerpc/kernel/module_32.c +++ b/trunk/arch/powerpc/kernel/module_32.c @@ -174,6 +174,17 @@ int module_frob_arch_sections(Elf32_Ehdr *hdr, return 0; } +int apply_relocate(Elf32_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *module) +{ + printk(KERN_ERR "%s: Non-ADD RELOCATION unsupported\n", + module->name); + return -ENOEXEC; +} + static inline int entry_matches(struct ppc_plt_entry *entry, Elf32_Addr val) { if (entry->jump[0] == 0x3d600000 + ((val + 0x8000) >> 16) diff --git a/trunk/arch/powerpc/kernel/module_64.c b/trunk/arch/powerpc/kernel/module_64.c index 9f44a775a106..8fbb12508bf3 100644 --- a/trunk/arch/powerpc/kernel/module_64.c +++ b/trunk/arch/powerpc/kernel/module_64.c @@ -243,6 +243,16 @@ int module_frob_arch_sections(Elf64_Ehdr *hdr, return 0; } +int apply_relocate(Elf64_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *me) +{ + printk(KERN_ERR "%s: Non-ADD RELOCATION unsupported\n", me->name); + return -ENOEXEC; +} + /* r2 is the TOC pointer: it actually points 0x8000 into the TOC (this gives the value maximum span in an instruction which uses a signed offset) */ diff --git a/trunk/arch/powerpc/kernel/mpc7450-pmu.c b/trunk/arch/powerpc/kernel/mpc7450-pmu.c index 845a58478890..2cc5e0301d0b 100644 --- a/trunk/arch/powerpc/kernel/mpc7450-pmu.c +++ b/trunk/arch/powerpc/kernel/mpc7450-pmu.c @@ -388,11 +388,6 @@ static int mpc7450_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = { [C(OP_WRITE)] = { -1, -1 }, [C(OP_PREFETCH)] = { -1, -1 }, }, - [C(NODE)] = { /* RESULT_ACCESS RESULT_MISS */ - [C(OP_READ)] = { -1, -1 }, - [C(OP_WRITE)] = { -1, -1 }, - [C(OP_PREFETCH)] = { -1, -1 }, - }, }; struct power_pmu mpc7450_pmu = { diff --git a/trunk/arch/powerpc/kernel/paca.c b/trunk/arch/powerpc/kernel/paca.c index 0a5a899846bb..efeb88184182 100644 --- a/trunk/arch/powerpc/kernel/paca.c +++ b/trunk/arch/powerpc/kernel/paca.c @@ -167,7 +167,7 @@ void setup_paca(struct paca_struct *new_paca) * if we do a GET_PACA() before the feature fixups have been * applied */ - if (cpu_has_feature(CPU_FTR_HVMODE)) + if (cpu_has_feature(CPU_FTR_HVMODE_206)) mtspr(SPRN_SPRG_HPACA, local_paca); #endif mtspr(SPRN_SPRG_PACA, local_paca); diff --git a/trunk/arch/powerpc/kernel/perf_event.c b/trunk/arch/powerpc/kernel/perf_event.c index 14967de98876..822f63008ae1 100644 --- a/trunk/arch/powerpc/kernel/perf_event.c +++ b/trunk/arch/powerpc/kernel/perf_event.c @@ -1207,7 +1207,7 @@ struct pmu power_pmu = { * here so there is no possibility of being interrupted. */ static void record_and_restart(struct perf_event *event, unsigned long val, - struct pt_regs *regs) + struct pt_regs *regs, int nmi) { u64 period = event->hw.sample_period; s64 prev, delta, left; @@ -1258,7 +1258,7 @@ static void record_and_restart(struct perf_event *event, unsigned long val, if (event->attr.sample_type & PERF_SAMPLE_ADDR) perf_get_data_addr(regs, &data.addr); - if (perf_event_overflow(event, &data, regs)) + if (perf_event_overflow(event, nmi, &data, regs)) power_pmu_stop(event, 0); } } @@ -1346,7 +1346,7 @@ static void perf_event_interrupt(struct pt_regs *regs) if ((int)val < 0) { /* event has overflowed */ found = 1; - record_and_restart(event, val, regs); + record_and_restart(event, val, regs, nmi); } } diff --git a/trunk/arch/powerpc/kernel/perf_event_fsl_emb.c b/trunk/arch/powerpc/kernel/perf_event_fsl_emb.c index 0a6d2a9d569c..b0dc8f7069cd 100644 --- a/trunk/arch/powerpc/kernel/perf_event_fsl_emb.c +++ b/trunk/arch/powerpc/kernel/perf_event_fsl_emb.c @@ -568,7 +568,7 @@ static struct pmu fsl_emb_pmu = { * here so there is no possibility of being interrupted. */ static void record_and_restart(struct perf_event *event, unsigned long val, - struct pt_regs *regs) + struct pt_regs *regs, int nmi) { u64 period = event->hw.sample_period; s64 prev, delta, left; @@ -616,7 +616,7 @@ static void record_and_restart(struct perf_event *event, unsigned long val, perf_sample_data_init(&data, 0); data.period = event->hw.last_period; - if (perf_event_overflow(event, &data, regs)) + if (perf_event_overflow(event, nmi, &data, regs)) fsl_emb_pmu_stop(event, 0); } } @@ -644,7 +644,7 @@ static void perf_event_interrupt(struct pt_regs *regs) if (event) { /* event has overflowed */ found = 1; - record_and_restart(event, val, regs); + record_and_restart(event, val, regs, nmi); } else { /* * Disabled counter is negative, diff --git a/trunk/arch/powerpc/kernel/power4-pmu.c b/trunk/arch/powerpc/kernel/power4-pmu.c index e9dbc2d35c9c..ead8b3c2649e 100644 --- a/trunk/arch/powerpc/kernel/power4-pmu.c +++ b/trunk/arch/powerpc/kernel/power4-pmu.c @@ -587,11 +587,6 @@ static int power4_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = { [C(OP_WRITE)] = { -1, -1 }, [C(OP_PREFETCH)] = { -1, -1 }, }, - [C(NODE)] = { /* RESULT_ACCESS RESULT_MISS */ - [C(OP_READ)] = { -1, -1 }, - [C(OP_WRITE)] = { -1, -1 }, - [C(OP_PREFETCH)] = { -1, -1 }, - }, }; static struct power_pmu power4_pmu = { diff --git a/trunk/arch/powerpc/kernel/power5+-pmu.c b/trunk/arch/powerpc/kernel/power5+-pmu.c index f58a2bd41b59..eca0ac595cb6 100644 --- a/trunk/arch/powerpc/kernel/power5+-pmu.c +++ b/trunk/arch/powerpc/kernel/power5+-pmu.c @@ -653,11 +653,6 @@ static int power5p_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = { [C(OP_WRITE)] = { -1, -1 }, [C(OP_PREFETCH)] = { -1, -1 }, }, - [C(NODE)] = { /* RESULT_ACCESS RESULT_MISS */ - [C(OP_READ)] = { -1, -1 }, - [C(OP_WRITE)] = { -1, -1 }, - [C(OP_PREFETCH)] = { -1, -1 }, - }, }; static struct power_pmu power5p_pmu = { diff --git a/trunk/arch/powerpc/kernel/power5-pmu.c b/trunk/arch/powerpc/kernel/power5-pmu.c index b1acab684142..d5ff0f64a5e6 100644 --- a/trunk/arch/powerpc/kernel/power5-pmu.c +++ b/trunk/arch/powerpc/kernel/power5-pmu.c @@ -595,11 +595,6 @@ static int power5_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = { [C(OP_WRITE)] = { -1, -1 }, [C(OP_PREFETCH)] = { -1, -1 }, }, - [C(NODE)] = { /* RESULT_ACCESS RESULT_MISS */ - [C(OP_READ)] = { -1, -1 }, - [C(OP_WRITE)] = { -1, -1 }, - [C(OP_PREFETCH)] = { -1, -1 }, - }, }; static struct power_pmu power5_pmu = { diff --git a/trunk/arch/powerpc/kernel/power6-pmu.c b/trunk/arch/powerpc/kernel/power6-pmu.c index b24a3a23d073..31603927e376 100644 --- a/trunk/arch/powerpc/kernel/power6-pmu.c +++ b/trunk/arch/powerpc/kernel/power6-pmu.c @@ -516,11 +516,6 @@ static int power6_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = { [C(OP_WRITE)] = { -1, -1 }, [C(OP_PREFETCH)] = { -1, -1 }, }, - [C(NODE)] = { /* RESULT_ACCESS RESULT_MISS */ - [C(OP_READ)] = { -1, -1 }, - [C(OP_WRITE)] = { -1, -1 }, - [C(OP_PREFETCH)] = { -1, -1 }, - }, }; static struct power_pmu power6_pmu = { diff --git a/trunk/arch/powerpc/kernel/power7-pmu.c b/trunk/arch/powerpc/kernel/power7-pmu.c index 6d9dccb2ea59..593740fcb799 100644 --- a/trunk/arch/powerpc/kernel/power7-pmu.c +++ b/trunk/arch/powerpc/kernel/power7-pmu.c @@ -342,11 +342,6 @@ static int power7_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = { [C(OP_WRITE)] = { -1, -1 }, [C(OP_PREFETCH)] = { -1, -1 }, }, - [C(NODE)] = { /* RESULT_ACCESS RESULT_MISS */ - [C(OP_READ)] = { -1, -1 }, - [C(OP_WRITE)] = { -1, -1 }, - [C(OP_PREFETCH)] = { -1, -1 }, - }, }; static struct power_pmu power7_pmu = { diff --git a/trunk/arch/powerpc/kernel/ppc970-pmu.c b/trunk/arch/powerpc/kernel/ppc970-pmu.c index b121de9658eb..9a6e093858fe 100644 --- a/trunk/arch/powerpc/kernel/ppc970-pmu.c +++ b/trunk/arch/powerpc/kernel/ppc970-pmu.c @@ -467,11 +467,6 @@ static int ppc970_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = { [C(OP_WRITE)] = { -1, -1 }, [C(OP_PREFETCH)] = { -1, -1 }, }, - [C(NODE)] = { /* RESULT_ACCESS RESULT_MISS */ - [C(OP_READ)] = { -1, -1 }, - [C(OP_WRITE)] = { -1, -1 }, - [C(OP_PREFETCH)] = { -1, -1 }, - }, }; static struct power_pmu ppc970_pmu = { diff --git a/trunk/arch/powerpc/kernel/process.c b/trunk/arch/powerpc/kernel/process.c index ec2d0edeb134..91e52df3d81d 100644 --- a/trunk/arch/powerpc/kernel/process.c +++ b/trunk/arch/powerpc/kernel/process.c @@ -96,7 +96,6 @@ void flush_fp_to_thread(struct task_struct *tsk) preempt_enable(); } } -EXPORT_SYMBOL_GPL(flush_fp_to_thread); void enable_kernel_fp(void) { @@ -146,7 +145,6 @@ void flush_altivec_to_thread(struct task_struct *tsk) preempt_enable(); } } -EXPORT_SYMBOL_GPL(flush_altivec_to_thread); #endif /* CONFIG_ALTIVEC */ #ifdef CONFIG_VSX @@ -188,7 +186,6 @@ void flush_vsx_to_thread(struct task_struct *tsk) preempt_enable(); } } -EXPORT_SYMBOL_GPL(flush_vsx_to_thread); #endif /* CONFIG_VSX */ #ifdef CONFIG_SPE @@ -216,7 +213,6 @@ void flush_spe_to_thread(struct task_struct *tsk) #ifdef CONFIG_SMP BUG_ON(tsk != current); #endif - tsk->thread.spefscr = mfspr(SPRN_SPEFSCR); giveup_spe(tsk); } preempt_enable(); diff --git a/trunk/arch/powerpc/kernel/ptrace.c b/trunk/arch/powerpc/kernel/ptrace.c index 05b7dd217f60..cb22024f2b42 100644 --- a/trunk/arch/powerpc/kernel/ptrace.c +++ b/trunk/arch/powerpc/kernel/ptrace.c @@ -882,7 +882,7 @@ void user_disable_single_step(struct task_struct *task) } #ifdef CONFIG_HAVE_HW_BREAKPOINT -void ptrace_triggered(struct perf_event *bp, +void ptrace_triggered(struct perf_event *bp, int nmi, struct perf_sample_data *data, struct pt_regs *regs) { struct perf_event_attr attr; @@ -973,7 +973,7 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, &attr.bp_type); thread->ptrace_bps[0] = bp = register_user_hw_breakpoint(&attr, - ptrace_triggered, NULL, task); + ptrace_triggered, task); if (IS_ERR(bp)) { thread->ptrace_bps[0] = NULL; ptrace_put_breakpoints(task); diff --git a/trunk/arch/powerpc/kernel/setup-common.c b/trunk/arch/powerpc/kernel/setup-common.c index 22051ef04bd9..79fca2651b65 100644 --- a/trunk/arch/powerpc/kernel/setup-common.c +++ b/trunk/arch/powerpc/kernel/setup-common.c @@ -375,9 +375,6 @@ void __init check_for_initrd(void) int threads_per_core, threads_shift; cpumask_t threads_core_mask; -EXPORT_SYMBOL_GPL(threads_per_core); -EXPORT_SYMBOL_GPL(threads_shift); -EXPORT_SYMBOL_GPL(threads_core_mask); static void __init cpu_init_thread_core_maps(int tpc) { diff --git a/trunk/arch/powerpc/kernel/setup_64.c b/trunk/arch/powerpc/kernel/setup_64.c index 532054f24ecb..a88bf2713d41 100644 --- a/trunk/arch/powerpc/kernel/setup_64.c +++ b/trunk/arch/powerpc/kernel/setup_64.c @@ -63,7 +63,6 @@ #include #include #include -#include #include "setup.h" @@ -581,8 +580,6 @@ void __init setup_arch(char **cmdline_p) /* Initialize the MMU context management stuff */ mmu_context_init(); - kvm_rma_init(); - ppc64_boot_msg(0x15, "Setup Done"); } diff --git a/trunk/arch/powerpc/kernel/smp.c b/trunk/arch/powerpc/kernel/smp.c index 09a85a9045d6..8ebc6700b98d 100644 --- a/trunk/arch/powerpc/kernel/smp.c +++ b/trunk/arch/powerpc/kernel/smp.c @@ -243,7 +243,6 @@ void smp_send_reschedule(int cpu) if (likely(smp_ops)) smp_ops->message_pass(cpu, PPC_MSG_RESCHEDULE); } -EXPORT_SYMBOL_GPL(smp_send_reschedule); void arch_send_call_function_single_ipi(int cpu) { diff --git a/trunk/arch/powerpc/kernel/time.c b/trunk/arch/powerpc/kernel/time.c index 03b29a6759ab..f33acfd872ad 100644 --- a/trunk/arch/powerpc/kernel/time.c +++ b/trunk/arch/powerpc/kernel/time.c @@ -544,7 +544,7 @@ DEFINE_PER_CPU(u8, irq_work_pending); #endif /* 32 vs 64 bit */ -void arch_irq_work_raise(void) +void set_irq_work_pending(void) { preempt_disable(); set_irq_work_pending_flag(); diff --git a/trunk/arch/powerpc/kernel/traps.c b/trunk/arch/powerpc/kernel/traps.c index f19d9777d3c1..1a0141426cda 100644 --- a/trunk/arch/powerpc/kernel/traps.c +++ b/trunk/arch/powerpc/kernel/traps.c @@ -1387,7 +1387,10 @@ void SPEFloatingPointException(struct pt_regs *regs) int code = 0; int err; - flush_spe_to_thread(current); + preempt_disable(); + if (regs->msr & MSR_SPE) + giveup_spe(current); + preempt_enable(); spefscr = current->thread.spefscr; fpexc_mode = current->thread.fpexc_mode; diff --git a/trunk/arch/powerpc/kvm/44x_tlb.c b/trunk/arch/powerpc/kvm/44x_tlb.c index 33aa715dab28..5f3cff83e089 100644 --- a/trunk/arch/powerpc/kvm/44x_tlb.c +++ b/trunk/arch/powerpc/kvm/44x_tlb.c @@ -387,10 +387,8 @@ static void kvmppc_44x_invalidate(struct kvm_vcpu *vcpu, } } -void kvmppc_mmu_msr_notify(struct kvm_vcpu *vcpu, u32 old_msr) +void kvmppc_mmu_priv_switch(struct kvm_vcpu *vcpu, int usermode) { - int usermode = vcpu->arch.shared->msr & MSR_PR; - vcpu->arch.shadow_pid = !usermode; } diff --git a/trunk/arch/powerpc/kvm/Kconfig b/trunk/arch/powerpc/kvm/Kconfig index 78133deb4b64..b7baff78f90c 100644 --- a/trunk/arch/powerpc/kvm/Kconfig +++ b/trunk/arch/powerpc/kvm/Kconfig @@ -20,6 +20,7 @@ config KVM bool select PREEMPT_NOTIFIERS select ANON_INODES + select KVM_MMIO config KVM_BOOK3S_HANDLER bool @@ -27,22 +28,16 @@ config KVM_BOOK3S_HANDLER config KVM_BOOK3S_32_HANDLER bool select KVM_BOOK3S_HANDLER - select KVM_MMIO config KVM_BOOK3S_64_HANDLER bool select KVM_BOOK3S_HANDLER -config KVM_BOOK3S_PR - bool - select KVM_MMIO - config KVM_BOOK3S_32 tristate "KVM support for PowerPC book3s_32 processors" depends on EXPERIMENTAL && PPC_BOOK3S_32 && !SMP && !PTE_64BIT select KVM select KVM_BOOK3S_32_HANDLER - select KVM_BOOK3S_PR ---help--- Support running unmodified book3s_32 guest kernels in virtual machines on book3s_32 host processors. @@ -55,8 +50,8 @@ config KVM_BOOK3S_32 config KVM_BOOK3S_64 tristate "KVM support for PowerPC book3s_64 processors" depends on EXPERIMENTAL && PPC_BOOK3S_64 - select KVM_BOOK3S_64_HANDLER select KVM + select KVM_BOOK3S_64_HANDLER ---help--- Support running unmodified book3s_64 and book3s_32 guest kernels in virtual machines on book3s_64 host processors. @@ -66,34 +61,10 @@ config KVM_BOOK3S_64 If unsure, say N. -config KVM_BOOK3S_64_HV - bool "KVM support for POWER7 and PPC970 using hypervisor mode in host" - depends on KVM_BOOK3S_64 - ---help--- - Support running unmodified book3s_64 guest kernels in - virtual machines on POWER7 and PPC970 processors that have - hypervisor mode available to the host. - - If you say Y here, KVM will use the hardware virtualization - facilities of POWER7 (and later) processors, meaning that - guest operating systems will run at full hardware speed - using supervisor and user modes. However, this also means - that KVM is not usable under PowerVM (pHyp), is only usable - on POWER7 (or later) processors and PPC970-family processors, - and cannot emulate a different processor from the host processor. - - If unsure, say N. - -config KVM_BOOK3S_64_PR - def_bool y - depends on KVM_BOOK3S_64 && !KVM_BOOK3S_64_HV - select KVM_BOOK3S_PR - config KVM_440 bool "KVM support for PowerPC 440 processors" depends on EXPERIMENTAL && 44x select KVM - select KVM_MMIO ---help--- Support running unmodified 440 guest kernels in virtual machines on 440 host processors. @@ -118,7 +89,6 @@ config KVM_E500 bool "KVM support for PowerPC E500 processors" depends on EXPERIMENTAL && E500 select KVM - select KVM_MMIO ---help--- Support running unmodified E500 guest kernels in virtual machines on E500 host processors. @@ -129,5 +99,6 @@ config KVM_E500 If unsure, say N. source drivers/vhost/Kconfig +source drivers/virtio/Kconfig endif # VIRTUALIZATION diff --git a/trunk/arch/powerpc/kvm/Makefile b/trunk/arch/powerpc/kvm/Makefile index 08428e2c188d..4d6863823f69 100644 --- a/trunk/arch/powerpc/kvm/Makefile +++ b/trunk/arch/powerpc/kvm/Makefile @@ -38,42 +38,24 @@ kvm-e500-objs := \ e500_emulate.o kvm-objs-$(CONFIG_KVM_E500) := $(kvm-e500-objs) -kvm-book3s_64-objs-$(CONFIG_KVM_BOOK3S_64_PR) := \ - ../../../virt/kvm/coalesced_mmio.o \ +kvm-book3s_64-objs := \ + $(common-objs-y) \ fpu.o \ book3s_paired_singles.o \ - book3s_pr.o \ + book3s.o \ book3s_emulate.o \ book3s_interrupts.o \ book3s_mmu_hpte.o \ book3s_64_mmu_host.o \ book3s_64_mmu.o \ book3s_32_mmu.o - -kvm-book3s_64-objs-$(CONFIG_KVM_BOOK3S_64_HV) := \ - book3s_hv.o \ - book3s_hv_interrupts.o \ - book3s_64_mmu_hv.o -kvm-book3s_64-builtin-objs-$(CONFIG_KVM_BOOK3S_64_HV) := \ - book3s_hv_rm_mmu.o \ - book3s_64_vio_hv.o \ - book3s_hv_builtin.o - -kvm-book3s_64-module-objs := \ - ../../../virt/kvm/kvm_main.o \ - powerpc.o \ - emulate.o \ - book3s.o \ - $(kvm-book3s_64-objs-y) - -kvm-objs-$(CONFIG_KVM_BOOK3S_64) := $(kvm-book3s_64-module-objs) +kvm-objs-$(CONFIG_KVM_BOOK3S_64) := $(kvm-book3s_64-objs) kvm-book3s_32-objs := \ $(common-objs-y) \ fpu.o \ book3s_paired_singles.o \ book3s.o \ - book3s_pr.o \ book3s_emulate.o \ book3s_interrupts.o \ book3s_mmu_hpte.o \ @@ -88,4 +70,3 @@ obj-$(CONFIG_KVM_E500) += kvm.o obj-$(CONFIG_KVM_BOOK3S_64) += kvm.o obj-$(CONFIG_KVM_BOOK3S_32) += kvm.o -obj-y += $(kvm-book3s_64-builtin-objs-y) diff --git a/trunk/arch/powerpc/kvm/book3s.c b/trunk/arch/powerpc/kvm/book3s.c index f68a34d16035..0f95b5cce033 100644 --- a/trunk/arch/powerpc/kvm/book3s.c +++ b/trunk/arch/powerpc/kvm/book3s.c @@ -17,6 +17,7 @@ #include #include #include +#include "trace.h" #include #include @@ -27,17 +28,25 @@ #include #include #include -#include #include #include #include #include -#include "trace.h" - #define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU /* #define EXIT_DEBUG */ +/* #define DEBUG_EXT */ + +static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr, + ulong msr); + +/* Some compatibility defines */ +#ifdef CONFIG_PPC_BOOK3S_32 +#define MSR_USER32 MSR_USER +#define MSR_USER64 MSR_USER +#define HW_PAGE_SIZE PAGE_SIZE +#endif struct kvm_stats_debugfs_item debugfs_entries[] = { { "exits", VCPU_STAT(sum_exits) }, @@ -68,11 +77,100 @@ void kvmppc_core_load_guest_debugstate(struct kvm_vcpu *vcpu) { } +void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu) +{ +#ifdef CONFIG_PPC_BOOK3S_64 + memcpy(to_svcpu(vcpu)->slb, to_book3s(vcpu)->slb_shadow, sizeof(to_svcpu(vcpu)->slb)); + memcpy(&get_paca()->shadow_vcpu, to_book3s(vcpu)->shadow_vcpu, + sizeof(get_paca()->shadow_vcpu)); + to_svcpu(vcpu)->slb_max = to_book3s(vcpu)->slb_shadow_max; +#endif + +#ifdef CONFIG_PPC_BOOK3S_32 + current->thread.kvm_shadow_vcpu = to_book3s(vcpu)->shadow_vcpu; +#endif +} + +void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu) +{ +#ifdef CONFIG_PPC_BOOK3S_64 + memcpy(to_book3s(vcpu)->slb_shadow, to_svcpu(vcpu)->slb, sizeof(to_svcpu(vcpu)->slb)); + memcpy(to_book3s(vcpu)->shadow_vcpu, &get_paca()->shadow_vcpu, + sizeof(get_paca()->shadow_vcpu)); + to_book3s(vcpu)->slb_shadow_max = to_svcpu(vcpu)->slb_max; +#endif + + kvmppc_giveup_ext(vcpu, MSR_FP); + kvmppc_giveup_ext(vcpu, MSR_VEC); + kvmppc_giveup_ext(vcpu, MSR_VSX); +} + +static void kvmppc_recalc_shadow_msr(struct kvm_vcpu *vcpu) +{ + ulong smsr = vcpu->arch.shared->msr; + + /* Guest MSR values */ + smsr &= MSR_FE0 | MSR_FE1 | MSR_SF | MSR_SE | MSR_BE | MSR_DE; + /* Process MSR values */ + smsr |= MSR_ME | MSR_RI | MSR_IR | MSR_DR | MSR_PR | MSR_EE; + /* External providers the guest reserved */ + smsr |= (vcpu->arch.shared->msr & vcpu->arch.guest_owned_ext); + /* 64-bit Process MSR values */ +#ifdef CONFIG_PPC_BOOK3S_64 + smsr |= MSR_ISF | MSR_HV; +#endif + vcpu->arch.shadow_msr = smsr; +} + +void kvmppc_set_msr(struct kvm_vcpu *vcpu, u64 msr) +{ + ulong old_msr = vcpu->arch.shared->msr; + +#ifdef EXIT_DEBUG + printk(KERN_INFO "KVM: Set MSR to 0x%llx\n", msr); +#endif + + msr &= to_book3s(vcpu)->msr_mask; + vcpu->arch.shared->msr = msr; + kvmppc_recalc_shadow_msr(vcpu); + + if (msr & MSR_POW) { + if (!vcpu->arch.pending_exceptions) { + kvm_vcpu_block(vcpu); + vcpu->stat.halt_wakeup++; + + /* Unset POW bit after we woke up */ + msr &= ~MSR_POW; + vcpu->arch.shared->msr = msr; + } + } + + if ((vcpu->arch.shared->msr & (MSR_PR|MSR_IR|MSR_DR)) != + (old_msr & (MSR_PR|MSR_IR|MSR_DR))) { + kvmppc_mmu_flush_segments(vcpu); + kvmppc_mmu_map_segment(vcpu, kvmppc_get_pc(vcpu)); + + /* Preload magic page segment when in kernel mode */ + if (!(msr & MSR_PR) && vcpu->arch.magic_page_pa) { + struct kvm_vcpu_arch *a = &vcpu->arch; + + if (msr & MSR_DR) + kvmppc_mmu_map_segment(vcpu, a->magic_page_ea); + else + kvmppc_mmu_map_segment(vcpu, a->magic_page_pa); + } + } + + /* Preload FPU if it's enabled */ + if (vcpu->arch.shared->msr & MSR_FP) + kvmppc_handle_ext(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL, MSR_FP); +} + void kvmppc_inject_interrupt(struct kvm_vcpu *vcpu, int vec, u64 flags) { vcpu->arch.shared->srr0 = kvmppc_get_pc(vcpu); vcpu->arch.shared->srr1 = vcpu->arch.shared->msr | flags; - kvmppc_set_pc(vcpu, kvmppc_interrupt_offset(vcpu) + vec); + kvmppc_set_pc(vcpu, to_book3s(vcpu)->hior + vec); vcpu->arch.mmu.reset_msr(vcpu); } @@ -106,13 +204,11 @@ static int kvmppc_book3s_vec2irqprio(unsigned int vec) static void kvmppc_book3s_dequeue_irqprio(struct kvm_vcpu *vcpu, unsigned int vec) { - unsigned long old_pending = vcpu->arch.pending_exceptions; - clear_bit(kvmppc_book3s_vec2irqprio(vec), &vcpu->arch.pending_exceptions); - kvmppc_update_int_pending(vcpu, vcpu->arch.pending_exceptions, - old_pending); + if (!vcpu->arch.pending_exceptions) + vcpu->arch.shared->int_pending = 0; } void kvmppc_book3s_queue_irqprio(struct kvm_vcpu *vcpu, unsigned int vec) @@ -129,8 +225,8 @@ void kvmppc_book3s_queue_irqprio(struct kvm_vcpu *vcpu, unsigned int vec) void kvmppc_core_queue_program(struct kvm_vcpu *vcpu, ulong flags) { - /* might as well deliver this straight away */ - kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_PROGRAM, flags); + to_book3s(vcpu)->prog_flags = flags; + kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_PROGRAM); } void kvmppc_core_queue_dec(struct kvm_vcpu *vcpu) @@ -170,7 +266,21 @@ int kvmppc_book3s_irqprio_deliver(struct kvm_vcpu *vcpu, unsigned int priority) { int deliver = 1; int vec = 0; - bool crit = kvmppc_critical_section(vcpu); + ulong flags = 0ULL; + ulong crit_raw = vcpu->arch.shared->critical; + ulong crit_r1 = kvmppc_get_gpr(vcpu, 1); + bool crit; + + /* Truncate crit indicators in 32 bit mode */ + if (!(vcpu->arch.shared->msr & MSR_SF)) { + crit_raw &= 0xffffffff; + crit_r1 &= 0xffffffff; + } + + /* Critical section when crit == r1 */ + crit = (crit_raw == crit_r1); + /* ... and we're in supervisor mode */ + crit = crit && !(vcpu->arch.shared->msr & MSR_PR); switch (priority) { case BOOK3S_IRQPRIO_DECREMENTER: @@ -205,6 +315,7 @@ int kvmppc_book3s_irqprio_deliver(struct kvm_vcpu *vcpu, unsigned int priority) break; case BOOK3S_IRQPRIO_PROGRAM: vec = BOOK3S_INTERRUPT_PROGRAM; + flags = to_book3s(vcpu)->prog_flags; break; case BOOK3S_IRQPRIO_VSX: vec = BOOK3S_INTERRUPT_VSX; @@ -235,7 +346,7 @@ int kvmppc_book3s_irqprio_deliver(struct kvm_vcpu *vcpu, unsigned int priority) #endif if (deliver) - kvmppc_inject_interrupt(vcpu, vec, 0); + kvmppc_inject_interrupt(vcpu, vec, flags); return deliver; } @@ -281,7 +392,64 @@ void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu) } /* Tell the guest about our interrupt status */ - kvmppc_update_int_pending(vcpu, *pending, old_pending); + if (*pending) + vcpu->arch.shared->int_pending = 1; + else if (old_pending) + vcpu->arch.shared->int_pending = 0; +} + +void kvmppc_set_pvr(struct kvm_vcpu *vcpu, u32 pvr) +{ + u32 host_pvr; + + vcpu->arch.hflags &= ~BOOK3S_HFLAG_SLB; + vcpu->arch.pvr = pvr; +#ifdef CONFIG_PPC_BOOK3S_64 + if ((pvr >= 0x330000) && (pvr < 0x70330000)) { + kvmppc_mmu_book3s_64_init(vcpu); + to_book3s(vcpu)->hior = 0xfff00000; + to_book3s(vcpu)->msr_mask = 0xffffffffffffffffULL; + } else +#endif + { + kvmppc_mmu_book3s_32_init(vcpu); + to_book3s(vcpu)->hior = 0; + to_book3s(vcpu)->msr_mask = 0xffffffffULL; + } + + /* If we are in hypervisor level on 970, we can tell the CPU to + * treat DCBZ as 32 bytes store */ + vcpu->arch.hflags &= ~BOOK3S_HFLAG_DCBZ32; + if (vcpu->arch.mmu.is_dcbz32(vcpu) && (mfmsr() & MSR_HV) && + !strcmp(cur_cpu_spec->platform, "ppc970")) + vcpu->arch.hflags |= BOOK3S_HFLAG_DCBZ32; + + /* Cell performs badly if MSR_FEx are set. So let's hope nobody + really needs them in a VM on Cell and force disable them. */ + if (!strcmp(cur_cpu_spec->platform, "ppc-cell-be")) + to_book3s(vcpu)->msr_mask &= ~(MSR_FE0 | MSR_FE1); + +#ifdef CONFIG_PPC_BOOK3S_32 + /* 32 bit Book3S always has 32 byte dcbz */ + vcpu->arch.hflags |= BOOK3S_HFLAG_DCBZ32; +#endif + + /* On some CPUs we can execute paired single operations natively */ + asm ( "mfpvr %0" : "=r"(host_pvr)); + switch (host_pvr) { + case 0x00080200: /* lonestar 2.0 */ + case 0x00088202: /* lonestar 2.2 */ + case 0x70000100: /* gekko 1.0 */ + case 0x00080100: /* gekko 2.0 */ + case 0x00083203: /* gekko 2.3a */ + case 0x00083213: /* gekko 2.3b */ + case 0x00083204: /* gekko 2.4 */ + case 0x00083214: /* gekko 2.4e (8SE) - retail HW2 */ + case 0x00087200: /* broadway */ + vcpu->arch.hflags |= BOOK3S_HFLAG_NATIVE_PS; + /* Enable HID2.PSE - in case we need it later */ + mtspr(SPRN_HID2_GEKKO, mfspr(SPRN_HID2_GEKKO) | (1 << 29)); + } } pfn_t kvmppc_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn) @@ -303,6 +471,44 @@ pfn_t kvmppc_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn) return gfn_to_pfn(vcpu->kvm, gfn); } +/* Book3s_32 CPUs always have 32 bytes cache line size, which Linux assumes. To + * make Book3s_32 Linux work on Book3s_64, we have to make sure we trap dcbz to + * emulate 32 bytes dcbz length. + * + * The Book3s_64 inventors also realized this case and implemented a special bit + * in the HID5 register, which is a hypervisor ressource. Thus we can't use it. + * + * My approach here is to patch the dcbz instruction on executing pages. + */ +static void kvmppc_patch_dcbz(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte) +{ + struct page *hpage; + u64 hpage_offset; + u32 *page; + int i; + + hpage = gfn_to_page(vcpu->kvm, pte->raddr >> PAGE_SHIFT); + if (is_error_page(hpage)) { + kvm_release_page_clean(hpage); + return; + } + + hpage_offset = pte->raddr & ~PAGE_MASK; + hpage_offset &= ~0xFFFULL; + hpage_offset /= 4; + + get_page(hpage); + page = kmap_atomic(hpage, KM_USER0); + + /* patch dcbz into reserved instruction, so we trap */ + for (i=hpage_offset; i < hpage_offset + (HW_PAGE_SIZE / 4); i++) + if ((page[i] & 0xff0007ff) == INS_DCBZ) + page[i] &= 0xfffffff7; + + kunmap_atomic(page, KM_USER0); + put_page(hpage); +} + static int kvmppc_xlate(struct kvm_vcpu *vcpu, ulong eaddr, bool data, struct kvmppc_pte *pte) { @@ -400,6 +606,519 @@ int kvmppc_ld(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr, return EMULATE_DO_MMIO; } +static int kvmppc_visible_gfn(struct kvm_vcpu *vcpu, gfn_t gfn) +{ + ulong mp_pa = vcpu->arch.magic_page_pa; + + if (unlikely(mp_pa) && + unlikely((mp_pa & KVM_PAM) >> PAGE_SHIFT == gfn)) { + return 1; + } + + return kvm_is_visible_gfn(vcpu->kvm, gfn); +} + +int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu, + ulong eaddr, int vec) +{ + bool data = (vec == BOOK3S_INTERRUPT_DATA_STORAGE); + int r = RESUME_GUEST; + int relocated; + int page_found = 0; + struct kvmppc_pte pte; + bool is_mmio = false; + bool dr = (vcpu->arch.shared->msr & MSR_DR) ? true : false; + bool ir = (vcpu->arch.shared->msr & MSR_IR) ? true : false; + u64 vsid; + + relocated = data ? dr : ir; + + /* Resolve real address if translation turned on */ + if (relocated) { + page_found = vcpu->arch.mmu.xlate(vcpu, eaddr, &pte, data); + } else { + pte.may_execute = true; + pte.may_read = true; + pte.may_write = true; + pte.raddr = eaddr & KVM_PAM; + pte.eaddr = eaddr; + pte.vpage = eaddr >> 12; + } + + switch (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) { + case 0: + pte.vpage |= ((u64)VSID_REAL << (SID_SHIFT - 12)); + break; + case MSR_DR: + case MSR_IR: + vcpu->arch.mmu.esid_to_vsid(vcpu, eaddr >> SID_SHIFT, &vsid); + + if ((vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) == MSR_DR) + pte.vpage |= ((u64)VSID_REAL_DR << (SID_SHIFT - 12)); + else + pte.vpage |= ((u64)VSID_REAL_IR << (SID_SHIFT - 12)); + pte.vpage |= vsid; + + if (vsid == -1) + page_found = -EINVAL; + break; + } + + if (vcpu->arch.mmu.is_dcbz32(vcpu) && + (!(vcpu->arch.hflags & BOOK3S_HFLAG_DCBZ32))) { + /* + * If we do the dcbz hack, we have to NX on every execution, + * so we can patch the executing code. This renders our guest + * NX-less. + */ + pte.may_execute = !data; + } + + if (page_found == -ENOENT) { + /* Page not found in guest PTE entries */ + vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu); + vcpu->arch.shared->dsisr = to_svcpu(vcpu)->fault_dsisr; + vcpu->arch.shared->msr |= + (to_svcpu(vcpu)->shadow_srr1 & 0x00000000f8000000ULL); + kvmppc_book3s_queue_irqprio(vcpu, vec); + } else if (page_found == -EPERM) { + /* Storage protection */ + vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu); + vcpu->arch.shared->dsisr = + to_svcpu(vcpu)->fault_dsisr & ~DSISR_NOHPTE; + vcpu->arch.shared->dsisr |= DSISR_PROTFAULT; + vcpu->arch.shared->msr |= + (to_svcpu(vcpu)->shadow_srr1 & 0x00000000f8000000ULL); + kvmppc_book3s_queue_irqprio(vcpu, vec); + } else if (page_found == -EINVAL) { + /* Page not found in guest SLB */ + vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu); + kvmppc_book3s_queue_irqprio(vcpu, vec + 0x80); + } else if (!is_mmio && + kvmppc_visible_gfn(vcpu, pte.raddr >> PAGE_SHIFT)) { + /* The guest's PTE is not mapped yet. Map on the host */ + kvmppc_mmu_map_page(vcpu, &pte); + if (data) + vcpu->stat.sp_storage++; + else if (vcpu->arch.mmu.is_dcbz32(vcpu) && + (!(vcpu->arch.hflags & BOOK3S_HFLAG_DCBZ32))) + kvmppc_patch_dcbz(vcpu, &pte); + } else { + /* MMIO */ + vcpu->stat.mmio_exits++; + vcpu->arch.paddr_accessed = pte.raddr; + r = kvmppc_emulate_mmio(run, vcpu); + if ( r == RESUME_HOST_NV ) + r = RESUME_HOST; + } + + return r; +} + +static inline int get_fpr_index(int i) +{ +#ifdef CONFIG_VSX + i *= 2; +#endif + return i; +} + +/* Give up external provider (FPU, Altivec, VSX) */ +void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr) +{ + struct thread_struct *t = ¤t->thread; + u64 *vcpu_fpr = vcpu->arch.fpr; +#ifdef CONFIG_VSX + u64 *vcpu_vsx = vcpu->arch.vsr; +#endif + u64 *thread_fpr = (u64*)t->fpr; + int i; + + if (!(vcpu->arch.guest_owned_ext & msr)) + return; + +#ifdef DEBUG_EXT + printk(KERN_INFO "Giving up ext 0x%lx\n", msr); +#endif + + switch (msr) { + case MSR_FP: + giveup_fpu(current); + for (i = 0; i < ARRAY_SIZE(vcpu->arch.fpr); i++) + vcpu_fpr[i] = thread_fpr[get_fpr_index(i)]; + + vcpu->arch.fpscr = t->fpscr.val; + break; + case MSR_VEC: +#ifdef CONFIG_ALTIVEC + giveup_altivec(current); + memcpy(vcpu->arch.vr, t->vr, sizeof(vcpu->arch.vr)); + vcpu->arch.vscr = t->vscr; +#endif + break; + case MSR_VSX: +#ifdef CONFIG_VSX + __giveup_vsx(current); + for (i = 0; i < ARRAY_SIZE(vcpu->arch.vsr); i++) + vcpu_vsx[i] = thread_fpr[get_fpr_index(i) + 1]; +#endif + break; + default: + BUG(); + } + + vcpu->arch.guest_owned_ext &= ~msr; + current->thread.regs->msr &= ~msr; + kvmppc_recalc_shadow_msr(vcpu); +} + +static int kvmppc_read_inst(struct kvm_vcpu *vcpu) +{ + ulong srr0 = kvmppc_get_pc(vcpu); + u32 last_inst = kvmppc_get_last_inst(vcpu); + int ret; + + ret = kvmppc_ld(vcpu, &srr0, sizeof(u32), &last_inst, false); + if (ret == -ENOENT) { + ulong msr = vcpu->arch.shared->msr; + + msr = kvmppc_set_field(msr, 33, 33, 1); + msr = kvmppc_set_field(msr, 34, 36, 0); + vcpu->arch.shared->msr = kvmppc_set_field(msr, 42, 47, 0); + kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_INST_STORAGE); + return EMULATE_AGAIN; + } + + return EMULATE_DONE; +} + +static int kvmppc_check_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr) +{ + + /* Need to do paired single emulation? */ + if (!(vcpu->arch.hflags & BOOK3S_HFLAG_PAIRED_SINGLE)) + return EMULATE_DONE; + + /* Read out the instruction */ + if (kvmppc_read_inst(vcpu) == EMULATE_DONE) + /* Need to emulate */ + return EMULATE_FAIL; + + return EMULATE_AGAIN; +} + +/* Handle external providers (FPU, Altivec, VSX) */ +static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr, + ulong msr) +{ + struct thread_struct *t = ¤t->thread; + u64 *vcpu_fpr = vcpu->arch.fpr; +#ifdef CONFIG_VSX + u64 *vcpu_vsx = vcpu->arch.vsr; +#endif + u64 *thread_fpr = (u64*)t->fpr; + int i; + + /* When we have paired singles, we emulate in software */ + if (vcpu->arch.hflags & BOOK3S_HFLAG_PAIRED_SINGLE) + return RESUME_GUEST; + + if (!(vcpu->arch.shared->msr & msr)) { + kvmppc_book3s_queue_irqprio(vcpu, exit_nr); + return RESUME_GUEST; + } + + /* We already own the ext */ + if (vcpu->arch.guest_owned_ext & msr) { + return RESUME_GUEST; + } + +#ifdef DEBUG_EXT + printk(KERN_INFO "Loading up ext 0x%lx\n", msr); +#endif + + current->thread.regs->msr |= msr; + + switch (msr) { + case MSR_FP: + for (i = 0; i < ARRAY_SIZE(vcpu->arch.fpr); i++) + thread_fpr[get_fpr_index(i)] = vcpu_fpr[i]; + + t->fpscr.val = vcpu->arch.fpscr; + t->fpexc_mode = 0; + kvmppc_load_up_fpu(); + break; + case MSR_VEC: +#ifdef CONFIG_ALTIVEC + memcpy(t->vr, vcpu->arch.vr, sizeof(vcpu->arch.vr)); + t->vscr = vcpu->arch.vscr; + t->vrsave = -1; + kvmppc_load_up_altivec(); +#endif + break; + case MSR_VSX: +#ifdef CONFIG_VSX + for (i = 0; i < ARRAY_SIZE(vcpu->arch.vsr); i++) + thread_fpr[get_fpr_index(i) + 1] = vcpu_vsx[i]; + kvmppc_load_up_vsx(); +#endif + break; + default: + BUG(); + } + + vcpu->arch.guest_owned_ext |= msr; + + kvmppc_recalc_shadow_msr(vcpu); + + return RESUME_GUEST; +} + +int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, + unsigned int exit_nr) +{ + int r = RESUME_HOST; + + vcpu->stat.sum_exits++; + + run->exit_reason = KVM_EXIT_UNKNOWN; + run->ready_for_interrupt_injection = 1; + + trace_kvm_book3s_exit(exit_nr, vcpu); + kvm_resched(vcpu); + switch (exit_nr) { + case BOOK3S_INTERRUPT_INST_STORAGE: + vcpu->stat.pf_instruc++; + +#ifdef CONFIG_PPC_BOOK3S_32 + /* We set segments as unused segments when invalidating them. So + * treat the respective fault as segment fault. */ + if (to_svcpu(vcpu)->sr[kvmppc_get_pc(vcpu) >> SID_SHIFT] + == SR_INVALID) { + kvmppc_mmu_map_segment(vcpu, kvmppc_get_pc(vcpu)); + r = RESUME_GUEST; + break; + } +#endif + + /* only care about PTEG not found errors, but leave NX alone */ + if (to_svcpu(vcpu)->shadow_srr1 & 0x40000000) { + r = kvmppc_handle_pagefault(run, vcpu, kvmppc_get_pc(vcpu), exit_nr); + vcpu->stat.sp_instruc++; + } else if (vcpu->arch.mmu.is_dcbz32(vcpu) && + (!(vcpu->arch.hflags & BOOK3S_HFLAG_DCBZ32))) { + /* + * XXX If we do the dcbz hack we use the NX bit to flush&patch the page, + * so we can't use the NX bit inside the guest. Let's cross our fingers, + * that no guest that needs the dcbz hack does NX. + */ + kvmppc_mmu_pte_flush(vcpu, kvmppc_get_pc(vcpu), ~0xFFFUL); + r = RESUME_GUEST; + } else { + vcpu->arch.shared->msr |= + to_svcpu(vcpu)->shadow_srr1 & 0x58000000; + kvmppc_book3s_queue_irqprio(vcpu, exit_nr); + r = RESUME_GUEST; + } + break; + case BOOK3S_INTERRUPT_DATA_STORAGE: + { + ulong dar = kvmppc_get_fault_dar(vcpu); + vcpu->stat.pf_storage++; + +#ifdef CONFIG_PPC_BOOK3S_32 + /* We set segments as unused segments when invalidating them. So + * treat the respective fault as segment fault. */ + if ((to_svcpu(vcpu)->sr[dar >> SID_SHIFT]) == SR_INVALID) { + kvmppc_mmu_map_segment(vcpu, dar); + r = RESUME_GUEST; + break; + } +#endif + + /* The only case we need to handle is missing shadow PTEs */ + if (to_svcpu(vcpu)->fault_dsisr & DSISR_NOHPTE) { + r = kvmppc_handle_pagefault(run, vcpu, dar, exit_nr); + } else { + vcpu->arch.shared->dar = dar; + vcpu->arch.shared->dsisr = to_svcpu(vcpu)->fault_dsisr; + kvmppc_book3s_queue_irqprio(vcpu, exit_nr); + r = RESUME_GUEST; + } + break; + } + case BOOK3S_INTERRUPT_DATA_SEGMENT: + if (kvmppc_mmu_map_segment(vcpu, kvmppc_get_fault_dar(vcpu)) < 0) { + vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu); + kvmppc_book3s_queue_irqprio(vcpu, + BOOK3S_INTERRUPT_DATA_SEGMENT); + } + r = RESUME_GUEST; + break; + case BOOK3S_INTERRUPT_INST_SEGMENT: + if (kvmppc_mmu_map_segment(vcpu, kvmppc_get_pc(vcpu)) < 0) { + kvmppc_book3s_queue_irqprio(vcpu, + BOOK3S_INTERRUPT_INST_SEGMENT); + } + r = RESUME_GUEST; + break; + /* We're good on these - the host merely wanted to get our attention */ + case BOOK3S_INTERRUPT_DECREMENTER: + vcpu->stat.dec_exits++; + r = RESUME_GUEST; + break; + case BOOK3S_INTERRUPT_EXTERNAL: + vcpu->stat.ext_intr_exits++; + r = RESUME_GUEST; + break; + case BOOK3S_INTERRUPT_PERFMON: + r = RESUME_GUEST; + break; + case BOOK3S_INTERRUPT_PROGRAM: + { + enum emulation_result er; + ulong flags; + +program_interrupt: + flags = to_svcpu(vcpu)->shadow_srr1 & 0x1f0000ull; + + if (vcpu->arch.shared->msr & MSR_PR) { +#ifdef EXIT_DEBUG + printk(KERN_INFO "Userspace triggered 0x700 exception at 0x%lx (0x%x)\n", kvmppc_get_pc(vcpu), kvmppc_get_last_inst(vcpu)); +#endif + if ((kvmppc_get_last_inst(vcpu) & 0xff0007ff) != + (INS_DCBZ & 0xfffffff7)) { + kvmppc_core_queue_program(vcpu, flags); + r = RESUME_GUEST; + break; + } + } + + vcpu->stat.emulated_inst_exits++; + er = kvmppc_emulate_instruction(run, vcpu); + switch (er) { + case EMULATE_DONE: + r = RESUME_GUEST_NV; + break; + case EMULATE_AGAIN: + r = RESUME_GUEST; + break; + case EMULATE_FAIL: + printk(KERN_CRIT "%s: emulation at %lx failed (%08x)\n", + __func__, kvmppc_get_pc(vcpu), kvmppc_get_last_inst(vcpu)); + kvmppc_core_queue_program(vcpu, flags); + r = RESUME_GUEST; + break; + case EMULATE_DO_MMIO: + run->exit_reason = KVM_EXIT_MMIO; + r = RESUME_HOST_NV; + break; + default: + BUG(); + } + break; + } + case BOOK3S_INTERRUPT_SYSCALL: + if (vcpu->arch.osi_enabled && + (((u32)kvmppc_get_gpr(vcpu, 3)) == OSI_SC_MAGIC_R3) && + (((u32)kvmppc_get_gpr(vcpu, 4)) == OSI_SC_MAGIC_R4)) { + /* MOL hypercalls */ + u64 *gprs = run->osi.gprs; + int i; + + run->exit_reason = KVM_EXIT_OSI; + for (i = 0; i < 32; i++) + gprs[i] = kvmppc_get_gpr(vcpu, i); + vcpu->arch.osi_needed = 1; + r = RESUME_HOST_NV; + } else if (!(vcpu->arch.shared->msr & MSR_PR) && + (((u32)kvmppc_get_gpr(vcpu, 0)) == KVM_SC_MAGIC_R0)) { + /* KVM PV hypercalls */ + kvmppc_set_gpr(vcpu, 3, kvmppc_kvm_pv(vcpu)); + r = RESUME_GUEST; + } else { + /* Guest syscalls */ + vcpu->stat.syscall_exits++; + kvmppc_book3s_queue_irqprio(vcpu, exit_nr); + r = RESUME_GUEST; + } + break; + case BOOK3S_INTERRUPT_FP_UNAVAIL: + case BOOK3S_INTERRUPT_ALTIVEC: + case BOOK3S_INTERRUPT_VSX: + { + int ext_msr = 0; + + switch (exit_nr) { + case BOOK3S_INTERRUPT_FP_UNAVAIL: ext_msr = MSR_FP; break; + case BOOK3S_INTERRUPT_ALTIVEC: ext_msr = MSR_VEC; break; + case BOOK3S_INTERRUPT_VSX: ext_msr = MSR_VSX; break; + } + + switch (kvmppc_check_ext(vcpu, exit_nr)) { + case EMULATE_DONE: + /* everything ok - let's enable the ext */ + r = kvmppc_handle_ext(vcpu, exit_nr, ext_msr); + break; + case EMULATE_FAIL: + /* we need to emulate this instruction */ + goto program_interrupt; + break; + default: + /* nothing to worry about - go again */ + break; + } + break; + } + case BOOK3S_INTERRUPT_ALIGNMENT: + if (kvmppc_read_inst(vcpu) == EMULATE_DONE) { + vcpu->arch.shared->dsisr = kvmppc_alignment_dsisr(vcpu, + kvmppc_get_last_inst(vcpu)); + vcpu->arch.shared->dar = kvmppc_alignment_dar(vcpu, + kvmppc_get_last_inst(vcpu)); + kvmppc_book3s_queue_irqprio(vcpu, exit_nr); + } + r = RESUME_GUEST; + break; + case BOOK3S_INTERRUPT_MACHINE_CHECK: + case BOOK3S_INTERRUPT_TRACE: + kvmppc_book3s_queue_irqprio(vcpu, exit_nr); + r = RESUME_GUEST; + break; + default: + /* Ugh - bork here! What did we get? */ + printk(KERN_EMERG "exit_nr=0x%x | pc=0x%lx | msr=0x%lx\n", + exit_nr, kvmppc_get_pc(vcpu), to_svcpu(vcpu)->shadow_srr1); + r = RESUME_HOST; + BUG(); + break; + } + + + if (!(r & RESUME_HOST)) { + /* To avoid clobbering exit_reason, only check for signals if + * we aren't already exiting to userspace for some other + * reason. */ + if (signal_pending(current)) { +#ifdef EXIT_DEBUG + printk(KERN_EMERG "KVM: Going back to host\n"); +#endif + vcpu->stat.signal_exits++; + run->exit_reason = KVM_EXIT_INTR; + r = -EINTR; + } else { + /* In case an interrupt came in that was triggered + * from userspace (like DEC), we need to check what + * to inject now! */ + kvmppc_core_deliver_interrupts(vcpu); + } + } + + trace_kvm_book3s_reenter(r, vcpu); + + return r; +} + int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) { return 0; @@ -460,6 +1179,69 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) return 0; } +int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, + struct kvm_sregs *sregs) +{ + struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu); + int i; + + sregs->pvr = vcpu->arch.pvr; + + sregs->u.s.sdr1 = to_book3s(vcpu)->sdr1; + if (vcpu->arch.hflags & BOOK3S_HFLAG_SLB) { + for (i = 0; i < 64; i++) { + sregs->u.s.ppc64.slb[i].slbe = vcpu3s->slb[i].orige | i; + sregs->u.s.ppc64.slb[i].slbv = vcpu3s->slb[i].origv; + } + } else { + for (i = 0; i < 16; i++) + sregs->u.s.ppc32.sr[i] = vcpu->arch.shared->sr[i]; + + for (i = 0; i < 8; i++) { + sregs->u.s.ppc32.ibat[i] = vcpu3s->ibat[i].raw; + sregs->u.s.ppc32.dbat[i] = vcpu3s->dbat[i].raw; + } + } + + return 0; +} + +int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, + struct kvm_sregs *sregs) +{ + struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu); + int i; + + kvmppc_set_pvr(vcpu, sregs->pvr); + + vcpu3s->sdr1 = sregs->u.s.sdr1; + if (vcpu->arch.hflags & BOOK3S_HFLAG_SLB) { + for (i = 0; i < 64; i++) { + vcpu->arch.mmu.slbmte(vcpu, sregs->u.s.ppc64.slb[i].slbv, + sregs->u.s.ppc64.slb[i].slbe); + } + } else { + for (i = 0; i < 16; i++) { + vcpu->arch.mmu.mtsrin(vcpu, i, sregs->u.s.ppc32.sr[i]); + } + for (i = 0; i < 8; i++) { + kvmppc_set_bat(vcpu, &(vcpu3s->ibat[i]), false, + (u32)sregs->u.s.ppc32.ibat[i]); + kvmppc_set_bat(vcpu, &(vcpu3s->ibat[i]), true, + (u32)(sregs->u.s.ppc32.ibat[i] >> 32)); + kvmppc_set_bat(vcpu, &(vcpu3s->dbat[i]), false, + (u32)sregs->u.s.ppc32.dbat[i]); + kvmppc_set_bat(vcpu, &(vcpu3s->dbat[i]), true, + (u32)(sregs->u.s.ppc32.dbat[i] >> 32)); + } + } + + /* Flush the MMU after messing with the segments */ + kvmppc_mmu_pte_flush(vcpu, 0, 0); + + return 0; +} + int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) { return -ENOTSUPP; @@ -514,3 +1296,202 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, mutex_unlock(&kvm->slots_lock); return r; } + +int kvmppc_core_check_processor_compat(void) +{ + return 0; +} + +struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id) +{ + struct kvmppc_vcpu_book3s *vcpu_book3s; + struct kvm_vcpu *vcpu; + int err = -ENOMEM; + unsigned long p; + + vcpu_book3s = vzalloc(sizeof(struct kvmppc_vcpu_book3s)); + if (!vcpu_book3s) + goto out; + + vcpu_book3s->shadow_vcpu = (struct kvmppc_book3s_shadow_vcpu *) + kzalloc(sizeof(*vcpu_book3s->shadow_vcpu), GFP_KERNEL); + if (!vcpu_book3s->shadow_vcpu) + goto free_vcpu; + + vcpu = &vcpu_book3s->vcpu; + err = kvm_vcpu_init(vcpu, kvm, id); + if (err) + goto free_shadow_vcpu; + + p = __get_free_page(GFP_KERNEL|__GFP_ZERO); + /* the real shared page fills the last 4k of our page */ + vcpu->arch.shared = (void*)(p + PAGE_SIZE - 4096); + if (!p) + goto uninit_vcpu; + + vcpu->arch.host_retip = kvm_return_point; + vcpu->arch.host_msr = mfmsr(); +#ifdef CONFIG_PPC_BOOK3S_64 + /* default to book3s_64 (970fx) */ + vcpu->arch.pvr = 0x3C0301; +#else + /* default to book3s_32 (750) */ + vcpu->arch.pvr = 0x84202; +#endif + kvmppc_set_pvr(vcpu, vcpu->arch.pvr); + vcpu_book3s->slb_nr = 64; + + /* remember where some real-mode handlers are */ + vcpu->arch.trampoline_lowmem = kvmppc_trampoline_lowmem; + vcpu->arch.trampoline_enter = kvmppc_trampoline_enter; + vcpu->arch.highmem_handler = (ulong)kvmppc_handler_highmem; +#ifdef CONFIG_PPC_BOOK3S_64 + vcpu->arch.rmcall = *(ulong*)kvmppc_rmcall; +#else + vcpu->arch.rmcall = (ulong)kvmppc_rmcall; +#endif + + vcpu->arch.shadow_msr = MSR_USER64; + + err = kvmppc_mmu_init(vcpu); + if (err < 0) + goto uninit_vcpu; + + return vcpu; + +uninit_vcpu: + kvm_vcpu_uninit(vcpu); +free_shadow_vcpu: + kfree(vcpu_book3s->shadow_vcpu); +free_vcpu: + vfree(vcpu_book3s); +out: + return ERR_PTR(err); +} + +void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu) +{ + struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); + + free_page((unsigned long)vcpu->arch.shared & PAGE_MASK); + kvm_vcpu_uninit(vcpu); + kfree(vcpu_book3s->shadow_vcpu); + vfree(vcpu_book3s); +} + +extern int __kvmppc_vcpu_entry(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu); +int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) +{ + int ret; + double fpr[32][TS_FPRWIDTH]; + unsigned int fpscr; + int fpexc_mode; +#ifdef CONFIG_ALTIVEC + vector128 vr[32]; + vector128 vscr; + unsigned long uninitialized_var(vrsave); + int used_vr; +#endif +#ifdef CONFIG_VSX + int used_vsr; +#endif + ulong ext_msr; + + /* No need to go into the guest when all we do is going out */ + if (signal_pending(current)) { + kvm_run->exit_reason = KVM_EXIT_INTR; + return -EINTR; + } + + /* Save FPU state in stack */ + if (current->thread.regs->msr & MSR_FP) + giveup_fpu(current); + memcpy(fpr, current->thread.fpr, sizeof(current->thread.fpr)); + fpscr = current->thread.fpscr.val; + fpexc_mode = current->thread.fpexc_mode; + +#ifdef CONFIG_ALTIVEC + /* Save Altivec state in stack */ + used_vr = current->thread.used_vr; + if (used_vr) { + if (current->thread.regs->msr & MSR_VEC) + giveup_altivec(current); + memcpy(vr, current->thread.vr, sizeof(current->thread.vr)); + vscr = current->thread.vscr; + vrsave = current->thread.vrsave; + } +#endif + +#ifdef CONFIG_VSX + /* Save VSX state in stack */ + used_vsr = current->thread.used_vsr; + if (used_vsr && (current->thread.regs->msr & MSR_VSX)) + __giveup_vsx(current); +#endif + + /* Remember the MSR with disabled extensions */ + ext_msr = current->thread.regs->msr; + + /* XXX we get called with irq disabled - change that! */ + local_irq_enable(); + + /* Preload FPU if it's enabled */ + if (vcpu->arch.shared->msr & MSR_FP) + kvmppc_handle_ext(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL, MSR_FP); + + ret = __kvmppc_vcpu_entry(kvm_run, vcpu); + + local_irq_disable(); + + current->thread.regs->msr = ext_msr; + + /* Make sure we save the guest FPU/Altivec/VSX state */ + kvmppc_giveup_ext(vcpu, MSR_FP); + kvmppc_giveup_ext(vcpu, MSR_VEC); + kvmppc_giveup_ext(vcpu, MSR_VSX); + + /* Restore FPU state from stack */ + memcpy(current->thread.fpr, fpr, sizeof(current->thread.fpr)); + current->thread.fpscr.val = fpscr; + current->thread.fpexc_mode = fpexc_mode; + +#ifdef CONFIG_ALTIVEC + /* Restore Altivec state from stack */ + if (used_vr && current->thread.used_vr) { + memcpy(current->thread.vr, vr, sizeof(current->thread.vr)); + current->thread.vscr = vscr; + current->thread.vrsave = vrsave; + } + current->thread.used_vr = used_vr; +#endif + +#ifdef CONFIG_VSX + current->thread.used_vsr = used_vsr; +#endif + + return ret; +} + +static int kvmppc_book3s_init(void) +{ + int r; + + r = kvm_init(NULL, sizeof(struct kvmppc_vcpu_book3s), 0, + THIS_MODULE); + + if (r) + return r; + + r = kvmppc_mmu_hpte_sysinit(); + + return r; +} + +static void kvmppc_book3s_exit(void) +{ + kvmppc_mmu_hpte_sysexit(); + kvm_exit(); +} + +module_init(kvmppc_book3s_init); +module_exit(kvmppc_book3s_exit); diff --git a/trunk/arch/powerpc/kvm/book3s_64_mmu.c b/trunk/arch/powerpc/kvm/book3s_64_mmu.c index c6d3e194b6b4..d7889ef3211e 100644 --- a/trunk/arch/powerpc/kvm/book3s_64_mmu.c +++ b/trunk/arch/powerpc/kvm/book3s_64_mmu.c @@ -41,36 +41,36 @@ static void kvmppc_mmu_book3s_64_reset_msr(struct kvm_vcpu *vcpu) } static struct kvmppc_slb *kvmppc_mmu_book3s_64_find_slbe( - struct kvm_vcpu *vcpu, + struct kvmppc_vcpu_book3s *vcpu_book3s, gva_t eaddr) { int i; u64 esid = GET_ESID(eaddr); u64 esid_1t = GET_ESID_1T(eaddr); - for (i = 0; i < vcpu->arch.slb_nr; i++) { + for (i = 0; i < vcpu_book3s->slb_nr; i++) { u64 cmp_esid = esid; - if (!vcpu->arch.slb[i].valid) + if (!vcpu_book3s->slb[i].valid) continue; - if (vcpu->arch.slb[i].tb) + if (vcpu_book3s->slb[i].tb) cmp_esid = esid_1t; - if (vcpu->arch.slb[i].esid == cmp_esid) - return &vcpu->arch.slb[i]; + if (vcpu_book3s->slb[i].esid == cmp_esid) + return &vcpu_book3s->slb[i]; } dprintk("KVM: No SLB entry found for 0x%lx [%llx | %llx]\n", eaddr, esid, esid_1t); - for (i = 0; i < vcpu->arch.slb_nr; i++) { - if (vcpu->arch.slb[i].vsid) + for (i = 0; i < vcpu_book3s->slb_nr; i++) { + if (vcpu_book3s->slb[i].vsid) dprintk(" %d: %c%c%c %llx %llx\n", i, - vcpu->arch.slb[i].valid ? 'v' : ' ', - vcpu->arch.slb[i].large ? 'l' : ' ', - vcpu->arch.slb[i].tb ? 't' : ' ', - vcpu->arch.slb[i].esid, - vcpu->arch.slb[i].vsid); + vcpu_book3s->slb[i].valid ? 'v' : ' ', + vcpu_book3s->slb[i].large ? 'l' : ' ', + vcpu_book3s->slb[i].tb ? 't' : ' ', + vcpu_book3s->slb[i].esid, + vcpu_book3s->slb[i].vsid); } return NULL; @@ -81,7 +81,7 @@ static u64 kvmppc_mmu_book3s_64_ea_to_vp(struct kvm_vcpu *vcpu, gva_t eaddr, { struct kvmppc_slb *slb; - slb = kvmppc_mmu_book3s_64_find_slbe(vcpu, eaddr); + slb = kvmppc_mmu_book3s_64_find_slbe(to_book3s(vcpu), eaddr); if (!slb) return 0; @@ -180,7 +180,7 @@ static int kvmppc_mmu_book3s_64_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, return 0; } - slbe = kvmppc_mmu_book3s_64_find_slbe(vcpu, eaddr); + slbe = kvmppc_mmu_book3s_64_find_slbe(vcpu_book3s, eaddr); if (!slbe) goto no_seg_found; @@ -320,10 +320,10 @@ static void kvmppc_mmu_book3s_64_slbmte(struct kvm_vcpu *vcpu, u64 rs, u64 rb) esid_1t = GET_ESID_1T(rb); slb_nr = rb & 0xfff; - if (slb_nr > vcpu->arch.slb_nr) + if (slb_nr > vcpu_book3s->slb_nr) return; - slbe = &vcpu->arch.slb[slb_nr]; + slbe = &vcpu_book3s->slb[slb_nr]; slbe->large = (rs & SLB_VSID_L) ? 1 : 0; slbe->tb = (rs & SLB_VSID_B_1T) ? 1 : 0; @@ -344,35 +344,38 @@ static void kvmppc_mmu_book3s_64_slbmte(struct kvm_vcpu *vcpu, u64 rs, u64 rb) static u64 kvmppc_mmu_book3s_64_slbmfee(struct kvm_vcpu *vcpu, u64 slb_nr) { + struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); struct kvmppc_slb *slbe; - if (slb_nr > vcpu->arch.slb_nr) + if (slb_nr > vcpu_book3s->slb_nr) return 0; - slbe = &vcpu->arch.slb[slb_nr]; + slbe = &vcpu_book3s->slb[slb_nr]; return slbe->orige; } static u64 kvmppc_mmu_book3s_64_slbmfev(struct kvm_vcpu *vcpu, u64 slb_nr) { + struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); struct kvmppc_slb *slbe; - if (slb_nr > vcpu->arch.slb_nr) + if (slb_nr > vcpu_book3s->slb_nr) return 0; - slbe = &vcpu->arch.slb[slb_nr]; + slbe = &vcpu_book3s->slb[slb_nr]; return slbe->origv; } static void kvmppc_mmu_book3s_64_slbie(struct kvm_vcpu *vcpu, u64 ea) { + struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); struct kvmppc_slb *slbe; dprintk("KVM MMU: slbie(0x%llx)\n", ea); - slbe = kvmppc_mmu_book3s_64_find_slbe(vcpu, ea); + slbe = kvmppc_mmu_book3s_64_find_slbe(vcpu_book3s, ea); if (!slbe) return; @@ -386,12 +389,13 @@ static void kvmppc_mmu_book3s_64_slbie(struct kvm_vcpu *vcpu, u64 ea) static void kvmppc_mmu_book3s_64_slbia(struct kvm_vcpu *vcpu) { + struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); int i; dprintk("KVM MMU: slbia()\n"); - for (i = 1; i < vcpu->arch.slb_nr; i++) - vcpu->arch.slb[i].valid = false; + for (i = 1; i < vcpu_book3s->slb_nr; i++) + vcpu_book3s->slb[i].valid = false; if (vcpu->arch.shared->msr & MSR_IR) { kvmppc_mmu_flush_segments(vcpu); @@ -460,7 +464,7 @@ static int kvmppc_mmu_book3s_64_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid, ulong mp_ea = vcpu->arch.magic_page_ea; if (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) { - slb = kvmppc_mmu_book3s_64_find_slbe(vcpu, ea); + slb = kvmppc_mmu_book3s_64_find_slbe(to_book3s(vcpu), ea); if (slb) gvsid = slb->vsid; } diff --git a/trunk/arch/powerpc/kvm/book3s_64_mmu_hv.c b/trunk/arch/powerpc/kvm/book3s_64_mmu_hv.c deleted file mode 100644 index bc3a2ea94217..000000000000 --- a/trunk/arch/powerpc/kvm/book3s_64_mmu_hv.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - * 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. - * - * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright 2010 Paul Mackerras, IBM Corp. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -/* For now use fixed-size 16MB page table */ -#define HPT_ORDER 24 -#define HPT_NPTEG (1ul << (HPT_ORDER - 7)) /* 128B per pteg */ -#define HPT_HASH_MASK (HPT_NPTEG - 1) - -/* Pages in the VRMA are 16MB pages */ -#define VRMA_PAGE_ORDER 24 -#define VRMA_VSID 0x1ffffffUL /* 1TB VSID reserved for VRMA */ - -/* POWER7 has 10-bit LPIDs, PPC970 has 6-bit LPIDs */ -#define MAX_LPID_970 63 -#define NR_LPIDS (LPID_RSVD + 1) -unsigned long lpid_inuse[BITS_TO_LONGS(NR_LPIDS)]; - -long kvmppc_alloc_hpt(struct kvm *kvm) -{ - unsigned long hpt; - unsigned long lpid; - - hpt = __get_free_pages(GFP_KERNEL|__GFP_ZERO|__GFP_REPEAT|__GFP_NOWARN, - HPT_ORDER - PAGE_SHIFT); - if (!hpt) { - pr_err("kvm_alloc_hpt: Couldn't alloc HPT\n"); - return -ENOMEM; - } - kvm->arch.hpt_virt = hpt; - - do { - lpid = find_first_zero_bit(lpid_inuse, NR_LPIDS); - if (lpid >= NR_LPIDS) { - pr_err("kvm_alloc_hpt: No LPIDs free\n"); - free_pages(hpt, HPT_ORDER - PAGE_SHIFT); - return -ENOMEM; - } - } while (test_and_set_bit(lpid, lpid_inuse)); - - kvm->arch.sdr1 = __pa(hpt) | (HPT_ORDER - 18); - kvm->arch.lpid = lpid; - - pr_info("KVM guest htab at %lx, LPID %lx\n", hpt, lpid); - return 0; -} - -void kvmppc_free_hpt(struct kvm *kvm) -{ - clear_bit(kvm->arch.lpid, lpid_inuse); - free_pages(kvm->arch.hpt_virt, HPT_ORDER - PAGE_SHIFT); -} - -void kvmppc_map_vrma(struct kvm *kvm, struct kvm_userspace_memory_region *mem) -{ - unsigned long i; - unsigned long npages = kvm->arch.ram_npages; - unsigned long pfn; - unsigned long *hpte; - unsigned long hash; - struct kvmppc_pginfo *pginfo = kvm->arch.ram_pginfo; - - if (!pginfo) - return; - - /* VRMA can't be > 1TB */ - if (npages > 1ul << (40 - kvm->arch.ram_porder)) - npages = 1ul << (40 - kvm->arch.ram_porder); - /* Can't use more than 1 HPTE per HPTEG */ - if (npages > HPT_NPTEG) - npages = HPT_NPTEG; - - for (i = 0; i < npages; ++i) { - pfn = pginfo[i].pfn; - if (!pfn) - break; - /* can't use hpt_hash since va > 64 bits */ - hash = (i ^ (VRMA_VSID ^ (VRMA_VSID << 25))) & HPT_HASH_MASK; - /* - * We assume that the hash table is empty and no - * vcpus are using it at this stage. Since we create - * at most one HPTE per HPTEG, we just assume entry 7 - * is available and use it. - */ - hpte = (unsigned long *) (kvm->arch.hpt_virt + (hash << 7)); - hpte += 7 * 2; - /* HPTE low word - RPN, protection, etc. */ - hpte[1] = (pfn << PAGE_SHIFT) | HPTE_R_R | HPTE_R_C | - HPTE_R_M | PP_RWXX; - wmb(); - hpte[0] = HPTE_V_1TB_SEG | (VRMA_VSID << (40 - 16)) | - (i << (VRMA_PAGE_ORDER - 16)) | HPTE_V_BOLTED | - HPTE_V_LARGE | HPTE_V_VALID; - } -} - -int kvmppc_mmu_hv_init(void) -{ - unsigned long host_lpid, rsvd_lpid; - - if (!cpu_has_feature(CPU_FTR_HVMODE)) - return -EINVAL; - - memset(lpid_inuse, 0, sizeof(lpid_inuse)); - - if (cpu_has_feature(CPU_FTR_ARCH_206)) { - host_lpid = mfspr(SPRN_LPID); /* POWER7 */ - rsvd_lpid = LPID_RSVD; - } else { - host_lpid = 0; /* PPC970 */ - rsvd_lpid = MAX_LPID_970; - } - - set_bit(host_lpid, lpid_inuse); - /* rsvd_lpid is reserved for use in partition switching */ - set_bit(rsvd_lpid, lpid_inuse); - - return 0; -} - -void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu) -{ -} - -static void kvmppc_mmu_book3s_64_hv_reset_msr(struct kvm_vcpu *vcpu) -{ - kvmppc_set_msr(vcpu, MSR_SF | MSR_ME); -} - -static int kvmppc_mmu_book3s_64_hv_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, - struct kvmppc_pte *gpte, bool data) -{ - return -ENOENT; -} - -void kvmppc_mmu_book3s_hv_init(struct kvm_vcpu *vcpu) -{ - struct kvmppc_mmu *mmu = &vcpu->arch.mmu; - - if (cpu_has_feature(CPU_FTR_ARCH_206)) - vcpu->arch.slb_nr = 32; /* POWER7 */ - else - vcpu->arch.slb_nr = 64; - - mmu->xlate = kvmppc_mmu_book3s_64_hv_xlate; - mmu->reset_msr = kvmppc_mmu_book3s_64_hv_reset_msr; - - vcpu->arch.hflags |= BOOK3S_HFLAG_SLB; -} diff --git a/trunk/arch/powerpc/kvm/book3s_64_vio_hv.c b/trunk/arch/powerpc/kvm/book3s_64_vio_hv.c deleted file mode 100644 index ea0f8c537c28..000000000000 --- a/trunk/arch/powerpc/kvm/book3s_64_vio_hv.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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. - * - * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright 2010 Paul Mackerras, IBM Corp. - * Copyright 2011 David Gibson, IBM Corporation - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define TCES_PER_PAGE (PAGE_SIZE / sizeof(u64)) - -long kvmppc_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn, - unsigned long ioba, unsigned long tce) -{ - struct kvm *kvm = vcpu->kvm; - struct kvmppc_spapr_tce_table *stt; - - /* udbg_printf("H_PUT_TCE(): liobn=0x%lx ioba=0x%lx, tce=0x%lx\n", */ - /* liobn, ioba, tce); */ - - list_for_each_entry(stt, &kvm->arch.spapr_tce_tables, list) { - if (stt->liobn == liobn) { - unsigned long idx = ioba >> SPAPR_TCE_SHIFT; - struct page *page; - u64 *tbl; - - /* udbg_printf("H_PUT_TCE: liobn 0x%lx => stt=%p window_size=0x%x\n", */ - /* liobn, stt, stt->window_size); */ - if (ioba >= stt->window_size) - return H_PARAMETER; - - page = stt->pages[idx / TCES_PER_PAGE]; - tbl = (u64 *)page_address(page); - - /* FIXME: Need to validate the TCE itself */ - /* udbg_printf("tce @ %p\n", &tbl[idx % TCES_PER_PAGE]); */ - tbl[idx % TCES_PER_PAGE] = tce; - return H_SUCCESS; - } - } - - /* Didn't find the liobn, punt it to userspace */ - return H_TOO_HARD; -} diff --git a/trunk/arch/powerpc/kvm/book3s_exports.c b/trunk/arch/powerpc/kvm/book3s_exports.c index 88c8f26add02..1dd5a1ddfd0d 100644 --- a/trunk/arch/powerpc/kvm/book3s_exports.c +++ b/trunk/arch/powerpc/kvm/book3s_exports.c @@ -20,11 +20,8 @@ #include #include -#ifdef CONFIG_KVM_BOOK3S_64_HV -EXPORT_SYMBOL_GPL(kvmppc_hv_entry_trampoline); -#else -EXPORT_SYMBOL_GPL(kvmppc_handler_trampoline_enter); -EXPORT_SYMBOL_GPL(kvmppc_handler_lowmem_trampoline); +EXPORT_SYMBOL_GPL(kvmppc_trampoline_enter); +EXPORT_SYMBOL_GPL(kvmppc_trampoline_lowmem); EXPORT_SYMBOL_GPL(kvmppc_rmcall); EXPORT_SYMBOL_GPL(kvmppc_load_up_fpu); #ifdef CONFIG_ALTIVEC @@ -33,5 +30,3 @@ EXPORT_SYMBOL_GPL(kvmppc_load_up_altivec); #ifdef CONFIG_VSX EXPORT_SYMBOL_GPL(kvmppc_load_up_vsx); #endif -#endif - diff --git a/trunk/arch/powerpc/kvm/book3s_hv.c b/trunk/arch/powerpc/kvm/book3s_hv.c deleted file mode 100644 index cc0d7f1b19ab..000000000000 --- a/trunk/arch/powerpc/kvm/book3s_hv.c +++ /dev/null @@ -1,1269 +0,0 @@ -/* - * Copyright 2011 Paul Mackerras, IBM Corp. - * Copyright (C) 2009. SUSE Linux Products GmbH. All rights reserved. - * - * Authors: - * Paul Mackerras - * Alexander Graf - * Kevin Wolf - * - * Description: KVM functions specific to running on Book 3S - * processors in hypervisor mode (specifically POWER7 and later). - * - * This file is derived from arch/powerpc/kvm/book3s.c, - * by Alexander Graf . - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * For now, limit memory to 64GB and require it to be large pages. - * This value is chosen because it makes the ram_pginfo array be - * 64kB in size, which is about as large as we want to be trying - * to allocate with kmalloc. - */ -#define MAX_MEM_ORDER 36 - -#define LARGE_PAGE_ORDER 24 /* 16MB pages */ - -/* #define EXIT_DEBUG */ -/* #define EXIT_DEBUG_SIMPLE */ -/* #define EXIT_DEBUG_INT */ - -void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu) -{ - local_paca->kvm_hstate.kvm_vcpu = vcpu; - local_paca->kvm_hstate.kvm_vcore = vcpu->arch.vcore; -} - -void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu) -{ -} - -static void kvmppc_vcpu_blocked(struct kvm_vcpu *vcpu); -static void kvmppc_vcpu_unblocked(struct kvm_vcpu *vcpu); - -void kvmppc_vcpu_block(struct kvm_vcpu *vcpu) -{ - u64 now; - unsigned long dec_nsec; - - now = get_tb(); - if (now >= vcpu->arch.dec_expires && !kvmppc_core_pending_dec(vcpu)) - kvmppc_core_queue_dec(vcpu); - if (vcpu->arch.pending_exceptions) - return; - if (vcpu->arch.dec_expires != ~(u64)0) { - dec_nsec = (vcpu->arch.dec_expires - now) * NSEC_PER_SEC / - tb_ticks_per_sec; - hrtimer_start(&vcpu->arch.dec_timer, ktime_set(0, dec_nsec), - HRTIMER_MODE_REL); - } - - kvmppc_vcpu_blocked(vcpu); - - kvm_vcpu_block(vcpu); - vcpu->stat.halt_wakeup++; - - if (vcpu->arch.dec_expires != ~(u64)0) - hrtimer_try_to_cancel(&vcpu->arch.dec_timer); - - kvmppc_vcpu_unblocked(vcpu); -} - -void kvmppc_set_msr(struct kvm_vcpu *vcpu, u64 msr) -{ - vcpu->arch.shregs.msr = msr; -} - -void kvmppc_set_pvr(struct kvm_vcpu *vcpu, u32 pvr) -{ - vcpu->arch.pvr = pvr; -} - -void kvmppc_dump_regs(struct kvm_vcpu *vcpu) -{ - int r; - - pr_err("vcpu %p (%d):\n", vcpu, vcpu->vcpu_id); - pr_err("pc = %.16lx msr = %.16llx trap = %x\n", - vcpu->arch.pc, vcpu->arch.shregs.msr, vcpu->arch.trap); - for (r = 0; r < 16; ++r) - pr_err("r%2d = %.16lx r%d = %.16lx\n", - r, kvmppc_get_gpr(vcpu, r), - r+16, kvmppc_get_gpr(vcpu, r+16)); - pr_err("ctr = %.16lx lr = %.16lx\n", - vcpu->arch.ctr, vcpu->arch.lr); - pr_err("srr0 = %.16llx srr1 = %.16llx\n", - vcpu->arch.shregs.srr0, vcpu->arch.shregs.srr1); - pr_err("sprg0 = %.16llx sprg1 = %.16llx\n", - vcpu->arch.shregs.sprg0, vcpu->arch.shregs.sprg1); - pr_err("sprg2 = %.16llx sprg3 = %.16llx\n", - vcpu->arch.shregs.sprg2, vcpu->arch.shregs.sprg3); - pr_err("cr = %.8x xer = %.16lx dsisr = %.8x\n", - vcpu->arch.cr, vcpu->arch.xer, vcpu->arch.shregs.dsisr); - pr_err("dar = %.16llx\n", vcpu->arch.shregs.dar); - pr_err("fault dar = %.16lx dsisr = %.8x\n", - vcpu->arch.fault_dar, vcpu->arch.fault_dsisr); - pr_err("SLB (%d entries):\n", vcpu->arch.slb_max); - for (r = 0; r < vcpu->arch.slb_max; ++r) - pr_err(" ESID = %.16llx VSID = %.16llx\n", - vcpu->arch.slb[r].orige, vcpu->arch.slb[r].origv); - pr_err("lpcr = %.16lx sdr1 = %.16lx last_inst = %.8x\n", - vcpu->kvm->arch.lpcr, vcpu->kvm->arch.sdr1, - vcpu->arch.last_inst); -} - -struct kvm_vcpu *kvmppc_find_vcpu(struct kvm *kvm, int id) -{ - int r; - struct kvm_vcpu *v, *ret = NULL; - - mutex_lock(&kvm->lock); - kvm_for_each_vcpu(r, v, kvm) { - if (v->vcpu_id == id) { - ret = v; - break; - } - } - mutex_unlock(&kvm->lock); - return ret; -} - -static void init_vpa(struct kvm_vcpu *vcpu, struct lppaca *vpa) -{ - vpa->shared_proc = 1; - vpa->yield_count = 1; -} - -static unsigned long do_h_register_vpa(struct kvm_vcpu *vcpu, - unsigned long flags, - unsigned long vcpuid, unsigned long vpa) -{ - struct kvm *kvm = vcpu->kvm; - unsigned long pg_index, ra, len; - unsigned long pg_offset; - void *va; - struct kvm_vcpu *tvcpu; - - tvcpu = kvmppc_find_vcpu(kvm, vcpuid); - if (!tvcpu) - return H_PARAMETER; - - flags >>= 63 - 18; - flags &= 7; - if (flags == 0 || flags == 4) - return H_PARAMETER; - if (flags < 4) { - if (vpa & 0x7f) - return H_PARAMETER; - /* registering new area; convert logical addr to real */ - pg_index = vpa >> kvm->arch.ram_porder; - pg_offset = vpa & (kvm->arch.ram_psize - 1); - if (pg_index >= kvm->arch.ram_npages) - return H_PARAMETER; - if (kvm->arch.ram_pginfo[pg_index].pfn == 0) - return H_PARAMETER; - ra = kvm->arch.ram_pginfo[pg_index].pfn << PAGE_SHIFT; - ra |= pg_offset; - va = __va(ra); - if (flags <= 1) - len = *(unsigned short *)(va + 4); - else - len = *(unsigned int *)(va + 4); - if (pg_offset + len > kvm->arch.ram_psize) - return H_PARAMETER; - switch (flags) { - case 1: /* register VPA */ - if (len < 640) - return H_PARAMETER; - tvcpu->arch.vpa = va; - init_vpa(vcpu, va); - break; - case 2: /* register DTL */ - if (len < 48) - return H_PARAMETER; - if (!tvcpu->arch.vpa) - return H_RESOURCE; - len -= len % 48; - tvcpu->arch.dtl = va; - tvcpu->arch.dtl_end = va + len; - break; - case 3: /* register SLB shadow buffer */ - if (len < 8) - return H_PARAMETER; - if (!tvcpu->arch.vpa) - return H_RESOURCE; - tvcpu->arch.slb_shadow = va; - len = (len - 16) / 16; - tvcpu->arch.slb_shadow = va; - break; - } - } else { - switch (flags) { - case 5: /* unregister VPA */ - if (tvcpu->arch.slb_shadow || tvcpu->arch.dtl) - return H_RESOURCE; - tvcpu->arch.vpa = NULL; - break; - case 6: /* unregister DTL */ - tvcpu->arch.dtl = NULL; - break; - case 7: /* unregister SLB shadow buffer */ - tvcpu->arch.slb_shadow = NULL; - break; - } - } - return H_SUCCESS; -} - -int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu) -{ - unsigned long req = kvmppc_get_gpr(vcpu, 3); - unsigned long target, ret = H_SUCCESS; - struct kvm_vcpu *tvcpu; - - switch (req) { - case H_CEDE: - vcpu->arch.shregs.msr |= MSR_EE; - vcpu->arch.ceded = 1; - smp_mb(); - if (!vcpu->arch.prodded) - kvmppc_vcpu_block(vcpu); - else - vcpu->arch.prodded = 0; - smp_mb(); - vcpu->arch.ceded = 0; - break; - case H_PROD: - target = kvmppc_get_gpr(vcpu, 4); - tvcpu = kvmppc_find_vcpu(vcpu->kvm, target); - if (!tvcpu) { - ret = H_PARAMETER; - break; - } - tvcpu->arch.prodded = 1; - smp_mb(); - if (vcpu->arch.ceded) { - if (waitqueue_active(&vcpu->wq)) { - wake_up_interruptible(&vcpu->wq); - vcpu->stat.halt_wakeup++; - } - } - break; - case H_CONFER: - break; - case H_REGISTER_VPA: - ret = do_h_register_vpa(vcpu, kvmppc_get_gpr(vcpu, 4), - kvmppc_get_gpr(vcpu, 5), - kvmppc_get_gpr(vcpu, 6)); - break; - default: - return RESUME_HOST; - } - kvmppc_set_gpr(vcpu, 3, ret); - vcpu->arch.hcall_needed = 0; - return RESUME_GUEST; -} - -static int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, - struct task_struct *tsk) -{ - int r = RESUME_HOST; - - vcpu->stat.sum_exits++; - - run->exit_reason = KVM_EXIT_UNKNOWN; - run->ready_for_interrupt_injection = 1; - switch (vcpu->arch.trap) { - /* We're good on these - the host merely wanted to get our attention */ - case BOOK3S_INTERRUPT_HV_DECREMENTER: - vcpu->stat.dec_exits++; - r = RESUME_GUEST; - break; - case BOOK3S_INTERRUPT_EXTERNAL: - vcpu->stat.ext_intr_exits++; - r = RESUME_GUEST; - break; - case BOOK3S_INTERRUPT_PERFMON: - r = RESUME_GUEST; - break; - case BOOK3S_INTERRUPT_PROGRAM: - { - ulong flags; - /* - * Normally program interrupts are delivered directly - * to the guest by the hardware, but we can get here - * as a result of a hypervisor emulation interrupt - * (e40) getting turned into a 700 by BML RTAS. - */ - flags = vcpu->arch.shregs.msr & 0x1f0000ull; - kvmppc_core_queue_program(vcpu, flags); - r = RESUME_GUEST; - break; - } - case BOOK3S_INTERRUPT_SYSCALL: - { - /* hcall - punt to userspace */ - int i; - - if (vcpu->arch.shregs.msr & MSR_PR) { - /* sc 1 from userspace - reflect to guest syscall */ - kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_SYSCALL); - r = RESUME_GUEST; - break; - } - run->papr_hcall.nr = kvmppc_get_gpr(vcpu, 3); - for (i = 0; i < 9; ++i) - run->papr_hcall.args[i] = kvmppc_get_gpr(vcpu, 4 + i); - run->exit_reason = KVM_EXIT_PAPR_HCALL; - vcpu->arch.hcall_needed = 1; - r = RESUME_HOST; - break; - } - /* - * We get these next two if the guest does a bad real-mode access, - * as we have enabled VRMA (virtualized real mode area) mode in the - * LPCR. We just generate an appropriate DSI/ISI to the guest. - */ - case BOOK3S_INTERRUPT_H_DATA_STORAGE: - vcpu->arch.shregs.dsisr = vcpu->arch.fault_dsisr; - vcpu->arch.shregs.dar = vcpu->arch.fault_dar; - kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_DATA_STORAGE, 0); - r = RESUME_GUEST; - break; - case BOOK3S_INTERRUPT_H_INST_STORAGE: - kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_INST_STORAGE, - 0x08000000); - r = RESUME_GUEST; - break; - /* - * This occurs if the guest executes an illegal instruction. - * We just generate a program interrupt to the guest, since - * we don't emulate any guest instructions at this stage. - */ - case BOOK3S_INTERRUPT_H_EMUL_ASSIST: - kvmppc_core_queue_program(vcpu, 0x80000); - r = RESUME_GUEST; - break; - default: - kvmppc_dump_regs(vcpu); - printk(KERN_EMERG "trap=0x%x | pc=0x%lx | msr=0x%llx\n", - vcpu->arch.trap, kvmppc_get_pc(vcpu), - vcpu->arch.shregs.msr); - r = RESUME_HOST; - BUG(); - break; - } - - - if (!(r & RESUME_HOST)) { - /* To avoid clobbering exit_reason, only check for signals if - * we aren't already exiting to userspace for some other - * reason. */ - if (signal_pending(tsk)) { - vcpu->stat.signal_exits++; - run->exit_reason = KVM_EXIT_INTR; - r = -EINTR; - } else { - kvmppc_core_deliver_interrupts(vcpu); - } - } - - return r; -} - -int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, - struct kvm_sregs *sregs) -{ - int i; - - sregs->pvr = vcpu->arch.pvr; - - memset(sregs, 0, sizeof(struct kvm_sregs)); - for (i = 0; i < vcpu->arch.slb_max; i++) { - sregs->u.s.ppc64.slb[i].slbe = vcpu->arch.slb[i].orige; - sregs->u.s.ppc64.slb[i].slbv = vcpu->arch.slb[i].origv; - } - - return 0; -} - -int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, - struct kvm_sregs *sregs) -{ - int i, j; - - kvmppc_set_pvr(vcpu, sregs->pvr); - - j = 0; - for (i = 0; i < vcpu->arch.slb_nr; i++) { - if (sregs->u.s.ppc64.slb[i].slbe & SLB_ESID_V) { - vcpu->arch.slb[j].orige = sregs->u.s.ppc64.slb[i].slbe; - vcpu->arch.slb[j].origv = sregs->u.s.ppc64.slb[i].slbv; - ++j; - } - } - vcpu->arch.slb_max = j; - - return 0; -} - -int kvmppc_core_check_processor_compat(void) -{ - if (cpu_has_feature(CPU_FTR_HVMODE)) - return 0; - return -EIO; -} - -struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id) -{ - struct kvm_vcpu *vcpu; - int err = -EINVAL; - int core; - struct kvmppc_vcore *vcore; - - core = id / threads_per_core; - if (core >= KVM_MAX_VCORES) - goto out; - - err = -ENOMEM; - vcpu = kzalloc(sizeof(struct kvm_vcpu), GFP_KERNEL); - if (!vcpu) - goto out; - - err = kvm_vcpu_init(vcpu, kvm, id); - if (err) - goto free_vcpu; - - vcpu->arch.shared = &vcpu->arch.shregs; - vcpu->arch.last_cpu = -1; - vcpu->arch.mmcr[0] = MMCR0_FC; - vcpu->arch.ctrl = CTRL_RUNLATCH; - /* default to host PVR, since we can't spoof it */ - vcpu->arch.pvr = mfspr(SPRN_PVR); - kvmppc_set_pvr(vcpu, vcpu->arch.pvr); - - kvmppc_mmu_book3s_hv_init(vcpu); - - /* - * Some vcpus may start out in stopped state. If we initialize - * them to busy-in-host state they will stop other vcpus in the - * vcore from running. Instead we initialize them to blocked - * state, effectively considering them to be stopped until we - * see the first run ioctl for them. - */ - vcpu->arch.state = KVMPPC_VCPU_BLOCKED; - - init_waitqueue_head(&vcpu->arch.cpu_run); - - mutex_lock(&kvm->lock); - vcore = kvm->arch.vcores[core]; - if (!vcore) { - vcore = kzalloc(sizeof(struct kvmppc_vcore), GFP_KERNEL); - if (vcore) { - INIT_LIST_HEAD(&vcore->runnable_threads); - spin_lock_init(&vcore->lock); - } - kvm->arch.vcores[core] = vcore; - } - mutex_unlock(&kvm->lock); - - if (!vcore) - goto free_vcpu; - - spin_lock(&vcore->lock); - ++vcore->num_threads; - ++vcore->n_blocked; - spin_unlock(&vcore->lock); - vcpu->arch.vcore = vcore; - - return vcpu; - -free_vcpu: - kfree(vcpu); -out: - return ERR_PTR(err); -} - -void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu) -{ - kvm_vcpu_uninit(vcpu); - kfree(vcpu); -} - -static void kvmppc_vcpu_blocked(struct kvm_vcpu *vcpu) -{ - struct kvmppc_vcore *vc = vcpu->arch.vcore; - - spin_lock(&vc->lock); - vcpu->arch.state = KVMPPC_VCPU_BLOCKED; - ++vc->n_blocked; - if (vc->n_runnable > 0 && - vc->n_runnable + vc->n_blocked == vc->num_threads) { - vcpu = list_first_entry(&vc->runnable_threads, struct kvm_vcpu, - arch.run_list); - wake_up(&vcpu->arch.cpu_run); - } - spin_unlock(&vc->lock); -} - -static void kvmppc_vcpu_unblocked(struct kvm_vcpu *vcpu) -{ - struct kvmppc_vcore *vc = vcpu->arch.vcore; - - spin_lock(&vc->lock); - vcpu->arch.state = KVMPPC_VCPU_BUSY_IN_HOST; - --vc->n_blocked; - spin_unlock(&vc->lock); -} - -extern int __kvmppc_vcore_entry(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu); -extern void xics_wake_cpu(int cpu); - -static void kvmppc_remove_runnable(struct kvmppc_vcore *vc, - struct kvm_vcpu *vcpu) -{ - struct kvm_vcpu *v; - - if (vcpu->arch.state != KVMPPC_VCPU_RUNNABLE) - return; - vcpu->arch.state = KVMPPC_VCPU_BUSY_IN_HOST; - --vc->n_runnable; - /* decrement the physical thread id of each following vcpu */ - v = vcpu; - list_for_each_entry_continue(v, &vc->runnable_threads, arch.run_list) - --v->arch.ptid; - list_del(&vcpu->arch.run_list); -} - -static void kvmppc_start_thread(struct kvm_vcpu *vcpu) -{ - int cpu; - struct paca_struct *tpaca; - struct kvmppc_vcore *vc = vcpu->arch.vcore; - - cpu = vc->pcpu + vcpu->arch.ptid; - tpaca = &paca[cpu]; - tpaca->kvm_hstate.kvm_vcpu = vcpu; - tpaca->kvm_hstate.kvm_vcore = vc; - smp_wmb(); -#ifdef CONFIG_PPC_ICP_NATIVE - if (vcpu->arch.ptid) { - tpaca->cpu_start = 0x80; - tpaca->kvm_hstate.in_guest = KVM_GUEST_MODE_GUEST; - wmb(); - xics_wake_cpu(cpu); - ++vc->n_woken; - } -#endif -} - -static void kvmppc_wait_for_nap(struct kvmppc_vcore *vc) -{ - int i; - - HMT_low(); - i = 0; - while (vc->nap_count < vc->n_woken) { - if (++i >= 1000000) { - pr_err("kvmppc_wait_for_nap timeout %d %d\n", - vc->nap_count, vc->n_woken); - break; - } - cpu_relax(); - } - HMT_medium(); -} - -/* - * Check that we are on thread 0 and that any other threads in - * this core are off-line. - */ -static int on_primary_thread(void) -{ - int cpu = smp_processor_id(); - int thr = cpu_thread_in_core(cpu); - - if (thr) - return 0; - while (++thr < threads_per_core) - if (cpu_online(cpu + thr)) - return 0; - return 1; -} - -/* - * Run a set of guest threads on a physical core. - * Called with vc->lock held. - */ -static int kvmppc_run_core(struct kvmppc_vcore *vc) -{ - struct kvm_vcpu *vcpu, *vnext; - long ret; - u64 now; - - /* don't start if any threads have a signal pending */ - list_for_each_entry(vcpu, &vc->runnable_threads, arch.run_list) - if (signal_pending(vcpu->arch.run_task)) - return 0; - - /* - * Make sure we are running on thread 0, and that - * secondary threads are offline. - * XXX we should also block attempts to bring any - * secondary threads online. - */ - if (threads_per_core > 1 && !on_primary_thread()) { - list_for_each_entry(vcpu, &vc->runnable_threads, arch.run_list) - vcpu->arch.ret = -EBUSY; - goto out; - } - - vc->n_woken = 0; - vc->nap_count = 0; - vc->entry_exit_count = 0; - vc->vcore_running = 1; - vc->in_guest = 0; - vc->pcpu = smp_processor_id(); - list_for_each_entry(vcpu, &vc->runnable_threads, arch.run_list) - kvmppc_start_thread(vcpu); - vcpu = list_first_entry(&vc->runnable_threads, struct kvm_vcpu, - arch.run_list); - - spin_unlock(&vc->lock); - - preempt_disable(); - kvm_guest_enter(); - __kvmppc_vcore_entry(NULL, vcpu); - - /* wait for secondary threads to finish writing their state to memory */ - spin_lock(&vc->lock); - if (vc->nap_count < vc->n_woken) - kvmppc_wait_for_nap(vc); - /* prevent other vcpu threads from doing kvmppc_start_thread() now */ - vc->vcore_running = 2; - spin_unlock(&vc->lock); - - /* make sure updates to secondary vcpu structs are visible now */ - smp_mb(); - kvm_guest_exit(); - - preempt_enable(); - kvm_resched(vcpu); - - now = get_tb(); - list_for_each_entry(vcpu, &vc->runnable_threads, arch.run_list) { - /* cancel pending dec exception if dec is positive */ - if (now < vcpu->arch.dec_expires && - kvmppc_core_pending_dec(vcpu)) - kvmppc_core_dequeue_dec(vcpu); - if (!vcpu->arch.trap) { - if (signal_pending(vcpu->arch.run_task)) { - vcpu->arch.kvm_run->exit_reason = KVM_EXIT_INTR; - vcpu->arch.ret = -EINTR; - } - continue; /* didn't get to run */ - } - ret = kvmppc_handle_exit(vcpu->arch.kvm_run, vcpu, - vcpu->arch.run_task); - vcpu->arch.ret = ret; - vcpu->arch.trap = 0; - } - - spin_lock(&vc->lock); - out: - vc->vcore_running = 0; - list_for_each_entry_safe(vcpu, vnext, &vc->runnable_threads, - arch.run_list) { - if (vcpu->arch.ret != RESUME_GUEST) { - kvmppc_remove_runnable(vc, vcpu); - wake_up(&vcpu->arch.cpu_run); - } - } - - return 1; -} - -static int kvmppc_run_vcpu(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) -{ - int ptid; - int wait_state; - struct kvmppc_vcore *vc; - DEFINE_WAIT(wait); - - /* No need to go into the guest when all we do is going out */ - if (signal_pending(current)) { - kvm_run->exit_reason = KVM_EXIT_INTR; - return -EINTR; - } - - /* On PPC970, check that we have an RMA region */ - if (!vcpu->kvm->arch.rma && cpu_has_feature(CPU_FTR_ARCH_201)) - return -EPERM; - - kvm_run->exit_reason = 0; - vcpu->arch.ret = RESUME_GUEST; - vcpu->arch.trap = 0; - - flush_fp_to_thread(current); - flush_altivec_to_thread(current); - flush_vsx_to_thread(current); - - /* - * Synchronize with other threads in this virtual core - */ - vc = vcpu->arch.vcore; - spin_lock(&vc->lock); - /* This happens the first time this is called for a vcpu */ - if (vcpu->arch.state == KVMPPC_VCPU_BLOCKED) - --vc->n_blocked; - vcpu->arch.state = KVMPPC_VCPU_RUNNABLE; - ptid = vc->n_runnable; - vcpu->arch.run_task = current; - vcpu->arch.kvm_run = kvm_run; - vcpu->arch.ptid = ptid; - list_add_tail(&vcpu->arch.run_list, &vc->runnable_threads); - ++vc->n_runnable; - - wait_state = TASK_INTERRUPTIBLE; - while (vcpu->arch.state == KVMPPC_VCPU_RUNNABLE) { - if (signal_pending(current)) { - if (!vc->vcore_running) { - kvm_run->exit_reason = KVM_EXIT_INTR; - vcpu->arch.ret = -EINTR; - break; - } - /* have to wait for vcore to stop executing guest */ - wait_state = TASK_UNINTERRUPTIBLE; - smp_send_reschedule(vc->pcpu); - } - - if (!vc->vcore_running && - vc->n_runnable + vc->n_blocked == vc->num_threads) { - /* we can run now */ - if (kvmppc_run_core(vc)) - continue; - } - - if (vc->vcore_running == 1 && VCORE_EXIT_COUNT(vc) == 0) - kvmppc_start_thread(vcpu); - - /* wait for other threads to come in, or wait for vcore */ - prepare_to_wait(&vcpu->arch.cpu_run, &wait, wait_state); - spin_unlock(&vc->lock); - schedule(); - finish_wait(&vcpu->arch.cpu_run, &wait); - spin_lock(&vc->lock); - } - - if (vcpu->arch.state == KVMPPC_VCPU_RUNNABLE) - kvmppc_remove_runnable(vc, vcpu); - spin_unlock(&vc->lock); - - return vcpu->arch.ret; -} - -int kvmppc_vcpu_run(struct kvm_run *run, struct kvm_vcpu *vcpu) -{ - int r; - - do { - r = kvmppc_run_vcpu(run, vcpu); - - if (run->exit_reason == KVM_EXIT_PAPR_HCALL && - !(vcpu->arch.shregs.msr & MSR_PR)) { - r = kvmppc_pseries_do_hcall(vcpu); - kvmppc_core_deliver_interrupts(vcpu); - } - } while (r == RESUME_GUEST); - return r; -} - -static long kvmppc_stt_npages(unsigned long window_size) -{ - return ALIGN((window_size >> SPAPR_TCE_SHIFT) - * sizeof(u64), PAGE_SIZE) / PAGE_SIZE; -} - -static void release_spapr_tce_table(struct kvmppc_spapr_tce_table *stt) -{ - struct kvm *kvm = stt->kvm; - int i; - - mutex_lock(&kvm->lock); - list_del(&stt->list); - for (i = 0; i < kvmppc_stt_npages(stt->window_size); i++) - __free_page(stt->pages[i]); - kfree(stt); - mutex_unlock(&kvm->lock); - - kvm_put_kvm(kvm); -} - -static int kvm_spapr_tce_fault(struct vm_area_struct *vma, struct vm_fault *vmf) -{ - struct kvmppc_spapr_tce_table *stt = vma->vm_file->private_data; - struct page *page; - - if (vmf->pgoff >= kvmppc_stt_npages(stt->window_size)) - return VM_FAULT_SIGBUS; - - page = stt->pages[vmf->pgoff]; - get_page(page); - vmf->page = page; - return 0; -} - -static const struct vm_operations_struct kvm_spapr_tce_vm_ops = { - .fault = kvm_spapr_tce_fault, -}; - -static int kvm_spapr_tce_mmap(struct file *file, struct vm_area_struct *vma) -{ - vma->vm_ops = &kvm_spapr_tce_vm_ops; - return 0; -} - -static int kvm_spapr_tce_release(struct inode *inode, struct file *filp) -{ - struct kvmppc_spapr_tce_table *stt = filp->private_data; - - release_spapr_tce_table(stt); - return 0; -} - -static struct file_operations kvm_spapr_tce_fops = { - .mmap = kvm_spapr_tce_mmap, - .release = kvm_spapr_tce_release, -}; - -long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm, - struct kvm_create_spapr_tce *args) -{ - struct kvmppc_spapr_tce_table *stt = NULL; - long npages; - int ret = -ENOMEM; - int i; - - /* Check this LIOBN hasn't been previously allocated */ - list_for_each_entry(stt, &kvm->arch.spapr_tce_tables, list) { - if (stt->liobn == args->liobn) - return -EBUSY; - } - - npages = kvmppc_stt_npages(args->window_size); - - stt = kzalloc(sizeof(*stt) + npages* sizeof(struct page *), - GFP_KERNEL); - if (!stt) - goto fail; - - stt->liobn = args->liobn; - stt->window_size = args->window_size; - stt->kvm = kvm; - - for (i = 0; i < npages; i++) { - stt->pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO); - if (!stt->pages[i]) - goto fail; - } - - kvm_get_kvm(kvm); - - mutex_lock(&kvm->lock); - list_add(&stt->list, &kvm->arch.spapr_tce_tables); - - mutex_unlock(&kvm->lock); - - return anon_inode_getfd("kvm-spapr-tce", &kvm_spapr_tce_fops, - stt, O_RDWR); - -fail: - if (stt) { - for (i = 0; i < npages; i++) - if (stt->pages[i]) - __free_page(stt->pages[i]); - - kfree(stt); - } - return ret; -} - -/* Work out RMLS (real mode limit selector) field value for a given RMA size. - Assumes POWER7 or PPC970. */ -static inline int lpcr_rmls(unsigned long rma_size) -{ - switch (rma_size) { - case 32ul << 20: /* 32 MB */ - if (cpu_has_feature(CPU_FTR_ARCH_206)) - return 8; /* only supported on POWER7 */ - return -1; - case 64ul << 20: /* 64 MB */ - return 3; - case 128ul << 20: /* 128 MB */ - return 7; - case 256ul << 20: /* 256 MB */ - return 4; - case 1ul << 30: /* 1 GB */ - return 2; - case 16ul << 30: /* 16 GB */ - return 1; - case 256ul << 30: /* 256 GB */ - return 0; - default: - return -1; - } -} - -static int kvm_rma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) -{ - struct kvmppc_rma_info *ri = vma->vm_file->private_data; - struct page *page; - - if (vmf->pgoff >= ri->npages) - return VM_FAULT_SIGBUS; - - page = pfn_to_page(ri->base_pfn + vmf->pgoff); - get_page(page); - vmf->page = page; - return 0; -} - -static const struct vm_operations_struct kvm_rma_vm_ops = { - .fault = kvm_rma_fault, -}; - -static int kvm_rma_mmap(struct file *file, struct vm_area_struct *vma) -{ - vma->vm_flags |= VM_RESERVED; - vma->vm_ops = &kvm_rma_vm_ops; - return 0; -} - -static int kvm_rma_release(struct inode *inode, struct file *filp) -{ - struct kvmppc_rma_info *ri = filp->private_data; - - kvm_release_rma(ri); - return 0; -} - -static struct file_operations kvm_rma_fops = { - .mmap = kvm_rma_mmap, - .release = kvm_rma_release, -}; - -long kvm_vm_ioctl_allocate_rma(struct kvm *kvm, struct kvm_allocate_rma *ret) -{ - struct kvmppc_rma_info *ri; - long fd; - - ri = kvm_alloc_rma(); - if (!ri) - return -ENOMEM; - - fd = anon_inode_getfd("kvm-rma", &kvm_rma_fops, ri, O_RDWR); - if (fd < 0) - kvm_release_rma(ri); - - ret->rma_size = ri->npages << PAGE_SHIFT; - return fd; -} - -static struct page *hva_to_page(unsigned long addr) -{ - struct page *page[1]; - int npages; - - might_sleep(); - - npages = get_user_pages_fast(addr, 1, 1, page); - - if (unlikely(npages != 1)) - return 0; - - return page[0]; -} - -int kvmppc_core_prepare_memory_region(struct kvm *kvm, - struct kvm_userspace_memory_region *mem) -{ - unsigned long psize, porder; - unsigned long i, npages, totalpages; - unsigned long pg_ix; - struct kvmppc_pginfo *pginfo; - unsigned long hva; - struct kvmppc_rma_info *ri = NULL; - struct page *page; - - /* For now, only allow 16MB pages */ - porder = LARGE_PAGE_ORDER; - psize = 1ul << porder; - if ((mem->memory_size & (psize - 1)) || - (mem->guest_phys_addr & (psize - 1))) { - pr_err("bad memory_size=%llx @ %llx\n", - mem->memory_size, mem->guest_phys_addr); - return -EINVAL; - } - - npages = mem->memory_size >> porder; - totalpages = (mem->guest_phys_addr + mem->memory_size) >> porder; - - /* More memory than we have space to track? */ - if (totalpages > (1ul << (MAX_MEM_ORDER - LARGE_PAGE_ORDER))) - return -EINVAL; - - /* Do we already have an RMA registered? */ - if (mem->guest_phys_addr == 0 && kvm->arch.rma) - return -EINVAL; - - if (totalpages > kvm->arch.ram_npages) - kvm->arch.ram_npages = totalpages; - - /* Is this one of our preallocated RMAs? */ - if (mem->guest_phys_addr == 0) { - struct vm_area_struct *vma; - - down_read(¤t->mm->mmap_sem); - vma = find_vma(current->mm, mem->userspace_addr); - if (vma && vma->vm_file && - vma->vm_file->f_op == &kvm_rma_fops && - mem->userspace_addr == vma->vm_start) - ri = vma->vm_file->private_data; - up_read(¤t->mm->mmap_sem); - if (!ri && cpu_has_feature(CPU_FTR_ARCH_201)) { - pr_err("CPU requires an RMO\n"); - return -EINVAL; - } - } - - if (ri) { - unsigned long rma_size; - unsigned long lpcr; - long rmls; - - rma_size = ri->npages << PAGE_SHIFT; - if (rma_size > mem->memory_size) - rma_size = mem->memory_size; - rmls = lpcr_rmls(rma_size); - if (rmls < 0) { - pr_err("Can't use RMA of 0x%lx bytes\n", rma_size); - return -EINVAL; - } - atomic_inc(&ri->use_count); - kvm->arch.rma = ri; - kvm->arch.n_rma_pages = rma_size >> porder; - - /* Update LPCR and RMOR */ - lpcr = kvm->arch.lpcr; - if (cpu_has_feature(CPU_FTR_ARCH_201)) { - /* PPC970; insert RMLS value (split field) in HID4 */ - lpcr &= ~((1ul << HID4_RMLS0_SH) | - (3ul << HID4_RMLS2_SH)); - lpcr |= ((rmls >> 2) << HID4_RMLS0_SH) | - ((rmls & 3) << HID4_RMLS2_SH); - /* RMOR is also in HID4 */ - lpcr |= ((ri->base_pfn >> (26 - PAGE_SHIFT)) & 0xffff) - << HID4_RMOR_SH; - } else { - /* POWER7 */ - lpcr &= ~(LPCR_VPM0 | LPCR_VRMA_L); - lpcr |= rmls << LPCR_RMLS_SH; - kvm->arch.rmor = kvm->arch.rma->base_pfn << PAGE_SHIFT; - } - kvm->arch.lpcr = lpcr; - pr_info("Using RMO at %lx size %lx (LPCR = %lx)\n", - ri->base_pfn << PAGE_SHIFT, rma_size, lpcr); - } - - pg_ix = mem->guest_phys_addr >> porder; - pginfo = kvm->arch.ram_pginfo + pg_ix; - for (i = 0; i < npages; ++i, ++pg_ix) { - if (ri && pg_ix < kvm->arch.n_rma_pages) { - pginfo[i].pfn = ri->base_pfn + - (pg_ix << (porder - PAGE_SHIFT)); - continue; - } - hva = mem->userspace_addr + (i << porder); - page = hva_to_page(hva); - if (!page) { - pr_err("oops, no pfn for hva %lx\n", hva); - goto err; - } - /* Check it's a 16MB page */ - if (!PageHead(page) || - compound_order(page) != (LARGE_PAGE_ORDER - PAGE_SHIFT)) { - pr_err("page at %lx isn't 16MB (o=%d)\n", - hva, compound_order(page)); - goto err; - } - pginfo[i].pfn = page_to_pfn(page); - } - - return 0; - - err: - return -EINVAL; -} - -void kvmppc_core_commit_memory_region(struct kvm *kvm, - struct kvm_userspace_memory_region *mem) -{ - if (mem->guest_phys_addr == 0 && mem->memory_size != 0 && - !kvm->arch.rma) - kvmppc_map_vrma(kvm, mem); -} - -int kvmppc_core_init_vm(struct kvm *kvm) -{ - long r; - unsigned long npages = 1ul << (MAX_MEM_ORDER - LARGE_PAGE_ORDER); - long err = -ENOMEM; - unsigned long lpcr; - - /* Allocate hashed page table */ - r = kvmppc_alloc_hpt(kvm); - if (r) - return r; - - INIT_LIST_HEAD(&kvm->arch.spapr_tce_tables); - - kvm->arch.ram_pginfo = kzalloc(npages * sizeof(struct kvmppc_pginfo), - GFP_KERNEL); - if (!kvm->arch.ram_pginfo) { - pr_err("kvmppc_core_init_vm: couldn't alloc %lu bytes\n", - npages * sizeof(struct kvmppc_pginfo)); - goto out_free; - } - - kvm->arch.ram_npages = 0; - kvm->arch.ram_psize = 1ul << LARGE_PAGE_ORDER; - kvm->arch.ram_porder = LARGE_PAGE_ORDER; - kvm->arch.rma = NULL; - kvm->arch.n_rma_pages = 0; - - kvm->arch.host_sdr1 = mfspr(SPRN_SDR1); - - if (cpu_has_feature(CPU_FTR_ARCH_201)) { - /* PPC970; HID4 is effectively the LPCR */ - unsigned long lpid = kvm->arch.lpid; - kvm->arch.host_lpid = 0; - kvm->arch.host_lpcr = lpcr = mfspr(SPRN_HID4); - lpcr &= ~((3 << HID4_LPID1_SH) | (0xful << HID4_LPID5_SH)); - lpcr |= ((lpid >> 4) << HID4_LPID1_SH) | - ((lpid & 0xf) << HID4_LPID5_SH); - } else { - /* POWER7; init LPCR for virtual RMA mode */ - kvm->arch.host_lpid = mfspr(SPRN_LPID); - kvm->arch.host_lpcr = lpcr = mfspr(SPRN_LPCR); - lpcr &= LPCR_PECE | LPCR_LPES; - lpcr |= (4UL << LPCR_DPFD_SH) | LPCR_HDICE | - LPCR_VPM0 | LPCR_VRMA_L; - } - kvm->arch.lpcr = lpcr; - - return 0; - - out_free: - kvmppc_free_hpt(kvm); - return err; -} - -void kvmppc_core_destroy_vm(struct kvm *kvm) -{ - struct kvmppc_pginfo *pginfo; - unsigned long i; - - if (kvm->arch.ram_pginfo) { - pginfo = kvm->arch.ram_pginfo; - kvm->arch.ram_pginfo = NULL; - for (i = kvm->arch.n_rma_pages; i < kvm->arch.ram_npages; ++i) - if (pginfo[i].pfn) - put_page(pfn_to_page(pginfo[i].pfn)); - kfree(pginfo); - } - if (kvm->arch.rma) { - kvm_release_rma(kvm->arch.rma); - kvm->arch.rma = NULL; - } - - kvmppc_free_hpt(kvm); - WARN_ON(!list_empty(&kvm->arch.spapr_tce_tables)); -} - -/* These are stubs for now */ -void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, ulong pa_start, ulong pa_end) -{ -} - -/* We don't need to emulate any privileged instructions or dcbz */ -int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, - unsigned int inst, int *advance) -{ - return EMULATE_FAIL; -} - -int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs) -{ - return EMULATE_FAIL; -} - -int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt) -{ - return EMULATE_FAIL; -} - -static int kvmppc_book3s_hv_init(void) -{ - int r; - - r = kvm_init(NULL, sizeof(struct kvm_vcpu), 0, THIS_MODULE); - - if (r) - return r; - - r = kvmppc_mmu_hv_init(); - - return r; -} - -static void kvmppc_book3s_hv_exit(void) -{ - kvm_exit(); -} - -module_init(kvmppc_book3s_hv_init); -module_exit(kvmppc_book3s_hv_exit); diff --git a/trunk/arch/powerpc/kvm/book3s_hv_builtin.c b/trunk/arch/powerpc/kvm/book3s_hv_builtin.c deleted file mode 100644 index d43120355eec..000000000000 --- a/trunk/arch/powerpc/kvm/book3s_hv_builtin.c +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright 2011 Paul Mackerras, IBM Corp. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -/* - * This maintains a list of RMAs (real mode areas) for KVM guests to use. - * Each RMA has to be physically contiguous and of a size that the - * hardware supports. PPC970 and POWER7 support 64MB, 128MB and 256MB, - * and other larger sizes. Since we are unlikely to be allocate that - * much physically contiguous memory after the system is up and running, - * we preallocate a set of RMAs in early boot for KVM to use. - */ -static unsigned long kvm_rma_size = 64 << 20; /* 64MB */ -static unsigned long kvm_rma_count; - -static int __init early_parse_rma_size(char *p) -{ - if (!p) - return 1; - - kvm_rma_size = memparse(p, &p); - - return 0; -} -early_param("kvm_rma_size", early_parse_rma_size); - -static int __init early_parse_rma_count(char *p) -{ - if (!p) - return 1; - - kvm_rma_count = simple_strtoul(p, NULL, 0); - - return 0; -} -early_param("kvm_rma_count", early_parse_rma_count); - -static struct kvmppc_rma_info *rma_info; -static LIST_HEAD(free_rmas); -static DEFINE_SPINLOCK(rma_lock); - -/* Work out RMLS (real mode limit selector) field value for a given RMA size. - Assumes POWER7 or PPC970. */ -static inline int lpcr_rmls(unsigned long rma_size) -{ - switch (rma_size) { - case 32ul << 20: /* 32 MB */ - if (cpu_has_feature(CPU_FTR_ARCH_206)) - return 8; /* only supported on POWER7 */ - return -1; - case 64ul << 20: /* 64 MB */ - return 3; - case 128ul << 20: /* 128 MB */ - return 7; - case 256ul << 20: /* 256 MB */ - return 4; - case 1ul << 30: /* 1 GB */ - return 2; - case 16ul << 30: /* 16 GB */ - return 1; - case 256ul << 30: /* 256 GB */ - return 0; - default: - return -1; - } -} - -/* - * Called at boot time while the bootmem allocator is active, - * to allocate contiguous physical memory for the real memory - * areas for guests. - */ -void kvm_rma_init(void) -{ - unsigned long i; - unsigned long j, npages; - void *rma; - struct page *pg; - - /* Only do this on PPC970 in HV mode */ - if (!cpu_has_feature(CPU_FTR_HVMODE) || - !cpu_has_feature(CPU_FTR_ARCH_201)) - return; - - if (!kvm_rma_size || !kvm_rma_count) - return; - - /* Check that the requested size is one supported in hardware */ - if (lpcr_rmls(kvm_rma_size) < 0) { - pr_err("RMA size of 0x%lx not supported\n", kvm_rma_size); - return; - } - - npages = kvm_rma_size >> PAGE_SHIFT; - rma_info = alloc_bootmem(kvm_rma_count * sizeof(struct kvmppc_rma_info)); - for (i = 0; i < kvm_rma_count; ++i) { - rma = alloc_bootmem_align(kvm_rma_size, kvm_rma_size); - pr_info("Allocated KVM RMA at %p (%ld MB)\n", rma, - kvm_rma_size >> 20); - rma_info[i].base_virt = rma; - rma_info[i].base_pfn = __pa(rma) >> PAGE_SHIFT; - rma_info[i].npages = npages; - list_add_tail(&rma_info[i].list, &free_rmas); - atomic_set(&rma_info[i].use_count, 0); - - pg = pfn_to_page(rma_info[i].base_pfn); - for (j = 0; j < npages; ++j) { - atomic_inc(&pg->_count); - ++pg; - } - } -} - -struct kvmppc_rma_info *kvm_alloc_rma(void) -{ - struct kvmppc_rma_info *ri; - - ri = NULL; - spin_lock(&rma_lock); - if (!list_empty(&free_rmas)) { - ri = list_first_entry(&free_rmas, struct kvmppc_rma_info, list); - list_del(&ri->list); - atomic_inc(&ri->use_count); - } - spin_unlock(&rma_lock); - return ri; -} -EXPORT_SYMBOL_GPL(kvm_alloc_rma); - -void kvm_release_rma(struct kvmppc_rma_info *ri) -{ - if (atomic_dec_and_test(&ri->use_count)) { - spin_lock(&rma_lock); - list_add_tail(&ri->list, &free_rmas); - spin_unlock(&rma_lock); - - } -} -EXPORT_SYMBOL_GPL(kvm_release_rma); - diff --git a/trunk/arch/powerpc/kvm/book3s_hv_interrupts.S b/trunk/arch/powerpc/kvm/book3s_hv_interrupts.S deleted file mode 100644 index 3f7b674dd4bf..000000000000 --- a/trunk/arch/powerpc/kvm/book3s_hv_interrupts.S +++ /dev/null @@ -1,166 +0,0 @@ -/* - * 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. - * - * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright 2011 Paul Mackerras, IBM Corp. - * - * Derived from book3s_interrupts.S, which is: - * Copyright SUSE Linux Products GmbH 2009 - * - * Authors: Alexander Graf - */ - -#include -#include -#include -#include -#include -#include -#include - -/***************************************************************************** - * * - * Guest entry / exit code that is in kernel module memory (vmalloc) * - * * - ****************************************************************************/ - -/* Registers: - * r4: vcpu pointer - */ -_GLOBAL(__kvmppc_vcore_entry) - - /* Write correct stack frame */ - mflr r0 - std r0,PPC_LR_STKOFF(r1) - - /* Save host state to the stack */ - stdu r1, -SWITCH_FRAME_SIZE(r1) - - /* Save non-volatile registers (r14 - r31) */ - SAVE_NVGPRS(r1) - - /* Save host DSCR */ -BEGIN_FTR_SECTION - mfspr r3, SPRN_DSCR - std r3, HSTATE_DSCR(r13) -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) - - /* Save host DABR */ - mfspr r3, SPRN_DABR - std r3, HSTATE_DABR(r13) - - /* Hard-disable interrupts */ - mfmsr r10 - std r10, HSTATE_HOST_MSR(r13) - rldicl r10,r10,48,1 - rotldi r10,r10,16 - mtmsrd r10,1 - - /* Save host PMU registers and load guest PMU registers */ - /* R4 is live here (vcpu pointer) but not r3 or r5 */ - li r3, 1 - sldi r3, r3, 31 /* MMCR0_FC (freeze counters) bit */ - mfspr r7, SPRN_MMCR0 /* save MMCR0 */ - mtspr SPRN_MMCR0, r3 /* freeze all counters, disable interrupts */ - isync - ld r3, PACALPPACAPTR(r13) /* is the host using the PMU? */ - lbz r5, LPPACA_PMCINUSE(r3) - cmpwi r5, 0 - beq 31f /* skip if not */ - mfspr r5, SPRN_MMCR1 - mfspr r6, SPRN_MMCRA - std r7, HSTATE_MMCR(r13) - std r5, HSTATE_MMCR + 8(r13) - std r6, HSTATE_MMCR + 16(r13) - mfspr r3, SPRN_PMC1 - mfspr r5, SPRN_PMC2 - mfspr r6, SPRN_PMC3 - mfspr r7, SPRN_PMC4 - mfspr r8, SPRN_PMC5 - mfspr r9, SPRN_PMC6 -BEGIN_FTR_SECTION - mfspr r10, SPRN_PMC7 - mfspr r11, SPRN_PMC8 -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) - stw r3, HSTATE_PMC(r13) - stw r5, HSTATE_PMC + 4(r13) - stw r6, HSTATE_PMC + 8(r13) - stw r7, HSTATE_PMC + 12(r13) - stw r8, HSTATE_PMC + 16(r13) - stw r9, HSTATE_PMC + 20(r13) -BEGIN_FTR_SECTION - stw r10, HSTATE_PMC + 24(r13) - stw r11, HSTATE_PMC + 28(r13) -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) -31: - - /* - * Put whatever is in the decrementer into the - * hypervisor decrementer. - */ - mfspr r8,SPRN_DEC - mftb r7 - mtspr SPRN_HDEC,r8 - extsw r8,r8 - add r8,r8,r7 - std r8,HSTATE_DECEXP(r13) - - /* - * On PPC970, if the guest vcpu has an external interrupt pending, - * send ourselves an IPI so as to interrupt the guest once it - * enables interrupts. (It must have interrupts disabled, - * otherwise we would already have delivered the interrupt.) - */ -BEGIN_FTR_SECTION - ld r0, VCPU_PENDING_EXC(r4) - li r7, (1 << BOOK3S_IRQPRIO_EXTERNAL) - oris r7, r7, (1 << BOOK3S_IRQPRIO_EXTERNAL_LEVEL)@h - and. r0, r0, r7 - beq 32f - mr r31, r4 - lhz r3, PACAPACAINDEX(r13) - bl smp_send_reschedule - nop - mr r4, r31 -32: -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) - - /* Jump to partition switch code */ - bl .kvmppc_hv_entry_trampoline - nop - -/* - * We return here in virtual mode after the guest exits - * with something that we can't handle in real mode. - * Interrupts are enabled again at this point. - */ - -.global kvmppc_handler_highmem -kvmppc_handler_highmem: - - /* - * Register usage at this point: - * - * R1 = host R1 - * R2 = host R2 - * R12 = exit handler id - * R13 = PACA - */ - - /* Restore non-volatile host registers (r14 - r31) */ - REST_NVGPRS(r1) - - addi r1, r1, SWITCH_FRAME_SIZE - ld r0, PPC_LR_STKOFF(r1) - mtlr r0 - blr diff --git a/trunk/arch/powerpc/kvm/book3s_hv_rm_mmu.c b/trunk/arch/powerpc/kvm/book3s_hv_rm_mmu.c deleted file mode 100644 index fcfe6b055558..000000000000 --- a/trunk/arch/powerpc/kvm/book3s_hv_rm_mmu.c +++ /dev/null @@ -1,370 +0,0 @@ -/* - * 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. - * - * Copyright 2010-2011 Paul Mackerras, IBM Corp. - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -/* For now use fixed-size 16MB page table */ -#define HPT_ORDER 24 -#define HPT_NPTEG (1ul << (HPT_ORDER - 7)) /* 128B per pteg */ -#define HPT_HASH_MASK (HPT_NPTEG - 1) - -#define HPTE_V_HVLOCK 0x40UL - -static inline long lock_hpte(unsigned long *hpte, unsigned long bits) -{ - unsigned long tmp, old; - - asm volatile(" ldarx %0,0,%2\n" - " and. %1,%0,%3\n" - " bne 2f\n" - " ori %0,%0,%4\n" - " stdcx. %0,0,%2\n" - " beq+ 2f\n" - " li %1,%3\n" - "2: isync" - : "=&r" (tmp), "=&r" (old) - : "r" (hpte), "r" (bits), "i" (HPTE_V_HVLOCK) - : "cc", "memory"); - return old == 0; -} - -long kvmppc_h_enter(struct kvm_vcpu *vcpu, unsigned long flags, - long pte_index, unsigned long pteh, unsigned long ptel) -{ - unsigned long porder; - struct kvm *kvm = vcpu->kvm; - unsigned long i, lpn, pa; - unsigned long *hpte; - - /* only handle 4k, 64k and 16M pages for now */ - porder = 12; - if (pteh & HPTE_V_LARGE) { - if (cpu_has_feature(CPU_FTR_ARCH_206) && - (ptel & 0xf000) == 0x1000) { - /* 64k page */ - porder = 16; - } else if ((ptel & 0xff000) == 0) { - /* 16M page */ - porder = 24; - /* lowest AVA bit must be 0 for 16M pages */ - if (pteh & 0x80) - return H_PARAMETER; - } else - return H_PARAMETER; - } - lpn = (ptel & HPTE_R_RPN) >> kvm->arch.ram_porder; - if (lpn >= kvm->arch.ram_npages || porder > kvm->arch.ram_porder) - return H_PARAMETER; - pa = kvm->arch.ram_pginfo[lpn].pfn << PAGE_SHIFT; - if (!pa) - return H_PARAMETER; - /* Check WIMG */ - if ((ptel & HPTE_R_WIMG) != HPTE_R_M && - (ptel & HPTE_R_WIMG) != (HPTE_R_W | HPTE_R_I | HPTE_R_M)) - return H_PARAMETER; - pteh &= ~0x60UL; - ptel &= ~(HPTE_R_PP0 - kvm->arch.ram_psize); - ptel |= pa; - if (pte_index >= (HPT_NPTEG << 3)) - return H_PARAMETER; - if (likely((flags & H_EXACT) == 0)) { - pte_index &= ~7UL; - hpte = (unsigned long *)(kvm->arch.hpt_virt + (pte_index << 4)); - for (i = 0; ; ++i) { - if (i == 8) - return H_PTEG_FULL; - if ((*hpte & HPTE_V_VALID) == 0 && - lock_hpte(hpte, HPTE_V_HVLOCK | HPTE_V_VALID)) - break; - hpte += 2; - } - } else { - i = 0; - hpte = (unsigned long *)(kvm->arch.hpt_virt + (pte_index << 4)); - if (!lock_hpte(hpte, HPTE_V_HVLOCK | HPTE_V_VALID)) - return H_PTEG_FULL; - } - hpte[1] = ptel; - eieio(); - hpte[0] = pteh; - asm volatile("ptesync" : : : "memory"); - atomic_inc(&kvm->arch.ram_pginfo[lpn].refcnt); - vcpu->arch.gpr[4] = pte_index + i; - return H_SUCCESS; -} - -static unsigned long compute_tlbie_rb(unsigned long v, unsigned long r, - unsigned long pte_index) -{ - unsigned long rb, va_low; - - rb = (v & ~0x7fUL) << 16; /* AVA field */ - va_low = pte_index >> 3; - if (v & HPTE_V_SECONDARY) - va_low = ~va_low; - /* xor vsid from AVA */ - if (!(v & HPTE_V_1TB_SEG)) - va_low ^= v >> 12; - else - va_low ^= v >> 24; - va_low &= 0x7ff; - if (v & HPTE_V_LARGE) { - rb |= 1; /* L field */ - if (cpu_has_feature(CPU_FTR_ARCH_206) && - (r & 0xff000)) { - /* non-16MB large page, must be 64k */ - /* (masks depend on page size) */ - rb |= 0x1000; /* page encoding in LP field */ - rb |= (va_low & 0x7f) << 16; /* 7b of VA in AVA/LP field */ - rb |= (va_low & 0xfe); /* AVAL field (P7 doesn't seem to care) */ - } - } else { - /* 4kB page */ - rb |= (va_low & 0x7ff) << 12; /* remaining 11b of VA */ - } - rb |= (v >> 54) & 0x300; /* B field */ - return rb; -} - -#define LOCK_TOKEN (*(u32 *)(&get_paca()->lock_token)) - -static inline int try_lock_tlbie(unsigned int *lock) -{ - unsigned int tmp, old; - unsigned int token = LOCK_TOKEN; - - asm volatile("1:lwarx %1,0,%2\n" - " cmpwi cr0,%1,0\n" - " bne 2f\n" - " stwcx. %3,0,%2\n" - " bne- 1b\n" - " isync\n" - "2:" - : "=&r" (tmp), "=&r" (old) - : "r" (lock), "r" (token) - : "cc", "memory"); - return old == 0; -} - -long kvmppc_h_remove(struct kvm_vcpu *vcpu, unsigned long flags, - unsigned long pte_index, unsigned long avpn, - unsigned long va) -{ - struct kvm *kvm = vcpu->kvm; - unsigned long *hpte; - unsigned long v, r, rb; - - if (pte_index >= (HPT_NPTEG << 3)) - return H_PARAMETER; - hpte = (unsigned long *)(kvm->arch.hpt_virt + (pte_index << 4)); - while (!lock_hpte(hpte, HPTE_V_HVLOCK)) - cpu_relax(); - if ((hpte[0] & HPTE_V_VALID) == 0 || - ((flags & H_AVPN) && (hpte[0] & ~0x7fUL) != avpn) || - ((flags & H_ANDCOND) && (hpte[0] & avpn) != 0)) { - hpte[0] &= ~HPTE_V_HVLOCK; - return H_NOT_FOUND; - } - if (atomic_read(&kvm->online_vcpus) == 1) - flags |= H_LOCAL; - vcpu->arch.gpr[4] = v = hpte[0] & ~HPTE_V_HVLOCK; - vcpu->arch.gpr[5] = r = hpte[1]; - rb = compute_tlbie_rb(v, r, pte_index); - hpte[0] = 0; - if (!(flags & H_LOCAL)) { - while(!try_lock_tlbie(&kvm->arch.tlbie_lock)) - cpu_relax(); - asm volatile("ptesync" : : : "memory"); - asm volatile(PPC_TLBIE(%1,%0)"; eieio; tlbsync" - : : "r" (rb), "r" (kvm->arch.lpid)); - asm volatile("ptesync" : : : "memory"); - kvm->arch.tlbie_lock = 0; - } else { - asm volatile("ptesync" : : : "memory"); - asm volatile("tlbiel %0" : : "r" (rb)); - asm volatile("ptesync" : : : "memory"); - } - return H_SUCCESS; -} - -long kvmppc_h_bulk_remove(struct kvm_vcpu *vcpu) -{ - struct kvm *kvm = vcpu->kvm; - unsigned long *args = &vcpu->arch.gpr[4]; - unsigned long *hp, tlbrb[4]; - long int i, found; - long int n_inval = 0; - unsigned long flags, req, pte_index; - long int local = 0; - long int ret = H_SUCCESS; - - if (atomic_read(&kvm->online_vcpus) == 1) - local = 1; - for (i = 0; i < 4; ++i) { - pte_index = args[i * 2]; - flags = pte_index >> 56; - pte_index &= ((1ul << 56) - 1); - req = flags >> 6; - flags &= 3; - if (req == 3) - break; - if (req != 1 || flags == 3 || - pte_index >= (HPT_NPTEG << 3)) { - /* parameter error */ - args[i * 2] = ((0xa0 | flags) << 56) + pte_index; - ret = H_PARAMETER; - break; - } - hp = (unsigned long *)(kvm->arch.hpt_virt + (pte_index << 4)); - while (!lock_hpte(hp, HPTE_V_HVLOCK)) - cpu_relax(); - found = 0; - if (hp[0] & HPTE_V_VALID) { - switch (flags & 3) { - case 0: /* absolute */ - found = 1; - break; - case 1: /* andcond */ - if (!(hp[0] & args[i * 2 + 1])) - found = 1; - break; - case 2: /* AVPN */ - if ((hp[0] & ~0x7fUL) == args[i * 2 + 1]) - found = 1; - break; - } - } - if (!found) { - hp[0] &= ~HPTE_V_HVLOCK; - args[i * 2] = ((0x90 | flags) << 56) + pte_index; - continue; - } - /* insert R and C bits from PTE */ - flags |= (hp[1] >> 5) & 0x0c; - args[i * 2] = ((0x80 | flags) << 56) + pte_index; - tlbrb[n_inval++] = compute_tlbie_rb(hp[0], hp[1], pte_index); - hp[0] = 0; - } - if (n_inval == 0) - return ret; - - if (!local) { - while(!try_lock_tlbie(&kvm->arch.tlbie_lock)) - cpu_relax(); - asm volatile("ptesync" : : : "memory"); - for (i = 0; i < n_inval; ++i) - asm volatile(PPC_TLBIE(%1,%0) - : : "r" (tlbrb[i]), "r" (kvm->arch.lpid)); - asm volatile("eieio; tlbsync; ptesync" : : : "memory"); - kvm->arch.tlbie_lock = 0; - } else { - asm volatile("ptesync" : : : "memory"); - for (i = 0; i < n_inval; ++i) - asm volatile("tlbiel %0" : : "r" (tlbrb[i])); - asm volatile("ptesync" : : : "memory"); - } - return ret; -} - -long kvmppc_h_protect(struct kvm_vcpu *vcpu, unsigned long flags, - unsigned long pte_index, unsigned long avpn, - unsigned long va) -{ - struct kvm *kvm = vcpu->kvm; - unsigned long *hpte; - unsigned long v, r, rb; - - if (pte_index >= (HPT_NPTEG << 3)) - return H_PARAMETER; - hpte = (unsigned long *)(kvm->arch.hpt_virt + (pte_index << 4)); - while (!lock_hpte(hpte, HPTE_V_HVLOCK)) - cpu_relax(); - if ((hpte[0] & HPTE_V_VALID) == 0 || - ((flags & H_AVPN) && (hpte[0] & ~0x7fUL) != avpn)) { - hpte[0] &= ~HPTE_V_HVLOCK; - return H_NOT_FOUND; - } - if (atomic_read(&kvm->online_vcpus) == 1) - flags |= H_LOCAL; - v = hpte[0]; - r = hpte[1] & ~(HPTE_R_PP0 | HPTE_R_PP | HPTE_R_N | - HPTE_R_KEY_HI | HPTE_R_KEY_LO); - r |= (flags << 55) & HPTE_R_PP0; - r |= (flags << 48) & HPTE_R_KEY_HI; - r |= flags & (HPTE_R_PP | HPTE_R_N | HPTE_R_KEY_LO); - rb = compute_tlbie_rb(v, r, pte_index); - hpte[0] = v & ~HPTE_V_VALID; - if (!(flags & H_LOCAL)) { - while(!try_lock_tlbie(&kvm->arch.tlbie_lock)) - cpu_relax(); - asm volatile("ptesync" : : : "memory"); - asm volatile(PPC_TLBIE(%1,%0)"; eieio; tlbsync" - : : "r" (rb), "r" (kvm->arch.lpid)); - asm volatile("ptesync" : : : "memory"); - kvm->arch.tlbie_lock = 0; - } else { - asm volatile("ptesync" : : : "memory"); - asm volatile("tlbiel %0" : : "r" (rb)); - asm volatile("ptesync" : : : "memory"); - } - hpte[1] = r; - eieio(); - hpte[0] = v & ~HPTE_V_HVLOCK; - asm volatile("ptesync" : : : "memory"); - return H_SUCCESS; -} - -static unsigned long reverse_xlate(struct kvm *kvm, unsigned long realaddr) -{ - long int i; - unsigned long offset, rpn; - - offset = realaddr & (kvm->arch.ram_psize - 1); - rpn = (realaddr - offset) >> PAGE_SHIFT; - for (i = 0; i < kvm->arch.ram_npages; ++i) - if (rpn == kvm->arch.ram_pginfo[i].pfn) - return (i << PAGE_SHIFT) + offset; - return HPTE_R_RPN; /* all 1s in the RPN field */ -} - -long kvmppc_h_read(struct kvm_vcpu *vcpu, unsigned long flags, - unsigned long pte_index) -{ - struct kvm *kvm = vcpu->kvm; - unsigned long *hpte, r; - int i, n = 1; - - if (pte_index >= (HPT_NPTEG << 3)) - return H_PARAMETER; - if (flags & H_READ_4) { - pte_index &= ~3; - n = 4; - } - for (i = 0; i < n; ++i, ++pte_index) { - hpte = (unsigned long *)(kvm->arch.hpt_virt + (pte_index << 4)); - r = hpte[1]; - if ((flags & H_R_XLATE) && (hpte[0] & HPTE_V_VALID)) - r = reverse_xlate(kvm, r & HPTE_R_RPN) | - (r & ~HPTE_R_RPN); - vcpu->arch.gpr[4 + i * 2] = hpte[0]; - vcpu->arch.gpr[5 + i * 2] = r; - } - return H_SUCCESS; -} diff --git a/trunk/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/trunk/arch/powerpc/kvm/book3s_hv_rmhandlers.S deleted file mode 100644 index 6dd33581a228..000000000000 --- a/trunk/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ /dev/null @@ -1,1345 +0,0 @@ -/* - * 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. - * - * 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. - * - * Copyright 2011 Paul Mackerras, IBM Corp. - * - * Derived from book3s_rmhandlers.S and other files, which are: - * - * Copyright SUSE Linux Products GmbH 2009 - * - * Authors: Alexander Graf - */ - -#include -#include -#include -#include -#include -#include - -/***************************************************************************** - * * - * Real Mode handlers that need to be in the linear mapping * - * * - ****************************************************************************/ - - .globl kvmppc_skip_interrupt -kvmppc_skip_interrupt: - mfspr r13,SPRN_SRR0 - addi r13,r13,4 - mtspr SPRN_SRR0,r13 - GET_SCRATCH0(r13) - rfid - b . - - .globl kvmppc_skip_Hinterrupt -kvmppc_skip_Hinterrupt: - mfspr r13,SPRN_HSRR0 - addi r13,r13,4 - mtspr SPRN_HSRR0,r13 - GET_SCRATCH0(r13) - hrfid - b . - -/* - * Call kvmppc_handler_trampoline_enter in real mode. - * Must be called with interrupts hard-disabled. - * - * Input Registers: - * - * LR = return address to continue at after eventually re-enabling MMU - */ -_GLOBAL(kvmppc_hv_entry_trampoline) - mfmsr r10 - LOAD_REG_ADDR(r5, kvmppc_hv_entry) - li r0,MSR_RI - andc r0,r10,r0 - li r6,MSR_IR | MSR_DR - andc r6,r10,r6 - mtmsrd r0,1 /* clear RI in MSR */ - mtsrr0 r5 - mtsrr1 r6 - RFI - -#define ULONG_SIZE 8 -#define VCPU_GPR(n) (VCPU_GPRS + (n * ULONG_SIZE)) - -/****************************************************************************** - * * - * Entry code * - * * - *****************************************************************************/ - -#define XICS_XIRR 4 -#define XICS_QIRR 0xc - -/* - * We come in here when wakened from nap mode on a secondary hw thread. - * Relocation is off and most register values are lost. - * r13 points to the PACA. - */ - .globl kvm_start_guest -kvm_start_guest: - ld r1,PACAEMERGSP(r13) - subi r1,r1,STACK_FRAME_OVERHEAD - - /* get vcpu pointer */ - ld r4, HSTATE_KVM_VCPU(r13) - - /* We got here with an IPI; clear it */ - ld r5, HSTATE_XICS_PHYS(r13) - li r0, 0xff - li r6, XICS_QIRR - li r7, XICS_XIRR - lwzcix r8, r5, r7 /* ack the interrupt */ - sync - stbcix r0, r5, r6 /* clear it */ - stwcix r8, r5, r7 /* EOI it */ - -.global kvmppc_hv_entry -kvmppc_hv_entry: - - /* Required state: - * - * R4 = vcpu pointer - * MSR = ~IR|DR - * R13 = PACA - * R1 = host R1 - * all other volatile GPRS = free - */ - mflr r0 - std r0, HSTATE_VMHANDLER(r13) - - ld r14, VCPU_GPR(r14)(r4) - ld r15, VCPU_GPR(r15)(r4) - ld r16, VCPU_GPR(r16)(r4) - ld r17, VCPU_GPR(r17)(r4) - ld r18, VCPU_GPR(r18)(r4) - ld r19, VCPU_GPR(r19)(r4) - ld r20, VCPU_GPR(r20)(r4) - ld r21, VCPU_GPR(r21)(r4) - ld r22, VCPU_GPR(r22)(r4) - ld r23, VCPU_GPR(r23)(r4) - ld r24, VCPU_GPR(r24)(r4) - ld r25, VCPU_GPR(r25)(r4) - ld r26, VCPU_GPR(r26)(r4) - ld r27, VCPU_GPR(r27)(r4) - ld r28, VCPU_GPR(r28)(r4) - ld r29, VCPU_GPR(r29)(r4) - ld r30, VCPU_GPR(r30)(r4) - ld r31, VCPU_GPR(r31)(r4) - - /* Load guest PMU registers */ - /* R4 is live here (vcpu pointer) */ - li r3, 1 - sldi r3, r3, 31 /* MMCR0_FC (freeze counters) bit */ - mtspr SPRN_MMCR0, r3 /* freeze all counters, disable ints */ - isync - lwz r3, VCPU_PMC(r4) /* always load up guest PMU registers */ - lwz r5, VCPU_PMC + 4(r4) /* to prevent information leak */ - lwz r6, VCPU_PMC + 8(r4) - lwz r7, VCPU_PMC + 12(r4) - lwz r8, VCPU_PMC + 16(r4) - lwz r9, VCPU_PMC + 20(r4) -BEGIN_FTR_SECTION - lwz r10, VCPU_PMC + 24(r4) - lwz r11, VCPU_PMC + 28(r4) -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) - mtspr SPRN_PMC1, r3 - mtspr SPRN_PMC2, r5 - mtspr SPRN_PMC3, r6 - mtspr SPRN_PMC4, r7 - mtspr SPRN_PMC5, r8 - mtspr SPRN_PMC6, r9 -BEGIN_FTR_SECTION - mtspr SPRN_PMC7, r10 - mtspr SPRN_PMC8, r11 -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) - ld r3, VCPU_MMCR(r4) - ld r5, VCPU_MMCR + 8(r4) - ld r6, VCPU_MMCR + 16(r4) - mtspr SPRN_MMCR1, r5 - mtspr SPRN_MMCRA, r6 - mtspr SPRN_MMCR0, r3 - isync - - /* Load up FP, VMX and VSX registers */ - bl kvmppc_load_fp - -BEGIN_FTR_SECTION - /* Switch DSCR to guest value */ - ld r5, VCPU_DSCR(r4) - mtspr SPRN_DSCR, r5 -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) - - /* - * Set the decrementer to the guest decrementer. - */ - ld r8,VCPU_DEC_EXPIRES(r4) - mftb r7 - subf r3,r7,r8 - mtspr SPRN_DEC,r3 - stw r3,VCPU_DEC(r4) - - ld r5, VCPU_SPRG0(r4) - ld r6, VCPU_SPRG1(r4) - ld r7, VCPU_SPRG2(r4) - ld r8, VCPU_SPRG3(r4) - mtspr SPRN_SPRG0, r5 - mtspr SPRN_SPRG1, r6 - mtspr SPRN_SPRG2, r7 - mtspr SPRN_SPRG3, r8 - - /* Save R1 in the PACA */ - std r1, HSTATE_HOST_R1(r13) - - /* Increment yield count if they have a VPA */ - ld r3, VCPU_VPA(r4) - cmpdi r3, 0 - beq 25f - lwz r5, LPPACA_YIELDCOUNT(r3) - addi r5, r5, 1 - stw r5, LPPACA_YIELDCOUNT(r3) -25: - /* Load up DAR and DSISR */ - ld r5, VCPU_DAR(r4) - lwz r6, VCPU_DSISR(r4) - mtspr SPRN_DAR, r5 - mtspr SPRN_DSISR, r6 - - /* Set partition DABR */ - li r5,3 - ld r6,VCPU_DABR(r4) - mtspr SPRN_DABRX,r5 - mtspr SPRN_DABR,r6 - -BEGIN_FTR_SECTION - /* Restore AMR and UAMOR, set AMOR to all 1s */ - ld r5,VCPU_AMR(r4) - ld r6,VCPU_UAMOR(r4) - li r7,-1 - mtspr SPRN_AMR,r5 - mtspr SPRN_UAMOR,r6 - mtspr SPRN_AMOR,r7 -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) - - /* Clear out SLB */ - li r6,0 - slbmte r6,r6 - slbia - ptesync - -BEGIN_FTR_SECTION - b 30f -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) - /* - * POWER7 host -> guest partition switch code. - * We don't have to lock against concurrent tlbies, - * but we do have to coordinate across hardware threads. - */ - /* Increment entry count iff exit count is zero. */ - ld r5,HSTATE_KVM_VCORE(r13) - addi r9,r5,VCORE_ENTRY_EXIT -21: lwarx r3,0,r9 - cmpwi r3,0x100 /* any threads starting to exit? */ - bge secondary_too_late /* if so we're too late to the party */ - addi r3,r3,1 - stwcx. r3,0,r9 - bne 21b - - /* Primary thread switches to guest partition. */ - ld r9,VCPU_KVM(r4) /* pointer to struct kvm */ - lwz r6,VCPU_PTID(r4) - cmpwi r6,0 - bne 20f - ld r6,KVM_SDR1(r9) - lwz r7,KVM_LPID(r9) - li r0,LPID_RSVD /* switch to reserved LPID */ - mtspr SPRN_LPID,r0 - ptesync - mtspr SPRN_SDR1,r6 /* switch to partition page table */ - mtspr SPRN_LPID,r7 - isync - li r0,1 - stb r0,VCORE_IN_GUEST(r5) /* signal secondaries to continue */ - b 10f - - /* Secondary threads wait for primary to have done partition switch */ -20: lbz r0,VCORE_IN_GUEST(r5) - cmpwi r0,0 - beq 20b - - /* Set LPCR. Set the MER bit if there is a pending external irq. */ -10: ld r8,KVM_LPCR(r9) - ld r0,VCPU_PENDING_EXC(r4) - li r7,(1 << BOOK3S_IRQPRIO_EXTERNAL) - oris r7,r7,(1 << BOOK3S_IRQPRIO_EXTERNAL_LEVEL)@h - and. r0,r0,r7 - beq 11f - ori r8,r8,LPCR_MER -11: mtspr SPRN_LPCR,r8 - ld r8,KVM_RMOR(r9) - mtspr SPRN_RMOR,r8 - isync - - /* Check if HDEC expires soon */ - mfspr r3,SPRN_HDEC - cmpwi r3,10 - li r12,BOOK3S_INTERRUPT_HV_DECREMENTER - mr r9,r4 - blt hdec_soon - - /* - * Invalidate the TLB if we could possibly have stale TLB - * entries for this partition on this core due to the use - * of tlbiel. - * XXX maybe only need this on primary thread? - */ - ld r9,VCPU_KVM(r4) /* pointer to struct kvm */ - lwz r5,VCPU_VCPUID(r4) - lhz r6,PACAPACAINDEX(r13) - rldimi r6,r5,0,62 /* XXX map as if threads 1:1 p:v */ - lhz r8,VCPU_LAST_CPU(r4) - sldi r7,r6,1 /* see if this is the same vcpu */ - add r7,r7,r9 /* as last ran on this pcpu */ - lhz r0,KVM_LAST_VCPU(r7) - cmpw r6,r8 /* on the same cpu core as last time? */ - bne 3f - cmpw r0,r5 /* same vcpu as this core last ran? */ - beq 1f -3: sth r6,VCPU_LAST_CPU(r4) /* if not, invalidate partition TLB */ - sth r5,KVM_LAST_VCPU(r7) - li r6,128 - mtctr r6 - li r7,0x800 /* IS field = 0b10 */ - ptesync -2: tlbiel r7 - addi r7,r7,0x1000 - bdnz 2b - ptesync -1: - - /* Save purr/spurr */ - mfspr r5,SPRN_PURR - mfspr r6,SPRN_SPURR - std r5,HSTATE_PURR(r13) - std r6,HSTATE_SPURR(r13) - ld r7,VCPU_PURR(r4) - ld r8,VCPU_SPURR(r4) - mtspr SPRN_PURR,r7 - mtspr SPRN_SPURR,r8 - b 31f - - /* - * PPC970 host -> guest partition switch code. - * We have to lock against concurrent tlbies, - * using native_tlbie_lock to lock against host tlbies - * and kvm->arch.tlbie_lock to lock against guest tlbies. - * We also have to invalidate the TLB since its - * entries aren't tagged with the LPID. - */ -30: ld r9,VCPU_KVM(r4) /* pointer to struct kvm */ - - /* first take native_tlbie_lock */ - .section ".toc","aw" -toc_tlbie_lock: - .tc native_tlbie_lock[TC],native_tlbie_lock - .previous - ld r3,toc_tlbie_lock@toc(2) - lwz r8,PACA_LOCK_TOKEN(r13) -24: lwarx r0,0,r3 - cmpwi r0,0 - bne 24b - stwcx. r8,0,r3 - bne 24b - isync - - ld r7,KVM_LPCR(r9) /* use kvm->arch.lpcr to store HID4 */ - li r0,0x18f - rotldi r0,r0,HID4_LPID5_SH /* all lpid bits in HID4 = 1 */ - or r0,r7,r0 - ptesync - sync - mtspr SPRN_HID4,r0 /* switch to reserved LPID */ - isync - li r0,0 - stw r0,0(r3) /* drop native_tlbie_lock */ - - /* invalidate the whole TLB */ - li r0,256 - mtctr r0 - li r6,0 -25: tlbiel r6 - addi r6,r6,0x1000 - bdnz 25b - ptesync - - /* Take the guest's tlbie_lock */ - addi r3,r9,KVM_TLBIE_LOCK -24: lwarx r0,0,r3 - cmpwi r0,0 - bne 24b - stwcx. r8,0,r3 - bne 24b - isync - ld r6,KVM_SDR1(r9) - mtspr SPRN_SDR1,r6 /* switch to partition page table */ - - /* Set up HID4 with the guest's LPID etc. */ - sync - mtspr SPRN_HID4,r7 - isync - - /* drop the guest's tlbie_lock */ - li r0,0 - stw r0,0(r3) - - /* Check if HDEC expires soon */ - mfspr r3,SPRN_HDEC - cmpwi r3,10 - li r12,BOOK3S_INTERRUPT_HV_DECREMENTER - mr r9,r4 - blt hdec_soon - - /* Enable HDEC interrupts */ - mfspr r0,SPRN_HID0 - li r3,1 - rldimi r0,r3, HID0_HDICE_SH, 64-HID0_HDICE_SH-1 - sync - mtspr SPRN_HID0,r0 - mfspr r0,SPRN_HID0 - mfspr r0,SPRN_HID0 - mfspr r0,SPRN_HID0 - mfspr r0,SPRN_HID0 - mfspr r0,SPRN_HID0 - mfspr r0,SPRN_HID0 - - /* Load up guest SLB entries */ -31: lwz r5,VCPU_SLB_MAX(r4) - cmpwi r5,0 - beq 9f - mtctr r5 - addi r6,r4,VCPU_SLB -1: ld r8,VCPU_SLB_E(r6) - ld r9,VCPU_SLB_V(r6) - slbmte r9,r8 - addi r6,r6,VCPU_SLB_SIZE - bdnz 1b -9: - - /* Restore state of CTRL run bit; assume 1 on entry */ - lwz r5,VCPU_CTRL(r4) - andi. r5,r5,1 - bne 4f - mfspr r6,SPRN_CTRLF - clrrdi r6,r6,1 - mtspr SPRN_CTRLT,r6 -4: - ld r6, VCPU_CTR(r4) - lwz r7, VCPU_XER(r4) - - mtctr r6 - mtxer r7 - - /* Move SRR0 and SRR1 into the respective regs */ - ld r6, VCPU_SRR0(r4) - ld r7, VCPU_SRR1(r4) - mtspr SPRN_SRR0, r6 - mtspr SPRN_SRR1, r7 - - ld r10, VCPU_PC(r4) - - ld r11, VCPU_MSR(r4) /* r10 = vcpu->arch.msr & ~MSR_HV */ - rldicl r11, r11, 63 - MSR_HV_LG, 1 - rotldi r11, r11, 1 + MSR_HV_LG - ori r11, r11, MSR_ME - -fast_guest_return: - mtspr SPRN_HSRR0,r10 - mtspr SPRN_HSRR1,r11 - - /* Activate guest mode, so faults get handled by KVM */ - li r9, KVM_GUEST_MODE_GUEST - stb r9, HSTATE_IN_GUEST(r13) - - /* Enter guest */ - - ld r5, VCPU_LR(r4) - lwz r6, VCPU_CR(r4) - mtlr r5 - mtcr r6 - - ld r0, VCPU_GPR(r0)(r4) - ld r1, VCPU_GPR(r1)(r4) - ld r2, VCPU_GPR(r2)(r4) - ld r3, VCPU_GPR(r3)(r4) - ld r5, VCPU_GPR(r5)(r4) - ld r6, VCPU_GPR(r6)(r4) - ld r7, VCPU_GPR(r7)(r4) - ld r8, VCPU_GPR(r8)(r4) - ld r9, VCPU_GPR(r9)(r4) - ld r10, VCPU_GPR(r10)(r4) - ld r11, VCPU_GPR(r11)(r4) - ld r12, VCPU_GPR(r12)(r4) - ld r13, VCPU_GPR(r13)(r4) - - ld r4, VCPU_GPR(r4)(r4) - - hrfid - b . - -/****************************************************************************** - * * - * Exit code * - * * - *****************************************************************************/ - -/* - * We come here from the first-level interrupt handlers. - */ - .globl kvmppc_interrupt -kvmppc_interrupt: - /* - * Register contents: - * R12 = interrupt vector - * R13 = PACA - * guest CR, R12 saved in shadow VCPU SCRATCH1/0 - * guest R13 saved in SPRN_SCRATCH0 - */ - /* abuse host_r2 as third scratch area; we get r2 from PACATOC(r13) */ - std r9, HSTATE_HOST_R2(r13) - ld r9, HSTATE_KVM_VCPU(r13) - - /* Save registers */ - - std r0, VCPU_GPR(r0)(r9) - std r1, VCPU_GPR(r1)(r9) - std r2, VCPU_GPR(r2)(r9) - std r3, VCPU_GPR(r3)(r9) - std r4, VCPU_GPR(r4)(r9) - std r5, VCPU_GPR(r5)(r9) - std r6, VCPU_GPR(r6)(r9) - std r7, VCPU_GPR(r7)(r9) - std r8, VCPU_GPR(r8)(r9) - ld r0, HSTATE_HOST_R2(r13) - std r0, VCPU_GPR(r9)(r9) - std r10, VCPU_GPR(r10)(r9) - std r11, VCPU_GPR(r11)(r9) - ld r3, HSTATE_SCRATCH0(r13) - lwz r4, HSTATE_SCRATCH1(r13) - std r3, VCPU_GPR(r12)(r9) - stw r4, VCPU_CR(r9) - - /* Restore R1/R2 so we can handle faults */ - ld r1, HSTATE_HOST_R1(r13) - ld r2, PACATOC(r13) - - mfspr r10, SPRN_SRR0 - mfspr r11, SPRN_SRR1 - std r10, VCPU_SRR0(r9) - std r11, VCPU_SRR1(r9) - andi. r0, r12, 2 /* need to read HSRR0/1? */ - beq 1f - mfspr r10, SPRN_HSRR0 - mfspr r11, SPRN_HSRR1 - clrrdi r12, r12, 2 -1: std r10, VCPU_PC(r9) - std r11, VCPU_MSR(r9) - - GET_SCRATCH0(r3) - mflr r4 - std r3, VCPU_GPR(r13)(r9) - std r4, VCPU_LR(r9) - - /* Unset guest mode */ - li r0, KVM_GUEST_MODE_NONE - stb r0, HSTATE_IN_GUEST(r13) - - stw r12,VCPU_TRAP(r9) - - /* See if this is a leftover HDEC interrupt */ - cmpwi r12,BOOK3S_INTERRUPT_HV_DECREMENTER - bne 2f - mfspr r3,SPRN_HDEC - cmpwi r3,0 - bge ignore_hdec -2: - /* See if this is something we can handle in real mode */ - cmpwi r12,BOOK3S_INTERRUPT_SYSCALL - beq hcall_try_real_mode -hcall_real_cont: - - /* Check for mediated interrupts (could be done earlier really ...) */ -BEGIN_FTR_SECTION - cmpwi r12,BOOK3S_INTERRUPT_EXTERNAL - bne+ 1f - ld r5,VCPU_KVM(r9) - ld r5,KVM_LPCR(r5) - andi. r0,r11,MSR_EE - beq 1f - andi. r0,r5,LPCR_MER - bne bounce_ext_interrupt -1: -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) - - /* Save DEC */ - mfspr r5,SPRN_DEC - mftb r6 - extsw r5,r5 - add r5,r5,r6 - std r5,VCPU_DEC_EXPIRES(r9) - - /* Save HEIR (HV emulation assist reg) in last_inst - if this is an HEI (HV emulation interrupt, e40) */ - li r3,-1 -BEGIN_FTR_SECTION - cmpwi r12,BOOK3S_INTERRUPT_H_EMUL_ASSIST - bne 11f - mfspr r3,SPRN_HEIR -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) -11: stw r3,VCPU_LAST_INST(r9) - - /* Save more register state */ - mfxer r5 - mfdar r6 - mfdsisr r7 - mfctr r8 - - stw r5, VCPU_XER(r9) - std r6, VCPU_DAR(r9) - stw r7, VCPU_DSISR(r9) - std r8, VCPU_CTR(r9) - /* grab HDAR & HDSISR if HV data storage interrupt (HDSI) */ -BEGIN_FTR_SECTION - cmpwi r12,BOOK3S_INTERRUPT_H_DATA_STORAGE - beq 6f -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) -7: std r6, VCPU_FAULT_DAR(r9) - stw r7, VCPU_FAULT_DSISR(r9) - - /* Save guest CTRL register, set runlatch to 1 */ - mfspr r6,SPRN_CTRLF - stw r6,VCPU_CTRL(r9) - andi. r0,r6,1 - bne 4f - ori r6,r6,1 - mtspr SPRN_CTRLT,r6 -4: - /* Read the guest SLB and save it away */ - lwz r0,VCPU_SLB_NR(r9) /* number of entries in SLB */ - mtctr r0 - li r6,0 - addi r7,r9,VCPU_SLB - li r5,0 -1: slbmfee r8,r6 - andis. r0,r8,SLB_ESID_V@h - beq 2f - add r8,r8,r6 /* put index in */ - slbmfev r3,r6 - std r8,VCPU_SLB_E(r7) - std r3,VCPU_SLB_V(r7) - addi r7,r7,VCPU_SLB_SIZE - addi r5,r5,1 -2: addi r6,r6,1 - bdnz 1b - stw r5,VCPU_SLB_MAX(r9) - - /* - * Save the guest PURR/SPURR - */ -BEGIN_FTR_SECTION - mfspr r5,SPRN_PURR - mfspr r6,SPRN_SPURR - ld r7,VCPU_PURR(r9) - ld r8,VCPU_SPURR(r9) - std r5,VCPU_PURR(r9) - std r6,VCPU_SPURR(r9) - subf r5,r7,r5 - subf r6,r8,r6 - - /* - * Restore host PURR/SPURR and add guest times - * so that the time in the guest gets accounted. - */ - ld r3,HSTATE_PURR(r13) - ld r4,HSTATE_SPURR(r13) - add r3,r3,r5 - add r4,r4,r6 - mtspr SPRN_PURR,r3 - mtspr SPRN_SPURR,r4 -END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_201) - - /* Clear out SLB */ - li r5,0 - slbmte r5,r5 - slbia - ptesync - -hdec_soon: -BEGIN_FTR_SECTION - b 32f -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) - /* - * POWER7 guest -> host partition switch code. - * We don't have to lock against tlbies but we do - * have to coordinate the hardware threads. - */ - /* Increment the threads-exiting-guest count in the 0xff00 - bits of vcore->entry_exit_count */ - lwsync - ld r5,HSTATE_KVM_VCORE(r13) - addi r6,r5,VCORE_ENTRY_EXIT -41: lwarx r3,0,r6 - addi r0,r3,0x100 - stwcx. r0,0,r6 - bne 41b - - /* - * At this point we have an interrupt that we have to pass - * up to the kernel or qemu; we can't handle it in real mode. - * Thus we have to do a partition switch, so we have to - * collect the other threads, if we are the first thread - * to take an interrupt. To do this, we set the HDEC to 0, - * which causes an HDEC interrupt in all threads within 2ns - * because the HDEC register is shared between all 4 threads. - * However, we don't need to bother if this is an HDEC - * interrupt, since the other threads will already be on their - * way here in that case. - */ - cmpwi r12,BOOK3S_INTERRUPT_HV_DECREMENTER - beq 40f - cmpwi r3,0x100 /* Are we the first here? */ - bge 40f - cmpwi r3,1 - ble 40f - li r0,0 - mtspr SPRN_HDEC,r0 -40: - - /* Secondary threads wait for primary to do partition switch */ - ld r4,VCPU_KVM(r9) /* pointer to struct kvm */ - ld r5,HSTATE_KVM_VCORE(r13) - lwz r3,VCPU_PTID(r9) - cmpwi r3,0 - beq 15f - HMT_LOW -13: lbz r3,VCORE_IN_GUEST(r5) - cmpwi r3,0 - bne 13b - HMT_MEDIUM - b 16f - - /* Primary thread waits for all the secondaries to exit guest */ -15: lwz r3,VCORE_ENTRY_EXIT(r5) - srwi r0,r3,8 - clrldi r3,r3,56 - cmpw r3,r0 - bne 15b - isync - - /* Primary thread switches back to host partition */ - ld r6,KVM_HOST_SDR1(r4) - lwz r7,KVM_HOST_LPID(r4) - li r8,LPID_RSVD /* switch to reserved LPID */ - mtspr SPRN_LPID,r8 - ptesync - mtspr SPRN_SDR1,r6 /* switch to partition page table */ - mtspr SPRN_LPID,r7 - isync - li r0,0 - stb r0,VCORE_IN_GUEST(r5) - lis r8,0x7fff /* MAX_INT@h */ - mtspr SPRN_HDEC,r8 - -16: ld r8,KVM_HOST_LPCR(r4) - mtspr SPRN_LPCR,r8 - isync - b 33f - - /* - * PPC970 guest -> host partition switch code. - * We have to lock against concurrent tlbies, and - * we have to flush the whole TLB. - */ -32: ld r4,VCPU_KVM(r9) /* pointer to struct kvm */ - - /* Take the guest's tlbie_lock */ - lwz r8,PACA_LOCK_TOKEN(r13) - addi r3,r4,KVM_TLBIE_LOCK -24: lwarx r0,0,r3 - cmpwi r0,0 - bne 24b - stwcx. r8,0,r3 - bne 24b - isync - - ld r7,KVM_HOST_LPCR(r4) /* use kvm->arch.host_lpcr for HID4 */ - li r0,0x18f - rotldi r0,r0,HID4_LPID5_SH /* all lpid bits in HID4 = 1 */ - or r0,r7,r0 - ptesync - sync - mtspr SPRN_HID4,r0 /* switch to reserved LPID */ - isync - li r0,0 - stw r0,0(r3) /* drop guest tlbie_lock */ - - /* invalidate the whole TLB */ - li r0,256 - mtctr r0 - li r6,0 -25: tlbiel r6 - addi r6,r6,0x1000 - bdnz 25b - ptesync - - /* take native_tlbie_lock */ - ld r3,toc_tlbie_lock@toc(2) -24: lwarx r0,0,r3 - cmpwi r0,0 - bne 24b - stwcx. r8,0,r3 - bne 24b - isync - - ld r6,KVM_HOST_SDR1(r4) - mtspr SPRN_SDR1,r6 /* switch to host page table */ - - /* Set up host HID4 value */ - sync - mtspr SPRN_HID4,r7 - isync - li r0,0 - stw r0,0(r3) /* drop native_tlbie_lock */ - - lis r8,0x7fff /* MAX_INT@h */ - mtspr SPRN_HDEC,r8 - - /* Disable HDEC interrupts */ - mfspr r0,SPRN_HID0 - li r3,0 - rldimi r0,r3, HID0_HDICE_SH, 64-HID0_HDICE_SH-1 - sync - mtspr SPRN_HID0,r0 - mfspr r0,SPRN_HID0 - mfspr r0,SPRN_HID0 - mfspr r0,SPRN_HID0 - mfspr r0,SPRN_HID0 - mfspr r0,SPRN_HID0 - mfspr r0,SPRN_HID0 - - /* load host SLB entries */ -33: ld r8,PACA_SLBSHADOWPTR(r13) - - .rept SLB_NUM_BOLTED - ld r5,SLBSHADOW_SAVEAREA(r8) - ld r6,SLBSHADOW_SAVEAREA+8(r8) - andis. r7,r5,SLB_ESID_V@h - beq 1f - slbmte r6,r5 -1: addi r8,r8,16 - .endr - - /* Save and reset AMR and UAMOR before turning on the MMU */ -BEGIN_FTR_SECTION - mfspr r5,SPRN_AMR - mfspr r6,SPRN_UAMOR - std r5,VCPU_AMR(r9) - std r6,VCPU_UAMOR(r9) - li r6,0 - mtspr SPRN_AMR,r6 -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) - - /* Restore host DABR and DABRX */ - ld r5,HSTATE_DABR(r13) - li r6,7 - mtspr SPRN_DABR,r5 - mtspr SPRN_DABRX,r6 - - /* Switch DSCR back to host value */ -BEGIN_FTR_SECTION - mfspr r8, SPRN_DSCR - ld r7, HSTATE_DSCR(r13) - std r8, VCPU_DSCR(r7) - mtspr SPRN_DSCR, r7 -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) - - /* Save non-volatile GPRs */ - std r14, VCPU_GPR(r14)(r9) - std r15, VCPU_GPR(r15)(r9) - std r16, VCPU_GPR(r16)(r9) - std r17, VCPU_GPR(r17)(r9) - std r18, VCPU_GPR(r18)(r9) - std r19, VCPU_GPR(r19)(r9) - std r20, VCPU_GPR(r20)(r9) - std r21, VCPU_GPR(r21)(r9) - std r22, VCPU_GPR(r22)(r9) - std r23, VCPU_GPR(r23)(r9) - std r24, VCPU_GPR(r24)(r9) - std r25, VCPU_GPR(r25)(r9) - std r26, VCPU_GPR(r26)(r9) - std r27, VCPU_GPR(r27)(r9) - std r28, VCPU_GPR(r28)(r9) - std r29, VCPU_GPR(r29)(r9) - std r30, VCPU_GPR(r30)(r9) - std r31, VCPU_GPR(r31)(r9) - - /* Save SPRGs */ - mfspr r3, SPRN_SPRG0 - mfspr r4, SPRN_SPRG1 - mfspr r5, SPRN_SPRG2 - mfspr r6, SPRN_SPRG3 - std r3, VCPU_SPRG0(r9) - std r4, VCPU_SPRG1(r9) - std r5, VCPU_SPRG2(r9) - std r6, VCPU_SPRG3(r9) - - /* Increment yield count if they have a VPA */ - ld r8, VCPU_VPA(r9) /* do they have a VPA? */ - cmpdi r8, 0 - beq 25f - lwz r3, LPPACA_YIELDCOUNT(r8) - addi r3, r3, 1 - stw r3, LPPACA_YIELDCOUNT(r8) -25: - /* Save PMU registers if requested */ - /* r8 and cr0.eq are live here */ - li r3, 1 - sldi r3, r3, 31 /* MMCR0_FC (freeze counters) bit */ - mfspr r4, SPRN_MMCR0 /* save MMCR0 */ - mtspr SPRN_MMCR0, r3 /* freeze all counters, disable ints */ - isync - beq 21f /* if no VPA, save PMU stuff anyway */ - lbz r7, LPPACA_PMCINUSE(r8) - cmpwi r7, 0 /* did they ask for PMU stuff to be saved? */ - bne 21f - std r3, VCPU_MMCR(r9) /* if not, set saved MMCR0 to FC */ - b 22f -21: mfspr r5, SPRN_MMCR1 - mfspr r6, SPRN_MMCRA - std r4, VCPU_MMCR(r9) - std r5, VCPU_MMCR + 8(r9) - std r6, VCPU_MMCR + 16(r9) - mfspr r3, SPRN_PMC1 - mfspr r4, SPRN_PMC2 - mfspr r5, SPRN_PMC3 - mfspr r6, SPRN_PMC4 - mfspr r7, SPRN_PMC5 - mfspr r8, SPRN_PMC6 -BEGIN_FTR_SECTION - mfspr r10, SPRN_PMC7 - mfspr r11, SPRN_PMC8 -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) - stw r3, VCPU_PMC(r9) - stw r4, VCPU_PMC + 4(r9) - stw r5, VCPU_PMC + 8(r9) - stw r6, VCPU_PMC + 12(r9) - stw r7, VCPU_PMC + 16(r9) - stw r8, VCPU_PMC + 20(r9) -BEGIN_FTR_SECTION - stw r10, VCPU_PMC + 24(r9) - stw r11, VCPU_PMC + 28(r9) -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) -22: - /* save FP state */ - mr r3, r9 - bl .kvmppc_save_fp - - /* Secondary threads go off to take a nap on POWER7 */ -BEGIN_FTR_SECTION - lwz r0,VCPU_PTID(r3) - cmpwi r0,0 - bne secondary_nap -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) - - /* - * Reload DEC. HDEC interrupts were disabled when - * we reloaded the host's LPCR value. - */ - ld r3, HSTATE_DECEXP(r13) - mftb r4 - subf r4, r4, r3 - mtspr SPRN_DEC, r4 - - /* Reload the host's PMU registers */ - ld r3, PACALPPACAPTR(r13) /* is the host using the PMU? */ - lbz r4, LPPACA_PMCINUSE(r3) - cmpwi r4, 0 - beq 23f /* skip if not */ - lwz r3, HSTATE_PMC(r13) - lwz r4, HSTATE_PMC + 4(r13) - lwz r5, HSTATE_PMC + 8(r13) - lwz r6, HSTATE_PMC + 12(r13) - lwz r8, HSTATE_PMC + 16(r13) - lwz r9, HSTATE_PMC + 20(r13) -BEGIN_FTR_SECTION - lwz r10, HSTATE_PMC + 24(r13) - lwz r11, HSTATE_PMC + 28(r13) -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) - mtspr SPRN_PMC1, r3 - mtspr SPRN_PMC2, r4 - mtspr SPRN_PMC3, r5 - mtspr SPRN_PMC4, r6 - mtspr SPRN_PMC5, r8 - mtspr SPRN_PMC6, r9 -BEGIN_FTR_SECTION - mtspr SPRN_PMC7, r10 - mtspr SPRN_PMC8, r11 -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) - ld r3, HSTATE_MMCR(r13) - ld r4, HSTATE_MMCR + 8(r13) - ld r5, HSTATE_MMCR + 16(r13) - mtspr SPRN_MMCR1, r4 - mtspr SPRN_MMCRA, r5 - mtspr SPRN_MMCR0, r3 - isync -23: - /* - * For external and machine check interrupts, we need - * to call the Linux handler to process the interrupt. - * We do that by jumping to the interrupt vector address - * which we have in r12. The [h]rfid at the end of the - * handler will return to the book3s_hv_interrupts.S code. - * For other interrupts we do the rfid to get back - * to the book3s_interrupts.S code here. - */ - ld r8, HSTATE_VMHANDLER(r13) - ld r7, HSTATE_HOST_MSR(r13) - - cmpwi r12, BOOK3S_INTERRUPT_EXTERNAL - beq 11f - cmpwi r12, BOOK3S_INTERRUPT_MACHINE_CHECK - - /* RFI into the highmem handler, or branch to interrupt handler */ -12: mfmsr r6 - mtctr r12 - li r0, MSR_RI - andc r6, r6, r0 - mtmsrd r6, 1 /* Clear RI in MSR */ - mtsrr0 r8 - mtsrr1 r7 - beqctr - RFI - -11: -BEGIN_FTR_SECTION - b 12b -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) - mtspr SPRN_HSRR0, r8 - mtspr SPRN_HSRR1, r7 - ba 0x500 - -6: mfspr r6,SPRN_HDAR - mfspr r7,SPRN_HDSISR - b 7b - -/* - * Try to handle an hcall in real mode. - * Returns to the guest if we handle it, or continues on up to - * the kernel if we can't (i.e. if we don't have a handler for - * it, or if the handler returns H_TOO_HARD). - */ - .globl hcall_try_real_mode -hcall_try_real_mode: - ld r3,VCPU_GPR(r3)(r9) - andi. r0,r11,MSR_PR - bne hcall_real_cont - clrrdi r3,r3,2 - cmpldi r3,hcall_real_table_end - hcall_real_table - bge hcall_real_cont - LOAD_REG_ADDR(r4, hcall_real_table) - lwzx r3,r3,r4 - cmpwi r3,0 - beq hcall_real_cont - add r3,r3,r4 - mtctr r3 - mr r3,r9 /* get vcpu pointer */ - ld r4,VCPU_GPR(r4)(r9) - bctrl - cmpdi r3,H_TOO_HARD - beq hcall_real_fallback - ld r4,HSTATE_KVM_VCPU(r13) - std r3,VCPU_GPR(r3)(r4) - ld r10,VCPU_PC(r4) - ld r11,VCPU_MSR(r4) - b fast_guest_return - - /* We've attempted a real mode hcall, but it's punted it back - * to userspace. We need to restore some clobbered volatiles - * before resuming the pass-it-to-qemu path */ -hcall_real_fallback: - li r12,BOOK3S_INTERRUPT_SYSCALL - ld r9, HSTATE_KVM_VCPU(r13) - ld r11, VCPU_MSR(r9) - - b hcall_real_cont - - .globl hcall_real_table -hcall_real_table: - .long 0 /* 0 - unused */ - .long .kvmppc_h_remove - hcall_real_table - .long .kvmppc_h_enter - hcall_real_table - .long .kvmppc_h_read - hcall_real_table - .long 0 /* 0x10 - H_CLEAR_MOD */ - .long 0 /* 0x14 - H_CLEAR_REF */ - .long .kvmppc_h_protect - hcall_real_table - .long 0 /* 0x1c - H_GET_TCE */ - .long .kvmppc_h_put_tce - hcall_real_table - .long 0 /* 0x24 - H_SET_SPRG0 */ - .long .kvmppc_h_set_dabr - hcall_real_table - .long 0 /* 0x2c */ - .long 0 /* 0x30 */ - .long 0 /* 0x34 */ - .long 0 /* 0x38 */ - .long 0 /* 0x3c */ - .long 0 /* 0x40 */ - .long 0 /* 0x44 */ - .long 0 /* 0x48 */ - .long 0 /* 0x4c */ - .long 0 /* 0x50 */ - .long 0 /* 0x54 */ - .long 0 /* 0x58 */ - .long 0 /* 0x5c */ - .long 0 /* 0x60 */ - .long 0 /* 0x64 */ - .long 0 /* 0x68 */ - .long 0 /* 0x6c */ - .long 0 /* 0x70 */ - .long 0 /* 0x74 */ - .long 0 /* 0x78 */ - .long 0 /* 0x7c */ - .long 0 /* 0x80 */ - .long 0 /* 0x84 */ - .long 0 /* 0x88 */ - .long 0 /* 0x8c */ - .long 0 /* 0x90 */ - .long 0 /* 0x94 */ - .long 0 /* 0x98 */ - .long 0 /* 0x9c */ - .long 0 /* 0xa0 */ - .long 0 /* 0xa4 */ - .long 0 /* 0xa8 */ - .long 0 /* 0xac */ - .long 0 /* 0xb0 */ - .long 0 /* 0xb4 */ - .long 0 /* 0xb8 */ - .long 0 /* 0xbc */ - .long 0 /* 0xc0 */ - .long 0 /* 0xc4 */ - .long 0 /* 0xc8 */ - .long 0 /* 0xcc */ - .long 0 /* 0xd0 */ - .long 0 /* 0xd4 */ - .long 0 /* 0xd8 */ - .long 0 /* 0xdc */ - .long 0 /* 0xe0 */ - .long 0 /* 0xe4 */ - .long 0 /* 0xe8 */ - .long 0 /* 0xec */ - .long 0 /* 0xf0 */ - .long 0 /* 0xf4 */ - .long 0 /* 0xf8 */ - .long 0 /* 0xfc */ - .long 0 /* 0x100 */ - .long 0 /* 0x104 */ - .long 0 /* 0x108 */ - .long 0 /* 0x10c */ - .long 0 /* 0x110 */ - .long 0 /* 0x114 */ - .long 0 /* 0x118 */ - .long 0 /* 0x11c */ - .long 0 /* 0x120 */ - .long .kvmppc_h_bulk_remove - hcall_real_table -hcall_real_table_end: - -ignore_hdec: - mr r4,r9 - b fast_guest_return - -bounce_ext_interrupt: - mr r4,r9 - mtspr SPRN_SRR0,r10 - mtspr SPRN_SRR1,r11 - li r10,BOOK3S_INTERRUPT_EXTERNAL - LOAD_REG_IMMEDIATE(r11,MSR_SF | MSR_ME); - b fast_guest_return - -_GLOBAL(kvmppc_h_set_dabr) - std r4,VCPU_DABR(r3) - mtspr SPRN_DABR,r4 - li r3,0 - blr - -secondary_too_late: - ld r5,HSTATE_KVM_VCORE(r13) - HMT_LOW -13: lbz r3,VCORE_IN_GUEST(r5) - cmpwi r3,0 - bne 13b - HMT_MEDIUM - ld r11,PACA_SLBSHADOWPTR(r13) - - .rept SLB_NUM_BOLTED - ld r5,SLBSHADOW_SAVEAREA(r11) - ld r6,SLBSHADOW_SAVEAREA+8(r11) - andis. r7,r5,SLB_ESID_V@h - beq 1f - slbmte r6,r5 -1: addi r11,r11,16 - .endr - b 50f - -secondary_nap: - /* Clear any pending IPI */ -50: ld r5, HSTATE_XICS_PHYS(r13) - li r0, 0xff - li r6, XICS_QIRR - stbcix r0, r5, r6 - - /* increment the nap count and then go to nap mode */ - ld r4, HSTATE_KVM_VCORE(r13) - addi r4, r4, VCORE_NAP_COUNT - lwsync /* make previous updates visible */ -51: lwarx r3, 0, r4 - addi r3, r3, 1 - stwcx. r3, 0, r4 - bne 51b - isync - - mfspr r4, SPRN_LPCR - li r0, LPCR_PECE - andc r4, r4, r0 - ori r4, r4, LPCR_PECE0 /* exit nap on interrupt */ - mtspr SPRN_LPCR, r4 - li r0, 0 - std r0, HSTATE_SCRATCH0(r13) - ptesync - ld r0, HSTATE_SCRATCH0(r13) -1: cmpd r0, r0 - bne 1b - nap - b . - -/* - * Save away FP, VMX and VSX registers. - * r3 = vcpu pointer - */ -_GLOBAL(kvmppc_save_fp) - mfmsr r9 - ori r8,r9,MSR_FP -#ifdef CONFIG_ALTIVEC -BEGIN_FTR_SECTION - oris r8,r8,MSR_VEC@h -END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) -#endif -#ifdef CONFIG_VSX -BEGIN_FTR_SECTION - oris r8,r8,MSR_VSX@h -END_FTR_SECTION_IFSET(CPU_FTR_VSX) -#endif - mtmsrd r8 - isync -#ifdef CONFIG_VSX -BEGIN_FTR_SECTION - reg = 0 - .rept 32 - li r6,reg*16+VCPU_VSRS - stxvd2x reg,r6,r3 - reg = reg + 1 - .endr -FTR_SECTION_ELSE -#endif - reg = 0 - .rept 32 - stfd reg,reg*8+VCPU_FPRS(r3) - reg = reg + 1 - .endr -#ifdef CONFIG_VSX -ALT_FTR_SECTION_END_IFSET(CPU_FTR_VSX) -#endif - mffs fr0 - stfd fr0,VCPU_FPSCR(r3) - -#ifdef CONFIG_ALTIVEC -BEGIN_FTR_SECTION - reg = 0 - .rept 32 - li r6,reg*16+VCPU_VRS - stvx reg,r6,r3 - reg = reg + 1 - .endr - mfvscr vr0 - li r6,VCPU_VSCR - stvx vr0,r6,r3 -END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) -#endif - mfspr r6,SPRN_VRSAVE - stw r6,VCPU_VRSAVE(r3) - mtmsrd r9 - isync - blr - -/* - * Load up FP, VMX and VSX registers - * r4 = vcpu pointer - */ - .globl kvmppc_load_fp -kvmppc_load_fp: - mfmsr r9 - ori r8,r9,MSR_FP -#ifdef CONFIG_ALTIVEC -BEGIN_FTR_SECTION - oris r8,r8,MSR_VEC@h -END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) -#endif -#ifdef CONFIG_VSX -BEGIN_FTR_SECTION - oris r8,r8,MSR_VSX@h -END_FTR_SECTION_IFSET(CPU_FTR_VSX) -#endif - mtmsrd r8 - isync - lfd fr0,VCPU_FPSCR(r4) - MTFSF_L(fr0) -#ifdef CONFIG_VSX -BEGIN_FTR_SECTION - reg = 0 - .rept 32 - li r7,reg*16+VCPU_VSRS - lxvd2x reg,r7,r4 - reg = reg + 1 - .endr -FTR_SECTION_ELSE -#endif - reg = 0 - .rept 32 - lfd reg,reg*8+VCPU_FPRS(r4) - reg = reg + 1 - .endr -#ifdef CONFIG_VSX -ALT_FTR_SECTION_END_IFSET(CPU_FTR_VSX) -#endif - -#ifdef CONFIG_ALTIVEC -BEGIN_FTR_SECTION - li r7,VCPU_VSCR - lvx vr0,r7,r4 - mtvscr vr0 - reg = 0 - .rept 32 - li r7,reg*16+VCPU_VRS - lvx reg,r7,r4 - reg = reg + 1 - .endr -END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) -#endif - lwz r7,VCPU_VRSAVE(r4) - mtspr SPRN_VRSAVE,r7 - blr diff --git a/trunk/arch/powerpc/kvm/book3s_interrupts.S b/trunk/arch/powerpc/kvm/book3s_interrupts.S index c54b0e30cf3f..2f0bc928b08a 100644 --- a/trunk/arch/powerpc/kvm/book3s_interrupts.S +++ b/trunk/arch/powerpc/kvm/book3s_interrupts.S @@ -29,7 +29,8 @@ #define ULONG_SIZE 8 #define FUNC(name) GLUE(.,name) -#define GET_SHADOW_VCPU_R13 +#define GET_SHADOW_VCPU(reg) \ + addi reg, r13, PACA_KVM_SVCPU #define DISABLE_INTERRUPTS \ mfmsr r0; \ @@ -42,8 +43,8 @@ #define ULONG_SIZE 4 #define FUNC(name) name -#define GET_SHADOW_VCPU_R13 \ - lwz r13, (THREAD + THREAD_KVM_SVCPU)(r2) +#define GET_SHADOW_VCPU(reg) \ + lwz reg, (THREAD + THREAD_KVM_SVCPU)(r2) #define DISABLE_INTERRUPTS \ mfmsr r0; \ @@ -84,7 +85,7 @@ * r3: kvm_run pointer * r4: vcpu pointer */ -_GLOBAL(__kvmppc_vcpu_run) +_GLOBAL(__kvmppc_vcpu_entry) kvm_start_entry: /* Write correct stack frame */ @@ -106,11 +107,17 @@ kvm_start_entry: /* Load non-volatile guest state from the vcpu */ VCPU_LOAD_NVGPRS(r4) -kvm_start_lightweight: + GET_SHADOW_VCPU(r5) + + /* Save R1/R2 in the PACA */ + PPC_STL r1, SVCPU_HOST_R1(r5) + PPC_STL r2, SVCPU_HOST_R2(r5) - GET_SHADOW_VCPU_R13 + /* XXX swap in/out on load? */ PPC_LL r3, VCPU_HIGHMEM_HANDLER(r4) - PPC_STL r3, HSTATE_VMHANDLER(r13) + PPC_STL r3, SVCPU_VMHANDLER(r5) + +kvm_start_lightweight: PPC_LL r10, VCPU_SHADOW_MSR(r4) /* r10 = vcpu->arch.shadow_msr */ diff --git a/trunk/arch/powerpc/kvm/book3s_mmu_hpte.c b/trunk/arch/powerpc/kvm/book3s_mmu_hpte.c index 41cb0017e757..79751d8dd131 100644 --- a/trunk/arch/powerpc/kvm/book3s_mmu_hpte.c +++ b/trunk/arch/powerpc/kvm/book3s_mmu_hpte.c @@ -21,6 +21,7 @@ #include #include #include +#include "trace.h" #include #include @@ -28,8 +29,6 @@ #include #include -#include "trace.h" - #define PTE_SIZE 12 static struct kmem_cache *hpte_cache; @@ -59,31 +58,30 @@ static inline u64 kvmppc_mmu_hash_vpte_long(u64 vpage) void kvmppc_mmu_hpte_cache_map(struct kvm_vcpu *vcpu, struct hpte_cache *pte) { u64 index; - struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu); trace_kvm_book3s_mmu_map(pte); - spin_lock(&vcpu3s->mmu_lock); + spin_lock(&vcpu->arch.mmu_lock); /* Add to ePTE list */ index = kvmppc_mmu_hash_pte(pte->pte.eaddr); - hlist_add_head_rcu(&pte->list_pte, &vcpu3s->hpte_hash_pte[index]); + hlist_add_head_rcu(&pte->list_pte, &vcpu->arch.hpte_hash_pte[index]); /* Add to ePTE_long list */ index = kvmppc_mmu_hash_pte_long(pte->pte.eaddr); hlist_add_head_rcu(&pte->list_pte_long, - &vcpu3s->hpte_hash_pte_long[index]); + &vcpu->arch.hpte_hash_pte_long[index]); /* Add to vPTE list */ index = kvmppc_mmu_hash_vpte(pte->pte.vpage); - hlist_add_head_rcu(&pte->list_vpte, &vcpu3s->hpte_hash_vpte[index]); + hlist_add_head_rcu(&pte->list_vpte, &vcpu->arch.hpte_hash_vpte[index]); /* Add to vPTE_long list */ index = kvmppc_mmu_hash_vpte_long(pte->pte.vpage); hlist_add_head_rcu(&pte->list_vpte_long, - &vcpu3s->hpte_hash_vpte_long[index]); + &vcpu->arch.hpte_hash_vpte_long[index]); - spin_unlock(&vcpu3s->mmu_lock); + spin_unlock(&vcpu->arch.mmu_lock); } static void free_pte_rcu(struct rcu_head *head) @@ -94,18 +92,16 @@ static void free_pte_rcu(struct rcu_head *head) static void invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte) { - struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu); - trace_kvm_book3s_mmu_invalidate(pte); /* Different for 32 and 64 bit */ kvmppc_mmu_invalidate_pte(vcpu, pte); - spin_lock(&vcpu3s->mmu_lock); + spin_lock(&vcpu->arch.mmu_lock); /* pte already invalidated in between? */ if (hlist_unhashed(&pte->list_pte)) { - spin_unlock(&vcpu3s->mmu_lock); + spin_unlock(&vcpu->arch.mmu_lock); return; } @@ -119,15 +115,14 @@ static void invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte) else kvm_release_pfn_clean(pte->pfn); - spin_unlock(&vcpu3s->mmu_lock); + spin_unlock(&vcpu->arch.mmu_lock); - vcpu3s->hpte_cache_count--; + vcpu->arch.hpte_cache_count--; call_rcu(&pte->rcu_head, free_pte_rcu); } static void kvmppc_mmu_pte_flush_all(struct kvm_vcpu *vcpu) { - struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu); struct hpte_cache *pte; struct hlist_node *node; int i; @@ -135,7 +130,7 @@ static void kvmppc_mmu_pte_flush_all(struct kvm_vcpu *vcpu) rcu_read_lock(); for (i = 0; i < HPTEG_HASH_NUM_VPTE_LONG; i++) { - struct hlist_head *list = &vcpu3s->hpte_hash_vpte_long[i]; + struct hlist_head *list = &vcpu->arch.hpte_hash_vpte_long[i]; hlist_for_each_entry_rcu(pte, node, list, list_vpte_long) invalidate_pte(vcpu, pte); @@ -146,13 +141,12 @@ static void kvmppc_mmu_pte_flush_all(struct kvm_vcpu *vcpu) static void kvmppc_mmu_pte_flush_page(struct kvm_vcpu *vcpu, ulong guest_ea) { - struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu); struct hlist_head *list; struct hlist_node *node; struct hpte_cache *pte; /* Find the list of entries in the map */ - list = &vcpu3s->hpte_hash_pte[kvmppc_mmu_hash_pte(guest_ea)]; + list = &vcpu->arch.hpte_hash_pte[kvmppc_mmu_hash_pte(guest_ea)]; rcu_read_lock(); @@ -166,13 +160,12 @@ static void kvmppc_mmu_pte_flush_page(struct kvm_vcpu *vcpu, ulong guest_ea) static void kvmppc_mmu_pte_flush_long(struct kvm_vcpu *vcpu, ulong guest_ea) { - struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu); struct hlist_head *list; struct hlist_node *node; struct hpte_cache *pte; /* Find the list of entries in the map */ - list = &vcpu3s->hpte_hash_pte_long[ + list = &vcpu->arch.hpte_hash_pte_long[ kvmppc_mmu_hash_pte_long(guest_ea)]; rcu_read_lock(); @@ -210,13 +203,12 @@ void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong guest_ea, ulong ea_mask) /* Flush with mask 0xfffffffff */ static void kvmppc_mmu_pte_vflush_short(struct kvm_vcpu *vcpu, u64 guest_vp) { - struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu); struct hlist_head *list; struct hlist_node *node; struct hpte_cache *pte; u64 vp_mask = 0xfffffffffULL; - list = &vcpu3s->hpte_hash_vpte[kvmppc_mmu_hash_vpte(guest_vp)]; + list = &vcpu->arch.hpte_hash_vpte[kvmppc_mmu_hash_vpte(guest_vp)]; rcu_read_lock(); @@ -231,13 +223,12 @@ static void kvmppc_mmu_pte_vflush_short(struct kvm_vcpu *vcpu, u64 guest_vp) /* Flush with mask 0xffffff000 */ static void kvmppc_mmu_pte_vflush_long(struct kvm_vcpu *vcpu, u64 guest_vp) { - struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu); struct hlist_head *list; struct hlist_node *node; struct hpte_cache *pte; u64 vp_mask = 0xffffff000ULL; - list = &vcpu3s->hpte_hash_vpte_long[ + list = &vcpu->arch.hpte_hash_vpte_long[ kvmppc_mmu_hash_vpte_long(guest_vp)]; rcu_read_lock(); @@ -270,7 +261,6 @@ void kvmppc_mmu_pte_vflush(struct kvm_vcpu *vcpu, u64 guest_vp, u64 vp_mask) void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, ulong pa_start, ulong pa_end) { - struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu); struct hlist_node *node; struct hpte_cache *pte; int i; @@ -280,7 +270,7 @@ void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, ulong pa_start, ulong pa_end) rcu_read_lock(); for (i = 0; i < HPTEG_HASH_NUM_VPTE_LONG; i++) { - struct hlist_head *list = &vcpu3s->hpte_hash_vpte_long[i]; + struct hlist_head *list = &vcpu->arch.hpte_hash_vpte_long[i]; hlist_for_each_entry_rcu(pte, node, list, list_vpte_long) if ((pte->pte.raddr >= pa_start) && @@ -293,13 +283,12 @@ void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, ulong pa_start, ulong pa_end) struct hpte_cache *kvmppc_mmu_hpte_cache_next(struct kvm_vcpu *vcpu) { - struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu); struct hpte_cache *pte; pte = kmem_cache_zalloc(hpte_cache, GFP_KERNEL); - vcpu3s->hpte_cache_count++; + vcpu->arch.hpte_cache_count++; - if (vcpu3s->hpte_cache_count == HPTEG_CACHE_NUM) + if (vcpu->arch.hpte_cache_count == HPTEG_CACHE_NUM) kvmppc_mmu_pte_flush_all(vcpu); return pte; @@ -320,19 +309,17 @@ static void kvmppc_mmu_hpte_init_hash(struct hlist_head *hash_list, int len) int kvmppc_mmu_hpte_init(struct kvm_vcpu *vcpu) { - struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu); - /* init hpte lookup hashes */ - kvmppc_mmu_hpte_init_hash(vcpu3s->hpte_hash_pte, - ARRAY_SIZE(vcpu3s->hpte_hash_pte)); - kvmppc_mmu_hpte_init_hash(vcpu3s->hpte_hash_pte_long, - ARRAY_SIZE(vcpu3s->hpte_hash_pte_long)); - kvmppc_mmu_hpte_init_hash(vcpu3s->hpte_hash_vpte, - ARRAY_SIZE(vcpu3s->hpte_hash_vpte)); - kvmppc_mmu_hpte_init_hash(vcpu3s->hpte_hash_vpte_long, - ARRAY_SIZE(vcpu3s->hpte_hash_vpte_long)); - - spin_lock_init(&vcpu3s->mmu_lock); + kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_pte, + ARRAY_SIZE(vcpu->arch.hpte_hash_pte)); + kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_pte_long, + ARRAY_SIZE(vcpu->arch.hpte_hash_pte_long)); + kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_vpte, + ARRAY_SIZE(vcpu->arch.hpte_hash_vpte)); + kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_vpte_long, + ARRAY_SIZE(vcpu->arch.hpte_hash_vpte_long)); + + spin_lock_init(&vcpu->arch.mmu_lock); return 0; } diff --git a/trunk/arch/powerpc/kvm/book3s_pr.c b/trunk/arch/powerpc/kvm/book3s_pr.c deleted file mode 100644 index 0c0d3f274437..000000000000 --- a/trunk/arch/powerpc/kvm/book3s_pr.c +++ /dev/null @@ -1,1029 +0,0 @@ -/* - * Copyright (C) 2009. SUSE Linux Products GmbH. All rights reserved. - * - * Authors: - * Alexander Graf - * Kevin Wolf - * Paul Mackerras - * - * Description: - * Functions relating to running KVM on Book 3S processors where - * we don't have access to hypervisor mode, and we run the guest - * in problem state (user mode). - * - * This file is derived from arch/powerpc/kvm/44x.c, - * by Hollis Blanchard . - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, as - * published by the Free Software Foundation. - */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "trace.h" - -/* #define EXIT_DEBUG */ -/* #define DEBUG_EXT */ - -static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr, - ulong msr); - -/* Some compatibility defines */ -#ifdef CONFIG_PPC_BOOK3S_32 -#define MSR_USER32 MSR_USER -#define MSR_USER64 MSR_USER -#define HW_PAGE_SIZE PAGE_SIZE -#endif - -void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu) -{ -#ifdef CONFIG_PPC_BOOK3S_64 - memcpy(to_svcpu(vcpu)->slb, to_book3s(vcpu)->slb_shadow, sizeof(to_svcpu(vcpu)->slb)); - memcpy(&get_paca()->shadow_vcpu, to_book3s(vcpu)->shadow_vcpu, - sizeof(get_paca()->shadow_vcpu)); - to_svcpu(vcpu)->slb_max = to_book3s(vcpu)->slb_shadow_max; -#endif - -#ifdef CONFIG_PPC_BOOK3S_32 - current->thread.kvm_shadow_vcpu = to_book3s(vcpu)->shadow_vcpu; -#endif -} - -void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu) -{ -#ifdef CONFIG_PPC_BOOK3S_64 - memcpy(to_book3s(vcpu)->slb_shadow, to_svcpu(vcpu)->slb, sizeof(to_svcpu(vcpu)->slb)); - memcpy(to_book3s(vcpu)->shadow_vcpu, &get_paca()->shadow_vcpu, - sizeof(get_paca()->shadow_vcpu)); - to_book3s(vcpu)->slb_shadow_max = to_svcpu(vcpu)->slb_max; -#endif - - kvmppc_giveup_ext(vcpu, MSR_FP); - kvmppc_giveup_ext(vcpu, MSR_VEC); - kvmppc_giveup_ext(vcpu, MSR_VSX); -} - -static void kvmppc_recalc_shadow_msr(struct kvm_vcpu *vcpu) -{ - ulong smsr = vcpu->arch.shared->msr; - - /* Guest MSR values */ - smsr &= MSR_FE0 | MSR_FE1 | MSR_SF | MSR_SE | MSR_BE | MSR_DE; - /* Process MSR values */ - smsr |= MSR_ME | MSR_RI | MSR_IR | MSR_DR | MSR_PR | MSR_EE; - /* External providers the guest reserved */ - smsr |= (vcpu->arch.shared->msr & vcpu->arch.guest_owned_ext); - /* 64-bit Process MSR values */ -#ifdef CONFIG_PPC_BOOK3S_64 - smsr |= MSR_ISF | MSR_HV; -#endif - vcpu->arch.shadow_msr = smsr; -} - -void kvmppc_set_msr(struct kvm_vcpu *vcpu, u64 msr) -{ - ulong old_msr = vcpu->arch.shared->msr; - -#ifdef EXIT_DEBUG - printk(KERN_INFO "KVM: Set MSR to 0x%llx\n", msr); -#endif - - msr &= to_book3s(vcpu)->msr_mask; - vcpu->arch.shared->msr = msr; - kvmppc_recalc_shadow_msr(vcpu); - - if (msr & MSR_POW) { - if (!vcpu->arch.pending_exceptions) { - kvm_vcpu_block(vcpu); - vcpu->stat.halt_wakeup++; - - /* Unset POW bit after we woke up */ - msr &= ~MSR_POW; - vcpu->arch.shared->msr = msr; - } - } - - if ((vcpu->arch.shared->msr & (MSR_PR|MSR_IR|MSR_DR)) != - (old_msr & (MSR_PR|MSR_IR|MSR_DR))) { - kvmppc_mmu_flush_segments(vcpu); - kvmppc_mmu_map_segment(vcpu, kvmppc_get_pc(vcpu)); - - /* Preload magic page segment when in kernel mode */ - if (!(msr & MSR_PR) && vcpu->arch.magic_page_pa) { - struct kvm_vcpu_arch *a = &vcpu->arch; - - if (msr & MSR_DR) - kvmppc_mmu_map_segment(vcpu, a->magic_page_ea); - else - kvmppc_mmu_map_segment(vcpu, a->magic_page_pa); - } - } - - /* Preload FPU if it's enabled */ - if (vcpu->arch.shared->msr & MSR_FP) - kvmppc_handle_ext(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL, MSR_FP); -} - -void kvmppc_set_pvr(struct kvm_vcpu *vcpu, u32 pvr) -{ - u32 host_pvr; - - vcpu->arch.hflags &= ~BOOK3S_HFLAG_SLB; - vcpu->arch.pvr = pvr; -#ifdef CONFIG_PPC_BOOK3S_64 - if ((pvr >= 0x330000) && (pvr < 0x70330000)) { - kvmppc_mmu_book3s_64_init(vcpu); - to_book3s(vcpu)->hior = 0xfff00000; - to_book3s(vcpu)->msr_mask = 0xffffffffffffffffULL; - } else -#endif - { - kvmppc_mmu_book3s_32_init(vcpu); - to_book3s(vcpu)->hior = 0; - to_book3s(vcpu)->msr_mask = 0xffffffffULL; - } - - /* If we are in hypervisor level on 970, we can tell the CPU to - * treat DCBZ as 32 bytes store */ - vcpu->arch.hflags &= ~BOOK3S_HFLAG_DCBZ32; - if (vcpu->arch.mmu.is_dcbz32(vcpu) && (mfmsr() & MSR_HV) && - !strcmp(cur_cpu_spec->platform, "ppc970")) - vcpu->arch.hflags |= BOOK3S_HFLAG_DCBZ32; - - /* Cell performs badly if MSR_FEx are set. So let's hope nobody - really needs them in a VM on Cell and force disable them. */ - if (!strcmp(cur_cpu_spec->platform, "ppc-cell-be")) - to_book3s(vcpu)->msr_mask &= ~(MSR_FE0 | MSR_FE1); - -#ifdef CONFIG_PPC_BOOK3S_32 - /* 32 bit Book3S always has 32 byte dcbz */ - vcpu->arch.hflags |= BOOK3S_HFLAG_DCBZ32; -#endif - - /* On some CPUs we can execute paired single operations natively */ - asm ( "mfpvr %0" : "=r"(host_pvr)); - switch (host_pvr) { - case 0x00080200: /* lonestar 2.0 */ - case 0x00088202: /* lonestar 2.2 */ - case 0x70000100: /* gekko 1.0 */ - case 0x00080100: /* gekko 2.0 */ - case 0x00083203: /* gekko 2.3a */ - case 0x00083213: /* gekko 2.3b */ - case 0x00083204: /* gekko 2.4 */ - case 0x00083214: /* gekko 2.4e (8SE) - retail HW2 */ - case 0x00087200: /* broadway */ - vcpu->arch.hflags |= BOOK3S_HFLAG_NATIVE_PS; - /* Enable HID2.PSE - in case we need it later */ - mtspr(SPRN_HID2_GEKKO, mfspr(SPRN_HID2_GEKKO) | (1 << 29)); - } -} - -/* Book3s_32 CPUs always have 32 bytes cache line size, which Linux assumes. To - * make Book3s_32 Linux work on Book3s_64, we have to make sure we trap dcbz to - * emulate 32 bytes dcbz length. - * - * The Book3s_64 inventors also realized this case and implemented a special bit - * in the HID5 register, which is a hypervisor ressource. Thus we can't use it. - * - * My approach here is to patch the dcbz instruction on executing pages. - */ -static void kvmppc_patch_dcbz(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte) -{ - struct page *hpage; - u64 hpage_offset; - u32 *page; - int i; - - hpage = gfn_to_page(vcpu->kvm, pte->raddr >> PAGE_SHIFT); - if (is_error_page(hpage)) { - kvm_release_page_clean(hpage); - return; - } - - hpage_offset = pte->raddr & ~PAGE_MASK; - hpage_offset &= ~0xFFFULL; - hpage_offset /= 4; - - get_page(hpage); - page = kmap_atomic(hpage, KM_USER0); - - /* patch dcbz into reserved instruction, so we trap */ - for (i=hpage_offset; i < hpage_offset + (HW_PAGE_SIZE / 4); i++) - if ((page[i] & 0xff0007ff) == INS_DCBZ) - page[i] &= 0xfffffff7; - - kunmap_atomic(page, KM_USER0); - put_page(hpage); -} - -static int kvmppc_visible_gfn(struct kvm_vcpu *vcpu, gfn_t gfn) -{ - ulong mp_pa = vcpu->arch.magic_page_pa; - - if (unlikely(mp_pa) && - unlikely((mp_pa & KVM_PAM) >> PAGE_SHIFT == gfn)) { - return 1; - } - - return kvm_is_visible_gfn(vcpu->kvm, gfn); -} - -int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu, - ulong eaddr, int vec) -{ - bool data = (vec == BOOK3S_INTERRUPT_DATA_STORAGE); - int r = RESUME_GUEST; - int relocated; - int page_found = 0; - struct kvmppc_pte pte; - bool is_mmio = false; - bool dr = (vcpu->arch.shared->msr & MSR_DR) ? true : false; - bool ir = (vcpu->arch.shared->msr & MSR_IR) ? true : false; - u64 vsid; - - relocated = data ? dr : ir; - - /* Resolve real address if translation turned on */ - if (relocated) { - page_found = vcpu->arch.mmu.xlate(vcpu, eaddr, &pte, data); - } else { - pte.may_execute = true; - pte.may_read = true; - pte.may_write = true; - pte.raddr = eaddr & KVM_PAM; - pte.eaddr = eaddr; - pte.vpage = eaddr >> 12; - } - - switch (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) { - case 0: - pte.vpage |= ((u64)VSID_REAL << (SID_SHIFT - 12)); - break; - case MSR_DR: - case MSR_IR: - vcpu->arch.mmu.esid_to_vsid(vcpu, eaddr >> SID_SHIFT, &vsid); - - if ((vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) == MSR_DR) - pte.vpage |= ((u64)VSID_REAL_DR << (SID_SHIFT - 12)); - else - pte.vpage |= ((u64)VSID_REAL_IR << (SID_SHIFT - 12)); - pte.vpage |= vsid; - - if (vsid == -1) - page_found = -EINVAL; - break; - } - - if (vcpu->arch.mmu.is_dcbz32(vcpu) && - (!(vcpu->arch.hflags & BOOK3S_HFLAG_DCBZ32))) { - /* - * If we do the dcbz hack, we have to NX on every execution, - * so we can patch the executing code. This renders our guest - * NX-less. - */ - pte.may_execute = !data; - } - - if (page_found == -ENOENT) { - /* Page not found in guest PTE entries */ - vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu); - vcpu->arch.shared->dsisr = to_svcpu(vcpu)->fault_dsisr; - vcpu->arch.shared->msr |= - (to_svcpu(vcpu)->shadow_srr1 & 0x00000000f8000000ULL); - kvmppc_book3s_queue_irqprio(vcpu, vec); - } else if (page_found == -EPERM) { - /* Storage protection */ - vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu); - vcpu->arch.shared->dsisr = - to_svcpu(vcpu)->fault_dsisr & ~DSISR_NOHPTE; - vcpu->arch.shared->dsisr |= DSISR_PROTFAULT; - vcpu->arch.shared->msr |= - (to_svcpu(vcpu)->shadow_srr1 & 0x00000000f8000000ULL); - kvmppc_book3s_queue_irqprio(vcpu, vec); - } else if (page_found == -EINVAL) { - /* Page not found in guest SLB */ - vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu); - kvmppc_book3s_queue_irqprio(vcpu, vec + 0x80); - } else if (!is_mmio && - kvmppc_visible_gfn(vcpu, pte.raddr >> PAGE_SHIFT)) { - /* The guest's PTE is not mapped yet. Map on the host */ - kvmppc_mmu_map_page(vcpu, &pte); - if (data) - vcpu->stat.sp_storage++; - else if (vcpu->arch.mmu.is_dcbz32(vcpu) && - (!(vcpu->arch.hflags & BOOK3S_HFLAG_DCBZ32))) - kvmppc_patch_dcbz(vcpu, &pte); - } else { - /* MMIO */ - vcpu->stat.mmio_exits++; - vcpu->arch.paddr_accessed = pte.raddr; - r = kvmppc_emulate_mmio(run, vcpu); - if ( r == RESUME_HOST_NV ) - r = RESUME_HOST; - } - - return r; -} - -static inline int get_fpr_index(int i) -{ -#ifdef CONFIG_VSX - i *= 2; -#endif - return i; -} - -/* Give up external provider (FPU, Altivec, VSX) */ -void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr) -{ - struct thread_struct *t = ¤t->thread; - u64 *vcpu_fpr = vcpu->arch.fpr; -#ifdef CONFIG_VSX - u64 *vcpu_vsx = vcpu->arch.vsr; -#endif - u64 *thread_fpr = (u64*)t->fpr; - int i; - - if (!(vcpu->arch.guest_owned_ext & msr)) - return; - -#ifdef DEBUG_EXT - printk(KERN_INFO "Giving up ext 0x%lx\n", msr); -#endif - - switch (msr) { - case MSR_FP: - giveup_fpu(current); - for (i = 0; i < ARRAY_SIZE(vcpu->arch.fpr); i++) - vcpu_fpr[i] = thread_fpr[get_fpr_index(i)]; - - vcpu->arch.fpscr = t->fpscr.val; - break; - case MSR_VEC: -#ifdef CONFIG_ALTIVEC - giveup_altivec(current); - memcpy(vcpu->arch.vr, t->vr, sizeof(vcpu->arch.vr)); - vcpu->arch.vscr = t->vscr; -#endif - break; - case MSR_VSX: -#ifdef CONFIG_VSX - __giveup_vsx(current); - for (i = 0; i < ARRAY_SIZE(vcpu->arch.vsr); i++) - vcpu_vsx[i] = thread_fpr[get_fpr_index(i) + 1]; -#endif - break; - default: - BUG(); - } - - vcpu->arch.guest_owned_ext &= ~msr; - current->thread.regs->msr &= ~msr; - kvmppc_recalc_shadow_msr(vcpu); -} - -static int kvmppc_read_inst(struct kvm_vcpu *vcpu) -{ - ulong srr0 = kvmppc_get_pc(vcpu); - u32 last_inst = kvmppc_get_last_inst(vcpu); - int ret; - - ret = kvmppc_ld(vcpu, &srr0, sizeof(u32), &last_inst, false); - if (ret == -ENOENT) { - ulong msr = vcpu->arch.shared->msr; - - msr = kvmppc_set_field(msr, 33, 33, 1); - msr = kvmppc_set_field(msr, 34, 36, 0); - vcpu->arch.shared->msr = kvmppc_set_field(msr, 42, 47, 0); - kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_INST_STORAGE); - return EMULATE_AGAIN; - } - - return EMULATE_DONE; -} - -static int kvmppc_check_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr) -{ - - /* Need to do paired single emulation? */ - if (!(vcpu->arch.hflags & BOOK3S_HFLAG_PAIRED_SINGLE)) - return EMULATE_DONE; - - /* Read out the instruction */ - if (kvmppc_read_inst(vcpu) == EMULATE_DONE) - /* Need to emulate */ - return EMULATE_FAIL; - - return EMULATE_AGAIN; -} - -/* Handle external providers (FPU, Altivec, VSX) */ -static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr, - ulong msr) -{ - struct thread_struct *t = ¤t->thread; - u64 *vcpu_fpr = vcpu->arch.fpr; -#ifdef CONFIG_VSX - u64 *vcpu_vsx = vcpu->arch.vsr; -#endif - u64 *thread_fpr = (u64*)t->fpr; - int i; - - /* When we have paired singles, we emulate in software */ - if (vcpu->arch.hflags & BOOK3S_HFLAG_PAIRED_SINGLE) - return RESUME_GUEST; - - if (!(vcpu->arch.shared->msr & msr)) { - kvmppc_book3s_queue_irqprio(vcpu, exit_nr); - return RESUME_GUEST; - } - - /* We already own the ext */ - if (vcpu->arch.guest_owned_ext & msr) { - return RESUME_GUEST; - } - -#ifdef DEBUG_EXT - printk(KERN_INFO "Loading up ext 0x%lx\n", msr); -#endif - - current->thread.regs->msr |= msr; - - switch (msr) { - case MSR_FP: - for (i = 0; i < ARRAY_SIZE(vcpu->arch.fpr); i++) - thread_fpr[get_fpr_index(i)] = vcpu_fpr[i]; - - t->fpscr.val = vcpu->arch.fpscr; - t->fpexc_mode = 0; - kvmppc_load_up_fpu(); - break; - case MSR_VEC: -#ifdef CONFIG_ALTIVEC - memcpy(t->vr, vcpu->arch.vr, sizeof(vcpu->arch.vr)); - t->vscr = vcpu->arch.vscr; - t->vrsave = -1; - kvmppc_load_up_altivec(); -#endif - break; - case MSR_VSX: -#ifdef CONFIG_VSX - for (i = 0; i < ARRAY_SIZE(vcpu->arch.vsr); i++) - thread_fpr[get_fpr_index(i) + 1] = vcpu_vsx[i]; - kvmppc_load_up_vsx(); -#endif - break; - default: - BUG(); - } - - vcpu->arch.guest_owned_ext |= msr; - - kvmppc_recalc_shadow_msr(vcpu); - - return RESUME_GUEST; -} - -int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, - unsigned int exit_nr) -{ - int r = RESUME_HOST; - - vcpu->stat.sum_exits++; - - run->exit_reason = KVM_EXIT_UNKNOWN; - run->ready_for_interrupt_injection = 1; - - trace_kvm_book3s_exit(exit_nr, vcpu); - kvm_resched(vcpu); - switch (exit_nr) { - case BOOK3S_INTERRUPT_INST_STORAGE: - vcpu->stat.pf_instruc++; - -#ifdef CONFIG_PPC_BOOK3S_32 - /* We set segments as unused segments when invalidating them. So - * treat the respective fault as segment fault. */ - if (to_svcpu(vcpu)->sr[kvmppc_get_pc(vcpu) >> SID_SHIFT] - == SR_INVALID) { - kvmppc_mmu_map_segment(vcpu, kvmppc_get_pc(vcpu)); - r = RESUME_GUEST; - break; - } -#endif - - /* only care about PTEG not found errors, but leave NX alone */ - if (to_svcpu(vcpu)->shadow_srr1 & 0x40000000) { - r = kvmppc_handle_pagefault(run, vcpu, kvmppc_get_pc(vcpu), exit_nr); - vcpu->stat.sp_instruc++; - } else if (vcpu->arch.mmu.is_dcbz32(vcpu) && - (!(vcpu->arch.hflags & BOOK3S_HFLAG_DCBZ32))) { - /* - * XXX If we do the dcbz hack we use the NX bit to flush&patch the page, - * so we can't use the NX bit inside the guest. Let's cross our fingers, - * that no guest that needs the dcbz hack does NX. - */ - kvmppc_mmu_pte_flush(vcpu, kvmppc_get_pc(vcpu), ~0xFFFUL); - r = RESUME_GUEST; - } else { - vcpu->arch.shared->msr |= - to_svcpu(vcpu)->shadow_srr1 & 0x58000000; - kvmppc_book3s_queue_irqprio(vcpu, exit_nr); - r = RESUME_GUEST; - } - break; - case BOOK3S_INTERRUPT_DATA_STORAGE: - { - ulong dar = kvmppc_get_fault_dar(vcpu); - vcpu->stat.pf_storage++; - -#ifdef CONFIG_PPC_BOOK3S_32 - /* We set segments as unused segments when invalidating them. So - * treat the respective fault as segment fault. */ - if ((to_svcpu(vcpu)->sr[dar >> SID_SHIFT]) == SR_INVALID) { - kvmppc_mmu_map_segment(vcpu, dar); - r = RESUME_GUEST; - break; - } -#endif - - /* The only case we need to handle is missing shadow PTEs */ - if (to_svcpu(vcpu)->fault_dsisr & DSISR_NOHPTE) { - r = kvmppc_handle_pagefault(run, vcpu, dar, exit_nr); - } else { - vcpu->arch.shared->dar = dar; - vcpu->arch.shared->dsisr = to_svcpu(vcpu)->fault_dsisr; - kvmppc_book3s_queue_irqprio(vcpu, exit_nr); - r = RESUME_GUEST; - } - break; - } - case BOOK3S_INTERRUPT_DATA_SEGMENT: - if (kvmppc_mmu_map_segment(vcpu, kvmppc_get_fault_dar(vcpu)) < 0) { - vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu); - kvmppc_book3s_queue_irqprio(vcpu, - BOOK3S_INTERRUPT_DATA_SEGMENT); - } - r = RESUME_GUEST; - break; - case BOOK3S_INTERRUPT_INST_SEGMENT: - if (kvmppc_mmu_map_segment(vcpu, kvmppc_get_pc(vcpu)) < 0) { - kvmppc_book3s_queue_irqprio(vcpu, - BOOK3S_INTERRUPT_INST_SEGMENT); - } - r = RESUME_GUEST; - break; - /* We're good on these - the host merely wanted to get our attention */ - case BOOK3S_INTERRUPT_DECREMENTER: - vcpu->stat.dec_exits++; - r = RESUME_GUEST; - break; - case BOOK3S_INTERRUPT_EXTERNAL: - vcpu->stat.ext_intr_exits++; - r = RESUME_GUEST; - break; - case BOOK3S_INTERRUPT_PERFMON: - r = RESUME_GUEST; - break; - case BOOK3S_INTERRUPT_PROGRAM: - { - enum emulation_result er; - ulong flags; - -program_interrupt: - flags = to_svcpu(vcpu)->shadow_srr1 & 0x1f0000ull; - - if (vcpu->arch.shared->msr & MSR_PR) { -#ifdef EXIT_DEBUG - printk(KERN_INFO "Userspace triggered 0x700 exception at 0x%lx (0x%x)\n", kvmppc_get_pc(vcpu), kvmppc_get_last_inst(vcpu)); -#endif - if ((kvmppc_get_last_inst(vcpu) & 0xff0007ff) != - (INS_DCBZ & 0xfffffff7)) { - kvmppc_core_queue_program(vcpu, flags); - r = RESUME_GUEST; - break; - } - } - - vcpu->stat.emulated_inst_exits++; - er = kvmppc_emulate_instruction(run, vcpu); - switch (er) { - case EMULATE_DONE: - r = RESUME_GUEST_NV; - break; - case EMULATE_AGAIN: - r = RESUME_GUEST; - break; - case EMULATE_FAIL: - printk(KERN_CRIT "%s: emulation at %lx failed (%08x)\n", - __func__, kvmppc_get_pc(vcpu), kvmppc_get_last_inst(vcpu)); - kvmppc_core_queue_program(vcpu, flags); - r = RESUME_GUEST; - break; - case EMULATE_DO_MMIO: - run->exit_reason = KVM_EXIT_MMIO; - r = RESUME_HOST_NV; - break; - default: - BUG(); - } - break; - } - case BOOK3S_INTERRUPT_SYSCALL: - if (vcpu->arch.osi_enabled && - (((u32)kvmppc_get_gpr(vcpu, 3)) == OSI_SC_MAGIC_R3) && - (((u32)kvmppc_get_gpr(vcpu, 4)) == OSI_SC_MAGIC_R4)) { - /* MOL hypercalls */ - u64 *gprs = run->osi.gprs; - int i; - - run->exit_reason = KVM_EXIT_OSI; - for (i = 0; i < 32; i++) - gprs[i] = kvmppc_get_gpr(vcpu, i); - vcpu->arch.osi_needed = 1; - r = RESUME_HOST_NV; - } else if (!(vcpu->arch.shared->msr & MSR_PR) && - (((u32)kvmppc_get_gpr(vcpu, 0)) == KVM_SC_MAGIC_R0)) { - /* KVM PV hypercalls */ - kvmppc_set_gpr(vcpu, 3, kvmppc_kvm_pv(vcpu)); - r = RESUME_GUEST; - } else { - /* Guest syscalls */ - vcpu->stat.syscall_exits++; - kvmppc_book3s_queue_irqprio(vcpu, exit_nr); - r = RESUME_GUEST; - } - break; - case BOOK3S_INTERRUPT_FP_UNAVAIL: - case BOOK3S_INTERRUPT_ALTIVEC: - case BOOK3S_INTERRUPT_VSX: - { - int ext_msr = 0; - - switch (exit_nr) { - case BOOK3S_INTERRUPT_FP_UNAVAIL: ext_msr = MSR_FP; break; - case BOOK3S_INTERRUPT_ALTIVEC: ext_msr = MSR_VEC; break; - case BOOK3S_INTERRUPT_VSX: ext_msr = MSR_VSX; break; - } - - switch (kvmppc_check_ext(vcpu, exit_nr)) { - case EMULATE_DONE: - /* everything ok - let's enable the ext */ - r = kvmppc_handle_ext(vcpu, exit_nr, ext_msr); - break; - case EMULATE_FAIL: - /* we need to emulate this instruction */ - goto program_interrupt; - break; - default: - /* nothing to worry about - go again */ - break; - } - break; - } - case BOOK3S_INTERRUPT_ALIGNMENT: - if (kvmppc_read_inst(vcpu) == EMULATE_DONE) { - vcpu->arch.shared->dsisr = kvmppc_alignment_dsisr(vcpu, - kvmppc_get_last_inst(vcpu)); - vcpu->arch.shared->dar = kvmppc_alignment_dar(vcpu, - kvmppc_get_last_inst(vcpu)); - kvmppc_book3s_queue_irqprio(vcpu, exit_nr); - } - r = RESUME_GUEST; - break; - case BOOK3S_INTERRUPT_MACHINE_CHECK: - case BOOK3S_INTERRUPT_TRACE: - kvmppc_book3s_queue_irqprio(vcpu, exit_nr); - r = RESUME_GUEST; - break; - default: - /* Ugh - bork here! What did we get? */ - printk(KERN_EMERG "exit_nr=0x%x | pc=0x%lx | msr=0x%lx\n", - exit_nr, kvmppc_get_pc(vcpu), to_svcpu(vcpu)->shadow_srr1); - r = RESUME_HOST; - BUG(); - break; - } - - - if (!(r & RESUME_HOST)) { - /* To avoid clobbering exit_reason, only check for signals if - * we aren't already exiting to userspace for some other - * reason. */ - if (signal_pending(current)) { -#ifdef EXIT_DEBUG - printk(KERN_EMERG "KVM: Going back to host\n"); -#endif - vcpu->stat.signal_exits++; - run->exit_reason = KVM_EXIT_INTR; - r = -EINTR; - } else { - /* In case an interrupt came in that was triggered - * from userspace (like DEC), we need to check what - * to inject now! */ - kvmppc_core_deliver_interrupts(vcpu); - } - } - - trace_kvm_book3s_reenter(r, vcpu); - - return r; -} - -int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, - struct kvm_sregs *sregs) -{ - struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu); - int i; - - sregs->pvr = vcpu->arch.pvr; - - sregs->u.s.sdr1 = to_book3s(vcpu)->sdr1; - if (vcpu->arch.hflags & BOOK3S_HFLAG_SLB) { - for (i = 0; i < 64; i++) { - sregs->u.s.ppc64.slb[i].slbe = vcpu->arch.slb[i].orige | i; - sregs->u.s.ppc64.slb[i].slbv = vcpu->arch.slb[i].origv; - } - } else { - for (i = 0; i < 16; i++) - sregs->u.s.ppc32.sr[i] = vcpu->arch.shared->sr[i]; - - for (i = 0; i < 8; i++) { - sregs->u.s.ppc32.ibat[i] = vcpu3s->ibat[i].raw; - sregs->u.s.ppc32.dbat[i] = vcpu3s->dbat[i].raw; - } - } - - return 0; -} - -int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, - struct kvm_sregs *sregs) -{ - struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu); - int i; - - kvmppc_set_pvr(vcpu, sregs->pvr); - - vcpu3s->sdr1 = sregs->u.s.sdr1; - if (vcpu->arch.hflags & BOOK3S_HFLAG_SLB) { - for (i = 0; i < 64; i++) { - vcpu->arch.mmu.slbmte(vcpu, sregs->u.s.ppc64.slb[i].slbv, - sregs->u.s.ppc64.slb[i].slbe); - } - } else { - for (i = 0; i < 16; i++) { - vcpu->arch.mmu.mtsrin(vcpu, i, sregs->u.s.ppc32.sr[i]); - } - for (i = 0; i < 8; i++) { - kvmppc_set_bat(vcpu, &(vcpu3s->ibat[i]), false, - (u32)sregs->u.s.ppc32.ibat[i]); - kvmppc_set_bat(vcpu, &(vcpu3s->ibat[i]), true, - (u32)(sregs->u.s.ppc32.ibat[i] >> 32)); - kvmppc_set_bat(vcpu, &(vcpu3s->dbat[i]), false, - (u32)sregs->u.s.ppc32.dbat[i]); - kvmppc_set_bat(vcpu, &(vcpu3s->dbat[i]), true, - (u32)(sregs->u.s.ppc32.dbat[i] >> 32)); - } - } - - /* Flush the MMU after messing with the segments */ - kvmppc_mmu_pte_flush(vcpu, 0, 0); - - return 0; -} - -int kvmppc_core_check_processor_compat(void) -{ - return 0; -} - -struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id) -{ - struct kvmppc_vcpu_book3s *vcpu_book3s; - struct kvm_vcpu *vcpu; - int err = -ENOMEM; - unsigned long p; - - vcpu_book3s = vzalloc(sizeof(struct kvmppc_vcpu_book3s)); - if (!vcpu_book3s) - goto out; - - vcpu_book3s->shadow_vcpu = (struct kvmppc_book3s_shadow_vcpu *) - kzalloc(sizeof(*vcpu_book3s->shadow_vcpu), GFP_KERNEL); - if (!vcpu_book3s->shadow_vcpu) - goto free_vcpu; - - vcpu = &vcpu_book3s->vcpu; - err = kvm_vcpu_init(vcpu, kvm, id); - if (err) - goto free_shadow_vcpu; - - p = __get_free_page(GFP_KERNEL|__GFP_ZERO); - /* the real shared page fills the last 4k of our page */ - vcpu->arch.shared = (void*)(p + PAGE_SIZE - 4096); - if (!p) - goto uninit_vcpu; - - vcpu->arch.host_retip = kvm_return_point; - vcpu->arch.host_msr = mfmsr(); -#ifdef CONFIG_PPC_BOOK3S_64 - /* default to book3s_64 (970fx) */ - vcpu->arch.pvr = 0x3C0301; -#else - /* default to book3s_32 (750) */ - vcpu->arch.pvr = 0x84202; -#endif - kvmppc_set_pvr(vcpu, vcpu->arch.pvr); - vcpu->arch.slb_nr = 64; - - /* remember where some real-mode handlers are */ - vcpu->arch.trampoline_lowmem = __pa(kvmppc_handler_lowmem_trampoline); - vcpu->arch.trampoline_enter = __pa(kvmppc_handler_trampoline_enter); - vcpu->arch.highmem_handler = (ulong)kvmppc_handler_highmem; -#ifdef CONFIG_PPC_BOOK3S_64 - vcpu->arch.rmcall = *(ulong*)kvmppc_rmcall; -#else - vcpu->arch.rmcall = (ulong)kvmppc_rmcall; -#endif - - vcpu->arch.shadow_msr = MSR_USER64; - - err = kvmppc_mmu_init(vcpu); - if (err < 0) - goto uninit_vcpu; - - return vcpu; - -uninit_vcpu: - kvm_vcpu_uninit(vcpu); -free_shadow_vcpu: - kfree(vcpu_book3s->shadow_vcpu); -free_vcpu: - vfree(vcpu_book3s); -out: - return ERR_PTR(err); -} - -void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu) -{ - struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); - - free_page((unsigned long)vcpu->arch.shared & PAGE_MASK); - kvm_vcpu_uninit(vcpu); - kfree(vcpu_book3s->shadow_vcpu); - vfree(vcpu_book3s); -} - -int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) -{ - int ret; - double fpr[32][TS_FPRWIDTH]; - unsigned int fpscr; - int fpexc_mode; -#ifdef CONFIG_ALTIVEC - vector128 vr[32]; - vector128 vscr; - unsigned long uninitialized_var(vrsave); - int used_vr; -#endif -#ifdef CONFIG_VSX - int used_vsr; -#endif - ulong ext_msr; - - /* No need to go into the guest when all we do is going out */ - if (signal_pending(current)) { - kvm_run->exit_reason = KVM_EXIT_INTR; - return -EINTR; - } - - /* Save FPU state in stack */ - if (current->thread.regs->msr & MSR_FP) - giveup_fpu(current); - memcpy(fpr, current->thread.fpr, sizeof(current->thread.fpr)); - fpscr = current->thread.fpscr.val; - fpexc_mode = current->thread.fpexc_mode; - -#ifdef CONFIG_ALTIVEC - /* Save Altivec state in stack */ - used_vr = current->thread.used_vr; - if (used_vr) { - if (current->thread.regs->msr & MSR_VEC) - giveup_altivec(current); - memcpy(vr, current->thread.vr, sizeof(current->thread.vr)); - vscr = current->thread.vscr; - vrsave = current->thread.vrsave; - } -#endif - -#ifdef CONFIG_VSX - /* Save VSX state in stack */ - used_vsr = current->thread.used_vsr; - if (used_vsr && (current->thread.regs->msr & MSR_VSX)) - __giveup_vsx(current); -#endif - - /* Remember the MSR with disabled extensions */ - ext_msr = current->thread.regs->msr; - - /* Preload FPU if it's enabled */ - if (vcpu->arch.shared->msr & MSR_FP) - kvmppc_handle_ext(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL, MSR_FP); - - kvm_guest_enter(); - - ret = __kvmppc_vcpu_run(kvm_run, vcpu); - - kvm_guest_exit(); - - local_irq_disable(); - - current->thread.regs->msr = ext_msr; - - /* Make sure we save the guest FPU/Altivec/VSX state */ - kvmppc_giveup_ext(vcpu, MSR_FP); - kvmppc_giveup_ext(vcpu, MSR_VEC); - kvmppc_giveup_ext(vcpu, MSR_VSX); - - /* Restore FPU state from stack */ - memcpy(current->thread.fpr, fpr, sizeof(current->thread.fpr)); - current->thread.fpscr.val = fpscr; - current->thread.fpexc_mode = fpexc_mode; - -#ifdef CONFIG_ALTIVEC - /* Restore Altivec state from stack */ - if (used_vr && current->thread.used_vr) { - memcpy(current->thread.vr, vr, sizeof(current->thread.vr)); - current->thread.vscr = vscr; - current->thread.vrsave = vrsave; - } - current->thread.used_vr = used_vr; -#endif - -#ifdef CONFIG_VSX - current->thread.used_vsr = used_vsr; -#endif - - return ret; -} - -int kvmppc_core_prepare_memory_region(struct kvm *kvm, - struct kvm_userspace_memory_region *mem) -{ - return 0; -} - -void kvmppc_core_commit_memory_region(struct kvm *kvm, - struct kvm_userspace_memory_region *mem) -{ -} - -int kvmppc_core_init_vm(struct kvm *kvm) -{ - return 0; -} - -void kvmppc_core_destroy_vm(struct kvm *kvm) -{ -} - -static int kvmppc_book3s_init(void) -{ - int r; - - r = kvm_init(NULL, sizeof(struct kvmppc_vcpu_book3s), 0, - THIS_MODULE); - - if (r) - return r; - - r = kvmppc_mmu_hpte_sysinit(); - - return r; -} - -static void kvmppc_book3s_exit(void) -{ - kvmppc_mmu_hpte_sysexit(); - kvm_exit(); -} - -module_init(kvmppc_book3s_init); -module_exit(kvmppc_book3s_exit); diff --git a/trunk/arch/powerpc/kvm/book3s_rmhandlers.S b/trunk/arch/powerpc/kvm/book3s_rmhandlers.S index c1f877c4a884..1a1b34487e71 100644 --- a/trunk/arch/powerpc/kvm/book3s_rmhandlers.S +++ b/trunk/arch/powerpc/kvm/book3s_rmhandlers.S @@ -36,44 +36,41 @@ #if defined(CONFIG_PPC_BOOK3S_64) #define LOAD_SHADOW_VCPU(reg) GET_PACA(reg) +#define SHADOW_VCPU_OFF PACA_KVM_SVCPU #define MSR_NOIRQ MSR_KERNEL & ~(MSR_IR | MSR_DR) #define FUNC(name) GLUE(.,name) -kvmppc_skip_interrupt: - /* - * Here all GPRs are unchanged from when the interrupt happened - * except for r13, which is saved in SPRG_SCRATCH0. - */ - mfspr r13, SPRN_SRR0 - addi r13, r13, 4 - mtspr SPRN_SRR0, r13 - GET_SCRATCH0(r13) - rfid - b . - -kvmppc_skip_Hinterrupt: - /* - * Here all GPRs are unchanged from when the interrupt happened - * except for r13, which is saved in SPRG_SCRATCH0. - */ - mfspr r13, SPRN_HSRR0 - addi r13, r13, 4 - mtspr SPRN_HSRR0, r13 - GET_SCRATCH0(r13) - hrfid - b . - #elif defined(CONFIG_PPC_BOOK3S_32) +#define LOAD_SHADOW_VCPU(reg) \ + mfspr reg, SPRN_SPRG_THREAD; \ + lwz reg, THREAD_KVM_SVCPU(reg); \ + /* PPC32 can have a NULL pointer - let's check for that */ \ + mtspr SPRN_SPRG_SCRATCH1, r12; /* Save r12 */ \ + mfcr r12; \ + cmpwi reg, 0; \ + bne 1f; \ + mfspr reg, SPRN_SPRG_SCRATCH0; \ + mtcr r12; \ + mfspr r12, SPRN_SPRG_SCRATCH1; \ + b kvmppc_resume_\intno; \ +1:; \ + mtcr r12; \ + mfspr r12, SPRN_SPRG_SCRATCH1; \ + tophys(reg, reg) + +#define SHADOW_VCPU_OFF 0 #define MSR_NOIRQ MSR_KERNEL #define FUNC(name) name +#endif + .macro INTERRUPT_TRAMPOLINE intno .global kvmppc_trampoline_\intno kvmppc_trampoline_\intno: - mtspr SPRN_SPRG_SCRATCH0, r13 /* Save r13 */ + SET_SCRATCH0(r13) /* Save r13 */ /* * First thing to do is to find out if we're coming @@ -81,28 +78,19 @@ kvmppc_trampoline_\intno: * * To distinguish, we check a magic byte in the PACA/current */ - mfspr r13, SPRN_SPRG_THREAD - lwz r13, THREAD_KVM_SVCPU(r13) - /* PPC32 can have a NULL pointer - let's check for that */ - mtspr SPRN_SPRG_SCRATCH1, r12 /* Save r12 */ + LOAD_SHADOW_VCPU(r13) + PPC_STL r12, (SHADOW_VCPU_OFF + SVCPU_SCRATCH0)(r13) mfcr r12 - cmpwi r13, 0 - bne 1f -2: mtcr r12 - mfspr r12, SPRN_SPRG_SCRATCH1 - mfspr r13, SPRN_SPRG_SCRATCH0 /* r13 = original r13 */ - b kvmppc_resume_\intno /* Get back original handler */ - -1: tophys(r13, r13) - stw r12, HSTATE_SCRATCH1(r13) - mfspr r12, SPRN_SPRG_SCRATCH1 - stw r12, HSTATE_SCRATCH0(r13) - lbz r12, HSTATE_IN_GUEST(r13) + stw r12, (SHADOW_VCPU_OFF + SVCPU_SCRATCH1)(r13) + lbz r12, (SHADOW_VCPU_OFF + SVCPU_IN_GUEST)(r13) cmpwi r12, KVM_GUEST_MODE_NONE bne ..kvmppc_handler_hasmagic_\intno /* No KVM guest? Then jump back to the Linux handler! */ - lwz r12, HSTATE_SCRATCH1(r13) - b 2b + lwz r12, (SHADOW_VCPU_OFF + SVCPU_SCRATCH1)(r13) + mtcr r12 + PPC_LL r12, (SHADOW_VCPU_OFF + SVCPU_SCRATCH0)(r13) + GET_SCRATCH0(r13) /* r13 = original r13 */ + b kvmppc_resume_\intno /* Get back original handler */ /* Now we know we're handling a KVM guest */ ..kvmppc_handler_hasmagic_\intno: @@ -124,6 +112,9 @@ INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_MACHINE_CHECK INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_DATA_STORAGE INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_INST_STORAGE INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_EXTERNAL +#ifdef CONFIG_PPC_BOOK3S_64 +INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_EXTERNAL_HV +#endif INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_ALIGNMENT INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_PROGRAM INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_FP_UNAVAIL @@ -133,6 +124,14 @@ INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_TRACE INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_PERFMON INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_ALTIVEC +/* Those are only available on 64 bit machines */ + +#ifdef CONFIG_PPC_BOOK3S_64 +INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_DATA_SEGMENT +INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_INST_SEGMENT +INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_VSX +#endif + /* * Bring us back to the faulting code, but skip the * faulting instruction. @@ -144,8 +143,8 @@ INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_ALTIVEC * * R12 = free * R13 = Shadow VCPU (PACA) - * HSTATE.SCRATCH0 = guest R12 - * HSTATE.SCRATCH1 = guest CR + * SVCPU.SCRATCH0 = guest R12 + * SVCPU.SCRATCH1 = guest CR * SPRG_SCRATCH0 = guest R13 * */ @@ -157,14 +156,13 @@ kvmppc_handler_skip_ins: mtsrr0 r12 /* Clean up all state */ - lwz r12, HSTATE_SCRATCH1(r13) + lwz r12, (SHADOW_VCPU_OFF + SVCPU_SCRATCH1)(r13) mtcr r12 - PPC_LL r12, HSTATE_SCRATCH0(r13) + PPC_LL r12, (SHADOW_VCPU_OFF + SVCPU_SCRATCH0)(r13) GET_SCRATCH0(r13) /* And get back into the code */ RFI -#endif /* * This trampoline brings us back to a real mode handler @@ -253,4 +251,12 @@ define_load_up(altivec) define_load_up(vsx) #endif +.global kvmppc_trampoline_lowmem +kvmppc_trampoline_lowmem: + PPC_LONG kvmppc_handler_lowmem_trampoline - CONFIG_KERNEL_START + +.global kvmppc_trampoline_enter +kvmppc_trampoline_enter: + PPC_LONG kvmppc_handler_trampoline_enter - CONFIG_KERNEL_START + #include "book3s_segment.S" diff --git a/trunk/arch/powerpc/kvm/book3s_segment.S b/trunk/arch/powerpc/kvm/book3s_segment.S index aed32e517212..451264274b8c 100644 --- a/trunk/arch/powerpc/kvm/book3s_segment.S +++ b/trunk/arch/powerpc/kvm/book3s_segment.S @@ -22,7 +22,7 @@ #if defined(CONFIG_PPC_BOOK3S_64) #define GET_SHADOW_VCPU(reg) \ - mr reg, r13 + addi reg, r13, PACA_KVM_SVCPU #elif defined(CONFIG_PPC_BOOK3S_32) @@ -71,10 +71,6 @@ kvmppc_handler_trampoline_enter: /* r3 = shadow vcpu */ GET_SHADOW_VCPU(r3) - /* Save R1/R2 in the PACA (64-bit) or shadow_vcpu (32-bit) */ - PPC_STL r1, HSTATE_HOST_R1(r3) - PPC_STL r2, HSTATE_HOST_R2(r3) - /* Move SRR0 and SRR1 into the respective regs */ PPC_LL r9, SVCPU_PC(r3) mtsrr0 r9 @@ -82,36 +78,36 @@ kvmppc_handler_trampoline_enter: /* Activate guest mode, so faults get handled by KVM */ li r11, KVM_GUEST_MODE_GUEST - stb r11, HSTATE_IN_GUEST(r3) + stb r11, SVCPU_IN_GUEST(r3) /* Switch to guest segment. This is subarch specific. */ LOAD_GUEST_SEGMENTS /* Enter guest */ - PPC_LL r4, SVCPU_CTR(r3) - PPC_LL r5, SVCPU_LR(r3) - lwz r6, SVCPU_CR(r3) - lwz r7, SVCPU_XER(r3) + PPC_LL r4, (SVCPU_CTR)(r3) + PPC_LL r5, (SVCPU_LR)(r3) + lwz r6, (SVCPU_CR)(r3) + lwz r7, (SVCPU_XER)(r3) mtctr r4 mtlr r5 mtcr r6 mtxer r7 - PPC_LL r0, SVCPU_R0(r3) - PPC_LL r1, SVCPU_R1(r3) - PPC_LL r2, SVCPU_R2(r3) - PPC_LL r4, SVCPU_R4(r3) - PPC_LL r5, SVCPU_R5(r3) - PPC_LL r6, SVCPU_R6(r3) - PPC_LL r7, SVCPU_R7(r3) - PPC_LL r8, SVCPU_R8(r3) - PPC_LL r9, SVCPU_R9(r3) - PPC_LL r10, SVCPU_R10(r3) - PPC_LL r11, SVCPU_R11(r3) - PPC_LL r12, SVCPU_R12(r3) - PPC_LL r13, SVCPU_R13(r3) + PPC_LL r0, (SVCPU_R0)(r3) + PPC_LL r1, (SVCPU_R1)(r3) + PPC_LL r2, (SVCPU_R2)(r3) + PPC_LL r4, (SVCPU_R4)(r3) + PPC_LL r5, (SVCPU_R5)(r3) + PPC_LL r6, (SVCPU_R6)(r3) + PPC_LL r7, (SVCPU_R7)(r3) + PPC_LL r8, (SVCPU_R8)(r3) + PPC_LL r9, (SVCPU_R9)(r3) + PPC_LL r10, (SVCPU_R10)(r3) + PPC_LL r11, (SVCPU_R11)(r3) + PPC_LL r12, (SVCPU_R12)(r3) + PPC_LL r13, (SVCPU_R13)(r3) PPC_LL r3, (SVCPU_R3)(r3) @@ -129,63 +125,56 @@ kvmppc_handler_trampoline_enter_end: .global kvmppc_handler_trampoline_exit kvmppc_handler_trampoline_exit: -.global kvmppc_interrupt -kvmppc_interrupt: - /* Register usage at this point: * * SPRG_SCRATCH0 = guest R13 * R12 = exit handler id - * R13 = shadow vcpu (32-bit) or PACA (64-bit) - * HSTATE.SCRATCH0 = guest R12 - * HSTATE.SCRATCH1 = guest CR + * R13 = shadow vcpu - SHADOW_VCPU_OFF [=PACA on PPC64] + * SVCPU.SCRATCH0 = guest R12 + * SVCPU.SCRATCH1 = guest CR * */ /* Save registers */ - PPC_STL r0, SVCPU_R0(r13) - PPC_STL r1, SVCPU_R1(r13) - PPC_STL r2, SVCPU_R2(r13) - PPC_STL r3, SVCPU_R3(r13) - PPC_STL r4, SVCPU_R4(r13) - PPC_STL r5, SVCPU_R5(r13) - PPC_STL r6, SVCPU_R6(r13) - PPC_STL r7, SVCPU_R7(r13) - PPC_STL r8, SVCPU_R8(r13) - PPC_STL r9, SVCPU_R9(r13) - PPC_STL r10, SVCPU_R10(r13) - PPC_STL r11, SVCPU_R11(r13) + PPC_STL r0, (SHADOW_VCPU_OFF + SVCPU_R0)(r13) + PPC_STL r1, (SHADOW_VCPU_OFF + SVCPU_R1)(r13) + PPC_STL r2, (SHADOW_VCPU_OFF + SVCPU_R2)(r13) + PPC_STL r3, (SHADOW_VCPU_OFF + SVCPU_R3)(r13) + PPC_STL r4, (SHADOW_VCPU_OFF + SVCPU_R4)(r13) + PPC_STL r5, (SHADOW_VCPU_OFF + SVCPU_R5)(r13) + PPC_STL r6, (SHADOW_VCPU_OFF + SVCPU_R6)(r13) + PPC_STL r7, (SHADOW_VCPU_OFF + SVCPU_R7)(r13) + PPC_STL r8, (SHADOW_VCPU_OFF + SVCPU_R8)(r13) + PPC_STL r9, (SHADOW_VCPU_OFF + SVCPU_R9)(r13) + PPC_STL r10, (SHADOW_VCPU_OFF + SVCPU_R10)(r13) + PPC_STL r11, (SHADOW_VCPU_OFF + SVCPU_R11)(r13) /* Restore R1/R2 so we can handle faults */ - PPC_LL r1, HSTATE_HOST_R1(r13) - PPC_LL r2, HSTATE_HOST_R2(r13) + PPC_LL r1, (SHADOW_VCPU_OFF + SVCPU_HOST_R1)(r13) + PPC_LL r2, (SHADOW_VCPU_OFF + SVCPU_HOST_R2)(r13) /* Save guest PC and MSR */ -#ifdef CONFIG_PPC64 -BEGIN_FTR_SECTION andi. r0,r12,0x2 beq 1f mfspr r3,SPRN_HSRR0 mfspr r4,SPRN_HSRR1 andi. r12,r12,0x3ffd b 2f -END_FTR_SECTION_IFSET(CPU_FTR_HVMODE) -#endif 1: mfsrr0 r3 mfsrr1 r4 2: - PPC_STL r3, SVCPU_PC(r13) - PPC_STL r4, SVCPU_SHADOW_SRR1(r13) + PPC_STL r3, (SHADOW_VCPU_OFF + SVCPU_PC)(r13) + PPC_STL r4, (SHADOW_VCPU_OFF + SVCPU_SHADOW_SRR1)(r13) /* Get scratch'ed off registers */ GET_SCRATCH0(r9) - PPC_LL r8, HSTATE_SCRATCH0(r13) - lwz r7, HSTATE_SCRATCH1(r13) + PPC_LL r8, (SHADOW_VCPU_OFF + SVCPU_SCRATCH0)(r13) + lwz r7, (SHADOW_VCPU_OFF + SVCPU_SCRATCH1)(r13) - PPC_STL r9, SVCPU_R13(r13) - PPC_STL r8, SVCPU_R12(r13) - stw r7, SVCPU_CR(r13) + PPC_STL r9, (SHADOW_VCPU_OFF + SVCPU_R13)(r13) + PPC_STL r8, (SHADOW_VCPU_OFF + SVCPU_R12)(r13) + stw r7, (SHADOW_VCPU_OFF + SVCPU_CR)(r13) /* Save more register state */ @@ -195,11 +184,11 @@ END_FTR_SECTION_IFSET(CPU_FTR_HVMODE) mfctr r8 mflr r9 - stw r5, SVCPU_XER(r13) - PPC_STL r6, SVCPU_FAULT_DAR(r13) - stw r7, SVCPU_FAULT_DSISR(r13) - PPC_STL r8, SVCPU_CTR(r13) - PPC_STL r9, SVCPU_LR(r13) + stw r5, (SHADOW_VCPU_OFF + SVCPU_XER)(r13) + PPC_STL r6, (SHADOW_VCPU_OFF + SVCPU_FAULT_DAR)(r13) + stw r7, (SHADOW_VCPU_OFF + SVCPU_FAULT_DSISR)(r13) + PPC_STL r8, (SHADOW_VCPU_OFF + SVCPU_CTR)(r13) + PPC_STL r9, (SHADOW_VCPU_OFF + SVCPU_LR)(r13) /* * In order for us to easily get the last instruction, @@ -229,7 +218,7 @@ ld_last_inst: /* Set guest mode to 'jump over instruction' so if lwz faults * we'll just continue at the next IP. */ li r9, KVM_GUEST_MODE_SKIP - stb r9, HSTATE_IN_GUEST(r13) + stb r9, (SHADOW_VCPU_OFF + SVCPU_IN_GUEST)(r13) /* 1) enable paging for data */ mfmsr r9 @@ -243,13 +232,13 @@ ld_last_inst: sync #endif - stw r0, SVCPU_LAST_INST(r13) + stw r0, (SHADOW_VCPU_OFF + SVCPU_LAST_INST)(r13) no_ld_last_inst: /* Unset guest mode */ li r9, KVM_GUEST_MODE_NONE - stb r9, HSTATE_IN_GUEST(r13) + stb r9, (SHADOW_VCPU_OFF + SVCPU_IN_GUEST)(r13) /* Switch back to host MMU */ LOAD_HOST_SEGMENTS @@ -259,7 +248,7 @@ no_ld_last_inst: * R1 = host R1 * R2 = host R2 * R12 = exit handler id - * R13 = shadow vcpu (32-bit) or PACA (64-bit) + * R13 = shadow vcpu - SHADOW_VCPU_OFF [=PACA on PPC64] * SVCPU.* = guest * * */ @@ -269,7 +258,7 @@ no_ld_last_inst: ori r7, r7, MSR_IR|MSR_DR|MSR_RI|MSR_ME /* Enable paging */ mtsrr1 r7 /* Load highmem handler address */ - PPC_LL r8, HSTATE_VMHANDLER(r13) + PPC_LL r8, (SHADOW_VCPU_OFF + SVCPU_VMHANDLER)(r13) mtsrr0 r8 RFI diff --git a/trunk/arch/powerpc/kvm/booke.c b/trunk/arch/powerpc/kvm/booke.c index ee45fa01220e..8462b3a1c1c7 100644 --- a/trunk/arch/powerpc/kvm/booke.c +++ b/trunk/arch/powerpc/kvm/booke.c @@ -13,7 +13,6 @@ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright IBM Corp. 2007 - * Copyright 2010-2011 Freescale Semiconductor, Inc. * * Authors: Hollis Blanchard * Christian Ehrhardt @@ -79,60 +78,6 @@ void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu) } } -#ifdef CONFIG_SPE -void kvmppc_vcpu_disable_spe(struct kvm_vcpu *vcpu) -{ - preempt_disable(); - enable_kernel_spe(); - kvmppc_save_guest_spe(vcpu); - vcpu->arch.shadow_msr &= ~MSR_SPE; - preempt_enable(); -} - -static void kvmppc_vcpu_enable_spe(struct kvm_vcpu *vcpu) -{ - preempt_disable(); - enable_kernel_spe(); - kvmppc_load_guest_spe(vcpu); - vcpu->arch.shadow_msr |= MSR_SPE; - preempt_enable(); -} - -static void kvmppc_vcpu_sync_spe(struct kvm_vcpu *vcpu) -{ - if (vcpu->arch.shared->msr & MSR_SPE) { - if (!(vcpu->arch.shadow_msr & MSR_SPE)) - kvmppc_vcpu_enable_spe(vcpu); - } else if (vcpu->arch.shadow_msr & MSR_SPE) { - kvmppc_vcpu_disable_spe(vcpu); - } -} -#else -static void kvmppc_vcpu_sync_spe(struct kvm_vcpu *vcpu) -{ -} -#endif - -/* - * Helper function for "full" MSR writes. No need to call this if only - * EE/CE/ME/DE/RI are changing. - */ -void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr) -{ - u32 old_msr = vcpu->arch.shared->msr; - - vcpu->arch.shared->msr = new_msr; - - kvmppc_mmu_msr_notify(vcpu, old_msr); - - if (vcpu->arch.shared->msr & MSR_WE) { - kvm_vcpu_block(vcpu); - kvmppc_set_exit_type(vcpu, EMULATED_MTMSRWE_EXITS); - }; - - kvmppc_vcpu_sync_spe(vcpu); -} - static void kvmppc_booke_queue_irqprio(struct kvm_vcpu *vcpu, unsigned int priority) { @@ -312,19 +257,6 @@ void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu) vcpu->arch.shared->int_pending = 0; } -int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) -{ - int ret; - - local_irq_disable(); - kvm_guest_enter(); - ret = __kvmppc_vcpu_run(kvm_run, vcpu); - kvm_guest_exit(); - local_irq_enable(); - - return ret; -} - /** * kvmppc_handle_exit * @@ -412,16 +344,10 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, r = RESUME_GUEST; break; -#ifdef CONFIG_SPE - case BOOKE_INTERRUPT_SPE_UNAVAIL: { - if (vcpu->arch.shared->msr & MSR_SPE) - kvmppc_vcpu_enable_spe(vcpu); - else - kvmppc_booke_queue_irqprio(vcpu, - BOOKE_IRQPRIO_SPE_UNAVAIL); + case BOOKE_INTERRUPT_SPE_UNAVAIL: + kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_SPE_UNAVAIL); r = RESUME_GUEST; break; - } case BOOKE_INTERRUPT_SPE_FP_DATA: kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_SPE_FP_DATA); @@ -432,28 +358,6 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_SPE_FP_ROUND); r = RESUME_GUEST; break; -#else - case BOOKE_INTERRUPT_SPE_UNAVAIL: - /* - * Guest wants SPE, but host kernel doesn't support it. Send - * an "unimplemented operation" program check to the guest. - */ - kvmppc_core_queue_program(vcpu, ESR_PUO | ESR_SPV); - r = RESUME_GUEST; - break; - - /* - * These really should never happen without CONFIG_SPE, - * as we should never enable the real MSR[SPE] in the guest. - */ - case BOOKE_INTERRUPT_SPE_FP_DATA: - case BOOKE_INTERRUPT_SPE_FP_ROUND: - printk(KERN_CRIT "%s: unexpected SPE interrupt %u at %08lx\n", - __func__, exit_nr, vcpu->arch.pc); - run->hw.hardware_exit_reason = exit_nr; - r = RESUME_HOST; - break; -#endif case BOOKE_INTERRUPT_DATA_STORAGE: kvmppc_core_queue_data_storage(vcpu, vcpu->arch.fault_dear, @@ -488,17 +392,6 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, gpa_t gpaddr; gfn_t gfn; -#ifdef CONFIG_KVM_E500 - if (!(vcpu->arch.shared->msr & MSR_PR) && - (eaddr & PAGE_MASK) == vcpu->arch.magic_page_ea) { - kvmppc_map_magic(vcpu); - kvmppc_account_exit(vcpu, DTLB_VIRT_MISS_EXITS); - r = RESUME_GUEST; - - break; - } -#endif - /* Check the guest TLB. */ gtlb_index = kvmppc_mmu_dtlb_index(vcpu, eaddr); if (gtlb_index < 0) { @@ -621,7 +514,6 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) vcpu->arch.pc = 0; vcpu->arch.shared->msr = 0; - vcpu->arch.shadow_msr = MSR_USER | MSR_DE | MSR_IS | MSR_DS; kvmppc_set_gpr(vcpu, 1, (16<<20) - 8); /* -8 for the callee-save LR slot */ vcpu->arch.shadow_pid = 1; @@ -878,26 +770,6 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log) return -ENOTSUPP; } -int kvmppc_core_prepare_memory_region(struct kvm *kvm, - struct kvm_userspace_memory_region *mem) -{ - return 0; -} - -void kvmppc_core_commit_memory_region(struct kvm *kvm, - struct kvm_userspace_memory_region *mem) -{ -} - -int kvmppc_core_init_vm(struct kvm *kvm) -{ - return 0; -} - -void kvmppc_core_destroy_vm(struct kvm *kvm) -{ -} - int __init kvmppc_booke_init(void) { unsigned long ivor[16]; diff --git a/trunk/arch/powerpc/kvm/booke.h b/trunk/arch/powerpc/kvm/booke.h index 8e1fe33d64e5..492bb7030358 100644 --- a/trunk/arch/powerpc/kvm/booke.h +++ b/trunk/arch/powerpc/kvm/booke.h @@ -52,19 +52,24 @@ extern unsigned long kvmppc_booke_handlers; -void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr); -void kvmppc_mmu_msr_notify(struct kvm_vcpu *vcpu, u32 old_msr); +/* Helper function for "full" MSR writes. No need to call this if only EE is + * changing. */ +static inline void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr) +{ + if ((new_msr & MSR_PR) != (vcpu->arch.shared->msr & MSR_PR)) + kvmppc_mmu_priv_switch(vcpu, new_msr & MSR_PR); + + vcpu->arch.shared->msr = new_msr; + + if (vcpu->arch.shared->msr & MSR_WE) { + kvm_vcpu_block(vcpu); + kvmppc_set_exit_type(vcpu, EMULATED_MTMSRWE_EXITS); + }; +} int kvmppc_booke_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, unsigned int inst, int *advance); int kvmppc_booke_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt); int kvmppc_booke_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs); -/* low-level asm code to transfer guest state */ -void kvmppc_load_guest_spe(struct kvm_vcpu *vcpu); -void kvmppc_save_guest_spe(struct kvm_vcpu *vcpu); - -/* high-level function, manages flags, host state */ -void kvmppc_vcpu_disable_spe(struct kvm_vcpu *vcpu); - #endif /* __KVM_BOOKE_H__ */ diff --git a/trunk/arch/powerpc/kvm/booke_interrupts.S b/trunk/arch/powerpc/kvm/booke_interrupts.S index 42f2fb1f66e9..b58ccae95904 100644 --- a/trunk/arch/powerpc/kvm/booke_interrupts.S +++ b/trunk/arch/powerpc/kvm/booke_interrupts.S @@ -13,7 +13,6 @@ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright IBM Corp. 2007 - * Copyright 2011 Freescale Semiconductor, Inc. * * Authors: Hollis Blanchard */ @@ -25,6 +24,8 @@ #include #include +#define KVMPPC_MSR_MASK (MSR_CE|MSR_EE|MSR_PR|MSR_DE|MSR_ME|MSR_IS|MSR_DS) + #define VCPU_GPR(n) (VCPU_GPRS + (n * 4)) /* The host stack layout: */ @@ -191,12 +192,6 @@ _GLOBAL(kvmppc_resume_host) lwz r3, VCPU_HOST_PID(r4) mtspr SPRN_PID, r3 -#ifdef CONFIG_FSL_BOOKE - /* we cheat and know that Linux doesn't use PID1 which is always 0 */ - lis r3, 0 - mtspr SPRN_PID1, r3 -#endif - /* Restore host IVPR before re-enabling interrupts. We cheat and know * that Linux IVPR is always 0xc0000000. */ lis r3, 0xc000 @@ -246,14 +241,6 @@ _GLOBAL(kvmppc_resume_host) heavyweight_exit: /* Not returning to guest. */ -#ifdef CONFIG_SPE - /* save guest SPEFSCR and load host SPEFSCR */ - mfspr r9, SPRN_SPEFSCR - stw r9, VCPU_SPEFSCR(r4) - lwz r9, VCPU_HOST_SPEFSCR(r4) - mtspr SPRN_SPEFSCR, r9 -#endif - /* We already saved guest volatile register state; now save the * non-volatiles. */ stw r15, VCPU_GPR(r15)(r4) @@ -355,14 +342,6 @@ _GLOBAL(__kvmppc_vcpu_run) lwz r30, VCPU_GPR(r30)(r4) lwz r31, VCPU_GPR(r31)(r4) -#ifdef CONFIG_SPE - /* save host SPEFSCR and load guest SPEFSCR */ - mfspr r3, SPRN_SPEFSCR - stw r3, VCPU_HOST_SPEFSCR(r4) - lwz r3, VCPU_SPEFSCR(r4) - mtspr SPRN_SPEFSCR, r3 -#endif - lightweight_exit: stw r2, HOST_R2(r1) @@ -371,11 +350,6 @@ lightweight_exit: lwz r3, VCPU_SHADOW_PID(r4) mtspr SPRN_PID, r3 -#ifdef CONFIG_FSL_BOOKE - lwz r3, VCPU_SHADOW_PID1(r4) - mtspr SPRN_PID1, r3 -#endif - #ifdef CONFIG_44x iccci 0, 0 /* XXX hack */ #endif @@ -431,17 +405,20 @@ lightweight_exit: /* Finish loading guest volatiles and jump to guest. */ lwz r3, VCPU_CTR(r4) - lwz r5, VCPU_CR(r4) - lwz r6, VCPU_PC(r4) - lwz r7, VCPU_SHADOW_MSR(r4) mtctr r3 - mtcr r5 - mtsrr0 r6 - mtsrr1 r7 + lwz r3, VCPU_CR(r4) + mtcr r3 lwz r5, VCPU_GPR(r5)(r4) lwz r6, VCPU_GPR(r6)(r4) lwz r7, VCPU_GPR(r7)(r4) lwz r8, VCPU_GPR(r8)(r4) + lwz r3, VCPU_PC(r4) + mtsrr0 r3 + lwz r3, VCPU_SHARED(r4) + lwz r3, (VCPU_SHARED_MSR + 4)(r3) + oris r3, r3, KVMPPC_MSR_MASK@h + ori r3, r3, KVMPPC_MSR_MASK@l + mtsrr1 r3 /* Clear any debug events which occurred since we disabled MSR[DE]. * XXX This gives us a 3-instruction window in which a breakpoint @@ -453,24 +430,3 @@ lightweight_exit: lwz r3, VCPU_GPR(r3)(r4) lwz r4, VCPU_GPR(r4)(r4) rfi - -#ifdef CONFIG_SPE -_GLOBAL(kvmppc_save_guest_spe) - cmpi 0,r3,0 - beqlr- - SAVE_32EVRS(0, r4, r3, VCPU_EVR) - evxor evr6, evr6, evr6 - evmwumiaa evr6, evr6, evr6 - li r4,VCPU_ACC - evstddx evr6, r4, r3 /* save acc */ - blr - -_GLOBAL(kvmppc_load_guest_spe) - cmpi 0,r3,0 - beqlr- - li r4,VCPU_ACC - evlddx evr6,r4,r3 - evmra evr6,evr6 /* load acc */ - REST_32EVRS(0, r4, r3, VCPU_EVR) - blr -#endif diff --git a/trunk/arch/powerpc/kvm/e500.c b/trunk/arch/powerpc/kvm/e500.c index 797a7447c268..318dbc61ba44 100644 --- a/trunk/arch/powerpc/kvm/e500.c +++ b/trunk/arch/powerpc/kvm/e500.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All rights reserved. + * Copyright (C) 2008 Freescale Semiconductor, Inc. All rights reserved. * * Author: Yu Liu, * @@ -41,11 +41,6 @@ void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu) void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu) { kvmppc_e500_tlb_put(vcpu); - -#ifdef CONFIG_SPE - if (vcpu->arch.shadow_msr & MSR_SPE) - kvmppc_vcpu_disable_spe(vcpu); -#endif } int kvmppc_core_check_processor_compat(void) diff --git a/trunk/arch/powerpc/kvm/e500_emulate.c b/trunk/arch/powerpc/kvm/e500_emulate.c index d48ae396f41e..69cd665a0caf 100644 --- a/trunk/arch/powerpc/kvm/e500_emulate.c +++ b/trunk/arch/powerpc/kvm/e500_emulate.c @@ -81,12 +81,8 @@ int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs) kvmppc_set_pid(vcpu, spr_val); break; case SPRN_PID1: - if (spr_val != 0) - return EMULATE_FAIL; vcpu_e500->pid[1] = spr_val; break; case SPRN_PID2: - if (spr_val != 0) - return EMULATE_FAIL; vcpu_e500->pid[2] = spr_val; break; case SPRN_MAS0: vcpu_e500->mas0 = spr_val; break; diff --git a/trunk/arch/powerpc/kvm/e500_tlb.c b/trunk/arch/powerpc/kvm/e500_tlb.c index 13c432ea2fa8..b18fe353397d 100644 --- a/trunk/arch/powerpc/kvm/e500_tlb.c +++ b/trunk/arch/powerpc/kvm/e500_tlb.c @@ -28,196 +28,8 @@ #define to_htlb1_esel(esel) (tlb1_entry_num - (esel) - 1) -struct id { - unsigned long val; - struct id **pentry; -}; - -#define NUM_TIDS 256 - -/* - * This table provide mappings from: - * (guestAS,guestTID,guestPR) --> ID of physical cpu - * guestAS [0..1] - * guestTID [0..255] - * guestPR [0..1] - * ID [1..255] - * Each vcpu keeps one vcpu_id_table. - */ -struct vcpu_id_table { - struct id id[2][NUM_TIDS][2]; -}; - -/* - * This table provide reversed mappings of vcpu_id_table: - * ID --> address of vcpu_id_table item. - * Each physical core has one pcpu_id_table. - */ -struct pcpu_id_table { - struct id *entry[NUM_TIDS]; -}; - -static DEFINE_PER_CPU(struct pcpu_id_table, pcpu_sids); - -/* This variable keeps last used shadow ID on local core. - * The valid range of shadow ID is [1..255] */ -static DEFINE_PER_CPU(unsigned long, pcpu_last_used_sid); - static unsigned int tlb1_entry_num; -/* - * Allocate a free shadow id and setup a valid sid mapping in given entry. - * A mapping is only valid when vcpu_id_table and pcpu_id_table are match. - * - * The caller must have preemption disabled, and keep it that way until - * it has finished with the returned shadow id (either written into the - * TLB or arch.shadow_pid, or discarded). - */ -static inline int local_sid_setup_one(struct id *entry) -{ - unsigned long sid; - int ret = -1; - - sid = ++(__get_cpu_var(pcpu_last_used_sid)); - if (sid < NUM_TIDS) { - __get_cpu_var(pcpu_sids).entry[sid] = entry; - entry->val = sid; - entry->pentry = &__get_cpu_var(pcpu_sids).entry[sid]; - ret = sid; - } - - /* - * If sid == NUM_TIDS, we've run out of sids. We return -1, and - * the caller will invalidate everything and start over. - * - * sid > NUM_TIDS indicates a race, which we disable preemption to - * avoid. - */ - WARN_ON(sid > NUM_TIDS); - - return ret; -} - -/* - * Check if given entry contain a valid shadow id mapping. - * An ID mapping is considered valid only if - * both vcpu and pcpu know this mapping. - * - * The caller must have preemption disabled, and keep it that way until - * it has finished with the returned shadow id (either written into the - * TLB or arch.shadow_pid, or discarded). - */ -static inline int local_sid_lookup(struct id *entry) -{ - if (entry && entry->val != 0 && - __get_cpu_var(pcpu_sids).entry[entry->val] == entry && - entry->pentry == &__get_cpu_var(pcpu_sids).entry[entry->val]) - return entry->val; - return -1; -} - -/* Invalidate all id mappings on local core */ -static inline void local_sid_destroy_all(void) -{ - preempt_disable(); - __get_cpu_var(pcpu_last_used_sid) = 0; - memset(&__get_cpu_var(pcpu_sids), 0, sizeof(__get_cpu_var(pcpu_sids))); - preempt_enable(); -} - -static void *kvmppc_e500_id_table_alloc(struct kvmppc_vcpu_e500 *vcpu_e500) -{ - vcpu_e500->idt = kzalloc(sizeof(struct vcpu_id_table), GFP_KERNEL); - return vcpu_e500->idt; -} - -static void kvmppc_e500_id_table_free(struct kvmppc_vcpu_e500 *vcpu_e500) -{ - kfree(vcpu_e500->idt); -} - -/* Invalidate all mappings on vcpu */ -static void kvmppc_e500_id_table_reset_all(struct kvmppc_vcpu_e500 *vcpu_e500) -{ - memset(vcpu_e500->idt, 0, sizeof(struct vcpu_id_table)); - - /* Update shadow pid when mappings are changed */ - kvmppc_e500_recalc_shadow_pid(vcpu_e500); -} - -/* Invalidate one ID mapping on vcpu */ -static inline void kvmppc_e500_id_table_reset_one( - struct kvmppc_vcpu_e500 *vcpu_e500, - int as, int pid, int pr) -{ - struct vcpu_id_table *idt = vcpu_e500->idt; - - BUG_ON(as >= 2); - BUG_ON(pid >= NUM_TIDS); - BUG_ON(pr >= 2); - - idt->id[as][pid][pr].val = 0; - idt->id[as][pid][pr].pentry = NULL; - - /* Update shadow pid when mappings are changed */ - kvmppc_e500_recalc_shadow_pid(vcpu_e500); -} - -/* - * Map guest (vcpu,AS,ID,PR) to physical core shadow id. - * This function first lookup if a valid mapping exists, - * if not, then creates a new one. - * - * The caller must have preemption disabled, and keep it that way until - * it has finished with the returned shadow id (either written into the - * TLB or arch.shadow_pid, or discarded). - */ -static unsigned int kvmppc_e500_get_sid(struct kvmppc_vcpu_e500 *vcpu_e500, - unsigned int as, unsigned int gid, - unsigned int pr, int avoid_recursion) -{ - struct vcpu_id_table *idt = vcpu_e500->idt; - int sid; - - BUG_ON(as >= 2); - BUG_ON(gid >= NUM_TIDS); - BUG_ON(pr >= 2); - - sid = local_sid_lookup(&idt->id[as][gid][pr]); - - while (sid <= 0) { - /* No mapping yet */ - sid = local_sid_setup_one(&idt->id[as][gid][pr]); - if (sid <= 0) { - _tlbil_all(); - local_sid_destroy_all(); - } - - /* Update shadow pid when mappings are changed */ - if (!avoid_recursion) - kvmppc_e500_recalc_shadow_pid(vcpu_e500); - } - - return sid; -} - -/* Map guest pid to shadow. - * We use PID to keep shadow of current guest non-zero PID, - * and use PID1 to keep shadow of guest zero PID. - * So that guest tlbe with TID=0 can be accessed at any time */ -void kvmppc_e500_recalc_shadow_pid(struct kvmppc_vcpu_e500 *vcpu_e500) -{ - preempt_disable(); - vcpu_e500->vcpu.arch.shadow_pid = kvmppc_e500_get_sid(vcpu_e500, - get_cur_as(&vcpu_e500->vcpu), - get_cur_pid(&vcpu_e500->vcpu), - get_cur_pr(&vcpu_e500->vcpu), 1); - vcpu_e500->vcpu.arch.shadow_pid1 = kvmppc_e500_get_sid(vcpu_e500, - get_cur_as(&vcpu_e500->vcpu), 0, - get_cur_pr(&vcpu_e500->vcpu), 1); - preempt_enable(); -} - void kvmppc_dump_tlbs(struct kvm_vcpu *vcpu) { struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); @@ -229,14 +41,25 @@ void kvmppc_dump_tlbs(struct kvm_vcpu *vcpu) for (tlbsel = 0; tlbsel < 2; tlbsel++) { printk("Guest TLB%d:\n", tlbsel); - for (i = 0; i < vcpu_e500->gtlb_size[tlbsel]; i++) { - tlbe = &vcpu_e500->gtlb_arch[tlbsel][i]; + for (i = 0; i < vcpu_e500->guest_tlb_size[tlbsel]; i++) { + tlbe = &vcpu_e500->guest_tlb[tlbsel][i]; if (tlbe->mas1 & MAS1_VALID) printk(" G[%d][%3d] | %08X | %08X | %08X | %08X |\n", tlbsel, i, tlbe->mas1, tlbe->mas2, tlbe->mas3, tlbe->mas7); } } + + for (tlbsel = 0; tlbsel < 2; tlbsel++) { + printk("Shadow TLB%d:\n", tlbsel); + for (i = 0; i < vcpu_e500->shadow_tlb_size[tlbsel]; i++) { + tlbe = &vcpu_e500->shadow_tlb[tlbsel][i]; + if (tlbe->mas1 & MAS1_VALID) + printk(" S[%d][%3d] | %08X | %08X | %08X | %08X |\n", + tlbsel, i, tlbe->mas1, tlbe->mas2, + tlbe->mas3, tlbe->mas7); + } + } } static inline unsigned int tlb0_get_next_victim( @@ -244,17 +67,16 @@ static inline unsigned int tlb0_get_next_victim( { unsigned int victim; - victim = vcpu_e500->gtlb_nv[0]++; - if (unlikely(vcpu_e500->gtlb_nv[0] >= KVM_E500_TLB0_WAY_NUM)) - vcpu_e500->gtlb_nv[0] = 0; + victim = vcpu_e500->guest_tlb_nv[0]++; + if (unlikely(vcpu_e500->guest_tlb_nv[0] >= KVM_E500_TLB0_WAY_NUM)) + vcpu_e500->guest_tlb_nv[0] = 0; return victim; } static inline unsigned int tlb1_max_shadow_size(void) { - /* reserve one entry for magic page */ - return tlb1_entry_num - tlbcam_index - 1; + return tlb1_entry_num - tlbcam_index; } static inline int tlbe_is_writable(struct tlbe *tlbe) @@ -290,149 +112,72 @@ static inline u32 e500_shadow_mas2_attrib(u32 mas2, int usermode) /* * writing shadow tlb entry to host TLB */ -static inline void __write_host_tlbe(struct tlbe *stlbe, uint32_t mas0) +static inline void __write_host_tlbe(struct tlbe *stlbe) { - unsigned long flags; - - local_irq_save(flags); - mtspr(SPRN_MAS0, mas0); mtspr(SPRN_MAS1, stlbe->mas1); mtspr(SPRN_MAS2, stlbe->mas2); mtspr(SPRN_MAS3, stlbe->mas3); mtspr(SPRN_MAS7, stlbe->mas7); - asm volatile("isync; tlbwe" : : : "memory"); - local_irq_restore(flags); + __asm__ __volatile__ ("tlbwe\n" : : ); } static inline void write_host_tlbe(struct kvmppc_vcpu_e500 *vcpu_e500, - int tlbsel, int esel, struct tlbe *stlbe) + int tlbsel, int esel) { + struct tlbe *stlbe = &vcpu_e500->shadow_tlb[tlbsel][esel]; + + local_irq_disable(); if (tlbsel == 0) { - __write_host_tlbe(stlbe, - MAS0_TLBSEL(0) | - MAS0_ESEL(esel & (KVM_E500_TLB0_WAY_NUM - 1))); + __write_host_tlbe(stlbe); } else { - __write_host_tlbe(stlbe, - MAS0_TLBSEL(1) | - MAS0_ESEL(to_htlb1_esel(esel))); - } - trace_kvm_stlb_write(index_of(tlbsel, esel), stlbe->mas1, stlbe->mas2, - stlbe->mas3, stlbe->mas7); -} + unsigned register mas0; -void kvmppc_map_magic(struct kvm_vcpu *vcpu) -{ - struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); - struct tlbe magic; - ulong shared_page = ((ulong)vcpu->arch.shared) & PAGE_MASK; - unsigned int stid; - pfn_t pfn; - - pfn = (pfn_t)virt_to_phys((void *)shared_page) >> PAGE_SHIFT; - get_page(pfn_to_page(pfn)); - - preempt_disable(); - stid = kvmppc_e500_get_sid(vcpu_e500, 0, 0, 0, 0); - - magic.mas1 = MAS1_VALID | MAS1_TS | MAS1_TID(stid) | - MAS1_TSIZE(BOOK3E_PAGESZ_4K); - magic.mas2 = vcpu->arch.magic_page_ea | MAS2_M; - magic.mas3 = (pfn << PAGE_SHIFT) | - MAS3_SW | MAS3_SR | MAS3_UW | MAS3_UR; - magic.mas7 = pfn >> (32 - PAGE_SHIFT); - - __write_host_tlbe(&magic, MAS0_TLBSEL(1) | MAS0_ESEL(tlbcam_index)); - preempt_enable(); + mas0 = mfspr(SPRN_MAS0); + + mtspr(SPRN_MAS0, MAS0_TLBSEL(1) | MAS0_ESEL(to_htlb1_esel(esel))); + __write_host_tlbe(stlbe); + + mtspr(SPRN_MAS0, mas0); + } + local_irq_enable(); } void kvmppc_e500_tlb_load(struct kvm_vcpu *vcpu, int cpu) { struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); - - /* Shadow PID may be expired on local core */ - kvmppc_e500_recalc_shadow_pid(vcpu_e500); + int i; + unsigned register mas0; + + /* Load all valid TLB1 entries to reduce guest tlb miss fault */ + local_irq_disable(); + mas0 = mfspr(SPRN_MAS0); + for (i = 0; i < tlb1_max_shadow_size(); i++) { + struct tlbe *stlbe = &vcpu_e500->shadow_tlb[1][i]; + + if (get_tlb_v(stlbe)) { + mtspr(SPRN_MAS0, MAS0_TLBSEL(1) + | MAS0_ESEL(to_htlb1_esel(i))); + __write_host_tlbe(stlbe); + } + } + mtspr(SPRN_MAS0, mas0); + local_irq_enable(); } void kvmppc_e500_tlb_put(struct kvm_vcpu *vcpu) { -} - -static void kvmppc_e500_stlbe_invalidate(struct kvmppc_vcpu_e500 *vcpu_e500, - int tlbsel, int esel) -{ - struct tlbe *gtlbe = &vcpu_e500->gtlb_arch[tlbsel][esel]; - struct vcpu_id_table *idt = vcpu_e500->idt; - unsigned int pr, tid, ts, pid; - u32 val, eaddr; - unsigned long flags; - - ts = get_tlb_ts(gtlbe); - tid = get_tlb_tid(gtlbe); - - preempt_disable(); - - /* One guest ID may be mapped to two shadow IDs */ - for (pr = 0; pr < 2; pr++) { - /* - * The shadow PID can have a valid mapping on at most one - * host CPU. In the common case, it will be valid on this - * CPU, in which case (for TLB0) we do a local invalidation - * of the specific address. - * - * If the shadow PID is not valid on the current host CPU, or - * if we're invalidating a TLB1 entry, we invalidate the - * entire shadow PID. - */ - if (tlbsel == 1 || - (pid = local_sid_lookup(&idt->id[ts][tid][pr])) <= 0) { - kvmppc_e500_id_table_reset_one(vcpu_e500, ts, tid, pr); - continue; - } - - /* - * The guest is invalidating a TLB0 entry which is in a PID - * that has a valid shadow mapping on this host CPU. We - * search host TLB0 to invalidate it's shadow TLB entry, - * similar to __tlbil_va except that we need to look in AS1. - */ - val = (pid << MAS6_SPID_SHIFT) | MAS6_SAS; - eaddr = get_tlb_eaddr(gtlbe); - - local_irq_save(flags); - - mtspr(SPRN_MAS6, val); - asm volatile("tlbsx 0, %[eaddr]" : : [eaddr] "r" (eaddr)); - val = mfspr(SPRN_MAS1); - if (val & MAS1_VALID) { - mtspr(SPRN_MAS1, val & ~MAS1_VALID); - asm volatile("tlbwe"); - } - - local_irq_restore(flags); - } - - preempt_enable(); + _tlbil_all(); } /* Search the guest TLB for a matching entry. */ static int kvmppc_e500_tlb_index(struct kvmppc_vcpu_e500 *vcpu_e500, gva_t eaddr, int tlbsel, unsigned int pid, int as) { - int size = vcpu_e500->gtlb_size[tlbsel]; - int set_base; int i; - if (tlbsel == 0) { - int mask = size / KVM_E500_TLB0_WAY_NUM - 1; - set_base = (eaddr >> PAGE_SHIFT) & mask; - set_base *= KVM_E500_TLB0_WAY_NUM; - size = KVM_E500_TLB0_WAY_NUM; - } else { - set_base = 0; - } - - for (i = 0; i < size; i++) { - struct tlbe *tlbe = &vcpu_e500->gtlb_arch[tlbsel][set_base + i]; + /* XXX Replace loop with fancy data structures. */ + for (i = 0; i < vcpu_e500->guest_tlb_size[tlbsel]; i++) { + struct tlbe *tlbe = &vcpu_e500->guest_tlb[tlbsel][i]; unsigned int tid; if (eaddr < get_tlb_eaddr(tlbe)) @@ -451,32 +196,66 @@ static int kvmppc_e500_tlb_index(struct kvmppc_vcpu_e500 *vcpu_e500, if (get_tlb_ts(tlbe) != as && as != -1) continue; - return set_base + i; + return i; } return -1; } -static inline void kvmppc_e500_priv_setup(struct tlbe_priv *priv, - struct tlbe *gtlbe, - pfn_t pfn) +static void kvmppc_e500_shadow_release(struct kvmppc_vcpu_e500 *vcpu_e500, + int tlbsel, int esel) +{ + struct tlbe *stlbe = &vcpu_e500->shadow_tlb[tlbsel][esel]; + struct page *page = vcpu_e500->shadow_pages[tlbsel][esel]; + + if (page) { + vcpu_e500->shadow_pages[tlbsel][esel] = NULL; + + if (get_tlb_v(stlbe)) { + if (tlbe_is_writable(stlbe)) + kvm_release_page_dirty(page); + else + kvm_release_page_clean(page); + } + } +} + +static void kvmppc_e500_stlbe_invalidate(struct kvmppc_vcpu_e500 *vcpu_e500, + int tlbsel, int esel) { - priv->pfn = pfn; - priv->flags = E500_TLB_VALID; + struct tlbe *stlbe = &vcpu_e500->shadow_tlb[tlbsel][esel]; - if (tlbe_is_writable(gtlbe)) - priv->flags |= E500_TLB_DIRTY; + kvmppc_e500_shadow_release(vcpu_e500, tlbsel, esel); + stlbe->mas1 = 0; + trace_kvm_stlb_inval(index_of(tlbsel, esel)); } -static inline void kvmppc_e500_priv_release(struct tlbe_priv *priv) +static void kvmppc_e500_tlb1_invalidate(struct kvmppc_vcpu_e500 *vcpu_e500, + gva_t eaddr, gva_t eend, u32 tid) { - if (priv->flags & E500_TLB_VALID) { - if (priv->flags & E500_TLB_DIRTY) - kvm_release_pfn_dirty(priv->pfn); - else - kvm_release_pfn_clean(priv->pfn); + unsigned int pid = tid & 0xff; + unsigned int i; + + /* XXX Replace loop with fancy data structures. */ + for (i = 0; i < vcpu_e500->guest_tlb_size[1]; i++) { + struct tlbe *stlbe = &vcpu_e500->shadow_tlb[1][i]; + unsigned int tid; + + if (!get_tlb_v(stlbe)) + continue; + + if (eend < get_tlb_eaddr(stlbe)) + continue; - priv->flags = 0; + if (eaddr > get_tlb_end(stlbe)) + continue; + + tid = get_tlb_tid(stlbe); + if (tid && (tid != pid)) + continue; + + kvmppc_e500_stlbe_invalidate(vcpu_e500, 1, i); + write_host_tlbe(vcpu_e500, 1, i); } } @@ -494,7 +273,7 @@ static inline void kvmppc_e500_deliver_tlb_miss(struct kvm_vcpu *vcpu, tsized = (vcpu_e500->mas4 >> 7) & 0x1f; vcpu_e500->mas0 = MAS0_TLBSEL(tlbsel) | MAS0_ESEL(victim) - | MAS0_NV(vcpu_e500->gtlb_nv[tlbsel]); + | MAS0_NV(vcpu_e500->guest_tlb_nv[tlbsel]); vcpu_e500->mas1 = MAS1_VALID | (as ? MAS1_TS : 0) | MAS1_TID(vcpu_e500->pid[pidsel]) | MAS1_TSIZE(tsized); @@ -507,154 +286,56 @@ static inline void kvmppc_e500_deliver_tlb_miss(struct kvm_vcpu *vcpu, vcpu_e500->mas7 = 0; } -static inline void kvmppc_e500_setup_stlbe(struct kvmppc_vcpu_e500 *vcpu_e500, - struct tlbe *gtlbe, int tsize, - struct tlbe_priv *priv, - u64 gvaddr, struct tlbe *stlbe) +static inline void kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500, + u64 gvaddr, gfn_t gfn, struct tlbe *gtlbe, int tlbsel, int esel) { - pfn_t pfn = priv->pfn; - unsigned int stid; + struct page *new_page; + struct tlbe *stlbe; + hpa_t hpaddr; + + stlbe = &vcpu_e500->shadow_tlb[tlbsel][esel]; + + /* Get reference to new page. */ + new_page = gfn_to_page(vcpu_e500->vcpu.kvm, gfn); + if (is_error_page(new_page)) { + printk(KERN_ERR "Couldn't get guest page for gfn %lx!\n", + (long)gfn); + kvm_release_page_clean(new_page); + return; + } + hpaddr = page_to_phys(new_page); + + /* Drop reference to old page. */ + kvmppc_e500_shadow_release(vcpu_e500, tlbsel, esel); - stid = kvmppc_e500_get_sid(vcpu_e500, get_tlb_ts(gtlbe), - get_tlb_tid(gtlbe), - get_cur_pr(&vcpu_e500->vcpu), 0); + vcpu_e500->shadow_pages[tlbsel][esel] = new_page; - /* Force TS=1 IPROT=0 for all guest mappings. */ - stlbe->mas1 = MAS1_TSIZE(tsize) - | MAS1_TID(stid) | MAS1_TS | MAS1_VALID; + /* Force TS=1 IPROT=0 TSIZE=4KB for all guest mappings. */ + stlbe->mas1 = MAS1_TSIZE(BOOK3E_PAGESZ_4K) + | MAS1_TID(get_tlb_tid(gtlbe)) | MAS1_TS | MAS1_VALID; stlbe->mas2 = (gvaddr & MAS2_EPN) | e500_shadow_mas2_attrib(gtlbe->mas2, vcpu_e500->vcpu.arch.shared->msr & MSR_PR); - stlbe->mas3 = ((pfn << PAGE_SHIFT) & MAS3_RPN) + stlbe->mas3 = (hpaddr & MAS3_RPN) | e500_shadow_mas3_attrib(gtlbe->mas3, vcpu_e500->vcpu.arch.shared->msr & MSR_PR); - stlbe->mas7 = (pfn >> (32 - PAGE_SHIFT)) & MAS7_RPN; -} - - -static inline void kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500, - u64 gvaddr, gfn_t gfn, struct tlbe *gtlbe, int tlbsel, int esel, - struct tlbe *stlbe) -{ - struct kvm_memory_slot *slot; - unsigned long pfn, hva; - int pfnmap = 0; - int tsize = BOOK3E_PAGESZ_4K; - struct tlbe_priv *priv; - - /* - * Translate guest physical to true physical, acquiring - * a page reference if it is normal, non-reserved memory. - * - * gfn_to_memslot() must succeed because otherwise we wouldn't - * have gotten this far. Eventually we should just pass the slot - * pointer through from the first lookup. - */ - slot = gfn_to_memslot(vcpu_e500->vcpu.kvm, gfn); - hva = gfn_to_hva_memslot(slot, gfn); + stlbe->mas7 = (hpaddr >> 32) & MAS7_RPN; - if (tlbsel == 1) { - struct vm_area_struct *vma; - down_read(¤t->mm->mmap_sem); - - vma = find_vma(current->mm, hva); - if (vma && hva >= vma->vm_start && - (vma->vm_flags & VM_PFNMAP)) { - /* - * This VMA is a physically contiguous region (e.g. - * /dev/mem) that bypasses normal Linux page - * management. Find the overlap between the - * vma and the memslot. - */ - - unsigned long start, end; - unsigned long slot_start, slot_end; - - pfnmap = 1; - - start = vma->vm_pgoff; - end = start + - ((vma->vm_end - vma->vm_start) >> PAGE_SHIFT); - - pfn = start + ((hva - vma->vm_start) >> PAGE_SHIFT); - - slot_start = pfn - (gfn - slot->base_gfn); - slot_end = slot_start + slot->npages; - - if (start < slot_start) - start = slot_start; - if (end > slot_end) - end = slot_end; - - tsize = (gtlbe->mas1 & MAS1_TSIZE_MASK) >> - MAS1_TSIZE_SHIFT; - - /* - * e500 doesn't implement the lowest tsize bit, - * or 1K pages. - */ - tsize = max(BOOK3E_PAGESZ_4K, tsize & ~1); - - /* - * Now find the largest tsize (up to what the guest - * requested) that will cover gfn, stay within the - * range, and for which gfn and pfn are mutually - * aligned. - */ - - for (; tsize > BOOK3E_PAGESZ_4K; tsize -= 2) { - unsigned long gfn_start, gfn_end, tsize_pages; - tsize_pages = 1 << (tsize - 2); - - gfn_start = gfn & ~(tsize_pages - 1); - gfn_end = gfn_start + tsize_pages; - - if (gfn_start + pfn - gfn < start) - continue; - if (gfn_end + pfn - gfn > end) - continue; - if ((gfn & (tsize_pages - 1)) != - (pfn & (tsize_pages - 1))) - continue; - - gvaddr &= ~((tsize_pages << PAGE_SHIFT) - 1); - pfn &= ~(tsize_pages - 1); - break; - } - } - - up_read(¤t->mm->mmap_sem); - } - - if (likely(!pfnmap)) { - pfn = gfn_to_pfn_memslot(vcpu_e500->vcpu.kvm, slot, gfn); - if (is_error_pfn(pfn)) { - printk(KERN_ERR "Couldn't get real page for gfn %lx!\n", - (long)gfn); - kvm_release_pfn_clean(pfn); - return; - } - } - - /* Drop old priv and setup new one. */ - priv = &vcpu_e500->gtlb_priv[tlbsel][esel]; - kvmppc_e500_priv_release(priv); - kvmppc_e500_priv_setup(priv, gtlbe, pfn); - - kvmppc_e500_setup_stlbe(vcpu_e500, gtlbe, tsize, priv, gvaddr, stlbe); + trace_kvm_stlb_write(index_of(tlbsel, esel), stlbe->mas1, stlbe->mas2, + stlbe->mas3, stlbe->mas7); } /* XXX only map the one-one case, for now use TLB0 */ -static int kvmppc_e500_tlb0_map(struct kvmppc_vcpu_e500 *vcpu_e500, - int esel, struct tlbe *stlbe) +static int kvmppc_e500_stlbe_map(struct kvmppc_vcpu_e500 *vcpu_e500, + int tlbsel, int esel) { struct tlbe *gtlbe; - gtlbe = &vcpu_e500->gtlb_arch[0][esel]; + gtlbe = &vcpu_e500->guest_tlb[tlbsel][esel]; kvmppc_e500_shadow_map(vcpu_e500, get_tlb_eaddr(gtlbe), get_tlb_raddr(gtlbe) >> PAGE_SHIFT, - gtlbe, 0, esel, stlbe); + gtlbe, tlbsel, esel); return esel; } @@ -663,37 +344,53 @@ static int kvmppc_e500_tlb0_map(struct kvmppc_vcpu_e500 *vcpu_e500, * the shadow TLB. */ /* XXX for both one-one and one-to-many , for now use TLB1 */ static int kvmppc_e500_tlb1_map(struct kvmppc_vcpu_e500 *vcpu_e500, - u64 gvaddr, gfn_t gfn, struct tlbe *gtlbe, struct tlbe *stlbe) + u64 gvaddr, gfn_t gfn, struct tlbe *gtlbe) { unsigned int victim; - victim = vcpu_e500->gtlb_nv[1]++; + victim = vcpu_e500->guest_tlb_nv[1]++; - if (unlikely(vcpu_e500->gtlb_nv[1] >= tlb1_max_shadow_size())) - vcpu_e500->gtlb_nv[1] = 0; + if (unlikely(vcpu_e500->guest_tlb_nv[1] >= tlb1_max_shadow_size())) + vcpu_e500->guest_tlb_nv[1] = 0; - kvmppc_e500_shadow_map(vcpu_e500, gvaddr, gfn, gtlbe, 1, victim, stlbe); + kvmppc_e500_shadow_map(vcpu_e500, gvaddr, gfn, gtlbe, 1, victim); return victim; } -void kvmppc_mmu_msr_notify(struct kvm_vcpu *vcpu, u32 old_msr) +/* Invalidate all guest kernel mappings when enter usermode, + * so that when they fault back in they will get the + * proper permission bits. */ +void kvmppc_mmu_priv_switch(struct kvm_vcpu *vcpu, int usermode) { - struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); + if (usermode) { + struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); + int i; + + /* XXX Replace loop with fancy data structures. */ + for (i = 0; i < tlb1_max_shadow_size(); i++) + kvmppc_e500_stlbe_invalidate(vcpu_e500, 1, i); - /* Recalc shadow pid since MSR changes */ - kvmppc_e500_recalc_shadow_pid(vcpu_e500); + _tlbil_all(); + } } -static inline int kvmppc_e500_gtlbe_invalidate( - struct kvmppc_vcpu_e500 *vcpu_e500, - int tlbsel, int esel) +static int kvmppc_e500_gtlbe_invalidate(struct kvmppc_vcpu_e500 *vcpu_e500, + int tlbsel, int esel) { - struct tlbe *gtlbe = &vcpu_e500->gtlb_arch[tlbsel][esel]; + struct tlbe *gtlbe = &vcpu_e500->guest_tlb[tlbsel][esel]; if (unlikely(get_tlb_iprot(gtlbe))) return -1; + if (tlbsel == 1) { + kvmppc_e500_tlb1_invalidate(vcpu_e500, get_tlb_eaddr(gtlbe), + get_tlb_end(gtlbe), + get_tlb_tid(gtlbe)); + } else { + kvmppc_e500_stlbe_invalidate(vcpu_e500, tlbsel, esel); + } + gtlbe->mas1 = 0; return 0; @@ -704,14 +401,13 @@ int kvmppc_e500_emul_mt_mmucsr0(struct kvmppc_vcpu_e500 *vcpu_e500, ulong value) int esel; if (value & MMUCSR0_TLB0FI) - for (esel = 0; esel < vcpu_e500->gtlb_size[0]; esel++) + for (esel = 0; esel < vcpu_e500->guest_tlb_size[0]; esel++) kvmppc_e500_gtlbe_invalidate(vcpu_e500, 0, esel); if (value & MMUCSR0_TLB1FI) - for (esel = 0; esel < vcpu_e500->gtlb_size[1]; esel++) + for (esel = 0; esel < vcpu_e500->guest_tlb_size[1]; esel++) kvmppc_e500_gtlbe_invalidate(vcpu_e500, 1, esel); - /* Invalidate all vcpu id mappings */ - kvmppc_e500_id_table_reset_all(vcpu_e500); + _tlbil_all(); return EMULATE_DONE; } @@ -732,7 +428,7 @@ int kvmppc_e500_emul_tlbivax(struct kvm_vcpu *vcpu, int ra, int rb) if (ia) { /* invalidate all entries */ - for (esel = 0; esel < vcpu_e500->gtlb_size[tlbsel]; esel++) + for (esel = 0; esel < vcpu_e500->guest_tlb_size[tlbsel]; esel++) kvmppc_e500_gtlbe_invalidate(vcpu_e500, tlbsel, esel); } else { ea &= 0xfffff000; @@ -742,8 +438,7 @@ int kvmppc_e500_emul_tlbivax(struct kvm_vcpu *vcpu, int ra, int rb) kvmppc_e500_gtlbe_invalidate(vcpu_e500, tlbsel, esel); } - /* Invalidate all vcpu id mappings */ - kvmppc_e500_id_table_reset_all(vcpu_e500); + _tlbil_all(); return EMULATE_DONE; } @@ -757,9 +452,9 @@ int kvmppc_e500_emul_tlbre(struct kvm_vcpu *vcpu) tlbsel = get_tlb_tlbsel(vcpu_e500); esel = get_tlb_esel(vcpu_e500, tlbsel); - gtlbe = &vcpu_e500->gtlb_arch[tlbsel][esel]; + gtlbe = &vcpu_e500->guest_tlb[tlbsel][esel]; vcpu_e500->mas0 &= ~MAS0_NV(~0); - vcpu_e500->mas0 |= MAS0_NV(vcpu_e500->gtlb_nv[tlbsel]); + vcpu_e500->mas0 |= MAS0_NV(vcpu_e500->guest_tlb_nv[tlbsel]); vcpu_e500->mas1 = gtlbe->mas1; vcpu_e500->mas2 = gtlbe->mas2; vcpu_e500->mas3 = gtlbe->mas3; @@ -782,14 +477,14 @@ int kvmppc_e500_emul_tlbsx(struct kvm_vcpu *vcpu, int rb) for (tlbsel = 0; tlbsel < 2; tlbsel++) { esel = kvmppc_e500_tlb_index(vcpu_e500, ea, tlbsel, pid, as); if (esel >= 0) { - gtlbe = &vcpu_e500->gtlb_arch[tlbsel][esel]; + gtlbe = &vcpu_e500->guest_tlb[tlbsel][esel]; break; } } if (gtlbe) { vcpu_e500->mas0 = MAS0_TLBSEL(tlbsel) | MAS0_ESEL(esel) - | MAS0_NV(vcpu_e500->gtlb_nv[tlbsel]); + | MAS0_NV(vcpu_e500->guest_tlb_nv[tlbsel]); vcpu_e500->mas1 = gtlbe->mas1; vcpu_e500->mas2 = gtlbe->mas2; vcpu_e500->mas3 = gtlbe->mas3; @@ -802,7 +497,7 @@ int kvmppc_e500_emul_tlbsx(struct kvm_vcpu *vcpu, int rb) victim = (tlbsel == 0) ? tlb0_get_next_victim(vcpu_e500) : 0; vcpu_e500->mas0 = MAS0_TLBSEL(tlbsel) | MAS0_ESEL(victim) - | MAS0_NV(vcpu_e500->gtlb_nv[tlbsel]); + | MAS0_NV(vcpu_e500->guest_tlb_nv[tlbsel]); vcpu_e500->mas1 = (vcpu_e500->mas6 & MAS6_SPID0) | (vcpu_e500->mas6 & (MAS6_SAS ? MAS1_TS : 0)) | (vcpu_e500->mas4 & MAS4_TSIZED(~0)); @@ -819,16 +514,23 @@ int kvmppc_e500_emul_tlbsx(struct kvm_vcpu *vcpu, int rb) int kvmppc_e500_emul_tlbwe(struct kvm_vcpu *vcpu) { struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); + u64 eaddr; + u64 raddr; + u32 tid; struct tlbe *gtlbe; - int tlbsel, esel; + int tlbsel, esel, stlbsel, sesel; tlbsel = get_tlb_tlbsel(vcpu_e500); esel = get_tlb_esel(vcpu_e500, tlbsel); - gtlbe = &vcpu_e500->gtlb_arch[tlbsel][esel]; + gtlbe = &vcpu_e500->guest_tlb[tlbsel][esel]; - if (get_tlb_v(gtlbe)) - kvmppc_e500_stlbe_invalidate(vcpu_e500, tlbsel, esel); + if (get_tlb_v(gtlbe) && tlbsel == 1) { + eaddr = get_tlb_eaddr(gtlbe); + tid = get_tlb_tid(gtlbe); + kvmppc_e500_tlb1_invalidate(vcpu_e500, eaddr, + get_tlb_end(gtlbe), tid); + } gtlbe->mas1 = vcpu_e500->mas1; gtlbe->mas2 = vcpu_e500->mas2; @@ -840,12 +542,6 @@ int kvmppc_e500_emul_tlbwe(struct kvm_vcpu *vcpu) /* Invalidate shadow mappings for the about-to-be-clobbered TLBE. */ if (tlbe_is_host_safe(vcpu, gtlbe)) { - struct tlbe stlbe; - int stlbsel, sesel; - u64 eaddr; - u64 raddr; - - preempt_disable(); switch (tlbsel) { case 0: /* TLB0 */ @@ -853,7 +549,7 @@ int kvmppc_e500_emul_tlbwe(struct kvm_vcpu *vcpu) gtlbe->mas1 |= MAS1_TSIZE(BOOK3E_PAGESZ_4K); stlbsel = 0; - sesel = kvmppc_e500_tlb0_map(vcpu_e500, esel, &stlbe); + sesel = kvmppc_e500_stlbe_map(vcpu_e500, 0, esel); break; @@ -868,14 +564,13 @@ int kvmppc_e500_emul_tlbwe(struct kvm_vcpu *vcpu) * are mapped on the fly. */ stlbsel = 1; sesel = kvmppc_e500_tlb1_map(vcpu_e500, eaddr, - raddr >> PAGE_SHIFT, gtlbe, &stlbe); + raddr >> PAGE_SHIFT, gtlbe); break; default: BUG(); } - write_host_tlbe(vcpu_e500, stlbsel, sesel, &stlbe); - preempt_enable(); + write_host_tlbe(vcpu_e500, stlbsel, sesel); } kvmppc_set_exit_type(vcpu, EMULATED_TLBWE_EXITS); @@ -915,7 +610,7 @@ gpa_t kvmppc_mmu_xlate(struct kvm_vcpu *vcpu, unsigned int index, { struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); struct tlbe *gtlbe = - &vcpu_e500->gtlb_arch[tlbsel_of(index)][esel_of(index)]; + &vcpu_e500->guest_tlb[tlbsel_of(index)][esel_of(index)]; u64 pgmask = get_tlb_bytes(gtlbe) - 1; return get_tlb_raddr(gtlbe) | (eaddr & pgmask); @@ -923,37 +618,38 @@ gpa_t kvmppc_mmu_xlate(struct kvm_vcpu *vcpu, unsigned int index, void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu) { + struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); + int tlbsel, i; + + for (tlbsel = 0; tlbsel < 2; tlbsel++) + for (i = 0; i < vcpu_e500->guest_tlb_size[tlbsel]; i++) + kvmppc_e500_shadow_release(vcpu_e500, tlbsel, i); + + /* discard all guest mapping */ + _tlbil_all(); } void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 eaddr, gpa_t gpaddr, unsigned int index) { struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); - struct tlbe_priv *priv; - struct tlbe *gtlbe, stlbe; int tlbsel = tlbsel_of(index); int esel = esel_of(index); int stlbsel, sesel; - gtlbe = &vcpu_e500->gtlb_arch[tlbsel][esel]; - - preempt_disable(); switch (tlbsel) { case 0: stlbsel = 0; sesel = esel; - priv = &vcpu_e500->gtlb_priv[stlbsel][sesel]; - - kvmppc_e500_setup_stlbe(vcpu_e500, gtlbe, BOOK3E_PAGESZ_4K, - priv, eaddr, &stlbe); break; case 1: { gfn_t gfn = gpaddr >> PAGE_SHIFT; + struct tlbe *gtlbe + = &vcpu_e500->guest_tlb[tlbsel][esel]; stlbsel = 1; - sesel = kvmppc_e500_tlb1_map(vcpu_e500, eaddr, gfn, - gtlbe, &stlbe); + sesel = kvmppc_e500_tlb1_map(vcpu_e500, eaddr, gfn, gtlbe); break; } @@ -961,9 +657,7 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 eaddr, gpa_t gpaddr, BUG(); break; } - - write_host_tlbe(vcpu_e500, stlbsel, sesel, &stlbe); - preempt_enable(); + write_host_tlbe(vcpu_e500, stlbsel, sesel); } int kvmppc_e500_tlb_search(struct kvm_vcpu *vcpu, @@ -985,10 +679,8 @@ void kvmppc_set_pid(struct kvm_vcpu *vcpu, u32 pid) { struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); - if (vcpu->arch.pid != pid) { - vcpu_e500->pid[0] = vcpu->arch.pid = pid; - kvmppc_e500_recalc_shadow_pid(vcpu_e500); - } + vcpu_e500->pid[0] = vcpu->arch.shadow_pid = + vcpu->arch.pid = pid; } void kvmppc_e500_tlb_setup(struct kvmppc_vcpu_e500 *vcpu_e500) @@ -996,14 +688,14 @@ void kvmppc_e500_tlb_setup(struct kvmppc_vcpu_e500 *vcpu_e500) struct tlbe *tlbe; /* Insert large initial mapping for guest. */ - tlbe = &vcpu_e500->gtlb_arch[1][0]; + tlbe = &vcpu_e500->guest_tlb[1][0]; tlbe->mas1 = MAS1_VALID | MAS1_TSIZE(BOOK3E_PAGESZ_256M); tlbe->mas2 = 0; tlbe->mas3 = E500_TLB_SUPER_PERM_MASK; tlbe->mas7 = 0; /* 4K map for serial output. Used by kernel wrapper. */ - tlbe = &vcpu_e500->gtlb_arch[1][1]; + tlbe = &vcpu_e500->guest_tlb[1][1]; tlbe->mas1 = MAS1_VALID | MAS1_TSIZE(BOOK3E_PAGESZ_4K); tlbe->mas2 = (0xe0004500 & 0xFFFFF000) | MAS2_I | MAS2_G; tlbe->mas3 = (0xe0004500 & 0xFFFFF000) | E500_TLB_SUPER_PERM_MASK; @@ -1014,64 +706,68 @@ int kvmppc_e500_tlb_init(struct kvmppc_vcpu_e500 *vcpu_e500) { tlb1_entry_num = mfspr(SPRN_TLB1CFG) & 0xFFF; - vcpu_e500->gtlb_size[0] = KVM_E500_TLB0_SIZE; - vcpu_e500->gtlb_arch[0] = + vcpu_e500->guest_tlb_size[0] = KVM_E500_TLB0_SIZE; + vcpu_e500->guest_tlb[0] = kzalloc(sizeof(struct tlbe) * KVM_E500_TLB0_SIZE, GFP_KERNEL); - if (vcpu_e500->gtlb_arch[0] == NULL) + if (vcpu_e500->guest_tlb[0] == NULL) goto err_out; - vcpu_e500->gtlb_size[1] = KVM_E500_TLB1_SIZE; - vcpu_e500->gtlb_arch[1] = - kzalloc(sizeof(struct tlbe) * KVM_E500_TLB1_SIZE, GFP_KERNEL); - if (vcpu_e500->gtlb_arch[1] == NULL) + vcpu_e500->shadow_tlb_size[0] = KVM_E500_TLB0_SIZE; + vcpu_e500->shadow_tlb[0] = + kzalloc(sizeof(struct tlbe) * KVM_E500_TLB0_SIZE, GFP_KERNEL); + if (vcpu_e500->shadow_tlb[0] == NULL) goto err_out_guest0; - vcpu_e500->gtlb_priv[0] = (struct tlbe_priv *) - kzalloc(sizeof(struct tlbe_priv) * KVM_E500_TLB0_SIZE, GFP_KERNEL); - if (vcpu_e500->gtlb_priv[0] == NULL) + vcpu_e500->guest_tlb_size[1] = KVM_E500_TLB1_SIZE; + vcpu_e500->guest_tlb[1] = + kzalloc(sizeof(struct tlbe) * KVM_E500_TLB1_SIZE, GFP_KERNEL); + if (vcpu_e500->guest_tlb[1] == NULL) + goto err_out_shadow0; + + vcpu_e500->shadow_tlb_size[1] = tlb1_entry_num; + vcpu_e500->shadow_tlb[1] = + kzalloc(sizeof(struct tlbe) * tlb1_entry_num, GFP_KERNEL); + if (vcpu_e500->shadow_tlb[1] == NULL) goto err_out_guest1; - vcpu_e500->gtlb_priv[1] = (struct tlbe_priv *) - kzalloc(sizeof(struct tlbe_priv) * KVM_E500_TLB1_SIZE, GFP_KERNEL); - if (vcpu_e500->gtlb_priv[1] == NULL) - goto err_out_priv0; + vcpu_e500->shadow_pages[0] = (struct page **) + kzalloc(sizeof(struct page *) * KVM_E500_TLB0_SIZE, GFP_KERNEL); + if (vcpu_e500->shadow_pages[0] == NULL) + goto err_out_shadow1; - if (kvmppc_e500_id_table_alloc(vcpu_e500) == NULL) - goto err_out_priv1; + vcpu_e500->shadow_pages[1] = (struct page **) + kzalloc(sizeof(struct page *) * tlb1_entry_num, GFP_KERNEL); + if (vcpu_e500->shadow_pages[1] == NULL) + goto err_out_page0; /* Init TLB configuration register */ vcpu_e500->tlb0cfg = mfspr(SPRN_TLB0CFG) & ~0xfffUL; - vcpu_e500->tlb0cfg |= vcpu_e500->gtlb_size[0]; + vcpu_e500->tlb0cfg |= vcpu_e500->guest_tlb_size[0]; vcpu_e500->tlb1cfg = mfspr(SPRN_TLB1CFG) & ~0xfffUL; - vcpu_e500->tlb1cfg |= vcpu_e500->gtlb_size[1]; + vcpu_e500->tlb1cfg |= vcpu_e500->guest_tlb_size[1]; return 0; -err_out_priv1: - kfree(vcpu_e500->gtlb_priv[1]); -err_out_priv0: - kfree(vcpu_e500->gtlb_priv[0]); +err_out_page0: + kfree(vcpu_e500->shadow_pages[0]); +err_out_shadow1: + kfree(vcpu_e500->shadow_tlb[1]); err_out_guest1: - kfree(vcpu_e500->gtlb_arch[1]); + kfree(vcpu_e500->guest_tlb[1]); +err_out_shadow0: + kfree(vcpu_e500->shadow_tlb[0]); err_out_guest0: - kfree(vcpu_e500->gtlb_arch[0]); + kfree(vcpu_e500->guest_tlb[0]); err_out: return -1; } void kvmppc_e500_tlb_uninit(struct kvmppc_vcpu_e500 *vcpu_e500) { - int stlbsel, i; - - /* release all privs */ - for (stlbsel = 0; stlbsel < 2; stlbsel++) - for (i = 0; i < vcpu_e500->gtlb_size[stlbsel]; i++) { - struct tlbe_priv *priv = - &vcpu_e500->gtlb_priv[stlbsel][i]; - kvmppc_e500_priv_release(priv); - } - - kvmppc_e500_id_table_free(vcpu_e500); - kfree(vcpu_e500->gtlb_arch[1]); - kfree(vcpu_e500->gtlb_arch[0]); + kfree(vcpu_e500->shadow_pages[1]); + kfree(vcpu_e500->shadow_pages[0]); + kfree(vcpu_e500->shadow_tlb[1]); + kfree(vcpu_e500->guest_tlb[1]); + kfree(vcpu_e500->shadow_tlb[0]); + kfree(vcpu_e500->guest_tlb[0]); } diff --git a/trunk/arch/powerpc/kvm/e500_tlb.h b/trunk/arch/powerpc/kvm/e500_tlb.h index 59b88e99a235..458946b4775d 100644 --- a/trunk/arch/powerpc/kvm/e500_tlb.h +++ b/trunk/arch/powerpc/kvm/e500_tlb.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All rights reserved. + * Copyright (C) 2008 Freescale Semiconductor, Inc. All rights reserved. * * Author: Yu Liu, yu.liu@freescale.com * @@ -55,7 +55,6 @@ extern void kvmppc_e500_tlb_load(struct kvm_vcpu *, int); extern int kvmppc_e500_tlb_init(struct kvmppc_vcpu_e500 *); extern void kvmppc_e500_tlb_uninit(struct kvmppc_vcpu_e500 *); extern void kvmppc_e500_tlb_setup(struct kvmppc_vcpu_e500 *); -extern void kvmppc_e500_recalc_shadow_pid(struct kvmppc_vcpu_e500 *); /* TLB helper functions */ static inline unsigned int get_tlb_size(const struct tlbe *tlbe) @@ -111,16 +110,6 @@ static inline unsigned int get_cur_pid(struct kvm_vcpu *vcpu) return vcpu->arch.pid & 0xff; } -static inline unsigned int get_cur_as(struct kvm_vcpu *vcpu) -{ - return !!(vcpu->arch.shared->msr & (MSR_IS | MSR_DS)); -} - -static inline unsigned int get_cur_pr(struct kvm_vcpu *vcpu) -{ - return !!(vcpu->arch.shared->msr & MSR_PR); -} - static inline unsigned int get_cur_spid( const struct kvmppc_vcpu_e500 *vcpu_e500) { diff --git a/trunk/arch/powerpc/kvm/powerpc.c b/trunk/arch/powerpc/kvm/powerpc.c index a107c9be0fb1..616dd516ca1f 100644 --- a/trunk/arch/powerpc/kvm/powerpc.c +++ b/trunk/arch/powerpc/kvm/powerpc.c @@ -30,7 +30,6 @@ #include #include #include -#include #include "timing.h" #include "../mm/mmu_decl.h" @@ -39,12 +38,8 @@ int kvm_arch_vcpu_runnable(struct kvm_vcpu *v) { -#ifndef CONFIG_KVM_BOOK3S_64_HV return !(v->arch.shared->msr & MSR_WE) || !!(v->arch.pending_exceptions); -#else - return !(v->arch.ceded) || !!(v->arch.pending_exceptions); -#endif } int kvmppc_kvm_pv(struct kvm_vcpu *vcpu) @@ -78,8 +73,7 @@ int kvmppc_kvm_pv(struct kvm_vcpu *vcpu) } case HC_VENDOR_KVM | KVM_HC_FEATURES: r = HC_EV_SUCCESS; -#if defined(CONFIG_PPC_BOOK3S) || defined(CONFIG_KVM_E500) - /* XXX Missing magic page on 44x */ +#if defined(CONFIG_PPC_BOOK3S) /* XXX Missing magic page on BookE */ r2 |= (1 << KVM_FEATURE_MAGIC_PAGE); #endif @@ -153,7 +147,7 @@ void kvm_arch_check_processor_compat(void *rtn) int kvm_arch_init_vm(struct kvm *kvm) { - return kvmppc_core_init_vm(kvm); + return 0; } void kvm_arch_destroy_vm(struct kvm *kvm) @@ -169,9 +163,6 @@ void kvm_arch_destroy_vm(struct kvm *kvm) kvm->vcpus[i] = NULL; atomic_set(&kvm->online_vcpus, 0); - - kvmppc_core_destroy_vm(kvm); - mutex_unlock(&kvm->lock); } @@ -189,13 +180,10 @@ int kvm_dev_ioctl_check_extension(long ext) #else case KVM_CAP_PPC_SEGSTATE: #endif + case KVM_CAP_PPC_PAIRED_SINGLES: case KVM_CAP_PPC_UNSET_IRQ: case KVM_CAP_PPC_IRQ_LEVEL: case KVM_CAP_ENABLE_CAP: - r = 1; - break; -#ifndef CONFIG_KVM_BOOK3S_64_HV - case KVM_CAP_PPC_PAIRED_SINGLES: case KVM_CAP_PPC_OSI: case KVM_CAP_PPC_GET_PVINFO: r = 1; @@ -203,21 +191,6 @@ int kvm_dev_ioctl_check_extension(long ext) case KVM_CAP_COALESCED_MMIO: r = KVM_COALESCED_MMIO_PAGE_OFFSET; break; -#endif -#ifdef CONFIG_KVM_BOOK3S_64_HV - case KVM_CAP_SPAPR_TCE: - r = 1; - break; - case KVM_CAP_PPC_SMT: - r = threads_per_core; - break; - case KVM_CAP_PPC_RMA: - r = 1; - /* PPC970 requires an RMA */ - if (cpu_has_feature(CPU_FTR_ARCH_201)) - r = 2; - break; -#endif default: r = 0; break; @@ -238,7 +211,7 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm, struct kvm_userspace_memory_region *mem, int user_alloc) { - return kvmppc_core_prepare_memory_region(kvm, mem); + return 0; } void kvm_arch_commit_memory_region(struct kvm *kvm, @@ -246,7 +219,7 @@ void kvm_arch_commit_memory_region(struct kvm *kvm, struct kvm_memory_slot old, int user_alloc) { - kvmppc_core_commit_memory_region(kvm, mem); + return; } @@ -314,7 +287,6 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) hrtimer_init(&vcpu->arch.dec_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS); tasklet_init(&vcpu->arch.tasklet, kvmppc_decrementer_func, (ulong)vcpu); vcpu->arch.dec_timer.function = kvmppc_decrementer_wakeup; - vcpu->arch.dec_expires = ~(u64)0; #ifdef CONFIG_KVM_EXIT_TIMING mutex_init(&vcpu->arch.exit_timing_lock); @@ -341,7 +313,6 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) mtspr(SPRN_VRSAVE, vcpu->arch.vrsave); #endif kvmppc_core_vcpu_load(vcpu, cpu); - vcpu->cpu = smp_processor_id(); } void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) @@ -350,7 +321,6 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) #ifdef CONFIG_BOOKE vcpu->arch.vrsave = mfspr(SPRN_VRSAVE); #endif - vcpu->cpu = -1; } int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, @@ -522,18 +492,15 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) for (i = 0; i < 32; i++) kvmppc_set_gpr(vcpu, i, gprs[i]); vcpu->arch.osi_needed = 0; - } else if (vcpu->arch.hcall_needed) { - int i; - - kvmppc_set_gpr(vcpu, 3, run->papr_hcall.ret); - for (i = 0; i < 9; ++i) - kvmppc_set_gpr(vcpu, 4 + i, run->papr_hcall.args[i]); - vcpu->arch.hcall_needed = 0; } kvmppc_core_deliver_interrupts(vcpu); - r = kvmppc_vcpu_run(run, vcpu); + local_irq_disable(); + kvm_guest_enter(); + r = __kvmppc_vcpu_run(run, vcpu); + kvm_guest_exit(); + local_irq_enable(); if (vcpu->sigset_active) sigprocmask(SIG_SETMASK, &sigsaved, NULL); @@ -551,8 +518,6 @@ int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq) if (waitqueue_active(&vcpu->wq)) { wake_up_interruptible(&vcpu->wq); vcpu->stat.halt_wakeup++; - } else if (vcpu->cpu != -1) { - smp_send_reschedule(vcpu->cpu); } return 0; @@ -668,29 +633,6 @@ long kvm_arch_vm_ioctl(struct file *filp, break; } -#ifdef CONFIG_KVM_BOOK3S_64_HV - case KVM_CREATE_SPAPR_TCE: { - struct kvm_create_spapr_tce create_tce; - struct kvm *kvm = filp->private_data; - - r = -EFAULT; - if (copy_from_user(&create_tce, argp, sizeof(create_tce))) - goto out; - r = kvm_vm_ioctl_create_spapr_tce(kvm, &create_tce); - goto out; - } - - case KVM_ALLOCATE_RMA: { - struct kvm *kvm = filp->private_data; - struct kvm_allocate_rma rma; - - r = kvm_vm_ioctl_allocate_rma(kvm, &rma); - if (r >= 0 && copy_to_user(argp, &rma, sizeof(rma))) - r = -EFAULT; - break; - } -#endif /* CONFIG_KVM_BOOK3S_64_HV */ - default: r = -ENOTTY; } diff --git a/trunk/arch/powerpc/kvm/timing.c b/trunk/arch/powerpc/kvm/timing.c index 07b6110a4bb7..319177df9587 100644 --- a/trunk/arch/powerpc/kvm/timing.c +++ b/trunk/arch/powerpc/kvm/timing.c @@ -56,6 +56,15 @@ static void add_exit_timing(struct kvm_vcpu *vcpu, u64 duration, int type) { u64 old; + do_div(duration, tb_ticks_per_usec); + if (unlikely(duration > 0xFFFFFFFF)) { + printk(KERN_ERR"%s - duration too big -> overflow" + " duration %lld type %d exit #%d\n", + __func__, duration, type, + vcpu->arch.timing_count_type[type]); + return; + } + mutex_lock(&vcpu->arch.exit_timing_lock); vcpu->arch.timing_count_type[type]++; diff --git a/trunk/arch/powerpc/kvm/trace.h b/trunk/arch/powerpc/kvm/trace.h index b135d3d397db..3aca1b042b8c 100644 --- a/trunk/arch/powerpc/kvm/trace.h +++ b/trunk/arch/powerpc/kvm/trace.h @@ -103,7 +103,7 @@ TRACE_EVENT(kvm_gtlb_write, * Book3S trace points * *************************************************************************/ -#ifdef CONFIG_KVM_BOOK3S_PR +#ifdef CONFIG_PPC_BOOK3S TRACE_EVENT(kvm_book3s_exit, TP_PROTO(unsigned int exit_nr, struct kvm_vcpu *vcpu), @@ -252,7 +252,7 @@ TRACE_EVENT(kvm_book3s_mmu_flush, ), TP_fast_assign( - __entry->count = to_book3s(vcpu)->hpte_cache_count; + __entry->count = vcpu->arch.hpte_cache_count; __entry->p1 = p1; __entry->p2 = p2; __entry->type = type; diff --git a/trunk/arch/powerpc/mm/fault.c b/trunk/arch/powerpc/mm/fault.c index 5efe8c96d37f..ad35f66c69e8 100644 --- a/trunk/arch/powerpc/mm/fault.c +++ b/trunk/arch/powerpc/mm/fault.c @@ -174,7 +174,7 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, die("Weird page fault", regs, SIGSEGV); } - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address); + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address); /* When running in the kernel we expect faults to occur only to * addresses in user space. All other faults represent errors in the @@ -320,7 +320,7 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, } if (ret & VM_FAULT_MAJOR) { current->maj_flt++; - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0, regs, address); #ifdef CONFIG_PPC_SMLPAR if (firmware_has_feature(FW_FEATURE_CMO)) { @@ -331,7 +331,7 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, #endif } else { current->min_flt++; - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0, regs, address); } up_read(&mm->mmap_sem); diff --git a/trunk/arch/powerpc/mm/hash_native_64.c b/trunk/arch/powerpc/mm/hash_native_64.c index 90039bc64119..dfd764896db0 100644 --- a/trunk/arch/powerpc/mm/hash_native_64.c +++ b/trunk/arch/powerpc/mm/hash_native_64.c @@ -37,7 +37,7 @@ #define HPTE_LOCK_BIT 3 -DEFINE_RAW_SPINLOCK(native_tlbie_lock); +static DEFINE_RAW_SPINLOCK(native_tlbie_lock); static inline void __tlbie(unsigned long va, int psize, int ssize) { @@ -51,7 +51,7 @@ static inline void __tlbie(unsigned long va, int psize, int ssize) va &= ~0xffful; va |= ssize << 8; asm volatile(ASM_FTR_IFCLR("tlbie %0,0", PPC_TLBIE(%1,%0), %2) - : : "r" (va), "r"(0), "i" (CPU_FTR_ARCH_206) + : : "r" (va), "r"(0), "i" (CPU_FTR_HVMODE_206) : "memory"); break; default: @@ -61,7 +61,7 @@ static inline void __tlbie(unsigned long va, int psize, int ssize) va |= ssize << 8; va |= 1; /* L */ asm volatile(ASM_FTR_IFCLR("tlbie %0,1", PPC_TLBIE(%1,%0), %2) - : : "r" (va), "r"(0), "i" (CPU_FTR_ARCH_206) + : : "r" (va), "r"(0), "i" (CPU_FTR_HVMODE_206) : "memory"); break; } diff --git a/trunk/arch/powerpc/platforms/amigaone/Kconfig b/trunk/arch/powerpc/platforms/amigaone/Kconfig index 128de25cc284..022476717718 100644 --- a/trunk/arch/powerpc/platforms/amigaone/Kconfig +++ b/trunk/arch/powerpc/platforms/amigaone/Kconfig @@ -8,7 +8,7 @@ config AMIGAONE select NOT_COHERENT_CACHE select CHECK_CACHE_COHERENCY select DEFAULT_UIMAGE - select HAVE_PCSPKR_PLATFORM + select PCSPKR_PLATFORM help Select AmigaOne for the following machines: - AmigaOne SE/Teron CX (G3 only) diff --git a/trunk/arch/powerpc/platforms/cell/spufs/file.c b/trunk/arch/powerpc/platforms/cell/spufs/file.c index fb59c46e9e9e..3c7c3f82d842 100644 --- a/trunk/arch/powerpc/platforms/cell/spufs/file.c +++ b/trunk/arch/powerpc/platforms/cell/spufs/file.c @@ -1850,16 +1850,9 @@ static int spufs_mfc_flush(struct file *file, fl_owner_t id) return ret; } -static int spufs_mfc_fsync(struct file *file, loff_t start, loff_t end, int datasync) +static int spufs_mfc_fsync(struct file *file, int datasync) { - struct inode *inode = file->f_path.dentry->d_inode; - int err = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (!err) { - mutex_lock(&inode->i_mutex); - err = spufs_mfc_flush(file, NULL); - mutex_unlock(&inode->i_mutex); - } - return err; + return spufs_mfc_flush(file, NULL); } static int spufs_mfc_fasync(int fd, struct file *file, int on) diff --git a/trunk/arch/powerpc/platforms/cell/spufs/inode.c b/trunk/arch/powerpc/platforms/cell/spufs/inode.c index e481f6b9a789..856e9c398068 100644 --- a/trunk/arch/powerpc/platforms/cell/spufs/inode.c +++ b/trunk/arch/powerpc/platforms/cell/spufs/inode.c @@ -611,14 +611,15 @@ static int spufs_create_gang(struct inode *inode, static struct file_system_type spufs_type; -long spufs_create(struct path *path, struct dentry *dentry, - unsigned int flags, mode_t mode, struct file *filp) +long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode, + struct file *filp) { + struct dentry *dentry; int ret; ret = -EINVAL; /* check if we are on spufs */ - if (path->dentry->d_sb->s_type != &spufs_type) + if (nd->path.dentry->d_sb->s_type != &spufs_type) goto out; /* don't accept undefined flags */ @@ -626,27 +627,33 @@ long spufs_create(struct path *path, struct dentry *dentry, goto out; /* only threads can be underneath a gang */ - if (path->dentry != path->dentry->d_sb->s_root) { + if (nd->path.dentry != nd->path.dentry->d_sb->s_root) { if ((flags & SPU_CREATE_GANG) || - !SPUFS_I(path->dentry->d_inode)->i_gang) + !SPUFS_I(nd->path.dentry->d_inode)->i_gang) goto out; } + dentry = lookup_create(nd, 1); + ret = PTR_ERR(dentry); + if (IS_ERR(dentry)) + goto out_dir; + mode &= ~current_umask(); if (flags & SPU_CREATE_GANG) - ret = spufs_create_gang(path->dentry->d_inode, - dentry, path->mnt, mode); + ret = spufs_create_gang(nd->path.dentry->d_inode, + dentry, nd->path.mnt, mode); else - ret = spufs_create_context(path->dentry->d_inode, - dentry, path->mnt, flags, mode, + ret = spufs_create_context(nd->path.dentry->d_inode, + dentry, nd->path.mnt, flags, mode, filp); if (ret >= 0) - fsnotify_mkdir(path->dentry->d_inode, dentry); + fsnotify_mkdir(nd->path.dentry->d_inode, dentry); return ret; +out_dir: + mutex_unlock(&nd->path.dentry->d_inode->i_mutex); out: - mutex_unlock(&path->dentry->d_inode->i_mutex); return ret; } diff --git a/trunk/arch/powerpc/platforms/cell/spufs/spufs.h b/trunk/arch/powerpc/platforms/cell/spufs/spufs.h index 099245f230b2..c448bac65518 100644 --- a/trunk/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/trunk/arch/powerpc/platforms/cell/spufs/spufs.h @@ -248,7 +248,7 @@ extern const struct spufs_tree_descr spufs_dir_debug_contents[]; /* system call implementation */ extern struct spufs_calls spufs_calls; long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *status); -long spufs_create(struct path *nd, struct dentry *dentry, unsigned int flags, +long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode, struct file *filp); /* ELF coredump callbacks for writing SPU ELF notes */ extern int spufs_coredump_extra_notes_size(void); diff --git a/trunk/arch/powerpc/platforms/cell/spufs/syscalls.c b/trunk/arch/powerpc/platforms/cell/spufs/syscalls.c index 609e016e92d0..a3d2ce54ea2e 100644 --- a/trunk/arch/powerpc/platforms/cell/spufs/syscalls.c +++ b/trunk/arch/powerpc/platforms/cell/spufs/syscalls.c @@ -62,17 +62,21 @@ static long do_spu_run(struct file *filp, static long do_spu_create(const char __user *pathname, unsigned int flags, mode_t mode, struct file *neighbor) { - struct path path; - struct dentry *dentry; + char *tmp; int ret; - dentry = user_path_create(AT_FDCWD, pathname, &path, 1); - 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); + tmp = getname(pathname); + ret = PTR_ERR(tmp); + if (!IS_ERR(tmp)) { + struct nameidata nd; + + ret = kern_path_parent(tmp, &nd); + if (!ret) { + nd.flags |= LOOKUP_OPEN | LOOKUP_CREATE; + ret = spufs_create(&nd, flags, mode, neighbor); + path_put(&nd.path); + } + putname(tmp); } return ret; diff --git a/trunk/arch/powerpc/platforms/chrp/Kconfig b/trunk/arch/powerpc/platforms/chrp/Kconfig index d3cdab582c5d..bc0b0efdc5fe 100644 --- a/trunk/arch/powerpc/platforms/chrp/Kconfig +++ b/trunk/arch/powerpc/platforms/chrp/Kconfig @@ -1,7 +1,6 @@ config PPC_CHRP bool "Common Hardware Reference Platform (CHRP) based machines" depends on 6xx - select HAVE_PCSPKR_PLATFORM select MPIC select PPC_I8259 select PPC_INDIRECT_PCI diff --git a/trunk/arch/powerpc/platforms/iseries/exception.S b/trunk/arch/powerpc/platforms/iseries/exception.S index f519ee17ff7d..29c02f36b32f 100644 --- a/trunk/arch/powerpc/platforms/iseries/exception.S +++ b/trunk/arch/powerpc/platforms/iseries/exception.S @@ -167,7 +167,7 @@ BEGIN_FTR_SECTION std r12,PACA_EXGEN+EX_R13(r13) EXCEPTION_PROLOG_ISERIES_1 FTR_SECTION_ELSE - EXCEPTION_PROLOG_1(PACA_EXGEN, NOTEST, 0) + EXCEPTION_PROLOG_1(PACA_EXGEN) EXCEPTION_PROLOG_ISERIES_1 ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_SLB) b data_access_common diff --git a/trunk/arch/powerpc/platforms/iseries/exception.h b/trunk/arch/powerpc/platforms/iseries/exception.h index 50271b550a99..bae3fba5ad8e 100644 --- a/trunk/arch/powerpc/platforms/iseries/exception.h +++ b/trunk/arch/powerpc/platforms/iseries/exception.h @@ -39,7 +39,7 @@ label##_iSeries: \ HMT_MEDIUM; \ mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \ - EXCEPTION_PROLOG_1(area, NOTEST, 0); \ + EXCEPTION_PROLOG_1(area); \ EXCEPTION_PROLOG_ISERIES_1; \ b label##_common @@ -48,7 +48,7 @@ label##_iSeries: \ label##_iSeries: \ HMT_MEDIUM; \ mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \ - EXCEPTION_PROLOG_1(PACA_EXGEN, NOTEST, 0); \ + EXCEPTION_PROLOG_1(PACA_EXGEN); \ lbz r10,PACASOFTIRQEN(r13); \ cmpwi 0,r10,0; \ beq- label##_iSeries_masked; \ diff --git a/trunk/arch/powerpc/platforms/prep/Kconfig b/trunk/arch/powerpc/platforms/prep/Kconfig index f0536c7cda9f..bf8330ef2e76 100644 --- a/trunk/arch/powerpc/platforms/prep/Kconfig +++ b/trunk/arch/powerpc/platforms/prep/Kconfig @@ -1,7 +1,6 @@ config PPC_PREP bool "PowerPC Reference Platform (PReP) based machines" depends on 6xx && BROKEN - select HAVE_PCSPKR_PLATFORM select MPIC select PPC_I8259 select PPC_INDIRECT_PCI diff --git a/trunk/arch/powerpc/platforms/pseries/Kconfig b/trunk/arch/powerpc/platforms/pseries/Kconfig index 05cf4769b88c..71af4c5d6c05 100644 --- a/trunk/arch/powerpc/platforms/pseries/Kconfig +++ b/trunk/arch/powerpc/platforms/pseries/Kconfig @@ -1,7 +1,6 @@ config PPC_PSERIES depends on PPC64 && PPC_BOOK3S bool "IBM pSeries & new (POWER5-based) iSeries" - select HAVE_PCSPKR_PLATFORM select MPIC select PCI_MSI select PPC_XICS diff --git a/trunk/arch/powerpc/sysdev/xics/icp-native.c b/trunk/arch/powerpc/sysdev/xics/icp-native.c index ba382b59b926..1f15ad436140 100644 --- a/trunk/arch/powerpc/sysdev/xics/icp-native.c +++ b/trunk/arch/powerpc/sysdev/xics/icp-native.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include @@ -25,7 +24,6 @@ #include #include #include -#include struct icp_ipl { union { @@ -141,12 +139,6 @@ static void icp_native_cause_ipi(int cpu, unsigned long data) icp_native_set_qirr(cpu, IPI_PRIORITY); } -void xics_wake_cpu(int cpu) -{ - icp_native_set_qirr(cpu, IPI_PRIORITY); -} -EXPORT_SYMBOL_GPL(xics_wake_cpu); - static irqreturn_t icp_native_ipi_action(int irq, void *dev_id) { int cpu = smp_processor_id(); @@ -193,7 +185,6 @@ static int __init icp_native_map_one_cpu(int hw_id, unsigned long addr, } icp_native_regs[cpu] = ioremap(addr, size); - kvmppc_set_xics_phys(cpu, addr); if (!icp_native_regs[cpu]) { pr_warning("icp_native: Failed ioremap for CPU %d, " "interrupt server #0x%x, addr %#lx\n", diff --git a/trunk/arch/s390/boot/compressed/head31.S b/trunk/arch/s390/boot/compressed/head31.S index e8c9e18b8039..2a5523a32bcc 100644 --- a/trunk/arch/s390/boot/compressed/head31.S +++ b/trunk/arch/s390/boot/compressed/head31.S @@ -7,14 +7,14 @@ */ #include -#include #include #include #include #include "sizes.h" __HEAD -ENTRY(startup_continue) + .globl startup_continue +startup_continue: basr %r13,0 # get base .LPG1: # setup stack diff --git a/trunk/arch/s390/boot/compressed/head64.S b/trunk/arch/s390/boot/compressed/head64.S index f86a4eef28a9..2982cb140550 100644 --- a/trunk/arch/s390/boot/compressed/head64.S +++ b/trunk/arch/s390/boot/compressed/head64.S @@ -7,14 +7,14 @@ */ #include -#include #include #include #include #include "sizes.h" __HEAD -ENTRY(startup_continue) + .globl startup_continue +startup_continue: basr %r13,0 # get base .LPG1: # setup stack diff --git a/trunk/arch/s390/crypto/sha256_s390.c b/trunk/arch/s390/crypto/sha256_s390.c index 0317a3547cb9..5ed8d64fc2ed 100644 --- a/trunk/arch/s390/crypto/sha256_s390.c +++ b/trunk/arch/s390/crypto/sha256_s390.c @@ -1,12 +1,15 @@ /* * Cryptographic API. * - * s390 implementation of the SHA256 and SHA224 Secure Hash Algorithm. + * s390 implementation of the SHA256 Secure Hash Algorithm. * * s390 Version: - * Copyright IBM Corp. 2005,2011 + * Copyright IBM Corp. 2005,2007 * Author(s): Jan Glauber (jang@de.ibm.com) * + * Derived from "crypto/sha256_generic.c" + * and "arch/s390/crypto/sha1_s390.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 (at your option) @@ -62,7 +65,7 @@ static int sha256_import(struct shash_desc *desc, const void *in) return 0; } -static struct shash_alg sha256_alg = { +static struct shash_alg alg = { .digestsize = SHA256_DIGEST_SIZE, .init = sha256_init, .update = s390_sha_update, @@ -81,69 +84,22 @@ static struct shash_alg sha256_alg = { } }; -static int sha224_init(struct shash_desc *desc) +static int sha256_s390_init(void) { - struct s390_sha_ctx *sctx = shash_desc_ctx(desc); - - sctx->state[0] = SHA224_H0; - sctx->state[1] = SHA224_H1; - sctx->state[2] = SHA224_H2; - sctx->state[3] = SHA224_H3; - sctx->state[4] = SHA224_H4; - sctx->state[5] = SHA224_H5; - sctx->state[6] = SHA224_H6; - sctx->state[7] = SHA224_H7; - sctx->count = 0; - sctx->func = KIMD_SHA_256; - - return 0; -} - -static struct shash_alg sha224_alg = { - .digestsize = SHA224_DIGEST_SIZE, - .init = sha224_init, - .update = s390_sha_update, - .final = s390_sha_final, - .export = sha256_export, - .import = sha256_import, - .descsize = sizeof(struct s390_sha_ctx), - .statesize = sizeof(struct sha256_state), - .base = { - .cra_name = "sha224", - .cra_driver_name= "sha224-s390", - .cra_priority = CRYPT_S390_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_SHASH, - .cra_blocksize = SHA224_BLOCK_SIZE, - .cra_module = THIS_MODULE, - } -}; - -static int __init sha256_s390_init(void) -{ - int ret; - if (!crypt_s390_func_available(KIMD_SHA_256, CRYPT_S390_MSA)) return -EOPNOTSUPP; - ret = crypto_register_shash(&sha256_alg); - if (ret < 0) - goto out; - ret = crypto_register_shash(&sha224_alg); - if (ret < 0) - crypto_unregister_shash(&sha256_alg); -out: - return ret; + + return crypto_register_shash(&alg); } static void __exit sha256_s390_fini(void) { - crypto_unregister_shash(&sha224_alg); - crypto_unregister_shash(&sha256_alg); + crypto_unregister_shash(&alg); } module_init(sha256_s390_init); module_exit(sha256_s390_fini); MODULE_ALIAS("sha256"); -MODULE_ALIAS("sha224"); MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("SHA256 and SHA224 Secure Hash Algorithm"); +MODULE_DESCRIPTION("SHA256 Secure Hash Algorithm"); diff --git a/trunk/arch/s390/include/asm/irqflags.h b/trunk/arch/s390/include/asm/irqflags.h index 38fdf451febb..865d6d891ace 100644 --- a/trunk/arch/s390/include/asm/irqflags.h +++ b/trunk/arch/s390/include/asm/irqflags.h @@ -29,42 +29,42 @@ }) /* set system mask. */ -static inline notrace void __arch_local_irq_ssm(unsigned long flags) +static inline void __arch_local_irq_ssm(unsigned long flags) { asm volatile("ssm %0" : : "Q" (flags) : "memory"); } -static inline notrace unsigned long arch_local_save_flags(void) +static inline unsigned long arch_local_save_flags(void) { return __arch_local_irq_stosm(0x00); } -static inline notrace unsigned long arch_local_irq_save(void) +static inline unsigned long arch_local_irq_save(void) { return __arch_local_irq_stnsm(0xfc); } -static inline notrace void arch_local_irq_disable(void) +static inline void arch_local_irq_disable(void) { arch_local_irq_save(); } -static inline notrace void arch_local_irq_enable(void) +static inline void arch_local_irq_enable(void) { __arch_local_irq_stosm(0x03); } -static inline notrace void arch_local_irq_restore(unsigned long flags) +static inline void arch_local_irq_restore(unsigned long flags) { __arch_local_irq_ssm(flags); } -static inline notrace bool arch_irqs_disabled_flags(unsigned long flags) +static inline bool arch_irqs_disabled_flags(unsigned long flags) { return !(flags & (3UL << (BITS_PER_LONG - 8))); } -static inline notrace bool arch_irqs_disabled(void) +static inline bool arch_irqs_disabled(void) { return arch_irqs_disabled_flags(arch_local_save_flags()); } diff --git a/trunk/arch/s390/include/asm/kvm_host.h b/trunk/arch/s390/include/asm/kvm_host.h index 00ff00dfb24c..cef7dbf69dfc 100644 --- a/trunk/arch/s390/include/asm/kvm_host.h +++ b/trunk/arch/s390/include/asm/kvm_host.h @@ -93,7 +93,9 @@ struct kvm_s390_sie_block { __u32 scaol; /* 0x0064 */ __u8 reserved68[4]; /* 0x0068 */ __u32 todpr; /* 0x006c */ - __u8 reserved70[32]; /* 0x0070 */ + __u8 reserved70[16]; /* 0x0070 */ + __u64 gmsor; /* 0x0080 */ + __u64 gmslm; /* 0x0088 */ psw_t gpsw; /* 0x0090 */ __u64 gg14; /* 0x00a0 */ __u64 gg15; /* 0x00a8 */ @@ -136,7 +138,6 @@ struct kvm_vcpu_stat { u32 instruction_chsc; u32 instruction_stsi; u32 instruction_stfl; - u32 instruction_tprot; u32 instruction_sigp_sense; u32 instruction_sigp_emergency; u32 instruction_sigp_stop; @@ -174,10 +175,6 @@ struct kvm_s390_prefix_info { __u32 address; }; -struct kvm_s390_emerg_info { - __u16 code; -}; - struct kvm_s390_interrupt_info { struct list_head list; u64 type; @@ -185,7 +182,6 @@ struct kvm_s390_interrupt_info { struct kvm_s390_io_info io; struct kvm_s390_ext_info ext; struct kvm_s390_pgm_info pgm; - struct kvm_s390_emerg_info emerg; struct kvm_s390_prefix_info prefix; }; }; @@ -230,7 +226,6 @@ struct kvm_vcpu_arch { struct cpuid cpu_id; u64 stidp_data; }; - struct gmap *gmap; }; struct kvm_vm_stat { @@ -241,7 +236,6 @@ struct kvm_arch{ struct sca_block *sca; debug_info_t *dbf; struct kvm_s390_float_interrupt float_int; - struct gmap *gmap; }; extern int sie64a(struct kvm_s390_sie_block *, unsigned long *); diff --git a/trunk/arch/s390/include/asm/linkage.h b/trunk/arch/s390/include/asm/linkage.h index fc8a8284778e..291c2d01c44f 100644 --- a/trunk/arch/s390/include/asm/linkage.h +++ b/trunk/arch/s390/include/asm/linkage.h @@ -1,9 +1,6 @@ #ifndef __ASM_LINKAGE_H #define __ASM_LINKAGE_H -#include - -#define __ALIGN .align 4, 0x07 -#define __ALIGN_STR __stringify(__ALIGN) +/* Nothing to see here... */ #endif diff --git a/trunk/arch/s390/include/asm/lowcore.h b/trunk/arch/s390/include/asm/lowcore.h index f26280d9e88d..228cf0b295db 100644 --- a/trunk/arch/s390/include/asm/lowcore.h +++ b/trunk/arch/s390/include/asm/lowcore.h @@ -268,7 +268,7 @@ struct _lowcore { __u64 vdso_per_cpu_data; /* 0x0358 */ __u64 machine_flags; /* 0x0360 */ __u64 ftrace_func; /* 0x0368 */ - __u64 gmap; /* 0x0370 */ + __u64 sie_hook; /* 0x0370 */ __u64 cmf_hpp; /* 0x0378 */ /* Interrupt response block. */ diff --git a/trunk/arch/s390/include/asm/mmu.h b/trunk/arch/s390/include/asm/mmu.h index 4506791adcd5..82d0847896a0 100644 --- a/trunk/arch/s390/include/asm/mmu.h +++ b/trunk/arch/s390/include/asm/mmu.h @@ -6,7 +6,6 @@ typedef struct { unsigned int flush_mm; spinlock_t list_lock; struct list_head pgtable_list; - struct list_head gmap_list; unsigned long asce_bits; unsigned long asce_limit; unsigned long vdso_base; @@ -18,7 +17,6 @@ typedef struct { #define INIT_MM_CONTEXT(name) \ .context.list_lock = __SPIN_LOCK_UNLOCKED(name.context.list_lock), \ - .context.pgtable_list = LIST_HEAD_INIT(name.context.pgtable_list), \ - .context.gmap_list = LIST_HEAD_INIT(name.context.gmap_list), + .context.pgtable_list = LIST_HEAD_INIT(name.context.pgtable_list), #endif diff --git a/trunk/arch/s390/include/asm/pgalloc.h b/trunk/arch/s390/include/asm/pgalloc.h index 8eef9b5b3cf4..38e71ebcd3c2 100644 --- a/trunk/arch/s390/include/asm/pgalloc.h +++ b/trunk/arch/s390/include/asm/pgalloc.h @@ -20,7 +20,7 @@ unsigned long *crst_table_alloc(struct mm_struct *); void crst_table_free(struct mm_struct *, unsigned long *); -unsigned long *page_table_alloc(struct mm_struct *, unsigned long); +unsigned long *page_table_alloc(struct mm_struct *); void page_table_free(struct mm_struct *, unsigned long *); #ifdef CONFIG_HAVE_RCU_TABLE_FREE void page_table_free_rcu(struct mmu_gather *, unsigned long *); @@ -115,7 +115,6 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm) { spin_lock_init(&mm->context.list_lock); INIT_LIST_HEAD(&mm->context.pgtable_list); - INIT_LIST_HEAD(&mm->context.gmap_list); return (pgd_t *) crst_table_alloc(mm); } #define pgd_free(mm, pgd) crst_table_free(mm, (unsigned long *) pgd) @@ -134,8 +133,8 @@ static inline void pmd_populate(struct mm_struct *mm, /* * page table entry allocation/free routines. */ -#define pte_alloc_one_kernel(mm, vmaddr) ((pte_t *) page_table_alloc(mm, vmaddr)) -#define pte_alloc_one(mm, vmaddr) ((pte_t *) page_table_alloc(mm, vmaddr)) +#define pte_alloc_one_kernel(mm, vmaddr) ((pte_t *) page_table_alloc(mm)) +#define pte_alloc_one(mm, vmaddr) ((pte_t *) page_table_alloc(mm)) #define pte_free_kernel(mm, pte) page_table_free(mm, (unsigned long *) pte) #define pte_free(mm, pte) page_table_free(mm, (unsigned long *) pte) diff --git a/trunk/arch/s390/include/asm/pgtable.h b/trunk/arch/s390/include/asm/pgtable.h index 519eb5f187ef..801fbe1d837d 100644 --- a/trunk/arch/s390/include/asm/pgtable.h +++ b/trunk/arch/s390/include/asm/pgtable.h @@ -654,48 +654,6 @@ static inline void pgste_set_pte(pte_t *ptep, pgste_t pgste) #endif } -/** - * struct gmap_struct - guest address space - * @mm: pointer to the parent mm_struct - * @table: pointer to the page directory - * @crst_list: list of all crst tables used in the guest address space - */ -struct gmap { - struct list_head list; - struct mm_struct *mm; - unsigned long *table; - struct list_head crst_list; -}; - -/** - * struct gmap_rmap - reverse mapping for segment table entries - * @next: pointer to the next gmap_rmap structure in the list - * @entry: pointer to a segment table entry - */ -struct gmap_rmap { - struct list_head list; - unsigned long *entry; -}; - -/** - * struct gmap_pgtable - gmap information attached to a page table - * @vmaddr: address of the 1MB segment in the process virtual memory - * @mapper: list of segment table entries maping a page table - */ -struct gmap_pgtable { - unsigned long vmaddr; - struct list_head mapper; -}; - -struct gmap *gmap_alloc(struct mm_struct *mm); -void gmap_free(struct gmap *gmap); -void gmap_enable(struct gmap *gmap); -void gmap_disable(struct gmap *gmap); -int gmap_map_segment(struct gmap *gmap, unsigned long from, - unsigned long to, unsigned long length); -int gmap_unmap_segment(struct gmap *gmap, unsigned long to, unsigned long len); -unsigned long gmap_fault(unsigned long address, struct gmap *); - /* * Certain architectures need to do special things when PTEs * within a page table are directly modified. Thus, the following diff --git a/trunk/arch/s390/include/asm/processor.h b/trunk/arch/s390/include/asm/processor.h index 55dfcc8bdc0d..1300c3025334 100644 --- a/trunk/arch/s390/include/asm/processor.h +++ b/trunk/arch/s390/include/asm/processor.h @@ -80,7 +80,6 @@ struct thread_struct { mm_segment_t mm_segment; unsigned long prot_addr; /* address of protection-excep. */ unsigned int trap_no; - unsigned long gmap_addr; /* address of last gmap fault. */ struct per_regs per_user; /* User specified PER registers */ struct per_event per_event; /* Cause of the last PER trap */ /* pfault_wait is used to block the process on a pfault event */ diff --git a/trunk/arch/s390/include/asm/thread_info.h b/trunk/arch/s390/include/asm/thread_info.h index 1a5dbb6f1495..ad1382f7932e 100644 --- a/trunk/arch/s390/include/asm/thread_info.h +++ b/trunk/arch/s390/include/asm/thread_info.h @@ -94,7 +94,6 @@ static inline struct thread_info *current_thread_info(void) #define TIF_SYSCALL_AUDIT 9 /* syscall auditing active */ #define TIF_SECCOMP 10 /* secure computing */ #define TIF_SYSCALL_TRACEPOINT 11 /* syscall tracepoint instrumentation */ -#define TIF_SIE 12 /* guest execution active */ #define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */ #define TIF_31BIT 17 /* 32bit process */ @@ -114,7 +113,6 @@ static inline struct thread_info *current_thread_info(void) #define _TIF_SYSCALL_AUDIT (1<context.gmap_list)) + if (MACHINE_HAS_IDTE) __tlb_flush_idte((unsigned long) mm->pgd | mm->context.asce_bits); else diff --git a/trunk/arch/s390/kernel/asm-offsets.c b/trunk/arch/s390/kernel/asm-offsets.c index 05d8f38734ec..edfbd17d7082 100644 --- a/trunk/arch/s390/kernel/asm-offsets.c +++ b/trunk/arch/s390/kernel/asm-offsets.c @@ -151,7 +151,7 @@ int main(void) DEFINE(__LC_FP_CREG_SAVE_AREA, offsetof(struct _lowcore, fpt_creg_save_area)); DEFINE(__LC_LAST_BREAK, offsetof(struct _lowcore, breaking_event_addr)); DEFINE(__LC_VDSO_PER_CPU, offsetof(struct _lowcore, vdso_per_cpu_data)); - DEFINE(__LC_GMAP, offsetof(struct _lowcore, gmap)); + DEFINE(__LC_SIE_HOOK, offsetof(struct _lowcore, sie_hook)); DEFINE(__LC_CMF_HPP, offsetof(struct _lowcore, cmf_hpp)); #endif /* CONFIG_32BIT */ return 0; diff --git a/trunk/arch/s390/kernel/base.S b/trunk/arch/s390/kernel/base.S index 209938c1dfc8..15e46ca94335 100644 --- a/trunk/arch/s390/kernel/base.S +++ b/trunk/arch/s390/kernel/base.S @@ -6,13 +6,13 @@ * Michael Holzheu */ -#include #include #include #ifdef CONFIG_64BIT -ENTRY(s390_base_mcck_handler) + .globl s390_base_mcck_handler +s390_base_mcck_handler: basr %r13,0 0: lg %r15,__LC_PANIC_STACK # load panic stack aghi %r15,-STACK_FRAME_OVERHEAD @@ -26,13 +26,13 @@ ENTRY(s390_base_mcck_handler) lpswe __LC_MCK_OLD_PSW .section .bss - .align 8 .globl s390_base_mcck_handler_fn s390_base_mcck_handler_fn: .quad 0 .previous -ENTRY(s390_base_ext_handler) + .globl s390_base_ext_handler +s390_base_ext_handler: stmg %r0,%r15,__LC_SAVE_AREA basr %r13,0 0: aghi %r15,-STACK_FRAME_OVERHEAD @@ -46,13 +46,13 @@ ENTRY(s390_base_ext_handler) lpswe __LC_EXT_OLD_PSW .section .bss - .align 8 .globl s390_base_ext_handler_fn s390_base_ext_handler_fn: .quad 0 .previous -ENTRY(s390_base_pgm_handler) + .globl s390_base_pgm_handler +s390_base_pgm_handler: stmg %r0,%r15,__LC_SAVE_AREA basr %r13,0 0: aghi %r15,-STACK_FRAME_OVERHEAD @@ -70,7 +70,6 @@ disabled_wait_psw: .quad 0x0002000180000000,0x0000000000000000 + s390_base_pgm_handler .section .bss - .align 8 .globl s390_base_pgm_handler_fn s390_base_pgm_handler_fn: .quad 0 @@ -78,7 +77,8 @@ s390_base_pgm_handler_fn: #else /* CONFIG_64BIT */ -ENTRY(s390_base_mcck_handler) + .globl s390_base_mcck_handler +s390_base_mcck_handler: basr %r13,0 0: l %r15,__LC_PANIC_STACK # load panic stack ahi %r15,-STACK_FRAME_OVERHEAD @@ -93,13 +93,13 @@ ENTRY(s390_base_mcck_handler) 2: .long s390_base_mcck_handler_fn .section .bss - .align 4 .globl s390_base_mcck_handler_fn s390_base_mcck_handler_fn: .long 0 .previous -ENTRY(s390_base_ext_handler) + .globl s390_base_ext_handler +s390_base_ext_handler: stm %r0,%r15,__LC_SAVE_AREA basr %r13,0 0: ahi %r15,-STACK_FRAME_OVERHEAD @@ -115,13 +115,13 @@ ENTRY(s390_base_ext_handler) 2: .long s390_base_ext_handler_fn .section .bss - .align 4 .globl s390_base_ext_handler_fn s390_base_ext_handler_fn: .long 0 .previous -ENTRY(s390_base_pgm_handler) + .globl s390_base_pgm_handler +s390_base_pgm_handler: stm %r0,%r15,__LC_SAVE_AREA basr %r13,0 0: ahi %r15,-STACK_FRAME_OVERHEAD @@ -142,7 +142,6 @@ disabled_wait_psw: .long 0x000a0000,0x00000000 + s390_base_pgm_handler .section .bss - .align 4 .globl s390_base_pgm_handler_fn s390_base_pgm_handler_fn: .long 0 diff --git a/trunk/arch/s390/kernel/compat_wrapper.S b/trunk/arch/s390/kernel/compat_wrapper.S index 08ab9aa6a0d5..1f5eb789c3a7 100644 --- a/trunk/arch/s390/kernel/compat_wrapper.S +++ b/trunk/arch/s390/kernel/compat_wrapper.S @@ -7,74 +7,86 @@ * Thomas Spatzier (tspat@de.ibm.com) */ -#include - -ENTRY(sys32_exit_wrapper) + .globl sys32_exit_wrapper +sys32_exit_wrapper: lgfr %r2,%r2 # int jg sys_exit # branch to sys_exit -ENTRY(sys32_read_wrapper) + .globl sys32_read_wrapper +sys32_read_wrapper: llgfr %r2,%r2 # unsigned int llgtr %r3,%r3 # char * llgfr %r4,%r4 # size_t jg sys32_read # branch to sys_read -ENTRY(sys32_write_wrapper) + .globl sys32_write_wrapper +sys32_write_wrapper: llgfr %r2,%r2 # unsigned int llgtr %r3,%r3 # const char * llgfr %r4,%r4 # size_t jg sys32_write # branch to system call -ENTRY(sys32_open_wrapper) + .globl sys32_open_wrapper +sys32_open_wrapper: llgtr %r2,%r2 # const char * lgfr %r3,%r3 # int lgfr %r4,%r4 # int jg sys_open # branch to system call -ENTRY(sys32_close_wrapper) + .globl sys32_close_wrapper +sys32_close_wrapper: llgfr %r2,%r2 # unsigned int jg sys_close # branch to system call -ENTRY(sys32_creat_wrapper) + .globl sys32_creat_wrapper +sys32_creat_wrapper: llgtr %r2,%r2 # const char * lgfr %r3,%r3 # int jg sys_creat # branch to system call -ENTRY(sys32_link_wrapper) + .globl sys32_link_wrapper +sys32_link_wrapper: llgtr %r2,%r2 # const char * llgtr %r3,%r3 # const char * jg sys_link # branch to system call -ENTRY(sys32_unlink_wrapper) + .globl sys32_unlink_wrapper +sys32_unlink_wrapper: llgtr %r2,%r2 # const char * jg sys_unlink # branch to system call -ENTRY(sys32_chdir_wrapper) + .globl sys32_chdir_wrapper +sys32_chdir_wrapper: llgtr %r2,%r2 # const char * jg sys_chdir # branch to system call -ENTRY(sys32_time_wrapper) + .globl sys32_time_wrapper +sys32_time_wrapper: llgtr %r2,%r2 # int * jg compat_sys_time # branch to system call -ENTRY(sys32_mknod_wrapper) + .globl sys32_mknod_wrapper +sys32_mknod_wrapper: llgtr %r2,%r2 # const char * lgfr %r3,%r3 # int llgfr %r4,%r4 # dev jg sys_mknod # branch to system call -ENTRY(sys32_chmod_wrapper) + .globl sys32_chmod_wrapper +sys32_chmod_wrapper: llgtr %r2,%r2 # const char * llgfr %r3,%r3 # mode_t jg sys_chmod # branch to system call -ENTRY(sys32_lchown16_wrapper) + .globl sys32_lchown16_wrapper +sys32_lchown16_wrapper: llgtr %r2,%r2 # const char * llgfr %r3,%r3 # __kernel_old_uid_emu31_t llgfr %r4,%r4 # __kernel_old_uid_emu31_t jg sys32_lchown16 # branch to system call -ENTRY(sys32_lseek_wrapper) + .globl sys32_lseek_wrapper +sys32_lseek_wrapper: llgfr %r2,%r2 # unsigned int lgfr %r3,%r3 # off_t llgfr %r4,%r4 # unsigned int @@ -82,7 +94,8 @@ ENTRY(sys32_lseek_wrapper) #sys32_getpid_wrapper # void -ENTRY(sys32_mount_wrapper) + .globl sys32_mount_wrapper +sys32_mount_wrapper: llgtr %r2,%r2 # char * llgtr %r3,%r3 # char * llgtr %r4,%r4 # char * @@ -90,85 +103,102 @@ ENTRY(sys32_mount_wrapper) llgtr %r6,%r6 # void * jg compat_sys_mount # branch to system call -ENTRY(sys32_oldumount_wrapper) + .globl sys32_oldumount_wrapper +sys32_oldumount_wrapper: llgtr %r2,%r2 # char * jg sys_oldumount # branch to system call -ENTRY(sys32_setuid16_wrapper) + .globl sys32_setuid16_wrapper +sys32_setuid16_wrapper: llgfr %r2,%r2 # __kernel_old_uid_emu31_t jg sys32_setuid16 # branch to system call #sys32_getuid16_wrapper # void -ENTRY(sys32_ptrace_wrapper) + .globl sys32_ptrace_wrapper +sys32_ptrace_wrapper: lgfr %r2,%r2 # long lgfr %r3,%r3 # long llgtr %r4,%r4 # long llgfr %r5,%r5 # long jg compat_sys_ptrace # branch to system call -ENTRY(sys32_alarm_wrapper) + .globl sys32_alarm_wrapper +sys32_alarm_wrapper: llgfr %r2,%r2 # unsigned int jg sys_alarm # branch to system call -ENTRY(compat_sys_utime_wrapper) + .globl compat_sys_utime_wrapper +compat_sys_utime_wrapper: llgtr %r2,%r2 # char * llgtr %r3,%r3 # struct compat_utimbuf * jg compat_sys_utime # branch to system call -ENTRY(sys32_access_wrapper) + .globl sys32_access_wrapper +sys32_access_wrapper: llgtr %r2,%r2 # const char * lgfr %r3,%r3 # int jg sys_access # branch to system call -ENTRY(sys32_nice_wrapper) + .globl sys32_nice_wrapper +sys32_nice_wrapper: lgfr %r2,%r2 # int jg sys_nice # branch to system call #sys32_sync_wrapper # void -ENTRY(sys32_kill_wrapper) + .globl sys32_kill_wrapper +sys32_kill_wrapper: lgfr %r2,%r2 # int lgfr %r3,%r3 # int jg sys_kill # branch to system call -ENTRY(sys32_rename_wrapper) + .globl sys32_rename_wrapper +sys32_rename_wrapper: llgtr %r2,%r2 # const char * llgtr %r3,%r3 # const char * jg sys_rename # branch to system call -ENTRY(sys32_mkdir_wrapper) + .globl sys32_mkdir_wrapper +sys32_mkdir_wrapper: llgtr %r2,%r2 # const char * lgfr %r3,%r3 # int jg sys_mkdir # branch to system call -ENTRY(sys32_rmdir_wrapper) + .globl sys32_rmdir_wrapper +sys32_rmdir_wrapper: llgtr %r2,%r2 # const char * jg sys_rmdir # branch to system call -ENTRY(sys32_dup_wrapper) + .globl sys32_dup_wrapper +sys32_dup_wrapper: llgfr %r2,%r2 # unsigned int jg sys_dup # branch to system call -ENTRY(sys32_pipe_wrapper) + .globl sys32_pipe_wrapper +sys32_pipe_wrapper: llgtr %r2,%r2 # u32 * jg sys_pipe # branch to system call -ENTRY(compat_sys_times_wrapper) + .globl compat_sys_times_wrapper +compat_sys_times_wrapper: llgtr %r2,%r2 # struct compat_tms * jg compat_sys_times # branch to system call -ENTRY(sys32_brk_wrapper) + .globl sys32_brk_wrapper +sys32_brk_wrapper: llgtr %r2,%r2 # unsigned long jg sys_brk # branch to system call -ENTRY(sys32_setgid16_wrapper) + .globl sys32_setgid16_wrapper +sys32_setgid16_wrapper: llgfr %r2,%r2 # __kernel_old_gid_emu31_t jg sys32_setgid16 # branch to system call #sys32_getgid16_wrapper # void -ENTRY(sys32_signal_wrapper) + .globl sys32_signal_wrapper +sys32_signal_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # __sighandler_t jg sys_signal @@ -177,46 +207,55 @@ ENTRY(sys32_signal_wrapper) #sys32_getegid16_wrapper # void -ENTRY(sys32_acct_wrapper) + .globl sys32_acct_wrapper +sys32_acct_wrapper: llgtr %r2,%r2 # char * jg sys_acct # branch to system call -ENTRY(sys32_umount_wrapper) + .globl sys32_umount_wrapper +sys32_umount_wrapper: llgtr %r2,%r2 # char * lgfr %r3,%r3 # int jg sys_umount # branch to system call -ENTRY(compat_sys_ioctl_wrapper) + .globl compat_sys_ioctl_wrapper +compat_sys_ioctl_wrapper: llgfr %r2,%r2 # unsigned int llgfr %r3,%r3 # unsigned int llgfr %r4,%r4 # unsigned int jg compat_sys_ioctl # branch to system call -ENTRY(compat_sys_fcntl_wrapper) + .globl compat_sys_fcntl_wrapper +compat_sys_fcntl_wrapper: llgfr %r2,%r2 # unsigned int llgfr %r3,%r3 # unsigned int llgfr %r4,%r4 # unsigned long jg compat_sys_fcntl # branch to system call -ENTRY(sys32_setpgid_wrapper) + .globl sys32_setpgid_wrapper +sys32_setpgid_wrapper: lgfr %r2,%r2 # pid_t lgfr %r3,%r3 # pid_t jg sys_setpgid # branch to system call -ENTRY(sys32_umask_wrapper) + .globl sys32_umask_wrapper +sys32_umask_wrapper: lgfr %r2,%r2 # int jg sys_umask # branch to system call -ENTRY(sys32_chroot_wrapper) + .globl sys32_chroot_wrapper +sys32_chroot_wrapper: llgtr %r2,%r2 # char * jg sys_chroot # branch to system call -ENTRY(sys32_ustat_wrapper) + .globl sys32_ustat_wrapper +sys32_ustat_wrapper: llgfr %r2,%r2 # dev_t llgtr %r3,%r3 # struct ustat * jg compat_sys_ustat -ENTRY(sys32_dup2_wrapper) + .globl sys32_dup2_wrapper +sys32_dup2_wrapper: llgfr %r2,%r2 # unsigned int llgfr %r3,%r3 # unsigned int jg sys_dup2 # branch to system call @@ -227,220 +266,262 @@ ENTRY(sys32_dup2_wrapper) #sys32_setsid_wrapper # void -ENTRY(sys32_sigaction_wrapper) + .globl sys32_sigaction_wrapper +sys32_sigaction_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # const struct old_sigaction * llgtr %r4,%r4 # struct old_sigaction32 * jg sys32_sigaction # branch to system call -ENTRY(sys32_setreuid16_wrapper) + .globl sys32_setreuid16_wrapper +sys32_setreuid16_wrapper: llgfr %r2,%r2 # __kernel_old_uid_emu31_t llgfr %r3,%r3 # __kernel_old_uid_emu31_t jg sys32_setreuid16 # branch to system call -ENTRY(sys32_setregid16_wrapper) + .globl sys32_setregid16_wrapper +sys32_setregid16_wrapper: llgfr %r2,%r2 # __kernel_old_gid_emu31_t llgfr %r3,%r3 # __kernel_old_gid_emu31_t jg sys32_setregid16 # branch to system call -ENTRY(sys_sigsuspend_wrapper) + .globl sys_sigsuspend_wrapper +sys_sigsuspend_wrapper: lgfr %r2,%r2 # int lgfr %r3,%r3 # int llgfr %r4,%r4 # old_sigset_t jg sys_sigsuspend -ENTRY(compat_sys_sigpending_wrapper) + .globl compat_sys_sigpending_wrapper +compat_sys_sigpending_wrapper: llgtr %r2,%r2 # compat_old_sigset_t * jg compat_sys_sigpending # branch to system call -ENTRY(sys32_sethostname_wrapper) + .globl sys32_sethostname_wrapper +sys32_sethostname_wrapper: llgtr %r2,%r2 # char * lgfr %r3,%r3 # int jg sys_sethostname # branch to system call -ENTRY(compat_sys_setrlimit_wrapper) + .globl compat_sys_setrlimit_wrapper +compat_sys_setrlimit_wrapper: llgfr %r2,%r2 # unsigned int llgtr %r3,%r3 # struct rlimit_emu31 * jg compat_sys_setrlimit # branch to system call -ENTRY(compat_sys_old_getrlimit_wrapper) + .globl compat_sys_old_getrlimit_wrapper +compat_sys_old_getrlimit_wrapper: llgfr %r2,%r2 # unsigned int llgtr %r3,%r3 # struct rlimit_emu31 * jg compat_sys_old_getrlimit # branch to system call -ENTRY(compat_sys_getrlimit_wrapper) + .globl compat_sys_getrlimit_wrapper +compat_sys_getrlimit_wrapper: llgfr %r2,%r2 # unsigned int llgtr %r3,%r3 # struct rlimit_emu31 * jg compat_sys_getrlimit # branch to system call -ENTRY(sys32_mmap2_wrapper) + .globl sys32_mmap2_wrapper +sys32_mmap2_wrapper: llgtr %r2,%r2 # struct mmap_arg_struct_emu31 * jg sys32_mmap2 # branch to system call -ENTRY(compat_sys_getrusage_wrapper) + .globl compat_sys_getrusage_wrapper +compat_sys_getrusage_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # struct rusage_emu31 * jg compat_sys_getrusage # branch to system call -ENTRY(compat_sys_gettimeofday_wrapper) + .globl compat_sys_gettimeofday_wrapper +compat_sys_gettimeofday_wrapper: llgtr %r2,%r2 # struct timeval_emu31 * llgtr %r3,%r3 # struct timezone * jg compat_sys_gettimeofday # branch to system call -ENTRY(compat_sys_settimeofday_wrapper) + .globl compat_sys_settimeofday_wrapper +compat_sys_settimeofday_wrapper: llgtr %r2,%r2 # struct timeval_emu31 * llgtr %r3,%r3 # struct timezone * jg compat_sys_settimeofday # branch to system call -ENTRY(sys32_getgroups16_wrapper) + .globl sys32_getgroups16_wrapper +sys32_getgroups16_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # __kernel_old_gid_emu31_t * jg sys32_getgroups16 # branch to system call -ENTRY(sys32_setgroups16_wrapper) + .globl sys32_setgroups16_wrapper +sys32_setgroups16_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # __kernel_old_gid_emu31_t * jg sys32_setgroups16 # branch to system call -ENTRY(sys32_symlink_wrapper) + .globl sys32_symlink_wrapper +sys32_symlink_wrapper: llgtr %r2,%r2 # const char * llgtr %r3,%r3 # const char * jg sys_symlink # branch to system call -ENTRY(sys32_readlink_wrapper) + .globl sys32_readlink_wrapper +sys32_readlink_wrapper: llgtr %r2,%r2 # const char * llgtr %r3,%r3 # char * lgfr %r4,%r4 # int jg sys_readlink # branch to system call -ENTRY(sys32_uselib_wrapper) + .globl sys32_uselib_wrapper +sys32_uselib_wrapper: llgtr %r2,%r2 # const char * jg sys_uselib # branch to system call -ENTRY(sys32_swapon_wrapper) + .globl sys32_swapon_wrapper +sys32_swapon_wrapper: llgtr %r2,%r2 # const char * lgfr %r3,%r3 # int jg sys_swapon # branch to system call -ENTRY(sys32_reboot_wrapper) + .globl sys32_reboot_wrapper +sys32_reboot_wrapper: lgfr %r2,%r2 # int lgfr %r3,%r3 # int llgfr %r4,%r4 # unsigned int llgtr %r5,%r5 # void * jg sys_reboot # branch to system call -ENTRY(old32_readdir_wrapper) + .globl old32_readdir_wrapper +old32_readdir_wrapper: llgfr %r2,%r2 # unsigned int llgtr %r3,%r3 # void * llgfr %r4,%r4 # unsigned int jg compat_sys_old_readdir # branch to system call -ENTRY(old32_mmap_wrapper) + .globl old32_mmap_wrapper +old32_mmap_wrapper: llgtr %r2,%r2 # struct mmap_arg_struct_emu31 * jg old32_mmap # branch to system call -ENTRY(sys32_munmap_wrapper) + .globl sys32_munmap_wrapper +sys32_munmap_wrapper: llgfr %r2,%r2 # unsigned long llgfr %r3,%r3 # size_t jg sys_munmap # branch to system call -ENTRY(sys32_truncate_wrapper) + .globl sys32_truncate_wrapper +sys32_truncate_wrapper: llgtr %r2,%r2 # const char * lgfr %r3,%r3 # long jg sys_truncate # branch to system call -ENTRY(sys32_ftruncate_wrapper) + .globl sys32_ftruncate_wrapper +sys32_ftruncate_wrapper: llgfr %r2,%r2 # unsigned int llgfr %r3,%r3 # unsigned long jg sys_ftruncate # branch to system call -ENTRY(sys32_fchmod_wrapper) + .globl sys32_fchmod_wrapper +sys32_fchmod_wrapper: llgfr %r2,%r2 # unsigned int llgfr %r3,%r3 # mode_t jg sys_fchmod # branch to system call -ENTRY(sys32_fchown16_wrapper) + .globl sys32_fchown16_wrapper +sys32_fchown16_wrapper: llgfr %r2,%r2 # unsigned int llgfr %r3,%r3 # compat_uid_t llgfr %r4,%r4 # compat_uid_t jg sys32_fchown16 # branch to system call -ENTRY(sys32_getpriority_wrapper) + .globl sys32_getpriority_wrapper +sys32_getpriority_wrapper: lgfr %r2,%r2 # int lgfr %r3,%r3 # int jg sys_getpriority # branch to system call -ENTRY(sys32_setpriority_wrapper) + .globl sys32_setpriority_wrapper +sys32_setpriority_wrapper: lgfr %r2,%r2 # int lgfr %r3,%r3 # int lgfr %r4,%r4 # int jg sys_setpriority # branch to system call -ENTRY(compat_sys_statfs_wrapper) + .globl compat_sys_statfs_wrapper +compat_sys_statfs_wrapper: llgtr %r2,%r2 # char * llgtr %r3,%r3 # struct compat_statfs * jg compat_sys_statfs # branch to system call -ENTRY(compat_sys_fstatfs_wrapper) + .globl compat_sys_fstatfs_wrapper +compat_sys_fstatfs_wrapper: llgfr %r2,%r2 # unsigned int llgtr %r3,%r3 # struct compat_statfs * jg compat_sys_fstatfs # branch to system call -ENTRY(compat_sys_socketcall_wrapper) + .globl compat_sys_socketcall_wrapper +compat_sys_socketcall_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # u32 * jg compat_sys_socketcall # branch to system call -ENTRY(sys32_syslog_wrapper) + .globl sys32_syslog_wrapper +sys32_syslog_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # char * lgfr %r4,%r4 # int jg sys_syslog # branch to system call -ENTRY(compat_sys_setitimer_wrapper) + .globl compat_sys_setitimer_wrapper +compat_sys_setitimer_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # struct itimerval_emu31 * llgtr %r4,%r4 # struct itimerval_emu31 * jg compat_sys_setitimer # branch to system call -ENTRY(compat_sys_getitimer_wrapper) + .globl compat_sys_getitimer_wrapper +compat_sys_getitimer_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # struct itimerval_emu31 * jg compat_sys_getitimer # branch to system call -ENTRY(compat_sys_newstat_wrapper) + .globl compat_sys_newstat_wrapper +compat_sys_newstat_wrapper: llgtr %r2,%r2 # char * llgtr %r3,%r3 # struct stat_emu31 * jg compat_sys_newstat # branch to system call -ENTRY(compat_sys_newlstat_wrapper) + .globl compat_sys_newlstat_wrapper +compat_sys_newlstat_wrapper: llgtr %r2,%r2 # char * llgtr %r3,%r3 # struct stat_emu31 * jg compat_sys_newlstat # branch to system call -ENTRY(compat_sys_newfstat_wrapper) + .globl compat_sys_newfstat_wrapper +compat_sys_newfstat_wrapper: llgfr %r2,%r2 # unsigned int llgtr %r3,%r3 # struct stat_emu31 * jg compat_sys_newfstat # branch to system call #sys32_vhangup_wrapper # void -ENTRY(compat_sys_wait4_wrapper) + .globl compat_sys_wait4_wrapper +compat_sys_wait4_wrapper: lgfr %r2,%r2 # pid_t llgtr %r3,%r3 # unsigned int * lgfr %r4,%r4 # int llgtr %r5,%r5 # struct rusage * jg compat_sys_wait4 # branch to system call -ENTRY(sys32_swapoff_wrapper) + .globl sys32_swapoff_wrapper +sys32_swapoff_wrapper: llgtr %r2,%r2 # const char * jg sys_swapoff # branch to system call -ENTRY(compat_sys_sysinfo_wrapper) + .globl compat_sys_sysinfo_wrapper +compat_sys_sysinfo_wrapper: llgtr %r2,%r2 # struct sysinfo_emu31 * jg compat_sys_sysinfo # branch to system call -ENTRY(sys32_ipc_wrapper) + .globl sys32_ipc_wrapper +sys32_ipc_wrapper: llgfr %r2,%r2 # uint lgfr %r3,%r3 # int lgfr %r4,%r4 # int @@ -448,7 +529,8 @@ ENTRY(sys32_ipc_wrapper) llgfr %r6,%r6 # u32 jg sys32_ipc # branch to system call -ENTRY(sys32_fsync_wrapper) + .globl sys32_fsync_wrapper +sys32_fsync_wrapper: llgfr %r2,%r2 # unsigned int jg sys_fsync # branch to system call @@ -456,81 +538,97 @@ ENTRY(sys32_fsync_wrapper) #sys32_clone_wrapper # done in clone_glue -ENTRY(sys32_setdomainname_wrapper) + .globl sys32_setdomainname_wrapper +sys32_setdomainname_wrapper: llgtr %r2,%r2 # char * lgfr %r3,%r3 # int jg sys_setdomainname # branch to system call -ENTRY(sys32_newuname_wrapper) + .globl sys32_newuname_wrapper +sys32_newuname_wrapper: llgtr %r2,%r2 # struct new_utsname * jg sys_newuname # branch to system call -ENTRY(compat_sys_adjtimex_wrapper) + .globl compat_sys_adjtimex_wrapper +compat_sys_adjtimex_wrapper: llgtr %r2,%r2 # struct compat_timex * jg compat_sys_adjtimex # branch to system call -ENTRY(sys32_mprotect_wrapper) + .globl sys32_mprotect_wrapper +sys32_mprotect_wrapper: llgtr %r2,%r2 # unsigned long (actually pointer llgfr %r3,%r3 # size_t llgfr %r4,%r4 # unsigned long jg sys_mprotect # branch to system call -ENTRY(compat_sys_sigprocmask_wrapper) + .globl compat_sys_sigprocmask_wrapper +compat_sys_sigprocmask_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # compat_old_sigset_t * llgtr %r4,%r4 # compat_old_sigset_t * jg compat_sys_sigprocmask # branch to system call -ENTRY(sys_init_module_wrapper) + .globl sys_init_module_wrapper +sys_init_module_wrapper: llgtr %r2,%r2 # void * llgfr %r3,%r3 # unsigned long llgtr %r4,%r4 # char * jg sys_init_module # branch to system call -ENTRY(sys_delete_module_wrapper) + .globl sys_delete_module_wrapper +sys_delete_module_wrapper: llgtr %r2,%r2 # const char * llgfr %r3,%r3 # unsigned int jg sys_delete_module # branch to system call -ENTRY(sys32_quotactl_wrapper) + .globl sys32_quotactl_wrapper +sys32_quotactl_wrapper: llgfr %r2,%r2 # unsigned int llgtr %r3,%r3 # const char * llgfr %r4,%r4 # qid_t llgtr %r5,%r5 # caddr_t jg sys_quotactl # branch to system call -ENTRY(sys32_getpgid_wrapper) + .globl sys32_getpgid_wrapper +sys32_getpgid_wrapper: lgfr %r2,%r2 # pid_t jg sys_getpgid # branch to system call -ENTRY(sys32_fchdir_wrapper) + .globl sys32_fchdir_wrapper +sys32_fchdir_wrapper: llgfr %r2,%r2 # unsigned int jg sys_fchdir # branch to system call -ENTRY(sys32_bdflush_wrapper) + .globl sys32_bdflush_wrapper +sys32_bdflush_wrapper: lgfr %r2,%r2 # int lgfr %r3,%r3 # long jg sys_bdflush # branch to system call -ENTRY(sys32_sysfs_wrapper) + .globl sys32_sysfs_wrapper +sys32_sysfs_wrapper: lgfr %r2,%r2 # int llgfr %r3,%r3 # unsigned long llgfr %r4,%r4 # unsigned long jg sys_sysfs # branch to system call -ENTRY(sys32_personality_wrapper) + .globl sys32_personality_wrapper +sys32_personality_wrapper: llgfr %r2,%r2 # unsigned int jg sys_s390_personality # branch to system call -ENTRY(sys32_setfsuid16_wrapper) + .globl sys32_setfsuid16_wrapper +sys32_setfsuid16_wrapper: llgfr %r2,%r2 # __kernel_old_uid_emu31_t jg sys32_setfsuid16 # branch to system call -ENTRY(sys32_setfsgid16_wrapper) + .globl sys32_setfsgid16_wrapper +sys32_setfsgid16_wrapper: llgfr %r2,%r2 # __kernel_old_gid_emu31_t jg sys32_setfsgid16 # branch to system call -ENTRY(sys32_llseek_wrapper) + .globl sys32_llseek_wrapper +sys32_llseek_wrapper: llgfr %r2,%r2 # unsigned int llgfr %r3,%r3 # unsigned long llgfr %r4,%r4 # unsigned long @@ -538,13 +636,15 @@ ENTRY(sys32_llseek_wrapper) llgfr %r6,%r6 # unsigned int jg sys_llseek # branch to system call -ENTRY(sys32_getdents_wrapper) + .globl sys32_getdents_wrapper +sys32_getdents_wrapper: llgfr %r2,%r2 # unsigned int llgtr %r3,%r3 # void * llgfr %r4,%r4 # unsigned int jg compat_sys_getdents # branch to system call -ENTRY(compat_sys_select_wrapper) + .globl compat_sys_select_wrapper +compat_sys_select_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # compat_fd_set * llgtr %r4,%r4 # compat_fd_set * @@ -552,94 +652,112 @@ ENTRY(compat_sys_select_wrapper) llgtr %r6,%r6 # struct compat_timeval * jg compat_sys_select # branch to system call -ENTRY(sys32_flock_wrapper) + .globl sys32_flock_wrapper +sys32_flock_wrapper: llgfr %r2,%r2 # unsigned int llgfr %r3,%r3 # unsigned int jg sys_flock # branch to system call -ENTRY(sys32_msync_wrapper) + .globl sys32_msync_wrapper +sys32_msync_wrapper: llgfr %r2,%r2 # unsigned long llgfr %r3,%r3 # size_t lgfr %r4,%r4 # int jg sys_msync # branch to system call -ENTRY(compat_sys_readv_wrapper) + .globl compat_sys_readv_wrapper +compat_sys_readv_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # const struct compat_iovec * llgfr %r4,%r4 # unsigned long jg compat_sys_readv # branch to system call -ENTRY(compat_sys_writev_wrapper) + .globl compat_sys_writev_wrapper +compat_sys_writev_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # const struct compat_iovec * llgfr %r4,%r4 # unsigned long jg compat_sys_writev # branch to system call -ENTRY(sys32_getsid_wrapper) + .globl sys32_getsid_wrapper +sys32_getsid_wrapper: lgfr %r2,%r2 # pid_t jg sys_getsid # branch to system call -ENTRY(sys32_fdatasync_wrapper) + .globl sys32_fdatasync_wrapper +sys32_fdatasync_wrapper: llgfr %r2,%r2 # unsigned int jg sys_fdatasync # branch to system call -ENTRY(sys32_mlock_wrapper) + .globl sys32_mlock_wrapper +sys32_mlock_wrapper: llgfr %r2,%r2 # unsigned long llgfr %r3,%r3 # size_t jg sys_mlock # branch to system call -ENTRY(sys32_munlock_wrapper) + .globl sys32_munlock_wrapper +sys32_munlock_wrapper: llgfr %r2,%r2 # unsigned long llgfr %r3,%r3 # size_t jg sys_munlock # branch to system call -ENTRY(sys32_mlockall_wrapper) + .globl sys32_mlockall_wrapper +sys32_mlockall_wrapper: lgfr %r2,%r2 # int jg sys_mlockall # branch to system call #sys32_munlockall_wrapper # void -ENTRY(sys32_sched_setparam_wrapper) + .globl sys32_sched_setparam_wrapper +sys32_sched_setparam_wrapper: lgfr %r2,%r2 # pid_t llgtr %r3,%r3 # struct sched_param * jg sys_sched_setparam # branch to system call -ENTRY(sys32_sched_getparam_wrapper) + .globl sys32_sched_getparam_wrapper +sys32_sched_getparam_wrapper: lgfr %r2,%r2 # pid_t llgtr %r3,%r3 # struct sched_param * jg sys_sched_getparam # branch to system call -ENTRY(sys32_sched_setscheduler_wrapper) + .globl sys32_sched_setscheduler_wrapper +sys32_sched_setscheduler_wrapper: lgfr %r2,%r2 # pid_t lgfr %r3,%r3 # int llgtr %r4,%r4 # struct sched_param * jg sys_sched_setscheduler # branch to system call -ENTRY(sys32_sched_getscheduler_wrapper) + .globl sys32_sched_getscheduler_wrapper +sys32_sched_getscheduler_wrapper: lgfr %r2,%r2 # pid_t jg sys_sched_getscheduler # branch to system call #sys32_sched_yield_wrapper # void -ENTRY(sys32_sched_get_priority_max_wrapper) + .globl sys32_sched_get_priority_max_wrapper +sys32_sched_get_priority_max_wrapper: lgfr %r2,%r2 # int jg sys_sched_get_priority_max # branch to system call -ENTRY(sys32_sched_get_priority_min_wrapper) + .globl sys32_sched_get_priority_min_wrapper +sys32_sched_get_priority_min_wrapper: lgfr %r2,%r2 # int jg sys_sched_get_priority_min # branch to system call -ENTRY(sys32_sched_rr_get_interval_wrapper) + .globl sys32_sched_rr_get_interval_wrapper +sys32_sched_rr_get_interval_wrapper: lgfr %r2,%r2 # pid_t llgtr %r3,%r3 # struct compat_timespec * jg sys32_sched_rr_get_interval # branch to system call -ENTRY(compat_sys_nanosleep_wrapper) + .globl compat_sys_nanosleep_wrapper +compat_sys_nanosleep_wrapper: llgtr %r2,%r2 # struct compat_timespec * llgtr %r3,%r3 # struct compat_timespec * jg compat_sys_nanosleep # branch to system call -ENTRY(sys32_mremap_wrapper) + .globl sys32_mremap_wrapper +sys32_mremap_wrapper: llgfr %r2,%r2 # unsigned long llgfr %r3,%r3 # unsigned long llgfr %r4,%r4 # unsigned long @@ -647,43 +765,50 @@ ENTRY(sys32_mremap_wrapper) llgfr %r6,%r6 # unsigned long jg sys_mremap # branch to system call -ENTRY(sys32_setresuid16_wrapper) + .globl sys32_setresuid16_wrapper +sys32_setresuid16_wrapper: llgfr %r2,%r2 # __kernel_old_uid_emu31_t llgfr %r3,%r3 # __kernel_old_uid_emu31_t llgfr %r4,%r4 # __kernel_old_uid_emu31_t jg sys32_setresuid16 # branch to system call -ENTRY(sys32_getresuid16_wrapper) + .globl sys32_getresuid16_wrapper +sys32_getresuid16_wrapper: llgtr %r2,%r2 # __kernel_old_uid_emu31_t * llgtr %r3,%r3 # __kernel_old_uid_emu31_t * llgtr %r4,%r4 # __kernel_old_uid_emu31_t * jg sys32_getresuid16 # branch to system call -ENTRY(sys32_poll_wrapper) + .globl sys32_poll_wrapper +sys32_poll_wrapper: llgtr %r2,%r2 # struct pollfd * llgfr %r3,%r3 # unsigned int lgfr %r4,%r4 # long jg sys_poll # branch to system call -ENTRY(compat_sys_nfsservctl_wrapper) + .globl compat_sys_nfsservctl_wrapper +compat_sys_nfsservctl_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # struct compat_nfsctl_arg* llgtr %r4,%r4 # union compat_nfsctl_res* jg compat_sys_nfsservctl # branch to system call -ENTRY(sys32_setresgid16_wrapper) + .globl sys32_setresgid16_wrapper +sys32_setresgid16_wrapper: llgfr %r2,%r2 # __kernel_old_gid_emu31_t llgfr %r3,%r3 # __kernel_old_gid_emu31_t llgfr %r4,%r4 # __kernel_old_gid_emu31_t jg sys32_setresgid16 # branch to system call -ENTRY(sys32_getresgid16_wrapper) + .globl sys32_getresgid16_wrapper +sys32_getresgid16_wrapper: llgtr %r2,%r2 # __kernel_old_gid_emu31_t * llgtr %r3,%r3 # __kernel_old_gid_emu31_t * llgtr %r4,%r4 # __kernel_old_gid_emu31_t * jg sys32_getresgid16 # branch to system call -ENTRY(sys32_prctl_wrapper) + .globl sys32_prctl_wrapper +sys32_prctl_wrapper: lgfr %r2,%r2 # int llgfr %r3,%r3 # unsigned long llgfr %r4,%r4 # unsigned long @@ -693,44 +818,51 @@ ENTRY(sys32_prctl_wrapper) #sys32_rt_sigreturn_wrapper # done in rt_sigreturn_glue -ENTRY(sys32_rt_sigaction_wrapper) + .globl sys32_rt_sigaction_wrapper +sys32_rt_sigaction_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # const struct sigaction_emu31 * llgtr %r4,%r4 # const struct sigaction_emu31 * llgfr %r5,%r5 # size_t jg sys32_rt_sigaction # branch to system call -ENTRY(sys32_rt_sigprocmask_wrapper) + .globl sys32_rt_sigprocmask_wrapper +sys32_rt_sigprocmask_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # old_sigset_emu31 * llgtr %r4,%r4 # old_sigset_emu31 * llgfr %r5,%r5 # size_t jg sys32_rt_sigprocmask # branch to system call -ENTRY(sys32_rt_sigpending_wrapper) + .globl sys32_rt_sigpending_wrapper +sys32_rt_sigpending_wrapper: llgtr %r2,%r2 # sigset_emu31 * llgfr %r3,%r3 # size_t jg sys32_rt_sigpending # branch to system call -ENTRY(compat_sys_rt_sigtimedwait_wrapper) + .globl compat_sys_rt_sigtimedwait_wrapper +compat_sys_rt_sigtimedwait_wrapper: llgtr %r2,%r2 # const sigset_emu31_t * llgtr %r3,%r3 # siginfo_emu31_t * llgtr %r4,%r4 # const struct compat_timespec * llgfr %r5,%r5 # size_t jg compat_sys_rt_sigtimedwait # branch to system call -ENTRY(sys32_rt_sigqueueinfo_wrapper) + .globl sys32_rt_sigqueueinfo_wrapper +sys32_rt_sigqueueinfo_wrapper: lgfr %r2,%r2 # int lgfr %r3,%r3 # int llgtr %r4,%r4 # siginfo_emu31_t * jg sys32_rt_sigqueueinfo # branch to system call -ENTRY(compat_sys_rt_sigsuspend_wrapper) + .globl compat_sys_rt_sigsuspend_wrapper +compat_sys_rt_sigsuspend_wrapper: llgtr %r2,%r2 # compat_sigset_t * llgfr %r3,%r3 # compat_size_t jg compat_sys_rt_sigsuspend -ENTRY(sys32_pread64_wrapper) + .globl sys32_pread64_wrapper +sys32_pread64_wrapper: llgfr %r2,%r2 # unsigned int llgtr %r3,%r3 # char * llgfr %r4,%r4 # size_t @@ -738,7 +870,8 @@ ENTRY(sys32_pread64_wrapper) llgfr %r6,%r6 # u32 jg sys32_pread64 # branch to system call -ENTRY(sys32_pwrite64_wrapper) + .globl sys32_pwrite64_wrapper +sys32_pwrite64_wrapper: llgfr %r2,%r2 # unsigned int llgtr %r3,%r3 # const char * llgfr %r4,%r4 # size_t @@ -746,33 +879,39 @@ ENTRY(sys32_pwrite64_wrapper) llgfr %r6,%r6 # u32 jg sys32_pwrite64 # branch to system call -ENTRY(sys32_chown16_wrapper) + .globl sys32_chown16_wrapper +sys32_chown16_wrapper: llgtr %r2,%r2 # const char * llgfr %r3,%r3 # __kernel_old_uid_emu31_t llgfr %r4,%r4 # __kernel_old_gid_emu31_t jg sys32_chown16 # branch to system call -ENTRY(sys32_getcwd_wrapper) + .globl sys32_getcwd_wrapper +sys32_getcwd_wrapper: llgtr %r2,%r2 # char * llgfr %r3,%r3 # unsigned long jg sys_getcwd # branch to system call -ENTRY(sys32_capget_wrapper) + .globl sys32_capget_wrapper +sys32_capget_wrapper: llgtr %r2,%r2 # cap_user_header_t llgtr %r3,%r3 # cap_user_data_t jg sys_capget # branch to system call -ENTRY(sys32_capset_wrapper) + .globl sys32_capset_wrapper +sys32_capset_wrapper: llgtr %r2,%r2 # cap_user_header_t llgtr %r3,%r3 # const cap_user_data_t jg sys_capset # branch to system call -ENTRY(sys32_sigaltstack_wrapper) + .globl sys32_sigaltstack_wrapper +sys32_sigaltstack_wrapper: llgtr %r2,%r2 # const stack_emu31_t * llgtr %r3,%r3 # stack_emu31_t * jg sys32_sigaltstack -ENTRY(sys32_sendfile_wrapper) + .globl sys32_sendfile_wrapper +sys32_sendfile_wrapper: lgfr %r2,%r2 # int lgfr %r3,%r3 # int llgtr %r4,%r4 # __kernel_off_emu31_t * @@ -781,19 +920,22 @@ ENTRY(sys32_sendfile_wrapper) #sys32_vfork_wrapper # done in vfork_glue -ENTRY(sys32_truncate64_wrapper) + .globl sys32_truncate64_wrapper +sys32_truncate64_wrapper: llgtr %r2,%r2 # const char * llgfr %r3,%r3 # unsigned long llgfr %r4,%r4 # unsigned long jg sys32_truncate64 # branch to system call -ENTRY(sys32_ftruncate64_wrapper) + .globl sys32_ftruncate64_wrapper +sys32_ftruncate64_wrapper: llgfr %r2,%r2 # unsigned int llgfr %r3,%r3 # unsigned long llgfr %r4,%r4 # unsigned long jg sys32_ftruncate64 # branch to system call -ENTRY(sys32_lchown_wrapper) + .globl sys32_lchown_wrapper +sys32_lchown_wrapper: llgtr %r2,%r2 # const char * llgfr %r3,%r3 # uid_t llgfr %r4,%r4 # gid_t @@ -804,131 +946,156 @@ ENTRY(sys32_lchown_wrapper) #sys32_geteuid_wrapper # void #sys32_getegid_wrapper # void -ENTRY(sys32_setreuid_wrapper) + .globl sys32_setreuid_wrapper +sys32_setreuid_wrapper: llgfr %r2,%r2 # uid_t llgfr %r3,%r3 # uid_t jg sys_setreuid # branch to system call -ENTRY(sys32_setregid_wrapper) + .globl sys32_setregid_wrapper +sys32_setregid_wrapper: llgfr %r2,%r2 # gid_t llgfr %r3,%r3 # gid_t jg sys_setregid # branch to system call -ENTRY(sys32_getgroups_wrapper) + .globl sys32_getgroups_wrapper +sys32_getgroups_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # gid_t * jg sys_getgroups # branch to system call -ENTRY(sys32_setgroups_wrapper) + .globl sys32_setgroups_wrapper +sys32_setgroups_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # gid_t * jg sys_setgroups # branch to system call -ENTRY(sys32_fchown_wrapper) + .globl sys32_fchown_wrapper +sys32_fchown_wrapper: llgfr %r2,%r2 # unsigned int llgfr %r3,%r3 # uid_t llgfr %r4,%r4 # gid_t jg sys_fchown # branch to system call -ENTRY(sys32_setresuid_wrapper) + .globl sys32_setresuid_wrapper +sys32_setresuid_wrapper: llgfr %r2,%r2 # uid_t llgfr %r3,%r3 # uid_t llgfr %r4,%r4 # uid_t jg sys_setresuid # branch to system call -ENTRY(sys32_getresuid_wrapper) + .globl sys32_getresuid_wrapper +sys32_getresuid_wrapper: llgtr %r2,%r2 # uid_t * llgtr %r3,%r3 # uid_t * llgtr %r4,%r4 # uid_t * jg sys_getresuid # branch to system call -ENTRY(sys32_setresgid_wrapper) + .globl sys32_setresgid_wrapper +sys32_setresgid_wrapper: llgfr %r2,%r2 # gid_t llgfr %r3,%r3 # gid_t llgfr %r4,%r4 # gid_t jg sys_setresgid # branch to system call -ENTRY(sys32_getresgid_wrapper) + .globl sys32_getresgid_wrapper +sys32_getresgid_wrapper: llgtr %r2,%r2 # gid_t * llgtr %r3,%r3 # gid_t * llgtr %r4,%r4 # gid_t * jg sys_getresgid # branch to system call -ENTRY(sys32_chown_wrapper) + .globl sys32_chown_wrapper +sys32_chown_wrapper: llgtr %r2,%r2 # const char * llgfr %r3,%r3 # uid_t llgfr %r4,%r4 # gid_t jg sys_chown # branch to system call -ENTRY(sys32_setuid_wrapper) + .globl sys32_setuid_wrapper +sys32_setuid_wrapper: llgfr %r2,%r2 # uid_t jg sys_setuid # branch to system call -ENTRY(sys32_setgid_wrapper) + .globl sys32_setgid_wrapper +sys32_setgid_wrapper: llgfr %r2,%r2 # gid_t jg sys_setgid # branch to system call -ENTRY(sys32_setfsuid_wrapper) + .globl sys32_setfsuid_wrapper +sys32_setfsuid_wrapper: llgfr %r2,%r2 # uid_t jg sys_setfsuid # branch to system call -ENTRY(sys32_setfsgid_wrapper) + .globl sys32_setfsgid_wrapper +sys32_setfsgid_wrapper: llgfr %r2,%r2 # gid_t jg sys_setfsgid # branch to system call -ENTRY(sys32_pivot_root_wrapper) + .globl sys32_pivot_root_wrapper +sys32_pivot_root_wrapper: llgtr %r2,%r2 # const char * llgtr %r3,%r3 # const char * jg sys_pivot_root # branch to system call -ENTRY(sys32_mincore_wrapper) + .globl sys32_mincore_wrapper +sys32_mincore_wrapper: llgfr %r2,%r2 # unsigned long llgfr %r3,%r3 # size_t llgtr %r4,%r4 # unsigned char * jg sys_mincore # branch to system call -ENTRY(sys32_madvise_wrapper) + .globl sys32_madvise_wrapper +sys32_madvise_wrapper: llgfr %r2,%r2 # unsigned long llgfr %r3,%r3 # size_t lgfr %r4,%r4 # int jg sys_madvise # branch to system call -ENTRY(sys32_getdents64_wrapper) + .globl sys32_getdents64_wrapper +sys32_getdents64_wrapper: llgfr %r2,%r2 # unsigned int llgtr %r3,%r3 # void * llgfr %r4,%r4 # unsigned int jg sys_getdents64 # branch to system call -ENTRY(compat_sys_fcntl64_wrapper) + .globl compat_sys_fcntl64_wrapper +compat_sys_fcntl64_wrapper: llgfr %r2,%r2 # unsigned int llgfr %r3,%r3 # unsigned int llgfr %r4,%r4 # unsigned long jg compat_sys_fcntl64 # branch to system call -ENTRY(sys32_stat64_wrapper) + .globl sys32_stat64_wrapper +sys32_stat64_wrapper: llgtr %r2,%r2 # char * llgtr %r3,%r3 # struct stat64 * jg sys32_stat64 # branch to system call -ENTRY(sys32_lstat64_wrapper) + .globl sys32_lstat64_wrapper +sys32_lstat64_wrapper: llgtr %r2,%r2 # char * llgtr %r3,%r3 # struct stat64 * jg sys32_lstat64 # branch to system call -ENTRY(sys32_stime_wrapper) + .globl sys32_stime_wrapper +sys32_stime_wrapper: llgtr %r2,%r2 # long * jg compat_sys_stime # branch to system call -ENTRY(sys32_sysctl_wrapper) + .globl sys32_sysctl_wrapper +sys32_sysctl_wrapper: llgtr %r2,%r2 # struct compat_sysctl_args * jg compat_sys_sysctl -ENTRY(sys32_fstat64_wrapper) + .globl sys32_fstat64_wrapper +sys32_fstat64_wrapper: llgfr %r2,%r2 # unsigned long llgtr %r3,%r3 # struct stat64 * jg sys32_fstat64 # branch to system call -ENTRY(compat_sys_futex_wrapper) + .globl compat_sys_futex_wrapper +compat_sys_futex_wrapper: llgtr %r2,%r2 # u32 * lgfr %r3,%r3 # int lgfr %r4,%r4 # int @@ -938,7 +1105,8 @@ ENTRY(compat_sys_futex_wrapper) stg %r0,160(%r15) jg compat_sys_futex # branch to system call -ENTRY(sys32_setxattr_wrapper) + .globl sys32_setxattr_wrapper +sys32_setxattr_wrapper: llgtr %r2,%r2 # char * llgtr %r3,%r3 # char * llgtr %r4,%r4 # void * @@ -946,7 +1114,8 @@ ENTRY(sys32_setxattr_wrapper) lgfr %r6,%r6 # int jg sys_setxattr -ENTRY(sys32_lsetxattr_wrapper) + .globl sys32_lsetxattr_wrapper +sys32_lsetxattr_wrapper: llgtr %r2,%r2 # char * llgtr %r3,%r3 # char * llgtr %r4,%r4 # void * @@ -954,7 +1123,8 @@ ENTRY(sys32_lsetxattr_wrapper) lgfr %r6,%r6 # int jg sys_lsetxattr -ENTRY(sys32_fsetxattr_wrapper) + .globl sys32_fsetxattr_wrapper +sys32_fsetxattr_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # char * llgtr %r4,%r4 # void * @@ -962,106 +1132,124 @@ ENTRY(sys32_fsetxattr_wrapper) lgfr %r6,%r6 # int jg sys_fsetxattr -ENTRY(sys32_getxattr_wrapper) + .globl sys32_getxattr_wrapper +sys32_getxattr_wrapper: llgtr %r2,%r2 # char * llgtr %r3,%r3 # char * llgtr %r4,%r4 # void * llgfr %r5,%r5 # size_t jg sys_getxattr -ENTRY(sys32_lgetxattr_wrapper) + .globl sys32_lgetxattr_wrapper +sys32_lgetxattr_wrapper: llgtr %r2,%r2 # char * llgtr %r3,%r3 # char * llgtr %r4,%r4 # void * llgfr %r5,%r5 # size_t jg sys_lgetxattr -ENTRY(sys32_fgetxattr_wrapper) + .globl sys32_fgetxattr_wrapper +sys32_fgetxattr_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # char * llgtr %r4,%r4 # void * llgfr %r5,%r5 # size_t jg sys_fgetxattr -ENTRY(sys32_listxattr_wrapper) + .globl sys32_listxattr_wrapper +sys32_listxattr_wrapper: llgtr %r2,%r2 # char * llgtr %r3,%r3 # char * llgfr %r4,%r4 # size_t jg sys_listxattr -ENTRY(sys32_llistxattr_wrapper) + .globl sys32_llistxattr_wrapper +sys32_llistxattr_wrapper: llgtr %r2,%r2 # char * llgtr %r3,%r3 # char * llgfr %r4,%r4 # size_t jg sys_llistxattr -ENTRY(sys32_flistxattr_wrapper) + .globl sys32_flistxattr_wrapper +sys32_flistxattr_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # char * llgfr %r4,%r4 # size_t jg sys_flistxattr -ENTRY(sys32_removexattr_wrapper) + .globl sys32_removexattr_wrapper +sys32_removexattr_wrapper: llgtr %r2,%r2 # char * llgtr %r3,%r3 # char * jg sys_removexattr -ENTRY(sys32_lremovexattr_wrapper) + .globl sys32_lremovexattr_wrapper +sys32_lremovexattr_wrapper: llgtr %r2,%r2 # char * llgtr %r3,%r3 # char * jg sys_lremovexattr -ENTRY(sys32_fremovexattr_wrapper) + .globl sys32_fremovexattr_wrapper +sys32_fremovexattr_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # char * jg sys_fremovexattr -ENTRY(sys32_sched_setaffinity_wrapper) + .globl sys32_sched_setaffinity_wrapper +sys32_sched_setaffinity_wrapper: lgfr %r2,%r2 # int llgfr %r3,%r3 # unsigned int llgtr %r4,%r4 # unsigned long * jg compat_sys_sched_setaffinity -ENTRY(sys32_sched_getaffinity_wrapper) + .globl sys32_sched_getaffinity_wrapper +sys32_sched_getaffinity_wrapper: lgfr %r2,%r2 # int llgfr %r3,%r3 # unsigned int llgtr %r4,%r4 # unsigned long * jg compat_sys_sched_getaffinity -ENTRY(sys32_exit_group_wrapper) + .globl sys32_exit_group_wrapper +sys32_exit_group_wrapper: lgfr %r2,%r2 # int jg sys_exit_group # branch to system call -ENTRY(sys32_set_tid_address_wrapper) + .globl sys32_set_tid_address_wrapper +sys32_set_tid_address_wrapper: llgtr %r2,%r2 # int * jg sys_set_tid_address # branch to system call -ENTRY(sys_epoll_create_wrapper) + .globl sys_epoll_create_wrapper +sys_epoll_create_wrapper: lgfr %r2,%r2 # int jg sys_epoll_create # branch to system call -ENTRY(sys_epoll_ctl_wrapper) + .globl sys_epoll_ctl_wrapper +sys_epoll_ctl_wrapper: lgfr %r2,%r2 # int lgfr %r3,%r3 # int lgfr %r4,%r4 # int llgtr %r5,%r5 # struct epoll_event * jg sys_epoll_ctl # branch to system call -ENTRY(sys_epoll_wait_wrapper) + .globl sys_epoll_wait_wrapper +sys_epoll_wait_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # struct epoll_event * lgfr %r4,%r4 # int lgfr %r5,%r5 # int jg sys_epoll_wait # branch to system call -ENTRY(sys32_lookup_dcookie_wrapper) + .globl sys32_lookup_dcookie_wrapper +sys32_lookup_dcookie_wrapper: sllg %r2,%r2,32 # get high word of 64bit dcookie or %r2,%r3 # get low word of 64bit dcookie llgtr %r3,%r4 # char * llgfr %r4,%r5 # size_t jg sys_lookup_dcookie -ENTRY(sys32_fadvise64_wrapper) + .globl sys32_fadvise64_wrapper +sys32_fadvise64_wrapper: lgfr %r2,%r2 # int sllg %r3,%r3,32 # get high word of 64bit loff_t or %r3,%r4 # get low word of 64bit loff_t @@ -1069,68 +1257,81 @@ ENTRY(sys32_fadvise64_wrapper) lgfr %r5,%r6 # int jg sys32_fadvise64 -ENTRY(sys32_fadvise64_64_wrapper) + .globl sys32_fadvise64_64_wrapper +sys32_fadvise64_64_wrapper: llgtr %r2,%r2 # struct fadvise64_64_args * jg sys32_fadvise64_64 -ENTRY(sys32_clock_settime_wrapper) + .globl sys32_clock_settime_wrapper +sys32_clock_settime_wrapper: lgfr %r2,%r2 # clockid_t (int) llgtr %r3,%r3 # struct compat_timespec * jg compat_sys_clock_settime -ENTRY(sys32_clock_gettime_wrapper) + .globl sys32_clock_gettime_wrapper +sys32_clock_gettime_wrapper: lgfr %r2,%r2 # clockid_t (int) llgtr %r3,%r3 # struct compat_timespec * jg compat_sys_clock_gettime -ENTRY(sys32_clock_getres_wrapper) + .globl sys32_clock_getres_wrapper +sys32_clock_getres_wrapper: lgfr %r2,%r2 # clockid_t (int) llgtr %r3,%r3 # struct compat_timespec * jg compat_sys_clock_getres -ENTRY(sys32_clock_nanosleep_wrapper) + .globl sys32_clock_nanosleep_wrapper +sys32_clock_nanosleep_wrapper: lgfr %r2,%r2 # clockid_t (int) lgfr %r3,%r3 # int llgtr %r4,%r4 # struct compat_timespec * llgtr %r5,%r5 # struct compat_timespec * jg compat_sys_clock_nanosleep -ENTRY(sys32_timer_create_wrapper) + .globl sys32_timer_create_wrapper +sys32_timer_create_wrapper: lgfr %r2,%r2 # timer_t (int) llgtr %r3,%r3 # struct compat_sigevent * llgtr %r4,%r4 # timer_t * jg compat_sys_timer_create -ENTRY(sys32_timer_settime_wrapper) + .globl sys32_timer_settime_wrapper +sys32_timer_settime_wrapper: lgfr %r2,%r2 # timer_t (int) lgfr %r3,%r3 # int llgtr %r4,%r4 # struct compat_itimerspec * llgtr %r5,%r5 # struct compat_itimerspec * jg compat_sys_timer_settime -ENTRY(sys32_timer_gettime_wrapper) + .globl sys32_timer_gettime_wrapper +sys32_timer_gettime_wrapper: lgfr %r2,%r2 # timer_t (int) llgtr %r3,%r3 # struct compat_itimerspec * jg compat_sys_timer_gettime -ENTRY(sys32_timer_getoverrun_wrapper) + .globl sys32_timer_getoverrun_wrapper +sys32_timer_getoverrun_wrapper: lgfr %r2,%r2 # timer_t (int) jg sys_timer_getoverrun -ENTRY(sys32_timer_delete_wrapper) + .globl sys32_timer_delete_wrapper +sys32_timer_delete_wrapper: lgfr %r2,%r2 # timer_t (int) jg sys_timer_delete -ENTRY(sys32_io_setup_wrapper) + .globl sys32_io_setup_wrapper +sys32_io_setup_wrapper: llgfr %r2,%r2 # unsigned int llgtr %r3,%r3 # u32 * jg compat_sys_io_setup -ENTRY(sys32_io_destroy_wrapper) + .globl sys32_io_destroy_wrapper +sys32_io_destroy_wrapper: llgfr %r2,%r2 # (aio_context_t) u32 jg sys_io_destroy -ENTRY(sys32_io_getevents_wrapper) + .globl sys32_io_getevents_wrapper +sys32_io_getevents_wrapper: llgfr %r2,%r2 # (aio_context_t) u32 lgfr %r3,%r3 # long lgfr %r4,%r4 # long @@ -1138,42 +1339,49 @@ ENTRY(sys32_io_getevents_wrapper) llgtr %r6,%r6 # struct compat_timespec * jg compat_sys_io_getevents -ENTRY(sys32_io_submit_wrapper) + .globl sys32_io_submit_wrapper +sys32_io_submit_wrapper: llgfr %r2,%r2 # (aio_context_t) u32 lgfr %r3,%r3 # long llgtr %r4,%r4 # struct iocb ** jg compat_sys_io_submit -ENTRY(sys32_io_cancel_wrapper) + .globl sys32_io_cancel_wrapper +sys32_io_cancel_wrapper: llgfr %r2,%r2 # (aio_context_t) u32 llgtr %r3,%r3 # struct iocb * llgtr %r4,%r4 # struct io_event * jg sys_io_cancel -ENTRY(compat_sys_statfs64_wrapper) + .globl compat_sys_statfs64_wrapper +compat_sys_statfs64_wrapper: llgtr %r2,%r2 # const char * llgfr %r3,%r3 # compat_size_t llgtr %r4,%r4 # struct compat_statfs64 * jg compat_sys_statfs64 -ENTRY(compat_sys_fstatfs64_wrapper) + .globl compat_sys_fstatfs64_wrapper +compat_sys_fstatfs64_wrapper: llgfr %r2,%r2 # unsigned int fd llgfr %r3,%r3 # compat_size_t llgtr %r4,%r4 # struct compat_statfs64 * jg compat_sys_fstatfs64 -ENTRY(compat_sys_mq_open_wrapper) + .globl compat_sys_mq_open_wrapper +compat_sys_mq_open_wrapper: llgtr %r2,%r2 # const char * lgfr %r3,%r3 # int llgfr %r4,%r4 # mode_t llgtr %r5,%r5 # struct compat_mq_attr * jg compat_sys_mq_open -ENTRY(sys32_mq_unlink_wrapper) + .globl sys32_mq_unlink_wrapper +sys32_mq_unlink_wrapper: llgtr %r2,%r2 # const char * jg sys_mq_unlink -ENTRY(compat_sys_mq_timedsend_wrapper) + .globl compat_sys_mq_timedsend_wrapper +compat_sys_mq_timedsend_wrapper: lgfr %r2,%r2 # mqd_t llgtr %r3,%r3 # const char * llgfr %r4,%r4 # size_t @@ -1181,7 +1389,8 @@ ENTRY(compat_sys_mq_timedsend_wrapper) llgtr %r6,%r6 # const struct compat_timespec * jg compat_sys_mq_timedsend -ENTRY(compat_sys_mq_timedreceive_wrapper) + .globl compat_sys_mq_timedreceive_wrapper +compat_sys_mq_timedreceive_wrapper: lgfr %r2,%r2 # mqd_t llgtr %r3,%r3 # char * llgfr %r4,%r4 # size_t @@ -1189,18 +1398,21 @@ ENTRY(compat_sys_mq_timedreceive_wrapper) llgtr %r6,%r6 # const struct compat_timespec * jg compat_sys_mq_timedreceive -ENTRY(compat_sys_mq_notify_wrapper) + .globl compat_sys_mq_notify_wrapper +compat_sys_mq_notify_wrapper: lgfr %r2,%r2 # mqd_t llgtr %r3,%r3 # struct compat_sigevent * jg compat_sys_mq_notify -ENTRY(compat_sys_mq_getsetattr_wrapper) + .globl compat_sys_mq_getsetattr_wrapper +compat_sys_mq_getsetattr_wrapper: lgfr %r2,%r2 # mqd_t llgtr %r3,%r3 # struct compat_mq_attr * llgtr %r4,%r4 # struct compat_mq_attr * jg compat_sys_mq_getsetattr -ENTRY(compat_sys_add_key_wrapper) + .globl compat_sys_add_key_wrapper +compat_sys_add_key_wrapper: llgtr %r2,%r2 # const char * llgtr %r3,%r3 # const char * llgtr %r4,%r4 # const void * @@ -1208,14 +1420,16 @@ ENTRY(compat_sys_add_key_wrapper) llgfr %r6,%r6 # (key_serial_t) u32 jg sys_add_key -ENTRY(compat_sys_request_key_wrapper) + .globl compat_sys_request_key_wrapper +compat_sys_request_key_wrapper: llgtr %r2,%r2 # const char * llgtr %r3,%r3 # const char * llgtr %r4,%r4 # const void * llgfr %r5,%r5 # (key_serial_t) u32 jg sys_request_key -ENTRY(sys32_remap_file_pages_wrapper) + .globl sys32_remap_file_pages_wrapper +sys32_remap_file_pages_wrapper: llgfr %r2,%r2 # unsigned long llgfr %r3,%r3 # unsigned long llgfr %r4,%r4 # unsigned long @@ -1223,7 +1437,8 @@ ENTRY(sys32_remap_file_pages_wrapper) llgfr %r6,%r6 # unsigned long jg sys_remap_file_pages -ENTRY(compat_sys_waitid_wrapper) + .globl compat_sys_waitid_wrapper +compat_sys_waitid_wrapper: lgfr %r2,%r2 # int lgfr %r3,%r3 # pid_t llgtr %r4,%r4 # siginfo_emu31_t * @@ -1231,56 +1446,65 @@ ENTRY(compat_sys_waitid_wrapper) llgtr %r6,%r6 # struct rusage_emu31 * jg compat_sys_waitid -ENTRY(compat_sys_kexec_load_wrapper) + .globl compat_sys_kexec_load_wrapper +compat_sys_kexec_load_wrapper: llgfr %r2,%r2 # unsigned long llgfr %r3,%r3 # unsigned long llgtr %r4,%r4 # struct kexec_segment * llgfr %r5,%r5 # unsigned long jg compat_sys_kexec_load -ENTRY(sys_ioprio_set_wrapper) + .globl sys_ioprio_set_wrapper +sys_ioprio_set_wrapper: lgfr %r2,%r2 # int lgfr %r3,%r3 # int lgfr %r4,%r4 # int jg sys_ioprio_set -ENTRY(sys_ioprio_get_wrapper) + .globl sys_ioprio_get_wrapper +sys_ioprio_get_wrapper: lgfr %r2,%r2 # int lgfr %r3,%r3 # int jg sys_ioprio_get -ENTRY(sys_inotify_add_watch_wrapper) + .globl sys_inotify_add_watch_wrapper +sys_inotify_add_watch_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # const char * llgfr %r4,%r4 # u32 jg sys_inotify_add_watch -ENTRY(sys_inotify_rm_watch_wrapper) + .globl sys_inotify_rm_watch_wrapper +sys_inotify_rm_watch_wrapper: lgfr %r2,%r2 # int llgfr %r3,%r3 # u32 jg sys_inotify_rm_watch -ENTRY(compat_sys_openat_wrapper) + .globl compat_sys_openat_wrapper +compat_sys_openat_wrapper: llgfr %r2,%r2 # unsigned int llgtr %r3,%r3 # const char * lgfr %r4,%r4 # int lgfr %r5,%r5 # int jg compat_sys_openat -ENTRY(sys_mkdirat_wrapper) + .globl sys_mkdirat_wrapper +sys_mkdirat_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # const char * lgfr %r4,%r4 # int jg sys_mkdirat -ENTRY(sys_mknodat_wrapper) + .globl sys_mknodat_wrapper +sys_mknodat_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # const char * lgfr %r4,%r4 # int llgfr %r5,%r5 # unsigned int jg sys_mknodat -ENTRY(sys_fchownat_wrapper) + .globl sys_fchownat_wrapper +sys_fchownat_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # const char * llgfr %r4,%r4 # uid_t @@ -1288,33 +1512,38 @@ ENTRY(sys_fchownat_wrapper) lgfr %r6,%r6 # int jg sys_fchownat -ENTRY(compat_sys_futimesat_wrapper) + .globl compat_sys_futimesat_wrapper +compat_sys_futimesat_wrapper: llgfr %r2,%r2 # unsigned int llgtr %r3,%r3 # char * llgtr %r4,%r4 # struct timeval * jg compat_sys_futimesat -ENTRY(sys32_fstatat64_wrapper) + .globl sys32_fstatat64_wrapper +sys32_fstatat64_wrapper: llgfr %r2,%r2 # unsigned int llgtr %r3,%r3 # char * llgtr %r4,%r4 # struct stat64 * lgfr %r5,%r5 # int jg sys32_fstatat64 -ENTRY(sys_unlinkat_wrapper) + .globl sys_unlinkat_wrapper +sys_unlinkat_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # const char * lgfr %r4,%r4 # int jg sys_unlinkat -ENTRY(sys_renameat_wrapper) + .globl sys_renameat_wrapper +sys_renameat_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # const char * lgfr %r4,%r4 # int llgtr %r5,%r5 # const char * jg sys_renameat -ENTRY(sys_linkat_wrapper) + .globl sys_linkat_wrapper +sys_linkat_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # const char * lgfr %r4,%r4 # int @@ -1322,32 +1551,37 @@ ENTRY(sys_linkat_wrapper) lgfr %r6,%r6 # int jg sys_linkat -ENTRY(sys_symlinkat_wrapper) + .globl sys_symlinkat_wrapper +sys_symlinkat_wrapper: llgtr %r2,%r2 # const char * lgfr %r3,%r3 # int llgtr %r4,%r4 # const char * jg sys_symlinkat -ENTRY(sys_readlinkat_wrapper) + .globl sys_readlinkat_wrapper +sys_readlinkat_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # const char * llgtr %r4,%r4 # char * lgfr %r5,%r5 # int jg sys_readlinkat -ENTRY(sys_fchmodat_wrapper) + .globl sys_fchmodat_wrapper +sys_fchmodat_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # const char * llgfr %r4,%r4 # mode_t jg sys_fchmodat -ENTRY(sys_faccessat_wrapper) + .globl sys_faccessat_wrapper +sys_faccessat_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # const char * lgfr %r4,%r4 # int jg sys_faccessat -ENTRY(compat_sys_pselect6_wrapper) + .globl compat_sys_pselect6_wrapper +compat_sys_pselect6_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # fd_set * llgtr %r4,%r4 # fd_set * @@ -1357,7 +1591,8 @@ ENTRY(compat_sys_pselect6_wrapper) stg %r0,160(%r15) jg compat_sys_pselect6 -ENTRY(compat_sys_ppoll_wrapper) + .globl compat_sys_ppoll_wrapper +compat_sys_ppoll_wrapper: llgtr %r2,%r2 # struct pollfd * llgfr %r3,%r3 # unsigned int llgtr %r4,%r4 # struct timespec * @@ -1365,22 +1600,26 @@ ENTRY(compat_sys_ppoll_wrapper) llgfr %r6,%r6 # size_t jg compat_sys_ppoll -ENTRY(sys_unshare_wrapper) + .globl sys_unshare_wrapper +sys_unshare_wrapper: llgfr %r2,%r2 # unsigned long jg sys_unshare -ENTRY(compat_sys_set_robust_list_wrapper) + .globl compat_sys_set_robust_list_wrapper +compat_sys_set_robust_list_wrapper: llgtr %r2,%r2 # struct compat_robust_list_head * llgfr %r3,%r3 # size_t jg compat_sys_set_robust_list -ENTRY(compat_sys_get_robust_list_wrapper) + .globl compat_sys_get_robust_list_wrapper +compat_sys_get_robust_list_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # compat_uptr_t_t * llgtr %r4,%r4 # compat_size_t * jg compat_sys_get_robust_list -ENTRY(sys_splice_wrapper) + .globl sys_splice_wrapper +sys_splice_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # loff_t * lgfr %r4,%r4 # int @@ -1390,7 +1629,8 @@ ENTRY(sys_splice_wrapper) stg %r0,160(%r15) jg sys_splice -ENTRY(sys_sync_file_range_wrapper) + .globl sys_sync_file_range_wrapper +sys_sync_file_range_wrapper: lgfr %r2,%r2 # int sllg %r3,%r3,32 # get high word of 64bit loff_t or %r3,%r4 # get low word of 64bit loff_t @@ -1399,27 +1639,31 @@ ENTRY(sys_sync_file_range_wrapper) llgf %r5,164(%r15) # unsigned int jg sys_sync_file_range -ENTRY(sys_tee_wrapper) + .globl sys_tee_wrapper +sys_tee_wrapper: lgfr %r2,%r2 # int lgfr %r3,%r3 # int llgfr %r4,%r4 # size_t llgfr %r5,%r5 # unsigned int jg sys_tee -ENTRY(compat_sys_vmsplice_wrapper) + .globl compat_sys_vmsplice_wrapper +compat_sys_vmsplice_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # compat_iovec * llgfr %r4,%r4 # unsigned int llgfr %r5,%r5 # unsigned int jg compat_sys_vmsplice -ENTRY(sys_getcpu_wrapper) + .globl sys_getcpu_wrapper +sys_getcpu_wrapper: llgtr %r2,%r2 # unsigned * llgtr %r3,%r3 # unsigned * llgtr %r4,%r4 # struct getcpu_cache * jg sys_getcpu -ENTRY(compat_sys_epoll_pwait_wrapper) + .globl compat_sys_epoll_pwait_wrapper +compat_sys_epoll_pwait_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # struct compat_epoll_event * lgfr %r4,%r4 # int @@ -1429,29 +1673,34 @@ ENTRY(compat_sys_epoll_pwait_wrapper) stg %r0,160(%r15) jg compat_sys_epoll_pwait -ENTRY(compat_sys_utimes_wrapper) + .globl compat_sys_utimes_wrapper +compat_sys_utimes_wrapper: llgtr %r2,%r2 # char * llgtr %r3,%r3 # struct compat_timeval * jg compat_sys_utimes -ENTRY(compat_sys_utimensat_wrapper) + .globl compat_sys_utimensat_wrapper +compat_sys_utimensat_wrapper: llgfr %r2,%r2 # unsigned int llgtr %r3,%r3 # char * llgtr %r4,%r4 # struct compat_timespec * lgfr %r5,%r5 # int jg compat_sys_utimensat -ENTRY(compat_sys_signalfd_wrapper) + .globl compat_sys_signalfd_wrapper +compat_sys_signalfd_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # compat_sigset_t * llgfr %r4,%r4 # compat_size_t jg compat_sys_signalfd -ENTRY(sys_eventfd_wrapper) + .globl sys_eventfd_wrapper +sys_eventfd_wrapper: llgfr %r2,%r2 # unsigned int jg sys_eventfd -ENTRY(sys_fallocate_wrapper) + .globl sys_fallocate_wrapper +sys_fallocate_wrapper: lgfr %r2,%r2 # int lgfr %r3,%r3 # int sllg %r4,%r4,32 # get high word of 64bit loff_t @@ -1460,80 +1709,94 @@ ENTRY(sys_fallocate_wrapper) l %r5,164(%r15) # get low word of 64bit loff_t jg sys_fallocate -ENTRY(sys_timerfd_create_wrapper) + .globl sys_timerfd_create_wrapper +sys_timerfd_create_wrapper: lgfr %r2,%r2 # int lgfr %r3,%r3 # int jg sys_timerfd_create -ENTRY(compat_sys_timerfd_settime_wrapper) + .globl compat_sys_timerfd_settime_wrapper +compat_sys_timerfd_settime_wrapper: lgfr %r2,%r2 # int lgfr %r3,%r3 # int llgtr %r4,%r4 # struct compat_itimerspec * llgtr %r5,%r5 # struct compat_itimerspec * jg compat_sys_timerfd_settime -ENTRY(compat_sys_timerfd_gettime_wrapper) + .globl compat_sys_timerfd_gettime_wrapper +compat_sys_timerfd_gettime_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # struct compat_itimerspec * jg compat_sys_timerfd_gettime -ENTRY(compat_sys_signalfd4_wrapper) + .globl compat_sys_signalfd4_wrapper +compat_sys_signalfd4_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # compat_sigset_t * llgfr %r4,%r4 # compat_size_t lgfr %r5,%r5 # int jg compat_sys_signalfd4 -ENTRY(sys_eventfd2_wrapper) + .globl sys_eventfd2_wrapper +sys_eventfd2_wrapper: llgfr %r2,%r2 # unsigned int lgfr %r3,%r3 # int jg sys_eventfd2 -ENTRY(sys_inotify_init1_wrapper) + .globl sys_inotify_init1_wrapper +sys_inotify_init1_wrapper: lgfr %r2,%r2 # int jg sys_inotify_init1 -ENTRY(sys_pipe2_wrapper) + .globl sys_pipe2_wrapper +sys_pipe2_wrapper: llgtr %r2,%r2 # u32 * lgfr %r3,%r3 # int jg sys_pipe2 # branch to system call -ENTRY(sys_dup3_wrapper) + .globl sys_dup3_wrapper +sys_dup3_wrapper: llgfr %r2,%r2 # unsigned int llgfr %r3,%r3 # unsigned int lgfr %r4,%r4 # int jg sys_dup3 # branch to system call -ENTRY(sys_epoll_create1_wrapper) + .globl sys_epoll_create1_wrapper +sys_epoll_create1_wrapper: lgfr %r2,%r2 # int jg sys_epoll_create1 # branch to system call -ENTRY(sys32_readahead_wrapper) + .globl sys32_readahead_wrapper +sys32_readahead_wrapper: lgfr %r2,%r2 # int llgfr %r3,%r3 # u32 llgfr %r4,%r4 # u32 lgfr %r5,%r5 # s32 jg sys32_readahead # branch to system call -ENTRY(sys32_sendfile64_wrapper) + .globl sys32_sendfile64_wrapper +sys32_sendfile64_wrapper: lgfr %r2,%r2 # int lgfr %r3,%r3 # int llgtr %r4,%r4 # compat_loff_t * lgfr %r5,%r5 # s32 jg sys32_sendfile64 # branch to system call -ENTRY(sys_tkill_wrapper) + .globl sys_tkill_wrapper +sys_tkill_wrapper: lgfr %r2,%r2 # pid_t lgfr %r3,%r3 # int jg sys_tkill # branch to system call -ENTRY(sys_tgkill_wrapper) + .globl sys_tgkill_wrapper +sys_tgkill_wrapper: lgfr %r2,%r2 # pid_t lgfr %r3,%r3 # pid_t lgfr %r4,%r4 # int jg sys_tgkill # branch to system call -ENTRY(compat_sys_keyctl_wrapper) + .globl compat_sys_keyctl_wrapper +compat_sys_keyctl_wrapper: llgfr %r2,%r2 # u32 llgfr %r3,%r3 # u32 llgfr %r4,%r4 # u32 @@ -1541,7 +1804,8 @@ ENTRY(compat_sys_keyctl_wrapper) llgfr %r6,%r6 # u32 jg compat_sys_keyctl # branch to system call -ENTRY(compat_sys_preadv_wrapper) + .globl compat_sys_preadv_wrapper +compat_sys_preadv_wrapper: llgfr %r2,%r2 # unsigned long llgtr %r3,%r3 # compat_iovec * llgfr %r4,%r4 # unsigned long @@ -1549,7 +1813,8 @@ ENTRY(compat_sys_preadv_wrapper) llgfr %r6,%r6 # u32 jg compat_sys_preadv # branch to system call -ENTRY(compat_sys_pwritev_wrapper) + .globl compat_sys_pwritev_wrapper +compat_sys_pwritev_wrapper: llgfr %r2,%r2 # unsigned long llgtr %r3,%r3 # compat_iovec * llgfr %r4,%r4 # unsigned long @@ -1557,14 +1822,16 @@ ENTRY(compat_sys_pwritev_wrapper) llgfr %r6,%r6 # u32 jg compat_sys_pwritev # branch to system call -ENTRY(compat_sys_rt_tgsigqueueinfo_wrapper) + .globl compat_sys_rt_tgsigqueueinfo_wrapper +compat_sys_rt_tgsigqueueinfo_wrapper: lgfr %r2,%r2 # compat_pid_t lgfr %r3,%r3 # compat_pid_t lgfr %r4,%r4 # int llgtr %r5,%r5 # struct compat_siginfo * jg compat_sys_rt_tgsigqueueinfo_wrapper # branch to system call -ENTRY(sys_perf_event_open_wrapper) + .globl sys_perf_event_open_wrapper +sys_perf_event_open_wrapper: llgtr %r2,%r2 # const struct perf_event_attr * lgfr %r3,%r3 # pid_t lgfr %r4,%r4 # int @@ -1572,25 +1839,29 @@ ENTRY(sys_perf_event_open_wrapper) llgfr %r6,%r6 # unsigned long jg sys_perf_event_open # branch to system call -ENTRY(sys_clone_wrapper) + .globl sys_clone_wrapper +sys_clone_wrapper: llgfr %r2,%r2 # unsigned long llgfr %r3,%r3 # unsigned long llgtr %r4,%r4 # int * llgtr %r5,%r5 # int * jg sys_clone # branch to system call -ENTRY(sys32_execve_wrapper) + .globl sys32_execve_wrapper +sys32_execve_wrapper: llgtr %r2,%r2 # char * llgtr %r3,%r3 # compat_uptr_t * llgtr %r4,%r4 # compat_uptr_t * jg sys32_execve # branch to system call -ENTRY(sys_fanotify_init_wrapper) + .globl sys_fanotify_init_wrapper +sys_fanotify_init_wrapper: llgfr %r2,%r2 # unsigned int llgfr %r3,%r3 # unsigned int jg sys_fanotify_init # branch to system call -ENTRY(sys_fanotify_mark_wrapper) + .globl sys_fanotify_mark_wrapper +sys_fanotify_mark_wrapper: lgfr %r2,%r2 # int llgfr %r3,%r3 # unsigned int sllg %r4,%r4,32 # get high word of 64bit mask @@ -1599,14 +1870,16 @@ ENTRY(sys_fanotify_mark_wrapper) llgt %r6,164(%r15) # char * jg sys_fanotify_mark # branch to system call -ENTRY(sys_prlimit64_wrapper) + .globl sys_prlimit64_wrapper +sys_prlimit64_wrapper: lgfr %r2,%r2 # pid_t llgfr %r3,%r3 # unsigned int llgtr %r4,%r4 # const struct rlimit64 __user * llgtr %r5,%r5 # struct rlimit64 __user * jg sys_prlimit64 # branch to system call -ENTRY(sys_name_to_handle_at_wrapper) + .globl sys_name_to_handle_at_wrapper +sys_name_to_handle_at_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # const char __user * llgtr %r4,%r4 # struct file_handle __user * @@ -1614,18 +1887,21 @@ ENTRY(sys_name_to_handle_at_wrapper) lgfr %r6,%r6 # int jg sys_name_to_handle_at -ENTRY(compat_sys_open_by_handle_at_wrapper) + .globl compat_sys_open_by_handle_at_wrapper +compat_sys_open_by_handle_at_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # struct file_handle __user * lgfr %r4,%r4 # int jg compat_sys_open_by_handle_at -ENTRY(compat_sys_clock_adjtime_wrapper) + .globl compat_sys_clock_adjtime_wrapper +compat_sys_clock_adjtime_wrapper: lgfr %r2,%r2 # clockid_t (int) llgtr %r3,%r3 # struct compat_timex __user * jg compat_sys_clock_adjtime -ENTRY(sys_syncfs_wrapper) + .globl sys_syncfs_wrapper +sys_syncfs_wrapper: lgfr %r2,%r2 # int jg sys_syncfs diff --git a/trunk/arch/s390/kernel/entry.S b/trunk/arch/s390/kernel/entry.S index 3eab7cfab07c..0476174dfff5 100644 --- a/trunk/arch/s390/kernel/entry.S +++ b/trunk/arch/s390/kernel/entry.S @@ -9,8 +9,8 @@ * Heiko Carstens */ -#include #include +#include #include #include #include @@ -197,7 +197,8 @@ STACK_SIZE = 1 << STACK_SHIFT * Returns: * gpr2 = prev */ -ENTRY(__switch_to) + .globl __switch_to +__switch_to: basr %r1,0 0: l %r4,__THREAD_info(%r2) # get thread_info of prev l %r5,__THREAD_info(%r3) # get thread_info of next @@ -223,7 +224,8 @@ __critical_start: * are executed with interrupts enabled. */ -ENTRY(system_call) + .globl system_call +system_call: stpt __LC_SYNC_ENTER_TIMER sysc_saveall: SAVE_ALL_SVC __LC_SVC_OLD_PSW,__LC_SAVE_AREA @@ -386,7 +388,8 @@ sysc_tracenogo: # # a new process exits the kernel with ret_from_fork # -ENTRY(ret_from_fork) + .globl ret_from_fork +ret_from_fork: l %r13,__LC_SVC_NEW_PSW+4 l %r12,__LC_THREAD_INFO # load pointer to thread_info struct tm SP_PSW+1(%r15),0x01 # forking a kernel thread ? @@ -402,7 +405,8 @@ ENTRY(ret_from_fork) # kernel_execve function needs to deal with pt_regs that is not # at the usual place # -ENTRY(kernel_execve) + .globl kernel_execve +kernel_execve: stm %r12,%r15,48(%r15) lr %r14,%r15 l %r13,__LC_SVC_NEW_PSW+4 @@ -434,7 +438,8 @@ ENTRY(kernel_execve) * Program check handler routine */ -ENTRY(pgm_check_handler) + .globl pgm_check_handler +pgm_check_handler: /* * First we need to check for a special case: * Single stepping an instruction that disables the PER event mask will @@ -560,7 +565,8 @@ kernel_per: * IO interrupt handler routine */ -ENTRY(io_int_handler) + .globl io_int_handler +io_int_handler: stck __LC_INT_CLOCK stpt __LC_ASYNC_ENTER_TIMER SAVE_ALL_ASYNC __LC_IO_OLD_PSW,__LC_SAVE_AREA+16 @@ -697,7 +703,8 @@ io_notify_resume: * External interrupt handler routine */ -ENTRY(ext_int_handler) + .globl ext_int_handler +ext_int_handler: stck __LC_INT_CLOCK stpt __LC_ASYNC_ENTER_TIMER SAVE_ALL_ASYNC __LC_EXT_OLD_PSW,__LC_SAVE_AREA+16 @@ -724,7 +731,8 @@ __critical_end: * Machine check handler routines */ -ENTRY(mcck_int_handler) + .globl mcck_int_handler +mcck_int_handler: stck __LC_MCCK_CLOCK spt __LC_CPU_TIMER_SAVE_AREA # revalidate cpu timer lm %r0,%r15,__LC_GPREGS_SAVE_AREA # revalidate gprs @@ -810,7 +818,8 @@ mcck_return: */ #ifdef CONFIG_SMP __CPUINIT -ENTRY(restart_int_handler) + .globl restart_int_handler +restart_int_handler: basr %r1,0 restart_base: spt restart_vtime-restart_base(%r1) @@ -839,7 +848,8 @@ restart_vtime: /* * If we do not run with SMP enabled, let the new CPU crash ... */ -ENTRY(restart_int_handler) + .globl restart_int_handler +restart_int_handler: basr %r1,0 restart_base: lpsw restart_crash-restart_base(%r1) diff --git a/trunk/arch/s390/kernel/entry.h b/trunk/arch/s390/kernel/entry.h index 66729eb7bbc5..17a6f83a2d67 100644 --- a/trunk/arch/s390/kernel/entry.h +++ b/trunk/arch/s390/kernel/entry.h @@ -5,9 +5,10 @@ #include #include -void do_protection_exception(struct pt_regs *, long, unsigned long); -void do_dat_exception(struct pt_regs *, long, unsigned long); -void do_asce_exception(struct pt_regs *, long, unsigned long); +typedef void pgm_check_handler_t(struct pt_regs *, long, unsigned long); +extern pgm_check_handler_t *pgm_check_table[128]; +pgm_check_handler_t do_protection_exception; +pgm_check_handler_t do_dat_exception; extern int sysctl_userprocess_debug; diff --git a/trunk/arch/s390/kernel/entry64.S b/trunk/arch/s390/kernel/entry64.S index 7a0fd426ca92..d61967e2eab0 100644 --- a/trunk/arch/s390/kernel/entry64.S +++ b/trunk/arch/s390/kernel/entry64.S @@ -9,8 +9,8 @@ * Heiko Carstens */ -#include #include +#include #include #include #include @@ -56,28 +56,15 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \ _TIF_MCCK_PENDING) _TIF_SYSCALL = (_TIF_SYSCALL_TRACE>>8 | _TIF_SYSCALL_AUDIT>>8 | \ _TIF_SECCOMP>>8 | _TIF_SYSCALL_TRACEPOINT>>8) -_TIF_EXIT_SIE = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING) #define BASED(name) name-system_call(%r13) - .macro SPP newpp -#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE) - tm __LC_MACHINE_FLAGS+6,0x20 # MACHINE_FLAG_SPP - jz .+8 - .insn s,0xb2800000,\newpp -#endif - .endm - .macro HANDLE_SIE_INTERCEPT #if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE) - tm __TI_flags+6(%r12),_TIF_SIE>>8 + lg %r3,__LC_SIE_HOOK + ltgr %r3,%r3 jz 0f - SPP __LC_CMF_HPP # set host id - clc SP_PSW+8(8,%r15),BASED(.Lsie_loop) - jl 0f - clc SP_PSW+8(8,%r15),BASED(.Lsie_done) - jhe 0f - mvc SP_PSW+8(8,%r15),BASED(.Lsie_loop) + basr %r14,%r3 0: #endif .endm @@ -219,7 +206,8 @@ _TIF_EXIT_SIE = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING) * Returns: * gpr2 = prev */ -ENTRY(__switch_to) + .globl __switch_to +__switch_to: lg %r4,__THREAD_info(%r2) # get thread_info of prev lg %r5,__THREAD_info(%r3) # get thread_info of next tm __TI_flags+7(%r4),_TIF_MCCK_PENDING # machine check pending? @@ -244,7 +232,8 @@ __critical_start: * are executed with interrupts enabled. */ -ENTRY(system_call) + .globl system_call +system_call: stpt __LC_SYNC_ENTER_TIMER sysc_saveall: SAVE_ALL_SVC __LC_SVC_OLD_PSW,__LC_SAVE_AREA @@ -406,7 +395,8 @@ sysc_tracenogo: # # a new process exits the kernel with ret_from_fork # -ENTRY(ret_from_fork) + .globl ret_from_fork +ret_from_fork: lg %r13,__LC_SVC_NEW_PSW+8 lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct tm SP_PSW+1(%r15),0x01 # forking a kernel thread ? @@ -421,7 +411,8 @@ ENTRY(ret_from_fork) # kernel_execve function needs to deal with pt_regs that is not # at the usual place # -ENTRY(kernel_execve) + .globl kernel_execve +kernel_execve: stmg %r12,%r15,96(%r15) lgr %r14,%r15 aghi %r15,-SP_SIZE @@ -451,7 +442,8 @@ ENTRY(kernel_execve) * Program check handler routine */ -ENTRY(pgm_check_handler) + .globl pgm_check_handler +pgm_check_handler: /* * First we need to check for a special case: * Single stepping an instruction that disables the PER event mask will @@ -473,7 +465,6 @@ ENTRY(pgm_check_handler) xc SP_ILC(4,%r15),SP_ILC(%r15) mvc SP_PSW(16,%r15),__LC_PGM_OLD_PSW lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct - HANDLE_SIE_INTERCEPT tm SP_PSW+1(%r15),0x01 # interrupting from user ? jz pgm_no_vtime UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER @@ -481,6 +472,7 @@ ENTRY(pgm_check_handler) mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER LAST_BREAK pgm_no_vtime: + HANDLE_SIE_INTERCEPT stg %r11,SP_ARGS(%r15) lgf %r3,__LC_PGM_ILC # load program interruption code lg %r4,__LC_TRANS_EXC_CODE @@ -515,7 +507,6 @@ pgm_per_std: CREATE_STACK_FRAME __LC_SAVE_AREA mvc SP_PSW(16,%r15),__LC_PGM_OLD_PSW lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct - HANDLE_SIE_INTERCEPT tm SP_PSW+1(%r15),0x01 # interrupting from user ? jz pgm_no_vtime2 UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER @@ -523,6 +514,7 @@ pgm_per_std: mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER LAST_BREAK pgm_no_vtime2: + HANDLE_SIE_INTERCEPT lg %r1,__TI_task(%r12) tm SP_PSW+1(%r15),0x01 # kernel per event ? jz kernel_per @@ -579,14 +571,14 @@ kernel_per: /* * IO interrupt handler routine */ -ENTRY(io_int_handler) + .globl io_int_handler +io_int_handler: stck __LC_INT_CLOCK stpt __LC_ASYNC_ENTER_TIMER SAVE_ALL_ASYNC __LC_IO_OLD_PSW,__LC_SAVE_AREA+40 CREATE_STACK_FRAME __LC_SAVE_AREA+40 mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct - HANDLE_SIE_INTERCEPT tm SP_PSW+1(%r15),0x01 # interrupting from user ? jz io_no_vtime UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER @@ -594,6 +586,7 @@ ENTRY(io_int_handler) mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER LAST_BREAK io_no_vtime: + HANDLE_SIE_INTERCEPT TRACE_IRQS_OFF la %r2,SP_PTREGS(%r15) # address of register-save area brasl %r14,do_IRQ # call standard irq handler @@ -713,14 +706,14 @@ io_notify_resume: /* * External interrupt handler routine */ -ENTRY(ext_int_handler) + .globl ext_int_handler +ext_int_handler: stck __LC_INT_CLOCK stpt __LC_ASYNC_ENTER_TIMER SAVE_ALL_ASYNC __LC_EXT_OLD_PSW,__LC_SAVE_AREA+40 CREATE_STACK_FRAME __LC_SAVE_AREA+40 mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct - HANDLE_SIE_INTERCEPT tm SP_PSW+1(%r15),0x01 # interrupting from user ? jz ext_no_vtime UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER @@ -728,6 +721,7 @@ ENTRY(ext_int_handler) mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER LAST_BREAK ext_no_vtime: + HANDLE_SIE_INTERCEPT TRACE_IRQS_OFF lghi %r1,4096 la %r2,SP_PTREGS(%r15) # address of register-save area @@ -742,7 +736,8 @@ __critical_end: /* * Machine check handler routines */ -ENTRY(mcck_int_handler) + .globl mcck_int_handler +mcck_int_handler: stck __LC_MCCK_CLOCK la %r1,4095 # revalidate r1 spt __LC_CPU_TIMER_SAVE_AREA-4095(%r1) # revalidate cpu timer @@ -790,7 +785,6 @@ mcck_int_main: lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct tm __LC_MCCK_CODE+2,0x08 # mwp of old psw valid? jno mcck_no_vtime # no -> no timer update - HANDLE_SIE_INTERCEPT tm SP_PSW+1(%r15),0x01 # interrupting from user ? jz mcck_no_vtime UPDATE_VTIME __LC_EXIT_TIMER,__LC_MCCK_ENTER_TIMER,__LC_USER_TIMER @@ -810,6 +804,7 @@ mcck_no_vtime: stosm __SF_EMPTY(%r15),0x04 # turn dat on tm __TI_flags+7(%r12),_TIF_MCCK_PENDING jno mcck_return + HANDLE_SIE_INTERCEPT TRACE_IRQS_OFF brasl %r14,s390_handle_mcck TRACE_IRQS_ON @@ -828,7 +823,8 @@ mcck_done: */ #ifdef CONFIG_SMP __CPUINIT -ENTRY(restart_int_handler) + .globl restart_int_handler +restart_int_handler: basr %r1,0 restart_base: spt restart_vtime-restart_base(%r1) @@ -855,7 +851,8 @@ restart_vtime: /* * If we do not run with SMP enabled, let the new CPU crash ... */ -ENTRY(restart_int_handler) + .globl restart_int_handler +restart_int_handler: basr %r1,0 restart_base: lpswe restart_crash-restart_base(%r1) @@ -1039,56 +1036,6 @@ cleanup_io_restore_insn: .Lcritical_end: .quad __critical_end -#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE) -/* - * sie64a calling convention: - * %r2 pointer to sie control block - * %r3 guest register save area - */ -ENTRY(sie64a) - stmg %r6,%r14,__SF_GPRS(%r15) # save kernel registers - stg %r2,__SF_EMPTY(%r15) # save control block pointer - stg %r3,__SF_EMPTY+8(%r15) # save guest register save area - lmg %r0,%r13,0(%r3) # load guest gprs 0-13 - lg %r14,__LC_THREAD_INFO # pointer thread_info struct - oi __TI_flags+6(%r14),_TIF_SIE>>8 -sie_loop: - lg %r14,__LC_THREAD_INFO # pointer thread_info struct - tm __TI_flags+7(%r14),_TIF_EXIT_SIE - jnz sie_exit - lg %r14,__SF_EMPTY(%r15) # get control block pointer - SPP __SF_EMPTY(%r15) # set guest id - sie 0(%r14) -sie_done: - SPP __LC_CMF_HPP # set host id - lg %r14,__LC_THREAD_INFO # pointer thread_info struct -sie_exit: - ni __TI_flags+6(%r14),255-(_TIF_SIE>>8) - lg %r14,__SF_EMPTY+8(%r15) # load guest register save area - stmg %r0,%r13,0(%r14) # save guest gprs 0-13 - lmg %r6,%r14,__SF_GPRS(%r15) # restore kernel registers - lghi %r2,0 - br %r14 -sie_fault: - lg %r14,__LC_THREAD_INFO # pointer thread_info struct - ni __TI_flags+6(%r14),255-(_TIF_SIE>>8) - lg %r14,__SF_EMPTY+8(%r15) # load guest register save area - stmg %r0,%r13,0(%r14) # save guest gprs 0-13 - lmg %r6,%r14,__SF_GPRS(%r15) # restore kernel registers - lghi %r2,-EFAULT - br %r14 - - .align 8 -.Lsie_loop: - .quad sie_loop -.Lsie_done: - .quad sie_done - - .section __ex_table,"a" - .quad sie_loop,sie_fault - .previous -#endif - .section .rodata, "a" #define SYSCALL(esa,esame,emu) .long esame .globl sys_call_table diff --git a/trunk/arch/s390/kernel/head.S b/trunk/arch/s390/kernel/head.S index 2d781bab37bb..fb317bf2c378 100644 --- a/trunk/arch/s390/kernel/head.S +++ b/trunk/arch/s390/kernel/head.S @@ -22,7 +22,6 @@ */ #include -#include #include #include #include @@ -384,7 +383,8 @@ iplstart: # doesn't need a builtin ipl record. # .org 0x800 -ENTRY(start) + .globl start +start: stm %r0,%r15,0x07b0 # store registers basr %r12,%r0 .base: @@ -448,7 +448,8 @@ ENTRY(start) # or linload or SALIPL # .org 0x10000 -ENTRY(startup) + .globl startup +startup: basr %r13,0 # get base .LPG0: xc 0x200(256),0x200 # partially clear lowcore diff --git a/trunk/arch/s390/kernel/head31.S b/trunk/arch/s390/kernel/head31.S index f21954b44dc1..b8f8dc126102 100644 --- a/trunk/arch/s390/kernel/head31.S +++ b/trunk/arch/s390/kernel/head31.S @@ -11,13 +11,13 @@ */ #include -#include #include #include #include __HEAD -ENTRY(startup_continue) + .globl startup_continue +startup_continue: basr %r13,0 # get base .LPG1: @@ -45,7 +45,7 @@ ENTRY(startup_continue) # virtual and never return ... .align 8 .Lentry:.long 0x00080000,0x80000000 + _stext -.Lctl: .long 0x04b50000 # cr0: various things +.Lctl: .long 0x04b50002 # cr0: various things .long 0 # cr1: primary space segment table .long .Lduct # cr2: dispatchable unit control table .long 0 # cr3: instruction authorization @@ -78,7 +78,8 @@ ENTRY(startup_continue) .Lbase_cc: .long sched_clock_base_cc -ENTRY(_ehead) + .globl _ehead +_ehead: #ifdef CONFIG_SHARED_KERNEL .org 0x100000 - 0x11000 # head.o ends at 0x11000 @@ -87,8 +88,8 @@ ENTRY(_ehead) # # startup-code, running in absolute addressing mode # -ENTRY(_stext) - basr %r13,0 # get base + .globl _stext +_stext: basr %r13,0 # get base .LPG3: # check control registers stctl %c0,%c15,0(%r15) diff --git a/trunk/arch/s390/kernel/head64.S b/trunk/arch/s390/kernel/head64.S index ae5d492b069e..cdef68717416 100644 --- a/trunk/arch/s390/kernel/head64.S +++ b/trunk/arch/s390/kernel/head64.S @@ -11,13 +11,13 @@ */ #include -#include #include #include #include __HEAD -ENTRY(startup_continue) + .globl startup_continue +startup_continue: larl %r1,sched_clock_base_cc mvc 0(8,%r1),__LC_LAST_UPDATE_CLOCK larl %r13,.LPG1 # get base @@ -46,7 +46,7 @@ ENTRY(startup_continue) .align 16 .LPG1: .Lentry:.quad 0x0000000180000000,_stext -.Lctl: .quad 0x04040000 # cr0: AFP registers & secondary space +.Lctl: .quad 0x04350002 # cr0: various things .quad 0 # cr1: primary space segment table .quad .Lduct # cr2: dispatchable unit control table .quad 0 # cr3: instruction authorization @@ -76,7 +76,8 @@ ENTRY(startup_continue) .long 0x80000000,0,0,0 # invalid access-list entries .endr -ENTRY(_ehead) + .globl _ehead +_ehead: #ifdef CONFIG_SHARED_KERNEL .org 0x100000 - 0x11000 # head.o ends at 0x11000 @@ -85,8 +86,8 @@ ENTRY(_ehead) # # startup-code, running in absolute addressing mode # -ENTRY(_stext) - basr %r13,0 # get base + .globl _stext +_stext: basr %r13,0 # get base .LPG3: # check control registers stctg %c0,%c15,0(%r15) diff --git a/trunk/arch/s390/kernel/irq.c b/trunk/arch/s390/kernel/irq.c index 1f4050d45f78..e3264f6a9720 100644 --- a/trunk/arch/s390/kernel/irq.c +++ b/trunk/arch/s390/kernel/irq.c @@ -87,6 +87,15 @@ int show_interrupts(struct seq_file *p, void *v) return 0; } +/* + * For compatibilty only. S/390 specific setup of interrupts et al. is done + * much later in init_channel_subsystem(). + */ +void __init init_IRQ(void) +{ + /* nothing... */ +} + /* * Switch to the asynchronous interrupt stack for softirq execution. */ @@ -135,45 +144,28 @@ void init_irq_proc(void) #endif /* - * ext_int_hash[index] is the list head for all external interrupts that hash - * to this index. + * ext_int_hash[index] is the start of the list for all external interrupts + * that hash to this index. With the current set of external interrupts + * (0x1202 external call, 0x1004 cpu timer, 0x2401 hwc console, 0x4000 + * iucv and 0x2603 pfault) this is always the first element. */ -static struct list_head ext_int_hash[256]; struct ext_int_info { + struct ext_int_info *next; ext_int_handler_t handler; u16 code; - struct list_head entry; - struct rcu_head rcu; }; -/* ext_int_hash_lock protects the handler lists for external interrupts */ -DEFINE_SPINLOCK(ext_int_hash_lock); - -static void __init init_external_interrupts(void) -{ - int idx; - - for (idx = 0; idx < ARRAY_SIZE(ext_int_hash); idx++) - INIT_LIST_HEAD(&ext_int_hash[idx]); -} +static struct ext_int_info *ext_int_hash[256]; static inline int ext_hash(u16 code) { return (code + (code >> 9)) & 0xff; } -static void ext_int_hash_update(struct rcu_head *head) -{ - struct ext_int_info *p = container_of(head, struct ext_int_info, rcu); - - kfree(p); -} - int register_external_interrupt(u16 code, ext_int_handler_t handler) { struct ext_int_info *p; - unsigned long flags; int index; p = kmalloc(sizeof(*p), GFP_ATOMIC); @@ -182,27 +174,33 @@ int register_external_interrupt(u16 code, ext_int_handler_t handler) p->code = code; p->handler = handler; index = ext_hash(code); - - spin_lock_irqsave(&ext_int_hash_lock, flags); - list_add_rcu(&p->entry, &ext_int_hash[index]); - spin_unlock_irqrestore(&ext_int_hash_lock, flags); + p->next = ext_int_hash[index]; + ext_int_hash[index] = p; return 0; } EXPORT_SYMBOL(register_external_interrupt); int unregister_external_interrupt(u16 code, ext_int_handler_t handler) { - struct ext_int_info *p; - unsigned long flags; - int index = ext_hash(code); + struct ext_int_info *p, *q; + int index; - spin_lock_irqsave(&ext_int_hash_lock, flags); - list_for_each_entry_rcu(p, &ext_int_hash[index], entry) - if (p->code == code && p->handler == handler) { - list_del_rcu(&p->entry); - call_rcu(&p->rcu, ext_int_hash_update); - } - spin_unlock_irqrestore(&ext_int_hash_lock, flags); + index = ext_hash(code); + q = NULL; + p = ext_int_hash[index]; + while (p) { + if (p->code == code && p->handler == handler) + break; + q = p; + p = p->next; + } + if (!p) + return -ENOENT; + if (q) + q->next = p->next; + else + ext_int_hash[index] = p->next; + kfree(p); return 0; } EXPORT_SYMBOL(unregister_external_interrupt); @@ -226,22 +224,15 @@ void __irq_entry do_extint(struct pt_regs *regs, unsigned int ext_int_code, kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++; if (code != 0x1004) __get_cpu_var(s390_idle).nohz_delay = 1; - index = ext_hash(code); - rcu_read_lock(); - list_for_each_entry_rcu(p, &ext_int_hash[index], entry) + for (p = ext_int_hash[index]; p; p = p->next) { if (likely(p->code == code)) p->handler(ext_int_code, param32, param64); - rcu_read_unlock(); + } irq_exit(); set_irq_regs(old_regs); } -void __init init_IRQ(void) -{ - init_external_interrupts(); -} - static DEFINE_SPINLOCK(sc_irq_lock); static int sc_irq_refcount; diff --git a/trunk/arch/s390/kernel/mcount.S b/trunk/arch/s390/kernel/mcount.S index 7e2c38ba1373..1e6a55795628 100644 --- a/trunk/arch/s390/kernel/mcount.S +++ b/trunk/arch/s390/kernel/mcount.S @@ -5,19 +5,21 @@ * */ -#include #include .section .kprobes.text, "ax" -ENTRY(ftrace_stub) + .globl ftrace_stub +ftrace_stub: br %r14 -ENTRY(_mcount) + .globl _mcount +_mcount: #ifdef CONFIG_DYNAMIC_FTRACE br %r14 -ENTRY(ftrace_caller) + .globl ftrace_caller +ftrace_caller: #endif stm %r2,%r5,16(%r15) bras %r1,2f @@ -39,7 +41,8 @@ ENTRY(ftrace_caller) #ifdef CONFIG_FUNCTION_GRAPH_TRACER l %r2,100(%r15) l %r3,152(%r15) -ENTRY(ftrace_graph_caller) + .globl ftrace_graph_caller +ftrace_graph_caller: # The bras instruction gets runtime patched to call prepare_ftrace_return. # See ftrace_enable_ftrace_graph_caller. The patched instruction is: # bras %r14,prepare_ftrace_return @@ -53,7 +56,8 @@ ENTRY(ftrace_graph_caller) #ifdef CONFIG_FUNCTION_GRAPH_TRACER -ENTRY(return_to_handler) + .globl return_to_handler +return_to_handler: stm %r2,%r5,16(%r15) st %r14,56(%r15) lr %r0,%r15 diff --git a/trunk/arch/s390/kernel/mcount64.S b/trunk/arch/s390/kernel/mcount64.S index f70cadec68fc..e73667286ac0 100644 --- a/trunk/arch/s390/kernel/mcount64.S +++ b/trunk/arch/s390/kernel/mcount64.S @@ -5,19 +5,21 @@ * */ -#include #include .section .kprobes.text, "ax" -ENTRY(ftrace_stub) + .globl ftrace_stub +ftrace_stub: br %r14 -ENTRY(_mcount) + .globl _mcount +_mcount: #ifdef CONFIG_DYNAMIC_FTRACE br %r14 -ENTRY(ftrace_caller) + .globl ftrace_caller +ftrace_caller: #endif larl %r1,function_trace_stop icm %r1,0xf,0(%r1) @@ -35,7 +37,8 @@ ENTRY(ftrace_caller) #ifdef CONFIG_FUNCTION_GRAPH_TRACER lg %r2,168(%r15) lg %r3,272(%r15) -ENTRY(ftrace_graph_caller) + .globl ftrace_graph_caller +ftrace_graph_caller: # The bras instruction gets runtime patched to call prepare_ftrace_return. # See ftrace_enable_ftrace_graph_caller. The patched instruction is: # bras %r14,prepare_ftrace_return @@ -49,7 +52,8 @@ ENTRY(ftrace_graph_caller) #ifdef CONFIG_FUNCTION_GRAPH_TRACER -ENTRY(return_to_handler) + .globl return_to_handler +return_to_handler: stmg %r2,%r5,32(%r15) lgr %r1,%r15 aghi %r15,-160 diff --git a/trunk/arch/s390/kernel/module.c b/trunk/arch/s390/kernel/module.c index dfcb3436bad0..f7167ee4604c 100644 --- a/trunk/arch/s390/kernel/module.c +++ b/trunk/arch/s390/kernel/module.c @@ -45,6 +45,13 @@ #define PLT_ENTRY_SIZE 20 #endif /* CONFIG_64BIT */ +void *module_alloc(unsigned long size) +{ + if (size == 0) + return NULL; + return vmalloc(size); +} + /* Free memory returned from module_alloc */ void module_free(struct module *mod, void *module_region) { @@ -169,6 +176,15 @@ module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, return 0; } +int +apply_relocate(Elf_Shdr *sechdrs, const char *strtab, unsigned int symindex, + unsigned int relsec, struct module *me) +{ + printk(KERN_ERR "module %s: RELOCATION unsupported\n", + me->name); + return -ENOEXEC; +} + static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab, struct module *me) @@ -393,3 +409,7 @@ int module_finalize(const Elf_Ehdr *hdr, me->arch.syminfo = NULL; return 0; } + +void module_arch_cleanup(struct module *mod) +{ +} diff --git a/trunk/arch/s390/kernel/reipl.S b/trunk/arch/s390/kernel/reipl.S index 303d961c3bb5..cb899d9f8505 100644 --- a/trunk/arch/s390/kernel/reipl.S +++ b/trunk/arch/s390/kernel/reipl.S @@ -6,15 +6,14 @@ * Author(s): Holger Smolinski (Holger.Smolinski@de.ibm.com) */ -#include #include # # do_reipl_asm # Parameter: r2 = schid of reipl device # -ENTRY(do_reipl_asm) - basr %r13,0 + .globl do_reipl_asm +do_reipl_asm: basr %r13,0 .Lpg0: lpsw .Lnewpsw-.Lpg0(%r13) .Lpg1: # do store status of all registers diff --git a/trunk/arch/s390/kernel/reipl64.S b/trunk/arch/s390/kernel/reipl64.S index 78eb7cfbd3d1..9eabbc90795d 100644 --- a/trunk/arch/s390/kernel/reipl64.S +++ b/trunk/arch/s390/kernel/reipl64.S @@ -4,7 +4,6 @@ * Denis Joseph Barrow, */ -#include #include # @@ -12,8 +11,8 @@ # Parameter: r2 = schid of reipl device # -ENTRY(do_reipl_asm) - basr %r13,0 + .globl do_reipl_asm +do_reipl_asm: basr %r13,0 .Lpg0: lpswe .Lnewpsw-.Lpg0(%r13) .Lpg1: # do store status of all registers diff --git a/trunk/arch/s390/kernel/relocate_kernel.S b/trunk/arch/s390/kernel/relocate_kernel.S index c91d70aede91..3b456b80bcee 100644 --- a/trunk/arch/s390/kernel/relocate_kernel.S +++ b/trunk/arch/s390/kernel/relocate_kernel.S @@ -8,8 +8,6 @@ * */ -#include - /* * moves the new kernel to its destination... * %r2 = pointer to first kimage_entry_t @@ -24,7 +22,8 @@ */ .text -ENTRY(relocate_kernel) + .globl relocate_kernel + relocate_kernel: basr %r13,0 # base address .base: stnsm sys_msk-.base(%r13),0xfb # disable DAT @@ -113,7 +112,6 @@ ENTRY(relocate_kernel) .byte 0 .align 8 relocate_kernel_end: - .align 8 .globl relocate_kernel_len relocate_kernel_len: .quad relocate_kernel_end - relocate_kernel diff --git a/trunk/arch/s390/kernel/relocate_kernel64.S b/trunk/arch/s390/kernel/relocate_kernel64.S index 7c3ce589a7f0..1f9ea2067b59 100644 --- a/trunk/arch/s390/kernel/relocate_kernel64.S +++ b/trunk/arch/s390/kernel/relocate_kernel64.S @@ -8,8 +8,6 @@ * */ -#include - /* * moves the new kernel to its destination... * %r2 = pointer to first kimage_entry_t @@ -25,7 +23,8 @@ */ .text -ENTRY(relocate_kernel) + .globl relocate_kernel + relocate_kernel: basr %r13,0 # base address .base: stnsm sys_msk-.base(%r13),0xfb # disable DAT @@ -116,7 +115,6 @@ ENTRY(relocate_kernel) .byte 0 .align 8 relocate_kernel_end: - .align 8 .globl relocate_kernel_len relocate_kernel_len: .quad relocate_kernel_end - relocate_kernel diff --git a/trunk/arch/s390/kernel/s390_ksyms.c b/trunk/arch/s390/kernel/s390_ksyms.c index 57b536649b00..656fcbb9bd83 100644 --- a/trunk/arch/s390/kernel/s390_ksyms.c +++ b/trunk/arch/s390/kernel/s390_ksyms.c @@ -1,10 +1,6 @@ #include -#include #include #ifdef CONFIG_FUNCTION_TRACER EXPORT_SYMBOL(_mcount); #endif -#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE) -EXPORT_SYMBOL(sie64a); -#endif diff --git a/trunk/arch/s390/kernel/sclp.S b/trunk/arch/s390/kernel/sclp.S index 95792d846bb6..2e82fdd89320 100644 --- a/trunk/arch/s390/kernel/sclp.S +++ b/trunk/arch/s390/kernel/sclp.S @@ -8,8 +8,6 @@ * */ -#include - LC_EXT_NEW_PSW = 0x58 # addr of ext int handler LC_EXT_NEW_PSW_64 = 0x1b0 # addr of ext int handler 64 bit LC_EXT_INT_PARAM = 0x80 # addr of ext int parameter @@ -262,7 +260,8 @@ _sclp_print: # R2 = 0 on success, 1 on failure # -ENTRY(_sclp_print_early) + .globl _sclp_print_early +_sclp_print_early: stm %r6,%r15,24(%r15) # save registers ahi %r15,-96 # create stack frame #ifdef CONFIG_64BIT diff --git a/trunk/arch/s390/kernel/smp.c b/trunk/arch/s390/kernel/smp.c index a6d85c0a7f20..1d55c95f617c 100644 --- a/trunk/arch/s390/kernel/smp.c +++ b/trunk/arch/s390/kernel/smp.c @@ -654,8 +654,7 @@ int __cpu_disable(void) /* disable all external interrupts */ cr_parms.orvals[0] = 0; cr_parms.andvals[0] = ~(1 << 15 | 1 << 14 | 1 << 13 | 1 << 11 | - 1 << 10 | 1 << 9 | 1 << 6 | 1 << 5 | - 1 << 4); + 1 << 10 | 1 << 9 | 1 << 6 | 1 << 4); /* disable all I/O interrupts */ cr_parms.orvals[6] = 0; cr_parms.andvals[6] = ~(1 << 31 | 1 << 30 | 1 << 29 | 1 << 28 | diff --git a/trunk/arch/s390/kernel/switch_cpu.S b/trunk/arch/s390/kernel/switch_cpu.S index bfe070bc7659..20530dd2eab1 100644 --- a/trunk/arch/s390/kernel/switch_cpu.S +++ b/trunk/arch/s390/kernel/switch_cpu.S @@ -5,7 +5,6 @@ * */ -#include #include #include @@ -17,7 +16,9 @@ # %r6 - destination cpu .section .text -ENTRY(smp_switch_to_cpu) + .align 4 + .globl smp_switch_to_cpu +smp_switch_to_cpu: stm %r6,%r15,__SF_GPRS(%r15) lr %r1,%r15 ahi %r15,-STACK_FRAME_OVERHEAD @@ -32,7 +33,8 @@ ENTRY(smp_switch_to_cpu) brc 2,2b /* busy, try again */ 3: j 3b -ENTRY(smp_restart_cpu) + .globl smp_restart_cpu +smp_restart_cpu: basr %r13,0 0: la %r1,.gprregs_addr-0b(%r13) l %r1,0(%r1) diff --git a/trunk/arch/s390/kernel/switch_cpu64.S b/trunk/arch/s390/kernel/switch_cpu64.S index fcc42d799e41..5be3f43898f9 100644 --- a/trunk/arch/s390/kernel/switch_cpu64.S +++ b/trunk/arch/s390/kernel/switch_cpu64.S @@ -5,7 +5,6 @@ * */ -#include #include #include @@ -17,7 +16,9 @@ # %r6 - destination cpu .section .text -ENTRY(smp_switch_to_cpu) + .align 4 + .globl smp_switch_to_cpu +smp_switch_to_cpu: stmg %r6,%r15,__SF_GPRS(%r15) lgr %r1,%r15 aghi %r15,-STACK_FRAME_OVERHEAD @@ -30,7 +31,8 @@ ENTRY(smp_switch_to_cpu) brc 2,2b /* busy, try again */ 3: j 3b -ENTRY(smp_restart_cpu) + .globl smp_restart_cpu +smp_restart_cpu: larl %r1,.gprregs lmg %r0,%r15,0(%r1) 1: sigp %r0,%r5,__SIGP_SENSE /* Wait for calling CPU */ diff --git a/trunk/arch/s390/kernel/swsusp_asm64.S b/trunk/arch/s390/kernel/swsusp_asm64.S index 51bcdb50a230..1f066e46e83e 100644 --- a/trunk/arch/s390/kernel/swsusp_asm64.S +++ b/trunk/arch/s390/kernel/swsusp_asm64.S @@ -7,7 +7,6 @@ * Michael Holzheu */ -#include #include #include #include @@ -23,7 +22,9 @@ * This function runs with disabled interrupts. */ .section .text -ENTRY(swsusp_arch_suspend) + .align 4 + .globl swsusp_arch_suspend +swsusp_arch_suspend: stmg %r6,%r15,__SF_GPRS(%r15) lgr %r1,%r15 aghi %r15,-STACK_FRAME_OVERHEAD @@ -111,7 +112,8 @@ ENTRY(swsusp_arch_suspend) * Then we return to the function that called swsusp_arch_suspend(). * swsusp_arch_resume() runs with disabled interrupts. */ -ENTRY(swsusp_arch_resume) + .globl swsusp_arch_resume +swsusp_arch_resume: stmg %r6,%r15,__SF_GPRS(%r15) lgr %r1,%r15 aghi %r15,-STACK_FRAME_OVERHEAD diff --git a/trunk/arch/s390/kernel/traps.c b/trunk/arch/s390/kernel/traps.c index e9372c77cced..a63d34c3611e 100644 --- a/trunk/arch/s390/kernel/traps.c +++ b/trunk/arch/s390/kernel/traps.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include @@ -43,10 +43,14 @@ #include #include "entry.h" -void (*pgm_check_table[128])(struct pt_regs *, long, unsigned long); +pgm_check_handler_t *pgm_check_table[128]; int show_unhandled_signals; +extern pgm_check_handler_t do_protection_exception; +extern pgm_check_handler_t do_dat_exception; +extern pgm_check_handler_t do_asce_exception; + #define stack_pointer ({ void **sp; asm("la %0,0(15)" : "=&d" (sp)); sp; }) #ifndef CONFIG_64BIT @@ -325,17 +329,10 @@ static inline void __user *get_psw_address(struct pt_regs *regs, void __kprobes do_per_trap(struct pt_regs *regs) { - siginfo_t info; - if (notify_die(DIE_SSTEP, "sstep", regs, 0, 0, SIGTRAP) == NOTIFY_STOP) return; - if (!current->ptrace) - return; - info.si_signo = SIGTRAP; - info.si_errno = 0; - info.si_code = TRAP_HWBKPT; - info.si_addr = (void *) current->thread.per_event.address; - force_sig_info(SIGTRAP, &info, current); + if (current->ptrace) + force_sig(SIGTRAP, current); } static void default_trap_handler(struct pt_regs *regs, long pgm_int_code, @@ -428,13 +425,9 @@ static void __kprobes illegal_op(struct pt_regs *regs, long pgm_int_code, if (get_user(*((__u16 *) opcode), (__u16 __user *) location)) return; if (*((__u16 *) opcode) == S390_BREAKPOINT_U16) { - if (current->ptrace) { - info.si_signo = SIGTRAP; - info.si_errno = 0; - info.si_code = TRAP_BRKPT; - info.si_addr = location; - force_sig_info(SIGTRAP, &info, current); - } else + if (current->ptrace) + force_sig(SIGTRAP, current); + else signal = SIGILL; #ifdef CONFIG_MATHEMU } else if (opcode[0] == 0xb3) { @@ -496,8 +489,9 @@ static void __kprobes illegal_op(struct pt_regs *regs, long pgm_int_code, #ifdef CONFIG_MATHEMU -void specification_exception(struct pt_regs *regs, long pgm_int_code, - unsigned long trans_exc_code) +asmlinkage void specification_exception(struct pt_regs *regs, + long pgm_int_code, + unsigned long trans_exc_code) { __u8 opcode[6]; __u16 __user *location = NULL; @@ -654,7 +648,7 @@ static void space_switch_exception(struct pt_regs *regs, long pgm_int_code, do_trap(pgm_int_code, SIGILL, "space switch event", regs, &info); } -void __kprobes kernel_stack_overflow(struct pt_regs * regs) +asmlinkage void __kprobes kernel_stack_overflow(struct pt_regs * regs) { bust_spinlocks(1); printk("Kernel stack overflow.\n"); diff --git a/trunk/arch/s390/kvm/Kconfig b/trunk/arch/s390/kvm/Kconfig index a21634173a66..f66a1bdbb61d 100644 --- a/trunk/arch/s390/kvm/Kconfig +++ b/trunk/arch/s390/kvm/Kconfig @@ -37,5 +37,6 @@ config KVM # OK, it's a little counter-intuitive to do this, but it puts it neatly under # the virtualization menu. source drivers/vhost/Kconfig +source drivers/virtio/Kconfig endif # VIRTUALIZATION diff --git a/trunk/arch/s390/kvm/Makefile b/trunk/arch/s390/kvm/Makefile index 3975722bb19d..860d26514c08 100644 --- a/trunk/arch/s390/kvm/Makefile +++ b/trunk/arch/s390/kvm/Makefile @@ -10,5 +10,5 @@ common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o) ccflags-y := -Ivirt/kvm -Iarch/s390/kvm -kvm-objs := $(common-objs) kvm-s390.o intercept.o interrupt.o priv.o sigp.o diag.o +kvm-objs := $(common-objs) kvm-s390.o sie64a.o intercept.o interrupt.o priv.o sigp.o diag.o obj-$(CONFIG_KVM) += kvm.o diff --git a/trunk/arch/s390/kvm/gaccess.h b/trunk/arch/s390/kvm/gaccess.h index c86f6ae43f76..03c716a0f01f 100644 --- a/trunk/arch/s390/kvm/gaccess.h +++ b/trunk/arch/s390/kvm/gaccess.h @@ -1,5 +1,5 @@ /* - * access.h - access guest memory + * gaccess.h - access guest memory * * Copyright IBM Corp. 2008,2009 * @@ -22,13 +22,20 @@ static inline void __user *__guestaddr_to_user(struct kvm_vcpu *vcpu, unsigned long guestaddr) { unsigned long prefix = vcpu->arch.sie_block->prefix; + unsigned long origin = vcpu->arch.sie_block->gmsor; + unsigned long memsize = kvm_s390_vcpu_get_memsize(vcpu); if (guestaddr < 2 * PAGE_SIZE) guestaddr += prefix; else if ((guestaddr >= prefix) && (guestaddr < prefix + 2 * PAGE_SIZE)) guestaddr -= prefix; - return (void __user *) gmap_fault(guestaddr, vcpu->arch.gmap); + if (guestaddr > memsize) + return (void __user __force *) ERR_PTR(-EFAULT); + + guestaddr += origin; + + return (void __user *) guestaddr; } static inline int get_guest_u64(struct kvm_vcpu *vcpu, unsigned long guestaddr, @@ -134,11 +141,11 @@ static inline int put_guest_u8(struct kvm_vcpu *vcpu, unsigned long guestaddr, static inline int __copy_to_guest_slow(struct kvm_vcpu *vcpu, unsigned long guestdest, - void *from, unsigned long n) + const void *from, unsigned long n) { int rc; unsigned long i; - u8 *data = from; + const u8 *data = from; for (i = 0; i < n; i++) { rc = put_guest_u8(vcpu, guestdest++, *(data++)); @@ -148,95 +155,12 @@ static inline int __copy_to_guest_slow(struct kvm_vcpu *vcpu, return 0; } -static inline int __copy_to_guest_fast(struct kvm_vcpu *vcpu, - unsigned long guestdest, - void *from, unsigned long n) -{ - int r; - void __user *uptr; - unsigned long size; - - if (guestdest + n < guestdest) - return -EFAULT; - - /* simple case: all within one segment table entry? */ - if ((guestdest & PMD_MASK) == ((guestdest+n) & PMD_MASK)) { - uptr = (void __user *) gmap_fault(guestdest, vcpu->arch.gmap); - - if (IS_ERR((void __force *) uptr)) - return PTR_ERR((void __force *) uptr); - - r = copy_to_user(uptr, from, n); - - if (r) - r = -EFAULT; - - goto out; - } - - /* copy first segment */ - uptr = (void __user *)gmap_fault(guestdest, vcpu->arch.gmap); - - if (IS_ERR((void __force *) uptr)) - return PTR_ERR((void __force *) uptr); - - size = PMD_SIZE - (guestdest & ~PMD_MASK); - - r = copy_to_user(uptr, from, size); - - if (r) { - r = -EFAULT; - goto out; - } - from += size; - n -= size; - guestdest += size; - - /* copy full segments */ - while (n >= PMD_SIZE) { - uptr = (void __user *)gmap_fault(guestdest, vcpu->arch.gmap); - - if (IS_ERR((void __force *) uptr)) - return PTR_ERR((void __force *) uptr); - - r = copy_to_user(uptr, from, PMD_SIZE); - - if (r) { - r = -EFAULT; - goto out; - } - from += PMD_SIZE; - n -= PMD_SIZE; - guestdest += PMD_SIZE; - } - - /* copy the tail segment */ - if (n) { - uptr = (void __user *)gmap_fault(guestdest, vcpu->arch.gmap); - - if (IS_ERR((void __force *) uptr)) - return PTR_ERR((void __force *) uptr); - - r = copy_to_user(uptr, from, n); - - if (r) - r = -EFAULT; - } -out: - return r; -} - -static inline int copy_to_guest_absolute(struct kvm_vcpu *vcpu, - unsigned long guestdest, - void *from, unsigned long n) -{ - return __copy_to_guest_fast(vcpu, guestdest, from, n); -} - static inline int copy_to_guest(struct kvm_vcpu *vcpu, unsigned long guestdest, - void *from, unsigned long n) + const void *from, unsigned long n) { unsigned long prefix = vcpu->arch.sie_block->prefix; + unsigned long origin = vcpu->arch.sie_block->gmsor; + unsigned long memsize = kvm_s390_vcpu_get_memsize(vcpu); if ((guestdest < 2 * PAGE_SIZE) && (guestdest + n > 2 * PAGE_SIZE)) goto slowpath; @@ -253,7 +177,15 @@ static inline int copy_to_guest(struct kvm_vcpu *vcpu, unsigned long guestdest, else if ((guestdest >= prefix) && (guestdest < prefix + 2 * PAGE_SIZE)) guestdest -= prefix; - return __copy_to_guest_fast(vcpu, guestdest, from, n); + if (guestdest + n > memsize) + return -EFAULT; + + if (guestdest + n < guestdest) + return -EFAULT; + + guestdest += origin; + + return copy_to_user((void __user *) guestdest, from, n); slowpath: return __copy_to_guest_slow(vcpu, guestdest, from, n); } @@ -274,113 +206,74 @@ static inline int __copy_from_guest_slow(struct kvm_vcpu *vcpu, void *to, return 0; } -static inline int __copy_from_guest_fast(struct kvm_vcpu *vcpu, void *to, - unsigned long guestsrc, - unsigned long n) +static inline int copy_from_guest(struct kvm_vcpu *vcpu, void *to, + unsigned long guestsrc, unsigned long n) { - int r; - void __user *uptr; - unsigned long size; - - if (guestsrc + n < guestsrc) - return -EFAULT; - - /* simple case: all within one segment table entry? */ - if ((guestsrc & PMD_MASK) == ((guestsrc+n) & PMD_MASK)) { - uptr = (void __user *) gmap_fault(guestsrc, vcpu->arch.gmap); + unsigned long prefix = vcpu->arch.sie_block->prefix; + unsigned long origin = vcpu->arch.sie_block->gmsor; + unsigned long memsize = kvm_s390_vcpu_get_memsize(vcpu); - if (IS_ERR((void __force *) uptr)) - return PTR_ERR((void __force *) uptr); + if ((guestsrc < 2 * PAGE_SIZE) && (guestsrc + n > 2 * PAGE_SIZE)) + goto slowpath; - r = copy_from_user(to, uptr, n); + if ((guestsrc < prefix) && (guestsrc + n > prefix)) + goto slowpath; - if (r) - r = -EFAULT; + if ((guestsrc < prefix + 2 * PAGE_SIZE) + && (guestsrc + n > prefix + 2 * PAGE_SIZE)) + goto slowpath; - goto out; - } + if (guestsrc < 2 * PAGE_SIZE) + guestsrc += prefix; + else if ((guestsrc >= prefix) && (guestsrc < prefix + 2 * PAGE_SIZE)) + guestsrc -= prefix; - /* copy first segment */ - uptr = (void __user *)gmap_fault(guestsrc, vcpu->arch.gmap); + if (guestsrc + n > memsize) + return -EFAULT; - if (IS_ERR((void __force *) uptr)) - return PTR_ERR((void __force *) uptr); + if (guestsrc + n < guestsrc) + return -EFAULT; - size = PMD_SIZE - (guestsrc & ~PMD_MASK); + guestsrc += origin; - r = copy_from_user(to, uptr, size); + return copy_from_user(to, (void __user *) guestsrc, n); +slowpath: + return __copy_from_guest_slow(vcpu, to, guestsrc, n); +} - if (r) { - r = -EFAULT; - goto out; - } - to += size; - n -= size; - guestsrc += size; - - /* copy full segments */ - while (n >= PMD_SIZE) { - uptr = (void __user *)gmap_fault(guestsrc, vcpu->arch.gmap); - - if (IS_ERR((void __force *) uptr)) - return PTR_ERR((void __force *) uptr); - - r = copy_from_user(to, uptr, PMD_SIZE); - - if (r) { - r = -EFAULT; - goto out; - } - to += PMD_SIZE; - n -= PMD_SIZE; - guestsrc += PMD_SIZE; - } +static inline int copy_to_guest_absolute(struct kvm_vcpu *vcpu, + unsigned long guestdest, + const void *from, unsigned long n) +{ + unsigned long origin = vcpu->arch.sie_block->gmsor; + unsigned long memsize = kvm_s390_vcpu_get_memsize(vcpu); - /* copy the tail segment */ - if (n) { - uptr = (void __user *)gmap_fault(guestsrc, vcpu->arch.gmap); + if (guestdest + n > memsize) + return -EFAULT; - if (IS_ERR((void __force *) uptr)) - return PTR_ERR((void __force *) uptr); + if (guestdest + n < guestdest) + return -EFAULT; - r = copy_from_user(to, uptr, n); + guestdest += origin; - if (r) - r = -EFAULT; - } -out: - return r; + return copy_to_user((void __user *) guestdest, from, n); } static inline int copy_from_guest_absolute(struct kvm_vcpu *vcpu, void *to, unsigned long guestsrc, unsigned long n) { - return __copy_from_guest_fast(vcpu, to, guestsrc, n); -} + unsigned long origin = vcpu->arch.sie_block->gmsor; + unsigned long memsize = kvm_s390_vcpu_get_memsize(vcpu); -static inline int copy_from_guest(struct kvm_vcpu *vcpu, void *to, - unsigned long guestsrc, unsigned long n) -{ - unsigned long prefix = vcpu->arch.sie_block->prefix; - - if ((guestsrc < 2 * PAGE_SIZE) && (guestsrc + n > 2 * PAGE_SIZE)) - goto slowpath; - - if ((guestsrc < prefix) && (guestsrc + n > prefix)) - goto slowpath; + if (guestsrc + n > memsize) + return -EFAULT; - if ((guestsrc < prefix + 2 * PAGE_SIZE) - && (guestsrc + n > prefix + 2 * PAGE_SIZE)) - goto slowpath; + if (guestsrc + n < guestsrc) + return -EFAULT; - if (guestsrc < 2 * PAGE_SIZE) - guestsrc += prefix; - else if ((guestsrc >= prefix) && (guestsrc < prefix + 2 * PAGE_SIZE)) - guestsrc -= prefix; + guestsrc += origin; - return __copy_from_guest_fast(vcpu, to, guestsrc, n); -slowpath: - return __copy_from_guest_slow(vcpu, to, guestsrc, n); + return copy_from_user(to, (void __user *) guestsrc, n); } #endif diff --git a/trunk/arch/s390/kvm/intercept.c b/trunk/arch/s390/kvm/intercept.c index c7c51898984e..f7b6df45d8be 100644 --- a/trunk/arch/s390/kvm/intercept.c +++ b/trunk/arch/s390/kvm/intercept.c @@ -105,7 +105,6 @@ static intercept_handler_t instruction_handlers[256] = { [0xae] = kvm_s390_handle_sigp, [0xb2] = kvm_s390_handle_b2, [0xb7] = handle_lctl, - [0xe5] = kvm_s390_handle_e5, [0xeb] = handle_lctlg, }; @@ -160,42 +159,22 @@ static int handle_stop(struct kvm_vcpu *vcpu) static int handle_validity(struct kvm_vcpu *vcpu) { - unsigned long vmaddr; int viwhy = vcpu->arch.sie_block->ipb >> 16; int rc; vcpu->stat.exit_validity++; - if (viwhy == 0x37) { - vmaddr = gmap_fault(vcpu->arch.sie_block->prefix, - vcpu->arch.gmap); - if (IS_ERR_VALUE(vmaddr)) { - rc = -EOPNOTSUPP; - goto out; - } - rc = fault_in_pages_writeable((char __user *) vmaddr, - PAGE_SIZE); - if (rc) { - /* user will receive sigsegv, exit to user */ - rc = -EOPNOTSUPP; - goto out; - } - vmaddr = gmap_fault(vcpu->arch.sie_block->prefix + PAGE_SIZE, - vcpu->arch.gmap); - if (IS_ERR_VALUE(vmaddr)) { - rc = -EOPNOTSUPP; - goto out; - } - rc = fault_in_pages_writeable((char __user *) vmaddr, - PAGE_SIZE); - if (rc) { + if ((viwhy == 0x37) && (vcpu->arch.sie_block->prefix + <= kvm_s390_vcpu_get_memsize(vcpu) - 2*PAGE_SIZE)) { + rc = fault_in_pages_writeable((char __user *) + vcpu->arch.sie_block->gmsor + + vcpu->arch.sie_block->prefix, + 2*PAGE_SIZE); + if (rc) /* user will receive sigsegv, exit to user */ rc = -EOPNOTSUPP; - goto out; - } } else rc = -EOPNOTSUPP; -out: if (rc) VCPU_EVENT(vcpu, 2, "unhandled validity intercept code %d", viwhy); diff --git a/trunk/arch/s390/kvm/interrupt.c b/trunk/arch/s390/kvm/interrupt.c index c9aeb4b4d0b8..35c21bf910c5 100644 --- a/trunk/arch/s390/kvm/interrupt.c +++ b/trunk/arch/s390/kvm/interrupt.c @@ -128,10 +128,6 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, if (rc == -EFAULT) exception = 1; - rc = put_guest_u16(vcpu, __LC_CPU_ADDRESS, inti->emerg.code); - if (rc == -EFAULT) - exception = 1; - rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW, &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); if (rc == -EFAULT) diff --git a/trunk/arch/s390/kvm/kvm-s390.c b/trunk/arch/s390/kvm/kvm-s390.c index f17296e4fc89..67345ae7ce8d 100644 --- a/trunk/arch/s390/kvm/kvm-s390.c +++ b/trunk/arch/s390/kvm/kvm-s390.c @@ -62,7 +62,6 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { { "instruction_chsc", VCPU_STAT(instruction_chsc) }, { "instruction_stsi", VCPU_STAT(instruction_stsi) }, { "instruction_stfl", VCPU_STAT(instruction_stfl) }, - { "instruction_tprot", VCPU_STAT(instruction_tprot) }, { "instruction_sigp_sense", VCPU_STAT(instruction_sigp_sense) }, { "instruction_sigp_emergency", VCPU_STAT(instruction_sigp_emergency) }, { "instruction_sigp_stop", VCPU_STAT(instruction_sigp_stop) }, @@ -190,13 +189,7 @@ int kvm_arch_init_vm(struct kvm *kvm) debug_register_view(kvm->arch.dbf, &debug_sprintf_view); VM_EVENT(kvm, 3, "%s", "vm created"); - kvm->arch.gmap = gmap_alloc(current->mm); - if (!kvm->arch.gmap) - goto out_nogmap; - return 0; -out_nogmap: - debug_unregister(kvm->arch.dbf); out_nodbf: free_page((unsigned long)(kvm->arch.sca)); out_err: @@ -241,13 +234,11 @@ void kvm_arch_destroy_vm(struct kvm *kvm) kvm_free_vcpus(kvm); free_page((unsigned long)(kvm->arch.sca)); debug_unregister(kvm->arch.dbf); - gmap_free(kvm->arch.gmap); } /* Section: vcpu related */ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) { - vcpu->arch.gmap = vcpu->kvm->arch.gmap; return 0; } @@ -293,7 +284,8 @@ static void kvm_s390_vcpu_initial_reset(struct kvm_vcpu *vcpu) int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) { - atomic_set(&vcpu->arch.sie_block->cpuflags, CPUSTAT_ZARCH | CPUSTAT_SM); + atomic_set(&vcpu->arch.sie_block->cpuflags, CPUSTAT_ZARCH); + set_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests); vcpu->arch.sie_block->ecb = 6; vcpu->arch.sie_block->eca = 0xC1002001U; vcpu->arch.sie_block->fac = (int) (long) facilities; @@ -461,7 +453,6 @@ static void __vcpu_run(struct kvm_vcpu *vcpu) local_irq_disable(); kvm_guest_enter(); local_irq_enable(); - gmap_enable(vcpu->arch.gmap); VCPU_EVENT(vcpu, 6, "entering sie flags %x", atomic_read(&vcpu->arch.sie_block->cpuflags)); if (sie64a(vcpu->arch.sie_block, vcpu->arch.guest_gprs)) { @@ -470,7 +461,6 @@ static void __vcpu_run(struct kvm_vcpu *vcpu) } VCPU_EVENT(vcpu, 6, "exit sie icptcode %d", vcpu->arch.sie_block->icptcode); - gmap_disable(vcpu->arch.gmap); local_irq_disable(); kvm_guest_exit(); local_irq_enable(); @@ -484,6 +474,17 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) sigset_t sigsaved; rerun_vcpu: + if (vcpu->requests) + if (test_and_clear_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests)) + kvm_s390_vcpu_set_mem(vcpu); + + /* verify, that memory has been registered */ + if (!vcpu->arch.sie_block->gmslm) { + vcpu_put(vcpu); + VCPU_EVENT(vcpu, 3, "%s", "no memory registered to run vcpu"); + return -EINVAL; + } + if (vcpu->sigset_active) sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved); @@ -544,7 +545,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) return rc; } -static int __guestcopy(struct kvm_vcpu *vcpu, u64 guestdest, void *from, +static int __guestcopy(struct kvm_vcpu *vcpu, u64 guestdest, const void *from, unsigned long n, int prefix) { if (prefix) @@ -561,7 +562,7 @@ static int __guestcopy(struct kvm_vcpu *vcpu, u64 guestdest, void *from, */ int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr) { - unsigned char archmode = 1; + const unsigned char archmode = 1; int prefix; if (addr == KVM_S390_STORE_STATUS_NOADDR) { @@ -679,10 +680,10 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm, if (mem->guest_phys_addr) return -EINVAL; - if (mem->userspace_addr & 0xffffful) + if (mem->userspace_addr & (PAGE_SIZE - 1)) return -EINVAL; - if (mem->memory_size & 0xffffful) + if (mem->memory_size & (PAGE_SIZE - 1)) return -EINVAL; if (!user_alloc) @@ -696,14 +697,15 @@ void kvm_arch_commit_memory_region(struct kvm *kvm, struct kvm_memory_slot old, int user_alloc) { - int rc; - + int i; + struct kvm_vcpu *vcpu; - rc = gmap_map_segment(kvm->arch.gmap, mem->userspace_addr, - mem->guest_phys_addr, mem->memory_size); - if (rc) - printk(KERN_WARNING "kvm-s390: failed to commit memory region\n"); - return; + /* request update of sie control block for all available vcpus */ + kvm_for_each_vcpu(i, vcpu, kvm) { + if (test_and_set_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests)) + continue; + kvm_s390_inject_sigp_stop(vcpu, ACTION_RELOADVCPU_ON_STOP); + } } void kvm_arch_flush_shadow(struct kvm *kvm) diff --git a/trunk/arch/s390/kvm/kvm-s390.h b/trunk/arch/s390/kvm/kvm-s390.h index 99b0b7597115..a7b7586626db 100644 --- a/trunk/arch/s390/kvm/kvm-s390.h +++ b/trunk/arch/s390/kvm/kvm-s390.h @@ -58,9 +58,35 @@ int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu, int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code); int kvm_s390_inject_sigp_stop(struct kvm_vcpu *vcpu, int action); +static inline long kvm_s390_vcpu_get_memsize(struct kvm_vcpu *vcpu) +{ + return vcpu->arch.sie_block->gmslm + - vcpu->arch.sie_block->gmsor + - VIRTIODESCSPACE + 1ul; +} + +static inline void kvm_s390_vcpu_set_mem(struct kvm_vcpu *vcpu) +{ + int idx; + struct kvm_memory_slot *mem; + struct kvm_memslots *memslots; + + idx = srcu_read_lock(&vcpu->kvm->srcu); + memslots = kvm_memslots(vcpu->kvm); + + mem = &memslots->memslots[0]; + + vcpu->arch.sie_block->gmsor = mem->userspace_addr; + vcpu->arch.sie_block->gmslm = + mem->userspace_addr + + (mem->npages << PAGE_SHIFT) + + VIRTIODESCSPACE - 1ul; + + srcu_read_unlock(&vcpu->kvm->srcu, idx); +} + /* implemented in priv.c */ int kvm_s390_handle_b2(struct kvm_vcpu *vcpu); -int kvm_s390_handle_e5(struct kvm_vcpu *vcpu); /* implemented in sigp.c */ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu); diff --git a/trunk/arch/s390/kvm/priv.c b/trunk/arch/s390/kvm/priv.c index 391626361084..73c47bd95db3 100644 --- a/trunk/arch/s390/kvm/priv.c +++ b/trunk/arch/s390/kvm/priv.c @@ -326,52 +326,3 @@ int kvm_s390_handle_b2(struct kvm_vcpu *vcpu) } return -EOPNOTSUPP; } - -static int handle_tprot(struct kvm_vcpu *vcpu) -{ - int base1 = (vcpu->arch.sie_block->ipb & 0xf0000000) >> 28; - int disp1 = (vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16; - int base2 = (vcpu->arch.sie_block->ipb & 0xf000) >> 12; - int disp2 = vcpu->arch.sie_block->ipb & 0x0fff; - u64 address1 = disp1 + base1 ? vcpu->arch.guest_gprs[base1] : 0; - u64 address2 = disp2 + base2 ? vcpu->arch.guest_gprs[base2] : 0; - struct vm_area_struct *vma; - - vcpu->stat.instruction_tprot++; - - /* we only handle the Linux memory detection case: - * access key == 0 - * guest DAT == off - * everything else goes to userspace. */ - if (address2 & 0xf0) - return -EOPNOTSUPP; - if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_DAT) - return -EOPNOTSUPP; - - - down_read(¤t->mm->mmap_sem); - vma = find_vma(current->mm, - (unsigned long) __guestaddr_to_user(vcpu, address1)); - if (!vma) { - up_read(¤t->mm->mmap_sem); - return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); - } - - vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44); - if (!(vma->vm_flags & VM_WRITE) && (vma->vm_flags & VM_READ)) - vcpu->arch.sie_block->gpsw.mask |= (1ul << 44); - if (!(vma->vm_flags & VM_WRITE) && !(vma->vm_flags & VM_READ)) - vcpu->arch.sie_block->gpsw.mask |= (2ul << 44); - - up_read(¤t->mm->mmap_sem); - return 0; -} - -int kvm_s390_handle_e5(struct kvm_vcpu *vcpu) -{ - /* For e5xx... instructions we only handle TPROT */ - if ((vcpu->arch.sie_block->ipa & 0x00ff) == 0x01) - return handle_tprot(vcpu); - return -EOPNOTSUPP; -} - diff --git a/trunk/arch/s390/kvm/sie64a.S b/trunk/arch/s390/kvm/sie64a.S new file mode 100644 index 000000000000..5faa1b1b23fa --- /dev/null +++ b/trunk/arch/s390/kvm/sie64a.S @@ -0,0 +1,98 @@ +/* + * sie64a.S - low level sie call + * + * Copyright IBM Corp. 2008,2010 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License (version 2 only) + * as published by the Free Software Foundation. + * + * Author(s): Heiko Carstens + * Christian Ehrhardt + */ + +#include +#include +#include +#include +#include +#include + +_TIF_EXIT_SIE = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING) + +/* + * offsets into stackframe + * SP_ = offsets into stack sie64 is called with + * SPI_ = offsets into irq stack + */ +SP_GREGS = __SF_EMPTY +SP_HOOK = __SF_EMPTY+8 +SP_GPP = __SF_EMPTY+16 +SPI_PSW = STACK_FRAME_OVERHEAD + __PT_PSW + + + .macro SPP newpp + tm __LC_MACHINE_FLAGS+6,0x20 # MACHINE_FLAG_SPP + jz 0f + .insn s,0xb2800000,\newpp +0: + .endm + +sie_irq_handler: + SPP __LC_CMF_HPP # set host id + larl %r2,sie_inst + clg %r2,SPI_PSW+8(0,%r15) # intercepted sie + jne 1f + xc __LC_SIE_HOOK(8),__LC_SIE_HOOK + lg %r2,__LC_THREAD_INFO # pointer thread_info struct + tm __TI_flags+7(%r2),_TIF_EXIT_SIE + jz 0f + larl %r2,sie_exit # work pending, leave sie + stg %r2,SPI_PSW+8(0,%r15) + br %r14 +0: larl %r2,sie_reenter # re-enter with guest id + stg %r2,SPI_PSW+8(0,%r15) +1: br %r14 + +/* + * sie64a calling convention: + * %r2 pointer to sie control block + * %r3 guest register save area + */ + .globl sie64a +sie64a: + stg %r3,SP_GREGS(%r15) # save guest register save area + stmg %r6,%r14,__SF_GPRS(%r15) # save registers on entry + lgr %r14,%r2 # pointer to sie control block + larl %r5,sie_irq_handler + stg %r2,SP_GPP(%r15) + stg %r5,SP_HOOK(%r15) # save hook target + lmg %r0,%r13,0(%r3) # load guest gprs 0-13 +sie_reenter: + mvc __LC_SIE_HOOK(8),SP_HOOK(%r15) + SPP SP_GPP(%r15) # set guest id +sie_inst: + sie 0(%r14) + xc __LC_SIE_HOOK(8),__LC_SIE_HOOK + SPP __LC_CMF_HPP # set host id +sie_exit: + lg %r14,SP_GREGS(%r15) + stmg %r0,%r13,0(%r14) # save guest gprs 0-13 + lghi %r2,0 + lmg %r6,%r14,__SF_GPRS(%r15) + br %r14 + +sie_err: + xc __LC_SIE_HOOK(8),__LC_SIE_HOOK + SPP __LC_CMF_HPP # set host id + lg %r14,SP_GREGS(%r15) + stmg %r0,%r13,0(%r14) # save guest gprs 0-13 + lghi %r2,-EFAULT + lmg %r6,%r14,__SF_GPRS(%r15) + br %r14 + + .section __ex_table,"a" + .quad sie_inst,sie_err + .quad sie_exit,sie_err + .quad sie_reenter,sie_err + .previous diff --git a/trunk/arch/s390/kvm/sigp.c b/trunk/arch/s390/kvm/sigp.c index d6a50c1fb2e6..702276f5e2fa 100644 --- a/trunk/arch/s390/kvm/sigp.c +++ b/trunk/arch/s390/kvm/sigp.c @@ -189,8 +189,10 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address, /* make sure that the new value is valid memory */ address = address & 0x7fffe000u; - if (copy_from_guest_absolute(vcpu, &tmp, address, 1) || - copy_from_guest_absolute(vcpu, &tmp, address + PAGE_SIZE, 1)) { + if ((copy_from_user(&tmp, (void __user *) + (address + vcpu->arch.sie_block->gmsor) , 1)) || + (copy_from_user(&tmp, (void __user *)(address + + vcpu->arch.sie_block->gmsor + PAGE_SIZE), 1))) { *reg |= SIGP_STAT_INVALID_PARAMETER; return 1; /* invalid parameter */ } diff --git a/trunk/arch/s390/lib/qrnnd.S b/trunk/arch/s390/lib/qrnnd.S index d321329130ec..eb1df632e749 100644 --- a/trunk/arch/s390/lib/qrnnd.S +++ b/trunk/arch/s390/lib/qrnnd.S @@ -1,7 +1,5 @@ # S/390 __udiv_qrnnd -#include - # r2 : &__r # r3 : upper half of 64 bit word n # r4 : lower half of 64 bit word n @@ -10,7 +8,8 @@ # the quotient q is to be returned .text -ENTRY(__udiv_qrnnd) + .globl __udiv_qrnnd +__udiv_qrnnd: st %r2,24(%r15) # store pointer to reminder for later lr %r0,%r3 # reload n lr %r1,%r4 diff --git a/trunk/arch/s390/mm/fault.c b/trunk/arch/s390/mm/fault.c index 9564fc779b27..fe103e891e7a 100644 --- a/trunk/arch/s390/mm/fault.c +++ b/trunk/arch/s390/mm/fault.c @@ -299,28 +299,13 @@ static inline int do_exception(struct pt_regs *regs, int access, goto out; address = trans_exc_code & __FAIL_ADDR_MASK; - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address); + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address); flags = FAULT_FLAG_ALLOW_RETRY; if (access == VM_WRITE || (trans_exc_code & store_indication) == 0x400) flags |= FAULT_FLAG_WRITE; +retry: down_read(&mm->mmap_sem); -#ifdef CONFIG_PGSTE - if (test_tsk_thread_flag(current, TIF_SIE) && S390_lowcore.gmap) { - address = gmap_fault(address, - (struct gmap *) S390_lowcore.gmap); - if (address == -EFAULT) { - fault = VM_FAULT_BADMAP; - goto out_up; - } - if (address == -ENOMEM) { - fault = VM_FAULT_OOM; - goto out_up; - } - } -#endif - -retry: fault = VM_FAULT_BADMAP; vma = find_vma(mm, address); if (!vma) @@ -360,18 +345,17 @@ static inline int do_exception(struct pt_regs *regs, int access, if (flags & FAULT_FLAG_ALLOW_RETRY) { if (fault & VM_FAULT_MAJOR) { tsk->maj_flt++; - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0, regs, address); } else { tsk->min_flt++; - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0, regs, address); } if (fault & VM_FAULT_RETRY) { /* Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk * of starvation. */ flags &= ~FAULT_FLAG_ALLOW_RETRY; - down_read(&mm->mmap_sem); goto retry; } } diff --git a/trunk/arch/s390/mm/hugetlbpage.c b/trunk/arch/s390/mm/hugetlbpage.c index 597bb2d27c3c..a4d856db9154 100644 --- a/trunk/arch/s390/mm/hugetlbpage.c +++ b/trunk/arch/s390/mm/hugetlbpage.c @@ -35,7 +35,7 @@ int arch_prepare_hugepage(struct page *page) if (MACHINE_HAS_HPAGE) return 0; - ptep = (pte_t *) pte_alloc_one(&init_mm, addr); + ptep = (pte_t *) pte_alloc_one(&init_mm, address); if (!ptep) return -ENOMEM; diff --git a/trunk/arch/s390/mm/pgtable.c b/trunk/arch/s390/mm/pgtable.c index 2adb23938a7f..37a23c223705 100644 --- a/trunk/arch/s390/mm/pgtable.c +++ b/trunk/arch/s390/mm/pgtable.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include @@ -134,374 +133,30 @@ void crst_table_downgrade(struct mm_struct *mm, unsigned long limit) } #endif -#ifdef CONFIG_PGSTE - -/** - * gmap_alloc - allocate a guest address space - * @mm: pointer to the parent mm_struct - * - * Returns a guest address space structure. - */ -struct gmap *gmap_alloc(struct mm_struct *mm) -{ - struct gmap *gmap; - struct page *page; - unsigned long *table; - - gmap = kzalloc(sizeof(struct gmap), GFP_KERNEL); - if (!gmap) - goto out; - INIT_LIST_HEAD(&gmap->crst_list); - gmap->mm = mm; - page = alloc_pages(GFP_KERNEL, ALLOC_ORDER); - if (!page) - goto out_free; - list_add(&page->lru, &gmap->crst_list); - table = (unsigned long *) page_to_phys(page); - crst_table_init(table, _REGION1_ENTRY_EMPTY); - gmap->table = table; - list_add(&gmap->list, &mm->context.gmap_list); - return gmap; - -out_free: - kfree(gmap); -out: - return NULL; -} -EXPORT_SYMBOL_GPL(gmap_alloc); - -static int gmap_unlink_segment(struct gmap *gmap, unsigned long *table) -{ - struct gmap_pgtable *mp; - struct gmap_rmap *rmap; - struct page *page; - - if (*table & _SEGMENT_ENTRY_INV) - return 0; - page = pfn_to_page(*table >> PAGE_SHIFT); - mp = (struct gmap_pgtable *) page->index; - list_for_each_entry(rmap, &mp->mapper, list) { - if (rmap->entry != table) - continue; - list_del(&rmap->list); - kfree(rmap); - break; - } - *table = _SEGMENT_ENTRY_INV | _SEGMENT_ENTRY_RO | mp->vmaddr; - return 1; -} - -static void gmap_flush_tlb(struct gmap *gmap) -{ - if (MACHINE_HAS_IDTE) - __tlb_flush_idte((unsigned long) gmap->table | - _ASCE_TYPE_REGION1); - else - __tlb_flush_global(); -} - -/** - * gmap_free - free a guest address space - * @gmap: pointer to the guest address space structure - */ -void gmap_free(struct gmap *gmap) -{ - struct page *page, *next; - unsigned long *table; - int i; - - - /* Flush tlb. */ - if (MACHINE_HAS_IDTE) - __tlb_flush_idte((unsigned long) gmap->table | - _ASCE_TYPE_REGION1); - else - __tlb_flush_global(); - - /* Free all segment & region tables. */ - down_read(&gmap->mm->mmap_sem); - list_for_each_entry_safe(page, next, &gmap->crst_list, lru) { - table = (unsigned long *) page_to_phys(page); - if ((*table & _REGION_ENTRY_TYPE_MASK) == 0) - /* Remove gmap rmap structures for segment table. */ - for (i = 0; i < PTRS_PER_PMD; i++, table++) - gmap_unlink_segment(gmap, table); - __free_pages(page, ALLOC_ORDER); - } - up_read(&gmap->mm->mmap_sem); - list_del(&gmap->list); - kfree(gmap); -} -EXPORT_SYMBOL_GPL(gmap_free); - -/** - * gmap_enable - switch primary space to the guest address space - * @gmap: pointer to the guest address space structure - */ -void gmap_enable(struct gmap *gmap) -{ - /* Load primary space page table origin. */ - S390_lowcore.user_asce = _ASCE_TYPE_REGION1 | _ASCE_TABLE_LENGTH | - _ASCE_USER_BITS | __pa(gmap->table); - asm volatile("lctlg 1,1,%0\n" : : "m" (S390_lowcore.user_asce) ); - S390_lowcore.gmap = (unsigned long) gmap; -} -EXPORT_SYMBOL_GPL(gmap_enable); - -/** - * gmap_disable - switch back to the standard primary address space - * @gmap: pointer to the guest address space structure - */ -void gmap_disable(struct gmap *gmap) -{ - /* Load primary space page table origin. */ - S390_lowcore.user_asce = - gmap->mm->context.asce_bits | __pa(gmap->mm->pgd); - asm volatile("lctlg 1,1,%0\n" : : "m" (S390_lowcore.user_asce) ); - S390_lowcore.gmap = 0UL; -} -EXPORT_SYMBOL_GPL(gmap_disable); - -static int gmap_alloc_table(struct gmap *gmap, - unsigned long *table, unsigned long init) +static inline unsigned int atomic_xor_bits(atomic_t *v, unsigned int bits) { - struct page *page; - unsigned long *new; + unsigned int old, new; - page = alloc_pages(GFP_KERNEL, ALLOC_ORDER); - if (!page) - return -ENOMEM; - new = (unsigned long *) page_to_phys(page); - crst_table_init(new, init); - down_read(&gmap->mm->mmap_sem); - if (*table & _REGION_ENTRY_INV) { - list_add(&page->lru, &gmap->crst_list); - *table = (unsigned long) new | _REGION_ENTRY_LENGTH | - (*table & _REGION_ENTRY_TYPE_MASK); - } else - __free_pages(page, ALLOC_ORDER); - up_read(&gmap->mm->mmap_sem); - return 0; + do { + old = atomic_read(v); + new = old ^ bits; + } while (atomic_cmpxchg(v, old, new) != old); + return new; } -/** - * gmap_unmap_segment - unmap segment from the guest address space - * @gmap: pointer to the guest address space structure - * @addr: address in the guest address space - * @len: length of the memory area to unmap - * - * Returns 0 if the unmap succeded, -EINVAL if not. - */ -int gmap_unmap_segment(struct gmap *gmap, unsigned long to, unsigned long len) -{ - unsigned long *table; - unsigned long off; - int flush; - - if ((to | len) & (PMD_SIZE - 1)) - return -EINVAL; - if (len == 0 || to + len < to) - return -EINVAL; - - flush = 0; - down_read(&gmap->mm->mmap_sem); - for (off = 0; off < len; off += PMD_SIZE) { - /* Walk the guest addr space page table */ - table = gmap->table + (((to + off) >> 53) & 0x7ff); - if (*table & _REGION_ENTRY_INV) - return 0; - table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN); - table = table + (((to + off) >> 42) & 0x7ff); - if (*table & _REGION_ENTRY_INV) - return 0; - table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN); - table = table + (((to + off) >> 31) & 0x7ff); - if (*table & _REGION_ENTRY_INV) - return 0; - table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN); - table = table + (((to + off) >> 20) & 0x7ff); - - /* Clear segment table entry in guest address space. */ - flush |= gmap_unlink_segment(gmap, table); - *table = _SEGMENT_ENTRY_INV; - } - up_read(&gmap->mm->mmap_sem); - if (flush) - gmap_flush_tlb(gmap); - return 0; -} -EXPORT_SYMBOL_GPL(gmap_unmap_segment); - -/** - * gmap_mmap_segment - map a segment to the guest address space - * @gmap: pointer to the guest address space structure - * @from: source address in the parent address space - * @to: target address in the guest address space - * - * Returns 0 if the mmap succeded, -EINVAL or -ENOMEM if not. +/* + * page table entry allocation/free routines. */ -int gmap_map_segment(struct gmap *gmap, unsigned long from, - unsigned long to, unsigned long len) -{ - unsigned long *table; - unsigned long off; - int flush; - - if ((from | to | len) & (PMD_SIZE - 1)) - return -EINVAL; - if (len == 0 || from + len > PGDIR_SIZE || - from + len < from || to + len < to) - return -EINVAL; - - flush = 0; - down_read(&gmap->mm->mmap_sem); - for (off = 0; off < len; off += PMD_SIZE) { - /* Walk the gmap address space page table */ - table = gmap->table + (((to + off) >> 53) & 0x7ff); - if ((*table & _REGION_ENTRY_INV) && - gmap_alloc_table(gmap, table, _REGION2_ENTRY_EMPTY)) - goto out_unmap; - table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN); - table = table + (((to + off) >> 42) & 0x7ff); - if ((*table & _REGION_ENTRY_INV) && - gmap_alloc_table(gmap, table, _REGION3_ENTRY_EMPTY)) - goto out_unmap; - table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN); - table = table + (((to + off) >> 31) & 0x7ff); - if ((*table & _REGION_ENTRY_INV) && - gmap_alloc_table(gmap, table, _SEGMENT_ENTRY_EMPTY)) - goto out_unmap; - table = (unsigned long *) (*table & _REGION_ENTRY_ORIGIN); - table = table + (((to + off) >> 20) & 0x7ff); - - /* Store 'from' address in an invalid segment table entry. */ - flush |= gmap_unlink_segment(gmap, table); - *table = _SEGMENT_ENTRY_INV | _SEGMENT_ENTRY_RO | (from + off); - } - up_read(&gmap->mm->mmap_sem); - if (flush) - gmap_flush_tlb(gmap); - return 0; - -out_unmap: - up_read(&gmap->mm->mmap_sem); - gmap_unmap_segment(gmap, to, len); - return -ENOMEM; -} -EXPORT_SYMBOL_GPL(gmap_map_segment); - -unsigned long gmap_fault(unsigned long address, struct gmap *gmap) -{ - unsigned long *table, vmaddr, segment; - struct mm_struct *mm; - struct gmap_pgtable *mp; - struct gmap_rmap *rmap; - struct vm_area_struct *vma; - struct page *page; - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; - - current->thread.gmap_addr = address; - mm = gmap->mm; - /* Walk the gmap address space page table */ - table = gmap->table + ((address >> 53) & 0x7ff); - if (unlikely(*table & _REGION_ENTRY_INV)) - return -EFAULT; - table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN); - table = table + ((address >> 42) & 0x7ff); - if (unlikely(*table & _REGION_ENTRY_INV)) - return -EFAULT; - table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN); - table = table + ((address >> 31) & 0x7ff); - if (unlikely(*table & _REGION_ENTRY_INV)) - return -EFAULT; - table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN); - table = table + ((address >> 20) & 0x7ff); - - /* Convert the gmap address to an mm address. */ - segment = *table; - if (likely(!(segment & _SEGMENT_ENTRY_INV))) { - page = pfn_to_page(segment >> PAGE_SHIFT); - mp = (struct gmap_pgtable *) page->index; - return mp->vmaddr | (address & ~PMD_MASK); - } else if (segment & _SEGMENT_ENTRY_RO) { - vmaddr = segment & _SEGMENT_ENTRY_ORIGIN; - vma = find_vma(mm, vmaddr); - if (!vma || vma->vm_start > vmaddr) - return -EFAULT; - - /* Walk the parent mm page table */ - pgd = pgd_offset(mm, vmaddr); - pud = pud_alloc(mm, pgd, vmaddr); - if (!pud) - return -ENOMEM; - pmd = pmd_alloc(mm, pud, vmaddr); - if (!pmd) - return -ENOMEM; - if (!pmd_present(*pmd) && - __pte_alloc(mm, vma, pmd, vmaddr)) - return -ENOMEM; - /* pmd now points to a valid segment table entry. */ - rmap = kmalloc(sizeof(*rmap), GFP_KERNEL|__GFP_REPEAT); - if (!rmap) - return -ENOMEM; - /* Link gmap segment table entry location to page table. */ - page = pmd_page(*pmd); - mp = (struct gmap_pgtable *) page->index; - rmap->entry = table; - list_add(&rmap->list, &mp->mapper); - /* Set gmap segment table entry to page table. */ - *table = pmd_val(*pmd) & PAGE_MASK; - return vmaddr | (address & ~PMD_MASK); - } - return -EFAULT; - -} -EXPORT_SYMBOL_GPL(gmap_fault); - -void gmap_unmap_notifier(struct mm_struct *mm, unsigned long *table) -{ - struct gmap_rmap *rmap, *next; - struct gmap_pgtable *mp; - struct page *page; - int flush; - - flush = 0; - spin_lock(&mm->page_table_lock); - page = pfn_to_page(__pa(table) >> PAGE_SHIFT); - mp = (struct gmap_pgtable *) page->index; - list_for_each_entry_safe(rmap, next, &mp->mapper, list) { - *rmap->entry = - _SEGMENT_ENTRY_INV | _SEGMENT_ENTRY_RO | mp->vmaddr; - list_del(&rmap->list); - kfree(rmap); - flush = 1; - } - spin_unlock(&mm->page_table_lock); - if (flush) - __tlb_flush_global(); -} - -static inline unsigned long *page_table_alloc_pgste(struct mm_struct *mm, - unsigned long vmaddr) +#ifdef CONFIG_PGSTE +static inline unsigned long *page_table_alloc_pgste(struct mm_struct *mm) { struct page *page; unsigned long *table; - struct gmap_pgtable *mp; page = alloc_page(GFP_KERNEL|__GFP_REPEAT); if (!page) return NULL; - mp = kmalloc(sizeof(*mp), GFP_KERNEL|__GFP_REPEAT); - if (!mp) { - __free_page(page); - return NULL; - } pgtable_page_ctor(page); - mp->vmaddr = vmaddr & PMD_MASK; - INIT_LIST_HEAD(&mp->mapper); - page->index = (unsigned long) mp; atomic_set(&page->_mapcount, 3); table = (unsigned long *) page_to_phys(page); clear_table(table, _PAGE_TYPE_EMPTY, PAGE_SIZE/2); @@ -512,57 +167,24 @@ static inline unsigned long *page_table_alloc_pgste(struct mm_struct *mm, static inline void page_table_free_pgste(unsigned long *table) { struct page *page; - struct gmap_pgtable *mp; page = pfn_to_page(__pa(table) >> PAGE_SHIFT); - mp = (struct gmap_pgtable *) page->index; - BUG_ON(!list_empty(&mp->mapper)); pgtable_page_ctor(page); atomic_set(&page->_mapcount, -1); - kfree(mp); __free_page(page); } +#endif -#else /* CONFIG_PGSTE */ - -static inline unsigned long *page_table_alloc_pgste(struct mm_struct *mm, - unsigned long vmaddr) -{ -} - -static inline void page_table_free_pgste(unsigned long *table) -{ -} - -static inline void gmap_unmap_notifier(struct mm_struct *mm, - unsigned long *table) -{ -} - -#endif /* CONFIG_PGSTE */ - -static inline unsigned int atomic_xor_bits(atomic_t *v, unsigned int bits) -{ - unsigned int old, new; - - do { - old = atomic_read(v); - new = old ^ bits; - } while (atomic_cmpxchg(v, old, new) != old); - return new; -} - -/* - * page table entry allocation/free routines. - */ -unsigned long *page_table_alloc(struct mm_struct *mm, unsigned long vmaddr) +unsigned long *page_table_alloc(struct mm_struct *mm) { struct page *page; unsigned long *table; unsigned int mask, bit; +#ifdef CONFIG_PGSTE if (mm_has_pgste(mm)) - return page_table_alloc_pgste(mm, vmaddr); + return page_table_alloc_pgste(mm); +#endif /* Allocate fragments of a 4K page as 1K/2K page table */ spin_lock_bh(&mm->context.list_lock); mask = FRAG_MASK; @@ -600,10 +222,10 @@ void page_table_free(struct mm_struct *mm, unsigned long *table) struct page *page; unsigned int bit, mask; - if (mm_has_pgste(mm)) { - gmap_unmap_notifier(mm, table); +#ifdef CONFIG_PGSTE + if (mm_has_pgste(mm)) return page_table_free_pgste(table); - } +#endif /* Free 1K/2K page table fragment of a 4K page */ page = pfn_to_page(__pa(table) >> PAGE_SHIFT); bit = 1 << ((__pa(table) & ~PAGE_MASK)/(PTRS_PER_PTE*sizeof(pte_t))); @@ -627,8 +249,10 @@ static void __page_table_free_rcu(void *table, unsigned bit) { struct page *page; +#ifdef CONFIG_PGSTE if (bit == FRAG_MASK) return page_table_free_pgste(table); +#endif /* Free 1K/2K page table fragment of a 4K page */ page = pfn_to_page(__pa(table) >> PAGE_SHIFT); if (atomic_xor_bits(&page->_mapcount, bit) == 0) { @@ -645,12 +269,13 @@ void page_table_free_rcu(struct mmu_gather *tlb, unsigned long *table) unsigned int bit, mask; mm = tlb->mm; +#ifdef CONFIG_PGSTE if (mm_has_pgste(mm)) { - gmap_unmap_notifier(mm, table); table = (unsigned long *) (__pa(table) | FRAG_MASK); tlb_remove_table(tlb, table); return; } +#endif bit = 1 << ((__pa(table) & ~PAGE_MASK) / (PTRS_PER_PTE*sizeof(pte_t))); page = pfn_to_page(__pa(table) >> PAGE_SHIFT); spin_lock_bh(&mm->context.list_lock); diff --git a/trunk/arch/s390/mm/vmem.c b/trunk/arch/s390/mm/vmem.c index 781ff5169560..8c1970d1dd91 100644 --- a/trunk/arch/s390/mm/vmem.c +++ b/trunk/arch/s390/mm/vmem.c @@ -61,12 +61,12 @@ static inline pmd_t *vmem_pmd_alloc(void) return pmd; } -static pte_t __ref *vmem_pte_alloc(unsigned long address) +static pte_t __ref *vmem_pte_alloc(void) { pte_t *pte; if (slab_is_available()) - pte = (pte_t *) page_table_alloc(&init_mm, address); + pte = (pte_t *) page_table_alloc(&init_mm); else pte = alloc_bootmem(PTRS_PER_PTE * sizeof(pte_t)); if (!pte) @@ -120,7 +120,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro) } #endif if (pmd_none(*pm_dir)) { - pt_dir = vmem_pte_alloc(address); + pt_dir = vmem_pte_alloc(); if (!pt_dir) goto out; pmd_populate(&init_mm, pm_dir, pt_dir); @@ -205,7 +205,7 @@ int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node) pm_dir = pmd_offset(pu_dir, address); if (pmd_none(*pm_dir)) { - pt_dir = vmem_pte_alloc(address); + pt_dir = vmem_pte_alloc(); if (!pt_dir) goto out; pmd_populate(&init_mm, pm_dir, pt_dir); diff --git a/trunk/arch/score/kernel/module.c b/trunk/arch/score/kernel/module.c index 469e3b64e2f2..4de8d47becd3 100644 --- a/trunk/arch/score/kernel/module.c +++ b/trunk/arch/score/kernel/module.c @@ -27,6 +27,23 @@ #include #include +void *module_alloc(unsigned long size) +{ + return size ? vmalloc(size) : NULL; +} + +/* Free memory returned from module_alloc */ +void module_free(struct module *mod, void *module_region) +{ + vfree(module_region); +} + +int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, + char *secstrings, struct module *mod) +{ + return 0; +} + int apply_relocate(Elf_Shdr *sechdrs, const char *strtab, unsigned int symindex, unsigned int relindex, struct module *me) @@ -129,9 +146,6 @@ int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, unsigned int symindex, unsigned int relsec, struct module *me) { - /* Non-standard return value... most other arch's return -ENOEXEC - * for an unsupported relocation variant - */ return 0; } @@ -140,3 +154,12 @@ const struct exception_table_entry *search_module_dbetables(unsigned long addr) { return NULL; } + +/* Put in dbe list if necessary. */ +int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, + struct module *me) +{ + return 0; +} + +void module_arch_cleanup(struct module *mod) {} diff --git a/trunk/arch/sh/Kconfig b/trunk/arch/sh/Kconfig index 748ff1920068..bbdeb48bbf8e 100644 --- a/trunk/arch/sh/Kconfig +++ b/trunk/arch/sh/Kconfig @@ -897,4 +897,20 @@ source "security/Kconfig" source "crypto/Kconfig" +menuconfig VIRTUALIZATION + bool "Virtualization" + default n + ---help--- + Say Y here to get to see options for using your Linux host to run other + operating systems inside virtual machines (guests). + This option alone does not add any kernel code. + + If you say N, all options in this submenu will be skipped and disabled. + +if VIRTUALIZATION + +source drivers/virtio/Kconfig + +endif # VIRTUALIZATION + source "lib/Kconfig" diff --git a/trunk/arch/sh/include/asm/delay.h b/trunk/arch/sh/include/asm/delay.h index 9670e127b7b2..4b16bf9b56bd 100644 --- a/trunk/arch/sh/include/asm/delay.h +++ b/trunk/arch/sh/include/asm/delay.h @@ -1 +1,26 @@ -#include +#ifndef __ASM_SH_DELAY_H +#define __ASM_SH_DELAY_H + +/* + * Copyright (C) 1993 Linus Torvalds + * + * Delay routines calling functions in arch/sh/lib/delay.c + */ + +extern void __bad_udelay(void); +extern void __bad_ndelay(void); + +extern void __udelay(unsigned long usecs); +extern void __ndelay(unsigned long nsecs); +extern void __const_udelay(unsigned long xloops); +extern void __delay(unsigned long loops); + +#define udelay(n) (__builtin_constant_p(n) ? \ + ((n) > 20000 ? __bad_udelay() : __const_udelay((n) * 0x10c6ul)) : \ + __udelay(n)) + +#define ndelay(n) (__builtin_constant_p(n) ? \ + ((n) > 20000 ? __bad_ndelay() : __const_udelay((n) * 5ul)) : \ + __ndelay(n)) + +#endif /* __ASM_SH_DELAY_H */ diff --git a/trunk/arch/sh/kernel/cpu/sh4/perf_event.c b/trunk/arch/sh/kernel/cpu/sh4/perf_event.c index fa4f724b295a..748955df018d 100644 --- a/trunk/arch/sh/kernel/cpu/sh4/perf_event.c +++ b/trunk/arch/sh/kernel/cpu/sh4/perf_event.c @@ -180,21 +180,6 @@ static const int sh7750_cache_events [ C(RESULT_MISS) ] = -1, }, }, - - [ C(NODE) ] = { - [ C(OP_READ) ] = { - [ C(RESULT_ACCESS) ] = -1, - [ C(RESULT_MISS) ] = -1, - }, - [ C(OP_WRITE) ] = { - [ C(RESULT_ACCESS) ] = -1, - [ C(RESULT_MISS) ] = -1, - }, - [ C(OP_PREFETCH) ] = { - [ C(RESULT_ACCESS) ] = -1, - [ C(RESULT_MISS) ] = -1, - }, - }, }; static int sh7750_event_map(int event) diff --git a/trunk/arch/sh/kernel/cpu/sh4a/perf_event.c b/trunk/arch/sh/kernel/cpu/sh4a/perf_event.c index 84a2c396ceee..17e6bebfede0 100644 --- a/trunk/arch/sh/kernel/cpu/sh4a/perf_event.c +++ b/trunk/arch/sh/kernel/cpu/sh4a/perf_event.c @@ -205,21 +205,6 @@ static const int sh4a_cache_events [ C(RESULT_MISS) ] = -1, }, }, - - [ C(NODE) ] = { - [ C(OP_READ) ] = { - [ C(RESULT_ACCESS) ] = -1, - [ C(RESULT_MISS) ] = -1, - }, - [ C(OP_WRITE) ] = { - [ C(RESULT_ACCESS) ] = -1, - [ C(RESULT_MISS) ] = -1, - }, - [ C(OP_PREFETCH) ] = { - [ C(RESULT_ACCESS) ] = -1, - [ C(RESULT_MISS) ] = -1, - }, - }, }; static int sh4a_event_map(int event) diff --git a/trunk/arch/sh/kernel/module.c b/trunk/arch/sh/kernel/module.c index 1b525dedd29a..19b1f8826aef 100644 --- a/trunk/arch/sh/kernel/module.c +++ b/trunk/arch/sh/kernel/module.c @@ -34,6 +34,30 @@ #include #include +void *module_alloc(unsigned long size) +{ + if (size == 0) + return NULL; + + return vmalloc_exec(size); +} + + +/* Free memory returned from module_alloc */ +void module_free(struct module *mod, void *module_region) +{ + vfree(module_region); +} + +/* We don't need anything special. */ +int module_frob_arch_sections(Elf_Ehdr *hdr, + Elf_Shdr *sechdrs, + char *secstrings, + struct module *mod) +{ + return 0; +} + int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, @@ -109,6 +133,17 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, return 0; } +int apply_relocate(Elf32_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *me) +{ + printk(KERN_ERR "module %s: REL RELOCATION unsupported\n", + me->name); + return -ENOEXEC; +} + int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, struct module *me) diff --git a/trunk/arch/sh/kernel/ptrace_32.c b/trunk/arch/sh/kernel/ptrace_32.c index 92b3c276339a..3d7b209b2178 100644 --- a/trunk/arch/sh/kernel/ptrace_32.c +++ b/trunk/arch/sh/kernel/ptrace_32.c @@ -63,7 +63,7 @@ static inline int put_stack_long(struct task_struct *task, int offset, return 0; } -void ptrace_triggered(struct perf_event *bp, +void ptrace_triggered(struct perf_event *bp, int nmi, struct perf_sample_data *data, struct pt_regs *regs) { struct perf_event_attr attr; @@ -91,8 +91,7 @@ static int set_single_step(struct task_struct *tsk, unsigned long addr) attr.bp_len = HW_BREAKPOINT_LEN_2; attr.bp_type = HW_BREAKPOINT_R; - bp = register_user_hw_breakpoint(&attr, ptrace_triggered, - NULL, tsk); + bp = register_user_hw_breakpoint(&attr, ptrace_triggered, tsk); if (IS_ERR(bp)) return PTR_ERR(bp); diff --git a/trunk/arch/sh/kernel/traps_32.c b/trunk/arch/sh/kernel/traps_32.c index d9006f8ffc14..b51a17104b5f 100644 --- a/trunk/arch/sh/kernel/traps_32.c +++ b/trunk/arch/sh/kernel/traps_32.c @@ -393,7 +393,7 @@ int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs, */ if (!expected) { unaligned_fixups_notify(current, instruction, regs); - perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, + perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, 0, regs, address); } diff --git a/trunk/arch/sh/kernel/traps_64.c b/trunk/arch/sh/kernel/traps_64.c index 67110be83fd7..6713ca97e553 100644 --- a/trunk/arch/sh/kernel/traps_64.c +++ b/trunk/arch/sh/kernel/traps_64.c @@ -434,7 +434,7 @@ static int misaligned_load(struct pt_regs *regs, return error; } - perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, address); + perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, 0, regs, address); destreg = (opcode >> 4) & 0x3f; if (user_mode(regs)) { @@ -512,7 +512,7 @@ static int misaligned_store(struct pt_regs *regs, return error; } - perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, address); + perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, 0, regs, address); srcreg = (opcode >> 4) & 0x3f; if (user_mode(regs)) { @@ -588,7 +588,7 @@ static int misaligned_fpu_load(struct pt_regs *regs, return error; } - perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, address); + perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, 0, regs, address); destreg = (opcode >> 4) & 0x3f; if (user_mode(regs)) { @@ -665,7 +665,7 @@ static int misaligned_fpu_store(struct pt_regs *regs, return error; } - perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, address); + perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, 0, regs, address); srcreg = (opcode >> 4) & 0x3f; if (user_mode(regs)) { diff --git a/trunk/arch/sh/math-emu/math.c b/trunk/arch/sh/math-emu/math.c index 977195210653..f76a5090d5d1 100644 --- a/trunk/arch/sh/math-emu/math.c +++ b/trunk/arch/sh/math-emu/math.c @@ -620,7 +620,7 @@ int do_fpu_inst(unsigned short inst, struct pt_regs *regs) struct task_struct *tsk = current; struct sh_fpu_soft_struct *fpu = &(tsk->thread.xstate->softfpu); - perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0); + perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, 0, regs, 0); if (!(task_thread_info(tsk)->status & TS_USEDFPU)) { /* initialize once. */ diff --git a/trunk/arch/sh/mm/fault_32.c b/trunk/arch/sh/mm/fault_32.c index 7bebd044f2a1..d4c34d757f0d 100644 --- a/trunk/arch/sh/mm/fault_32.c +++ b/trunk/arch/sh/mm/fault_32.c @@ -160,7 +160,7 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, if ((regs->sr & SR_IMASK) != SR_IMASK) local_irq_enable(); - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address); + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address); /* * If we're in an interrupt, have no user context or are running @@ -210,11 +210,11 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, } if (fault & VM_FAULT_MAJOR) { tsk->maj_flt++; - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0, regs, address); } else { tsk->min_flt++; - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0, regs, address); } diff --git a/trunk/arch/sh/mm/tlbflush_64.c b/trunk/arch/sh/mm/tlbflush_64.c index e3430e093d43..7f5810f5dfdc 100644 --- a/trunk/arch/sh/mm/tlbflush_64.c +++ b/trunk/arch/sh/mm/tlbflush_64.c @@ -116,7 +116,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess, /* Not an IO address, so reenable interrupts */ local_irq_enable(); - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address); + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address); /* * If we're in an interrupt or have no user @@ -200,11 +200,11 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess, if (fault & VM_FAULT_MAJOR) { tsk->maj_flt++; - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0, regs, address); } else { tsk->min_flt++; - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0, regs, address); } diff --git a/trunk/arch/sparc/kernel/module.c b/trunk/arch/sparc/kernel/module.c index da0c6c70ccb2..99ba5baa9497 100644 --- a/trunk/arch/sparc/kernel/module.c +++ b/trunk/arch/sparc/kernel/module.c @@ -68,6 +68,12 @@ void *module_alloc(unsigned long size) return ret; } +/* Free memory returned from module_core_alloc/module_init_alloc */ +void module_free(struct module *mod, void *module_region) +{ + vfree(module_region); +} + /* Make generic code ignore STT_REGISTER dummy undefined symbols. */ int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, @@ -101,6 +107,17 @@ int module_frob_arch_sections(Elf_Ehdr *hdr, return 0; } +int apply_relocate(Elf_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *me) +{ + printk(KERN_ERR "module %s: non-ADD RELOCATION unsupported\n", + me->name); + return -ENOEXEC; +} + int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, unsigned int symindex, @@ -222,4 +239,15 @@ int module_finalize(const Elf_Ehdr *hdr, return 0; } +#else +int module_finalize(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + struct module *me) +{ + return 0; +} #endif /* CONFIG_SPARC64 */ + +void module_arch_cleanup(struct module *mod) +{ +} diff --git a/trunk/arch/sparc/kernel/perf_event.c b/trunk/arch/sparc/kernel/perf_event.c index 62a034318b18..2cb0e1c001e2 100644 --- a/trunk/arch/sparc/kernel/perf_event.c +++ b/trunk/arch/sparc/kernel/perf_event.c @@ -246,20 +246,6 @@ static const cache_map_t ultra3_cache_map = { [ C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED }, }, }, -[C(NODE)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED }, - [C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED }, - }, - [ C(OP_WRITE) ] = { - [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED }, - [ C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED }, - }, - [ C(OP_PREFETCH) ] = { - [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED }, - [ C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED }, - }, -}, }; static const struct sparc_pmu ultra3_pmu = { @@ -375,20 +361,6 @@ static const cache_map_t niagara1_cache_map = { [ C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED }, }, }, -[C(NODE)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED }, - [C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED }, - }, - [ C(OP_WRITE) ] = { - [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED }, - [ C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED }, - }, - [ C(OP_PREFETCH) ] = { - [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED }, - [ C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED }, - }, -}, }; static const struct sparc_pmu niagara1_pmu = { @@ -501,20 +473,6 @@ static const cache_map_t niagara2_cache_map = { [ C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED }, }, }, -[C(NODE)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED }, - [C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED }, - }, - [ C(OP_WRITE) ] = { - [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED }, - [ C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED }, - }, - [ C(OP_PREFETCH) ] = { - [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED }, - [ C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED }, - }, -}, }; static const struct sparc_pmu niagara2_pmu = { @@ -1319,7 +1277,7 @@ static int __kprobes perf_event_nmi_handler(struct notifier_block *self, if (!sparc_perf_event_set_period(event, hwc, idx)) continue; - if (perf_event_overflow(event, &data, regs)) + if (perf_event_overflow(event, 1, &data, regs)) sparc_pmu_stop(event, 0); } diff --git a/trunk/arch/sparc/kernel/unaligned_32.c b/trunk/arch/sparc/kernel/unaligned_32.c index 7efbb2f9e77f..4491f4cb2695 100644 --- a/trunk/arch/sparc/kernel/unaligned_32.c +++ b/trunk/arch/sparc/kernel/unaligned_32.c @@ -247,7 +247,7 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn) unsigned long addr = compute_effective_address(regs, insn); int err; - perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, addr); + perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, 0, regs, addr); switch (dir) { case load: err = do_int_load(fetch_reg_addr(((insn>>25)&0x1f), @@ -338,7 +338,7 @@ asmlinkage void user_unaligned_trap(struct pt_regs *regs, unsigned int insn) } addr = compute_effective_address(regs, insn); - perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, addr); + perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, 0, regs, addr); switch(dir) { case load: err = do_int_load(fetch_reg_addr(((insn>>25)&0x1f), diff --git a/trunk/arch/sparc/kernel/unaligned_64.c b/trunk/arch/sparc/kernel/unaligned_64.c index 35cff1673aa4..b2b019ea8caa 100644 --- a/trunk/arch/sparc/kernel/unaligned_64.c +++ b/trunk/arch/sparc/kernel/unaligned_64.c @@ -317,7 +317,7 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn) addr = compute_effective_address(regs, insn, ((insn >> 25) & 0x1f)); - perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, addr); + perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, 0, regs, addr); switch (asi) { case ASI_NL: case ASI_AIUPL: @@ -384,7 +384,7 @@ int handle_popc(u32 insn, struct pt_regs *regs) int ret, i, rd = ((insn >> 25) & 0x1f); int from_kernel = (regs->tstate & TSTATE_PRIV) != 0; - perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0); + perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, 0, regs, 0); if (insn & 0x2000) { maybe_flush_windows(0, 0, rd, from_kernel); value = sign_extend_imm13(insn); @@ -431,7 +431,7 @@ int handle_ldf_stq(u32 insn, struct pt_regs *regs) int asi = decode_asi(insn, regs); int flag = (freg < 32) ? FPRS_DL : FPRS_DU; - perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0); + perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, 0, regs, 0); save_and_clear_fpu(); current_thread_info()->xfsr[0] &= ~0x1c000; @@ -554,7 +554,7 @@ void handle_ld_nf(u32 insn, struct pt_regs *regs) int from_kernel = (regs->tstate & TSTATE_PRIV) != 0; unsigned long *reg; - perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0); + perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, 0, regs, 0); maybe_flush_windows(0, 0, rd, from_kernel); reg = fetch_reg_addr(rd, regs); @@ -586,7 +586,7 @@ void handle_lddfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr if (tstate & TSTATE_PRIV) die_if_kernel("lddfmna from kernel", regs); - perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, sfar); + perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, 0, regs, sfar); if (test_thread_flag(TIF_32BIT)) pc = (u32)pc; if (get_user(insn, (u32 __user *) pc) != -EFAULT) { @@ -647,7 +647,7 @@ void handle_stdfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr if (tstate & TSTATE_PRIV) die_if_kernel("stdfmna from kernel", regs); - perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, sfar); + perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, 0, regs, sfar); if (test_thread_flag(TIF_32BIT)) pc = (u32)pc; if (get_user(insn, (u32 __user *) pc) != -EFAULT) { diff --git a/trunk/arch/sparc/kernel/visemul.c b/trunk/arch/sparc/kernel/visemul.c index 32b626c9d815..36357717d691 100644 --- a/trunk/arch/sparc/kernel/visemul.c +++ b/trunk/arch/sparc/kernel/visemul.c @@ -802,7 +802,7 @@ int vis_emul(struct pt_regs *regs, unsigned int insn) BUG_ON(regs->tstate & TSTATE_PRIV); - perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0); + perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, 0, regs, 0); if (test_thread_flag(TIF_32BIT)) pc = (u32)pc; diff --git a/trunk/arch/sparc/math-emu/math_32.c b/trunk/arch/sparc/math-emu/math_32.c index aa4d55b0bdf0..a3fccde894ec 100644 --- a/trunk/arch/sparc/math-emu/math_32.c +++ b/trunk/arch/sparc/math-emu/math_32.c @@ -164,7 +164,7 @@ int do_mathemu(struct pt_regs *regs, struct task_struct *fpt) int retcode = 0; /* assume all succeed */ unsigned long insn; - perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0); + perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, 0, regs, 0); #ifdef DEBUG_MATHEMU printk("In do_mathemu()... pc is %08lx\n", regs->pc); diff --git a/trunk/arch/sparc/math-emu/math_64.c b/trunk/arch/sparc/math-emu/math_64.c index e575bd2fe381..56d2c44747b8 100644 --- a/trunk/arch/sparc/math-emu/math_64.c +++ b/trunk/arch/sparc/math-emu/math_64.c @@ -184,7 +184,7 @@ int do_mathemu(struct pt_regs *regs, struct fpustate *f) if (tstate & TSTATE_PRIV) die_if_kernel("unfinished/unimplemented FPop from kernel", regs); - perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0); + perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, 0, regs, 0); if (test_thread_flag(TIF_32BIT)) pc = (u32)pc; if (get_user(insn, (u32 __user *) pc) != -EFAULT) { diff --git a/trunk/arch/sparc/mm/fault_32.c b/trunk/arch/sparc/mm/fault_32.c index aa1c1b1ce5cc..7543ddbdadb2 100644 --- a/trunk/arch/sparc/mm/fault_32.c +++ b/trunk/arch/sparc/mm/fault_32.c @@ -251,7 +251,7 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write, if (in_atomic() || !mm) goto no_context; - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address); + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address); down_read(&mm->mmap_sem); @@ -301,10 +301,12 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write, } if (fault & VM_FAULT_MAJOR) { current->maj_flt++; - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, regs, address); + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0, + regs, address); } else { current->min_flt++; - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, regs, address); + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0, + regs, address); } up_read(&mm->mmap_sem); return; diff --git a/trunk/arch/sparc/mm/fault_64.c b/trunk/arch/sparc/mm/fault_64.c index 504c0622f729..f92ce56a8b22 100644 --- a/trunk/arch/sparc/mm/fault_64.c +++ b/trunk/arch/sparc/mm/fault_64.c @@ -325,7 +325,7 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs) if (in_atomic() || !mm) goto intr_or_no_mm; - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address); + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address); if (!down_read_trylock(&mm->mmap_sem)) { if ((regs->tstate & TSTATE_PRIV) && @@ -433,10 +433,12 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs) } if (fault & VM_FAULT_MAJOR) { current->maj_flt++; - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, regs, address); + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0, + regs, address); } else { current->min_flt++; - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, regs, address); + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0, + regs, address); } up_read(&mm->mmap_sem); diff --git a/trunk/arch/tile/kernel/module.c b/trunk/arch/tile/kernel/module.c index 28fa6ece9d3a..f68df69f1f67 100644 --- a/trunk/arch/tile/kernel/module.c +++ b/trunk/arch/tile/kernel/module.c @@ -98,6 +98,25 @@ void module_free(struct module *mod, void *module_region) */ } +/* We don't need anything special. */ +int module_frob_arch_sections(Elf_Ehdr *hdr, + Elf_Shdr *sechdrs, + char *secstrings, + struct module *mod) +{ + return 0; +} + +int apply_relocate(Elf_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *me) +{ + pr_err("module %s: .rel relocation unsupported\n", me->name); + return -ENOEXEC; +} + #ifdef __tilegx__ /* * Validate that the high 16 bits of "value" is just the sign-extension of @@ -230,3 +249,15 @@ int apply_relocate_add(Elf_Shdr *sechdrs, } return 0; } + +int module_finalize(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + struct module *me) +{ + /* FIXME: perhaps remove the "writable" bit from the TLB? */ + return 0; +} + +void module_arch_cleanup(struct module *mod) +{ +} diff --git a/trunk/arch/tile/kvm/Kconfig b/trunk/arch/tile/kvm/Kconfig index 669fcdba31ea..b88f9c047781 100644 --- a/trunk/arch/tile/kvm/Kconfig +++ b/trunk/arch/tile/kvm/Kconfig @@ -33,5 +33,6 @@ config KVM If unsure, say N. source drivers/vhost/Kconfig +source drivers/virtio/Kconfig endif # VIRTUALIZATION diff --git a/trunk/arch/um/sys-i386/Makefile b/trunk/arch/um/sys-i386/Makefile index 87b659dadf3f..b1da91c1b200 100644 --- a/trunk/arch/um/sys-i386/Makefile +++ b/trunk/arch/um/sys-i386/Makefile @@ -8,8 +8,7 @@ obj-y = bug.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \ obj-$(CONFIG_BINFMT_ELF) += elfcore.o -subarch-obj-y = lib/string_32.o -subarch-obj-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += lib/rwsem.o +subarch-obj-y = lib/semaphore_32.o lib/string_32.o subarch-obj-$(CONFIG_HIGHMEM) += mm/highmem_32.o subarch-obj-$(CONFIG_MODULES) += kernel/module.o diff --git a/trunk/arch/um/sys-x86_64/Makefile b/trunk/arch/um/sys-x86_64/Makefile index 61fc99a42e10..c1ea9eb04466 100644 --- a/trunk/arch/um/sys-x86_64/Makefile +++ b/trunk/arch/um/sys-x86_64/Makefile @@ -9,7 +9,7 @@ obj-y = bug.o bugs.o delay.o fault.o ldt.o mem.o ptrace.o ptrace_user.o \ sysrq.o ksyms.o tls.o subarch-obj-y = lib/csum-partial_64.o lib/memcpy_64.o lib/thunk_64.o \ - lib/rwsem.o + lib/rwsem_64.o subarch-obj-$(CONFIG_MODULES) += kernel/module.o ldt-y = ../sys-i386/ldt.o diff --git a/trunk/arch/unicore32/kernel/module.c b/trunk/arch/unicore32/kernel/module.c index 8fbe8577f5e6..3e5a38d71a1e 100644 --- a/trunk/arch/unicore32/kernel/module.c +++ b/trunk/arch/unicore32/kernel/module.c @@ -37,6 +37,19 @@ void *module_alloc(unsigned long size) return __vmalloc_area(area, GFP_KERNEL, PAGE_KERNEL_EXEC); } +void module_free(struct module *module, void *region) +{ + vfree(region); +} + +int module_frob_arch_sections(Elf_Ehdr *hdr, + Elf_Shdr *sechdrs, + char *secstrings, + struct module *mod) +{ + return 0; +} + int apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, unsigned int relindex, struct module *module) @@ -115,3 +128,25 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, } return 0; } + +int +apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab, + unsigned int symindex, unsigned int relsec, + struct module *module) +{ + printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n", + module->name); + return -ENOEXEC; +} + +int +module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs, + struct module *module) +{ + return 0; +} + +void +module_arch_cleanup(struct module *mod) +{ +} diff --git a/trunk/arch/x86/Kconfig b/trunk/arch/x86/Kconfig index a67e014e4e44..37357a599dca 100644 --- a/trunk/arch/x86/Kconfig +++ b/trunk/arch/x86/Kconfig @@ -20,7 +20,6 @@ config X86 select HAVE_UNSTABLE_SCHED_CLOCK select HAVE_IDE select HAVE_OPROFILE - select HAVE_PCSPKR_PLATFORM select HAVE_PERF_EVENTS select HAVE_IRQ_WORK select HAVE_IOREMAP_PROT @@ -71,7 +70,6 @@ config X86 select IRQ_FORCED_THREADING select USE_GENERIC_SMP_HELPERS if SMP select HAVE_BPF_JIT if (X86_64 && NET) - select CLKEVT_I8253 config INSTRUCTION_DECODER def_bool (KPROBES || PERF_EVENTS) @@ -95,10 +93,6 @@ config CLOCKSOURCE_WATCHDOG config GENERIC_CLOCKEVENTS def_bool y -config ARCH_CLOCKSOURCE_DATA - def_bool y - depends on X86_64 - config GENERIC_CLOCKEVENTS_BROADCAST def_bool y depends on X86_64 || (X86_32 && X86_LOCAL_APIC) @@ -390,21 +384,12 @@ config X86_INTEL_CE This option compiles in support for the CE4100 SOC for settop boxes and media devices. -config X86_INTEL_MID - bool "Intel MID platform support" - depends on X86_32 - depends on X86_EXTENDED_PLATFORM - ---help--- - Select to build a kernel capable of supporting Intel MID platform - systems which do not have the PCI legacy interfaces (Moorestown, - Medfield). If you are building for a PC class system say N here. - -if X86_INTEL_MID - config X86_MRST bool "Moorestown MID platform" depends on PCI depends on PCI_GOANY + depends on X86_32 + depends on X86_EXTENDED_PLATFORM depends on X86_IO_APIC select APB_TIMER select I2C @@ -419,8 +404,6 @@ config X86_MRST nor standard legacy replacement devices/features. e.g. Moorestown does not contain i8259, i8254, HPET, legacy BIOS, most of the io ports. -endif - config X86_RDC321X bool "RDC R-321x SoC" depends on X86_32 @@ -529,18 +512,6 @@ menuconfig PARAVIRT_GUEST if PARAVIRT_GUEST -config PARAVIRT_TIME_ACCOUNTING - bool "Paravirtual steal time accounting" - select PARAVIRT - default n - ---help--- - Select this option to enable fine granularity task steal time - accounting. Time spent executing other tasks in parallel with - the current vCPU is discounted from the vCPU power. To account for - that, there can be a small performance impact. - - If in doubt, say N here. - source "arch/x86/xen/Kconfig" config KVM_CLOCK @@ -646,7 +617,6 @@ config HPET_EMULATE_RTC config APB_TIMER def_bool y if MRST prompt "Langwell APB Timer Support" if X86_MRST - select DW_APB_TIMER help APB timer is the replacement for 8254, HPET on X86 MID platforms. The APBT provides a stable time base on SMP @@ -710,6 +680,33 @@ config CALGARY_IOMMU_ENABLED_BY_DEFAULT Calgary anyway, pass 'iommu=calgary' on the kernel command line. If unsure, say Y. +config AMD_IOMMU + bool "AMD IOMMU support" + select SWIOTLB + select PCI_MSI + select PCI_IOV + depends on X86_64 && PCI && ACPI + ---help--- + With this option you can enable support for AMD IOMMU hardware in + your system. An IOMMU is a hardware component which provides + remapping of DMA memory accesses from devices. With an AMD IOMMU you + can isolate the the DMA memory of different devices and protect the + system from misbehaving device drivers or hardware. + + You can find out if your system has an AMD IOMMU if you look into + your BIOS for an option to enable it or if you have an IVRS ACPI + table. + +config AMD_IOMMU_STATS + bool "Export AMD IOMMU statistics to debugfs" + depends on AMD_IOMMU + select DEBUG_FS + ---help--- + This option enables code in the AMD IOMMU driver to collect various + statistics about whats happening in the driver and exports that + information to userspace via debugfs. + If unsure, say N. + # need this always selected by IOMMU for the VIA workaround config SWIOTLB def_bool y if X86_64 @@ -723,6 +720,9 @@ config SWIOTLB config IOMMU_HELPER def_bool (CALGARY_IOMMU || GART_IOMMU || SWIOTLB || AMD_IOMMU) +config IOMMU_API + def_bool (AMD_IOMMU || DMAR) + config MAXSMP bool "Enable Maximum number of SMP Processors and NUMA Nodes" depends on X86_64 && SMP && DEBUG_KERNEL && EXPERIMENTAL @@ -1942,6 +1942,55 @@ config PCI_CNB20LE_QUIRK You should say N unless you know you need this. +config DMAR + bool "Support for DMA Remapping Devices (EXPERIMENTAL)" + depends on PCI_MSI && ACPI && EXPERIMENTAL + help + DMA remapping (DMAR) devices support enables independent address + translations for Direct Memory Access (DMA) from devices. + These DMA remapping devices are reported via ACPI tables + and include PCI device scope covered by these DMA + remapping devices. + +config DMAR_DEFAULT_ON + def_bool y + prompt "Enable DMA Remapping Devices by default" + depends on DMAR + help + Selecting this option will enable a DMAR device at boot time if + one is found. If this option is not selected, DMAR support can + be enabled by passing intel_iommu=on to the kernel. It is + recommended you say N here while the DMAR code remains + experimental. + +config DMAR_BROKEN_GFX_WA + bool "Workaround broken graphics drivers (going away soon)" + depends on DMAR && BROKEN + ---help--- + Current Graphics drivers tend to use physical address + for DMA and avoid using DMA APIs. Setting this config + option permits the IOMMU driver to set a unity map for + all the OS-visible memory. Hence the driver can continue + to use physical addresses for DMA, at least until this + option is removed in the 2.6.32 kernel. + +config DMAR_FLOPPY_WA + def_bool y + depends on DMAR + ---help--- + Floppy disk drivers are known to bypass DMA API calls + thereby failing to work when IOMMU is enabled. This + workaround will setup a 1:1 mapping for the first + 16MiB to make floppy (an ISA device) work. + +config INTR_REMAP + bool "Support for Interrupt Remapping (EXPERIMENTAL)" + depends on X86_64 && X86_IO_APIC && PCI_MSI && ACPI && EXPERIMENTAL + ---help--- + Supports Interrupt remapping for IO-APIC and MSI devices. + To use x2apic mode in the CPU's which support x2APIC enhancements or + to support platforms with CPU's having > 8 bit APIC ID, say Y. + source "drivers/pci/pcie/Kconfig" source "drivers/pci/Kconfig" diff --git a/trunk/arch/x86/Kconfig.cpu b/trunk/arch/x86/Kconfig.cpu index e3ca7e0d858c..6a7cfdf8ff69 100644 --- a/trunk/arch/x86/Kconfig.cpu +++ b/trunk/arch/x86/Kconfig.cpu @@ -312,9 +312,6 @@ config X86_CMPXCHG config CMPXCHG_LOCAL def_bool X86_64 || (X86_32 && !M386) -config CMPXCHG_DOUBLE - def_bool y - config X86_L1_CACHE_SHIFT int default "7" if MPENTIUM4 || MPSC diff --git a/trunk/arch/x86/boot/Makefile b/trunk/arch/x86/boot/Makefile index 95365a82b6a0..f7cb086b4add 100644 --- a/trunk/arch/x86/boot/Makefile +++ b/trunk/arch/x86/boot/Makefile @@ -9,6 +9,12 @@ # Changed by many, many contributors over the years. # +# ROOT_DEV specifies the default root-device when making the image. +# This can be either FLOPPY, CURRENT, /dev/xxxx or empty, in which case +# the default of FLOPPY is used by 'build'. + +ROOT_DEV := CURRENT + # If you want to preset the SVGA mode, uncomment the next line and # set SVGA_MODE to whatever number you want. # Set it to -DSVGA_MODE=NORMAL_VGA if you just want the EGA/VGA mode. @@ -69,7 +75,8 @@ GCOV_PROFILE := n $(obj)/bzImage: asflags-y := $(SVGA_MODE) quiet_cmd_image = BUILD $@ -cmd_image = $(obj)/tools/build $(obj)/setup.bin $(obj)/vmlinux.bin > $@ +cmd_image = $(obj)/tools/build $(obj)/setup.bin $(obj)/vmlinux.bin \ + $(ROOT_DEV) > $@ $(obj)/bzImage: $(obj)/setup.bin $(obj)/vmlinux.bin $(obj)/tools/build FORCE $(call if_changed,image) diff --git a/trunk/arch/x86/boot/tools/build.c b/trunk/arch/x86/boot/tools/build.c index fdc60a0b3c20..ee3a4ea923ac 100644 --- a/trunk/arch/x86/boot/tools/build.c +++ b/trunk/arch/x86/boot/tools/build.c @@ -130,7 +130,7 @@ static void die(const char * str, ...) static void usage(void) { - die("Usage: build setup system [> image]"); + die("Usage: build setup system [rootdev] [> image]"); } int main(int argc, char ** argv) @@ -138,14 +138,39 @@ int main(int argc, char ** argv) unsigned int i, sz, setup_sectors; int c; u32 sys_size; + u8 major_root, minor_root; struct stat sb; FILE *file; int fd; void *kernel; u32 crc = 0xffffffffUL; - if (argc != 3) + if ((argc < 3) || (argc > 4)) usage(); + if (argc > 3) { + if (!strcmp(argv[3], "CURRENT")) { + if (stat("/", &sb)) { + perror("/"); + die("Couldn't stat /"); + } + major_root = major(sb.st_dev); + minor_root = minor(sb.st_dev); + } else if (strcmp(argv[3], "FLOPPY")) { + if (stat(argv[3], &sb)) { + perror(argv[3]); + die("Couldn't stat root device."); + } + major_root = major(sb.st_rdev); + minor_root = minor(sb.st_rdev); + } else { + major_root = 0; + minor_root = 0; + } + } else { + major_root = DEFAULT_MAJOR_ROOT; + minor_root = DEFAULT_MINOR_ROOT; + } + fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root); /* Copy the setup code */ file = fopen(argv[1], "r"); @@ -168,8 +193,8 @@ int main(int argc, char ** argv) memset(buf+c, 0, i-c); /* Set the default root device */ - buf[508] = DEFAULT_MINOR_ROOT; - buf[509] = DEFAULT_MAJOR_ROOT; + buf[508] = minor_root; + buf[509] = major_root; fprintf(stderr, "Setup is %d bytes (padded to %d bytes).\n", c, i); diff --git a/trunk/arch/x86/crypto/ghash-clmulni-intel_glue.c b/trunk/arch/x86/crypto/ghash-clmulni-intel_glue.c index 976aa64d9a20..7a6e68e4f748 100644 --- a/trunk/arch/x86/crypto/ghash-clmulni-intel_glue.c +++ b/trunk/arch/x86/crypto/ghash-clmulni-intel_glue.c @@ -245,7 +245,7 @@ static int ghash_async_setkey(struct crypto_ahash *tfm, const u8 *key, crypto_ahash_set_flags(tfm, crypto_ahash_get_flags(child) & CRYPTO_TFM_RES_MASK); - return err; + return 0; } static int ghash_async_init_tfm(struct crypto_tfm *tfm) diff --git a/trunk/arch/x86/ia32/ia32_signal.c b/trunk/arch/x86/ia32/ia32_signal.c index 65577698cab2..588a7aa937e1 100644 --- a/trunk/arch/x86/ia32/ia32_signal.c +++ b/trunk/arch/x86/ia32/ia32_signal.c @@ -127,17 +127,15 @@ int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from) asmlinkage long sys32_sigsuspend(int history0, int history1, old_sigset_t mask) { - sigset_t blocked; - - current->saved_sigmask = current->blocked; - mask &= _BLOCKABLE; - siginitset(&blocked, mask); - set_current_blocked(&blocked); + spin_lock_irq(¤t->sighand->siglock); + current->saved_sigmask = current->blocked; + siginitset(¤t->blocked, mask); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); current->state = TASK_INTERRUPTIBLE; schedule(); - set_restore_sigmask(); return -ERESTARTNOHAND; } @@ -281,7 +279,10 @@ asmlinkage long sys32_sigreturn(struct pt_regs *regs) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); - set_current_blocked(&set); + spin_lock_irq(¤t->sighand->siglock); + current->blocked = set; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); if (ia32_restore_sigcontext(regs, &frame->sc, &ax)) goto badframe; @@ -307,7 +308,10 @@ asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); - set_current_blocked(&set); + spin_lock_irq(¤t->sighand->siglock); + current->blocked = set; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); if (ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax)) goto badframe; diff --git a/trunk/arch/x86/ia32/ia32entry.S b/trunk/arch/x86/ia32/ia32entry.S index a0e866d233ee..c1870dddd322 100644 --- a/trunk/arch/x86/ia32/ia32entry.S +++ b/trunk/arch/x86/ia32/ia32entry.S @@ -143,7 +143,7 @@ ENTRY(ia32_sysenter_target) CFI_REL_OFFSET rip,0 pushq_cfi %rax cld - SAVE_ARGS 0,1,0 + SAVE_ARGS 0,0,1 /* no need to do an access_ok check here because rbp has been 32bit zero extended */ 1: movl (%rbp),%ebp @@ -173,7 +173,7 @@ sysexit_from_sys_call: andl $~0x200,EFLAGS-R11(%rsp) movl RIP-R11(%rsp),%edx /* User %eip */ CFI_REGISTER rip,rdx - RESTORE_ARGS 0,24,0,0,0,0 + RESTORE_ARGS 1,24,1,1,1,1 xorq %r8,%r8 xorq %r9,%r9 xorq %r10,%r10 @@ -289,7 +289,7 @@ ENTRY(ia32_cstar_target) * disabled irqs and here we enable it straight after entry: */ ENABLE_INTERRUPTS(CLBR_NONE) - SAVE_ARGS 8,0,0 + SAVE_ARGS 8,1,1 movl %eax,%eax /* zero extension */ movq %rax,ORIG_RAX-ARGOFFSET(%rsp) movq %rcx,RIP-ARGOFFSET(%rsp) @@ -328,7 +328,7 @@ cstar_dispatch: jnz sysretl_audit sysretl_from_sys_call: andl $~TS_COMPAT,TI_status(%r10) - RESTORE_ARGS 0,-ARG_SKIP,0,0,0 + RESTORE_ARGS 1,-ARG_SKIP,1,1,1 movl RIP-ARGOFFSET(%rsp),%ecx CFI_REGISTER rip,rcx movl EFLAGS-ARGOFFSET(%rsp),%r11d @@ -419,7 +419,7 @@ ENTRY(ia32_syscall) cld /* note the registers are not zero extended to the sf. this could be a problem. */ - SAVE_ARGS 0,1,0 + SAVE_ARGS 0,0,1 GET_THREAD_INFO(%r10) orl $TS_COMPAT,TI_status(%r10) testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%r10) diff --git a/trunk/arch/x86/include/asm/alternative-asm.h b/trunk/arch/x86/include/asm/alternative-asm.h index 4554cc6fb96a..94d420b360d1 100644 --- a/trunk/arch/x86/include/asm/alternative-asm.h +++ b/trunk/arch/x86/include/asm/alternative-asm.h @@ -17,8 +17,8 @@ .macro altinstruction_entry orig alt feature orig_len alt_len .align 8 - .long \orig - . - .long \alt - . + .quad \orig + .quad \alt .word \feature .byte \orig_len .byte \alt_len diff --git a/trunk/arch/x86/include/asm/alternative.h b/trunk/arch/x86/include/asm/alternative.h index 23fb6d79f209..bf535f947e8c 100644 --- a/trunk/arch/x86/include/asm/alternative.h +++ b/trunk/arch/x86/include/asm/alternative.h @@ -43,8 +43,8 @@ #endif struct alt_instr { - s32 instr_offset; /* original instruction */ - s32 repl_offset; /* offset to replacement instruction */ + u8 *instr; /* original instruction */ + u8 *replacement; u16 cpuid; /* cpuid bit set for replacement */ u8 instrlen; /* length of original instruction */ u8 replacementlen; /* length of new instruction, <= instrlen */ @@ -84,8 +84,8 @@ static inline int alternatives_text_reserved(void *start, void *end) "661:\n\t" oldinstr "\n662:\n" \ ".section .altinstructions,\"a\"\n" \ _ASM_ALIGN "\n" \ - " .long 661b - .\n" /* label */ \ - " .long 663f - .\n" /* new instruction */ \ + _ASM_PTR "661b\n" /* label */ \ + _ASM_PTR "663f\n" /* new instruction */ \ " .word " __stringify(feature) "\n" /* feature bit */ \ " .byte 662b-661b\n" /* sourcelen */ \ " .byte 664f-663f\n" /* replacementlen */ \ diff --git a/trunk/include/linux/amd-iommu.h b/trunk/arch/x86/include/asm/amd_iommu.h similarity index 100% rename from trunk/include/linux/amd-iommu.h rename to trunk/arch/x86/include/asm/amd_iommu.h diff --git a/trunk/drivers/iommu/amd_iommu_proto.h b/trunk/arch/x86/include/asm/amd_iommu_proto.h similarity index 98% rename from trunk/drivers/iommu/amd_iommu_proto.h rename to trunk/arch/x86/include/asm/amd_iommu_proto.h index 7ffaa64410b0..55d95eb789b3 100644 --- a/trunk/drivers/iommu/amd_iommu_proto.h +++ b/trunk/arch/x86/include/asm/amd_iommu_proto.h @@ -19,7 +19,7 @@ #ifndef _ASM_X86_AMD_IOMMU_PROTO_H #define _ASM_X86_AMD_IOMMU_PROTO_H -#include "amd_iommu_types.h" +#include extern int amd_iommu_init_dma_ops(void); extern int amd_iommu_init_passthrough(void); diff --git a/trunk/drivers/iommu/amd_iommu_types.h b/trunk/arch/x86/include/asm/amd_iommu_types.h similarity index 98% rename from trunk/drivers/iommu/amd_iommu_types.h rename to trunk/arch/x86/include/asm/amd_iommu_types.h index 5b9c5075e81a..4c9982995414 100644 --- a/trunk/drivers/iommu/amd_iommu_types.h +++ b/trunk/arch/x86/include/asm/amd_iommu_types.h @@ -310,15 +310,10 @@ struct protection_domain { */ struct iommu_dev_data { struct list_head list; /* For domain->dev_list */ - struct list_head dev_data_list; /* For global dev_data_list */ - struct iommu_dev_data *alias_data;/* The alias dev_data */ + struct device *dev; /* Device this data belong to */ + struct device *alias; /* The Alias Device */ struct protection_domain *domain; /* Domain the device is bound to */ atomic_t bind; /* Domain attach reverent count */ - u16 devid; /* PCI Device ID */ - struct { - bool enabled; - int qdep; - } ats; /* ATS state */ }; /* diff --git a/trunk/arch/x86/include/asm/apb_timer.h b/trunk/arch/x86/include/asm/apb_timer.h index 0acbac299e49..af60d8a2e288 100644 --- a/trunk/arch/x86/include/asm/apb_timer.h +++ b/trunk/arch/x86/include/asm/apb_timer.h @@ -18,6 +18,24 @@ #ifdef CONFIG_APB_TIMER +/* Langwell DW APB timer registers */ +#define APBTMR_N_LOAD_COUNT 0x00 +#define APBTMR_N_CURRENT_VALUE 0x04 +#define APBTMR_N_CONTROL 0x08 +#define APBTMR_N_EOI 0x0c +#define APBTMR_N_INT_STATUS 0x10 + +#define APBTMRS_INT_STATUS 0xa0 +#define APBTMRS_EOI 0xa4 +#define APBTMRS_RAW_INT_STATUS 0xa8 +#define APBTMRS_COMP_VERSION 0xac +#define APBTMRS_REG_SIZE 0x14 + +/* register bits */ +#define APBTMR_CONTROL_ENABLE (1<<0) +#define APBTMR_CONTROL_MODE_PERIODIC (1<<1) /*1: periodic 0:free running */ +#define APBTMR_CONTROL_INT (1<<2) + /* default memory mapped register base */ #define LNW_SCU_ADDR 0xFF100000 #define LNW_EXT_TIMER_OFFSET 0x1B800 @@ -25,13 +43,14 @@ #define LNW_EXT_TIMER_PGOFFSET 0x800 /* APBT clock speed range from PCLK to fabric base, 25-100MHz */ -#define APBT_MAX_FREQ 50000000 -#define APBT_MIN_FREQ 1000000 +#define APBT_MAX_FREQ 50 +#define APBT_MIN_FREQ 1 #define APBT_MMAP_SIZE 1024 #define APBT_DEV_USED 1 extern void apbt_time_init(void); +extern struct clock_event_device *global_clock_event; extern unsigned long apbt_quick_calibrate(void); extern int arch_setup_apbt_irqs(int irq, int trigger, int mask, int cpu); extern void apbt_setup_secondary_clock(void); diff --git a/trunk/arch/x86/include/asm/asm.h b/trunk/arch/x86/include/asm/asm.h index 9412d6558c88..b3ed1e1460ff 100644 --- a/trunk/arch/x86/include/asm/asm.h +++ b/trunk/arch/x86/include/asm/asm.h @@ -3,11 +3,9 @@ #ifdef __ASSEMBLY__ # define __ASM_FORM(x) x -# define __ASM_FORM_COMMA(x) x, # define __ASM_EX_SEC .section __ex_table, "a" #else # define __ASM_FORM(x) " " #x " " -# define __ASM_FORM_COMMA(x) " " #x "," # define __ASM_EX_SEC " .section __ex_table,\"a\"\n" #endif @@ -17,8 +15,7 @@ # define __ASM_SEL(a,b) __ASM_FORM(b) #endif -#define __ASM_SIZE(inst, ...) __ASM_SEL(inst##l##__VA_ARGS__, \ - inst##q##__VA_ARGS__) +#define __ASM_SIZE(inst) __ASM_SEL(inst##l, inst##q) #define __ASM_REG(reg) __ASM_SEL(e##reg, r##reg) #define _ASM_PTR __ASM_SEL(.long, .quad) diff --git a/trunk/arch/x86/include/asm/calling.h b/trunk/arch/x86/include/asm/calling.h index a9e3a740f697..30af5a832163 100644 --- a/trunk/arch/x86/include/asm/calling.h +++ b/trunk/arch/x86/include/asm/calling.h @@ -46,7 +46,6 @@ For 32-bit we have the following conventions - kernel is built with */ -#include "dwarf2.h" /* * 64-bit system call stack frame layout defines and helpers, for @@ -85,57 +84,72 @@ For 32-bit we have the following conventions - kernel is built with #define ARGOFFSET R11 #define SWFRAME ORIG_RAX - .macro SAVE_ARGS addskip=0, save_rcx=1, save_r891011=1 + .macro SAVE_ARGS addskip=0, norcx=0, nor891011=0 subq $9*8+\addskip, %rsp CFI_ADJUST_CFA_OFFSET 9*8+\addskip - movq_cfi rdi, 8*8 - movq_cfi rsi, 7*8 - movq_cfi rdx, 6*8 - - .if \save_rcx - movq_cfi rcx, 5*8 + movq %rdi, 8*8(%rsp) + CFI_REL_OFFSET rdi, 8*8 + movq %rsi, 7*8(%rsp) + CFI_REL_OFFSET rsi, 7*8 + movq %rdx, 6*8(%rsp) + CFI_REL_OFFSET rdx, 6*8 + .if \norcx + .else + movq %rcx, 5*8(%rsp) + CFI_REL_OFFSET rcx, 5*8 .endif - - movq_cfi rax, 4*8 - - .if \save_r891011 - movq_cfi r8, 3*8 - movq_cfi r9, 2*8 - movq_cfi r10, 1*8 - movq_cfi r11, 0*8 + movq %rax, 4*8(%rsp) + CFI_REL_OFFSET rax, 4*8 + .if \nor891011 + .else + movq %r8, 3*8(%rsp) + CFI_REL_OFFSET r8, 3*8 + movq %r9, 2*8(%rsp) + CFI_REL_OFFSET r9, 2*8 + movq %r10, 1*8(%rsp) + CFI_REL_OFFSET r10, 1*8 + movq %r11, (%rsp) + CFI_REL_OFFSET r11, 0*8 .endif - .endm #define ARG_SKIP (9*8) - .macro RESTORE_ARGS rstor_rax=1, addskip=0, rstor_rcx=1, rstor_r11=1, \ - rstor_r8910=1, rstor_rdx=1 - .if \rstor_r11 - movq_cfi_restore 0*8, r11 + .macro RESTORE_ARGS skiprax=0, addskip=0, skiprcx=0, skipr11=0, \ + skipr8910=0, skiprdx=0 + .if \skipr11 + .else + movq (%rsp), %r11 + CFI_RESTORE r11 .endif - - .if \rstor_r8910 - movq_cfi_restore 1*8, r10 - movq_cfi_restore 2*8, r9 - movq_cfi_restore 3*8, r8 + .if \skipr8910 + .else + movq 1*8(%rsp), %r10 + CFI_RESTORE r10 + movq 2*8(%rsp), %r9 + CFI_RESTORE r9 + movq 3*8(%rsp), %r8 + CFI_RESTORE r8 .endif - - .if \rstor_rax - movq_cfi_restore 4*8, rax + .if \skiprax + .else + movq 4*8(%rsp), %rax + CFI_RESTORE rax .endif - - .if \rstor_rcx - movq_cfi_restore 5*8, rcx + .if \skiprcx + .else + movq 5*8(%rsp), %rcx + CFI_RESTORE rcx .endif - - .if \rstor_rdx - movq_cfi_restore 6*8, rdx + .if \skiprdx + .else + movq 6*8(%rsp), %rdx + CFI_RESTORE rdx .endif - - movq_cfi_restore 7*8, rsi - movq_cfi_restore 8*8, rdi - + movq 7*8(%rsp), %rsi + CFI_RESTORE rsi + movq 8*8(%rsp), %rdi + CFI_RESTORE rdi .if ARG_SKIP+\addskip > 0 addq $ARG_SKIP+\addskip, %rsp CFI_ADJUST_CFA_OFFSET -(ARG_SKIP+\addskip) @@ -162,21 +176,33 @@ For 32-bit we have the following conventions - kernel is built with .macro SAVE_REST subq $REST_SKIP, %rsp CFI_ADJUST_CFA_OFFSET REST_SKIP - movq_cfi rbx, 5*8 - movq_cfi rbp, 4*8 - movq_cfi r12, 3*8 - movq_cfi r13, 2*8 - movq_cfi r14, 1*8 - movq_cfi r15, 0*8 + movq %rbx, 5*8(%rsp) + CFI_REL_OFFSET rbx, 5*8 + movq %rbp, 4*8(%rsp) + CFI_REL_OFFSET rbp, 4*8 + movq %r12, 3*8(%rsp) + CFI_REL_OFFSET r12, 3*8 + movq %r13, 2*8(%rsp) + CFI_REL_OFFSET r13, 2*8 + movq %r14, 1*8(%rsp) + CFI_REL_OFFSET r14, 1*8 + movq %r15, (%rsp) + CFI_REL_OFFSET r15, 0*8 .endm .macro RESTORE_REST - movq_cfi_restore 0*8, r15 - movq_cfi_restore 1*8, r14 - movq_cfi_restore 2*8, r13 - movq_cfi_restore 3*8, r12 - movq_cfi_restore 4*8, rbp - movq_cfi_restore 5*8, rbx + movq (%rsp), %r15 + CFI_RESTORE r15 + movq 1*8(%rsp), %r14 + CFI_RESTORE r14 + movq 2*8(%rsp), %r13 + CFI_RESTORE r13 + movq 3*8(%rsp), %r12 + CFI_RESTORE r12 + movq 4*8(%rsp), %rbp + CFI_RESTORE rbp + movq 5*8(%rsp), %rbx + CFI_RESTORE rbx addq $REST_SKIP, %rsp CFI_ADJUST_CFA_OFFSET -(REST_SKIP) .endm @@ -188,7 +214,7 @@ For 32-bit we have the following conventions - kernel is built with .macro RESTORE_ALL addskip=0 RESTORE_REST - RESTORE_ARGS 1, \addskip + RESTORE_ARGS 0, \addskip .endm .macro icebp diff --git a/trunk/arch/x86/include/asm/clocksource.h b/trunk/arch/x86/include/asm/clocksource.h deleted file mode 100644 index 0bdbbb3b9ce7..000000000000 --- a/trunk/arch/x86/include/asm/clocksource.h +++ /dev/null @@ -1,18 +0,0 @@ -/* x86-specific clocksource additions */ - -#ifndef _ASM_X86_CLOCKSOURCE_H -#define _ASM_X86_CLOCKSOURCE_H - -#ifdef CONFIG_X86_64 - -#define VCLOCK_NONE 0 /* No vDSO clock available. */ -#define VCLOCK_TSC 1 /* vDSO should use vread_tsc. */ -#define VCLOCK_HPET 2 /* vDSO should use vread_hpet. */ - -struct arch_clocksource_data { - int vclock_mode; -}; - -#endif /* CONFIG_X86_64 */ - -#endif /* _ASM_X86_CLOCKSOURCE_H */ diff --git a/trunk/arch/x86/include/asm/cmpxchg_32.h b/trunk/arch/x86/include/asm/cmpxchg_32.h index 3deb7250624c..284a6e8f7ce1 100644 --- a/trunk/arch/x86/include/asm/cmpxchg_32.h +++ b/trunk/arch/x86/include/asm/cmpxchg_32.h @@ -280,52 +280,4 @@ static inline unsigned long cmpxchg_386(volatile void *ptr, unsigned long old, #endif -#define cmpxchg8b(ptr, o1, o2, n1, n2) \ -({ \ - char __ret; \ - __typeof__(o2) __dummy; \ - __typeof__(*(ptr)) __old1 = (o1); \ - __typeof__(o2) __old2 = (o2); \ - __typeof__(*(ptr)) __new1 = (n1); \ - __typeof__(o2) __new2 = (n2); \ - asm volatile(LOCK_PREFIX "cmpxchg8b %2; setz %1" \ - : "=d"(__dummy), "=a" (__ret), "+m" (*ptr)\ - : "a" (__old1), "d"(__old2), \ - "b" (__new1), "c" (__new2) \ - : "memory"); \ - __ret; }) - - -#define cmpxchg8b_local(ptr, o1, o2, n1, n2) \ -({ \ - char __ret; \ - __typeof__(o2) __dummy; \ - __typeof__(*(ptr)) __old1 = (o1); \ - __typeof__(o2) __old2 = (o2); \ - __typeof__(*(ptr)) __new1 = (n1); \ - __typeof__(o2) __new2 = (n2); \ - asm volatile("cmpxchg8b %2; setz %1" \ - : "=d"(__dummy), "=a"(__ret), "+m" (*ptr)\ - : "a" (__old), "d"(__old2), \ - "b" (__new1), "c" (__new2), \ - : "memory"); \ - __ret; }) - - -#define cmpxchg_double(ptr, o1, o2, n1, n2) \ -({ \ - BUILD_BUG_ON(sizeof(*(ptr)) != 4); \ - VM_BUG_ON((unsigned long)(ptr) % 8); \ - cmpxchg8b((ptr), (o1), (o2), (n1), (n2)); \ -}) - -#define cmpxchg_double_local(ptr, o1, o2, n1, n2) \ -({ \ - BUILD_BUG_ON(sizeof(*(ptr)) != 4); \ - VM_BUG_ON((unsigned long)(ptr) % 8); \ - cmpxchg16b_local((ptr), (o1), (o2), (n1), (n2)); \ -}) - -#define system_has_cmpxchg_double() cpu_has_cx8 - #endif /* _ASM_X86_CMPXCHG_32_H */ diff --git a/trunk/arch/x86/include/asm/cmpxchg_64.h b/trunk/arch/x86/include/asm/cmpxchg_64.h index 7cf5c0a24434..423ae58aa020 100644 --- a/trunk/arch/x86/include/asm/cmpxchg_64.h +++ b/trunk/arch/x86/include/asm/cmpxchg_64.h @@ -151,49 +151,4 @@ extern void __cmpxchg_wrong_size(void); cmpxchg_local((ptr), (o), (n)); \ }) -#define cmpxchg16b(ptr, o1, o2, n1, n2) \ -({ \ - char __ret; \ - __typeof__(o2) __junk; \ - __typeof__(*(ptr)) __old1 = (o1); \ - __typeof__(o2) __old2 = (o2); \ - __typeof__(*(ptr)) __new1 = (n1); \ - __typeof__(o2) __new2 = (n2); \ - asm volatile(LOCK_PREFIX "cmpxchg16b %2;setz %1" \ - : "=d"(__junk), "=a"(__ret), "+m" (*ptr) \ - : "b"(__new1), "c"(__new2), \ - "a"(__old1), "d"(__old2)); \ - __ret; }) - - -#define cmpxchg16b_local(ptr, o1, o2, n1, n2) \ -({ \ - char __ret; \ - __typeof__(o2) __junk; \ - __typeof__(*(ptr)) __old1 = (o1); \ - __typeof__(o2) __old2 = (o2); \ - __typeof__(*(ptr)) __new1 = (n1); \ - __typeof__(o2) __new2 = (n2); \ - asm volatile("cmpxchg16b %2;setz %1" \ - : "=d"(__junk), "=a"(__ret), "+m" (*ptr) \ - : "b"(__new1), "c"(__new2), \ - "a"(__old1), "d"(__old2)); \ - __ret; }) - -#define cmpxchg_double(ptr, o1, o2, n1, n2) \ -({ \ - BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ - VM_BUG_ON((unsigned long)(ptr) % 16); \ - cmpxchg16b((ptr), (o1), (o2), (n1), (n2)); \ -}) - -#define cmpxchg_double_local(ptr, o1, o2, n1, n2) \ -({ \ - BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ - VM_BUG_ON((unsigned long)(ptr) % 16); \ - cmpxchg16b_local((ptr), (o1), (o2), (n1), (n2)); \ -}) - -#define system_has_cmpxchg_double() cpu_has_cx16 - #endif /* _ASM_X86_CMPXCHG_64_H */ diff --git a/trunk/arch/x86/include/asm/cpufeature.h b/trunk/arch/x86/include/asm/cpufeature.h index 4258aac99a6e..71cc3800712c 100644 --- a/trunk/arch/x86/include/asm/cpufeature.h +++ b/trunk/arch/x86/include/asm/cpufeature.h @@ -288,8 +288,6 @@ extern const char * const x86_power_flags[32]; #define cpu_has_hypervisor boot_cpu_has(X86_FEATURE_HYPERVISOR) #define cpu_has_pclmulqdq boot_cpu_has(X86_FEATURE_PCLMULQDQ) #define cpu_has_perfctr_core boot_cpu_has(X86_FEATURE_PERFCTR_CORE) -#define cpu_has_cx8 boot_cpu_has(X86_FEATURE_CX8) -#define cpu_has_cx16 boot_cpu_has(X86_FEATURE_CX16) #if defined(CONFIG_X86_INVLPG) || defined(CONFIG_X86_64) # define cpu_has_invlpg 1 @@ -333,8 +331,8 @@ static __always_inline __pure bool __static_cpu_has(u16 bit) "2:\n" ".section .altinstructions,\"a\"\n" _ASM_ALIGN "\n" - " .long 1b - .\n" - " .long 0\n" /* no replacement */ + _ASM_PTR "1b\n" + _ASM_PTR "0\n" /* no replacement */ " .word %P0\n" /* feature bit */ " .byte 2b - 1b\n" /* source len */ " .byte 0\n" /* replacement len */ @@ -351,8 +349,8 @@ static __always_inline __pure bool __static_cpu_has(u16 bit) "2:\n" ".section .altinstructions,\"a\"\n" _ASM_ALIGN "\n" - " .long 1b - .\n" - " .long 3f - .\n" + _ASM_PTR "1b\n" + _ASM_PTR "3f\n" " .word %P1\n" /* feature bit */ " .byte 2b - 1b\n" /* source len */ " .byte 4f - 3f\n" /* replacement len */ diff --git a/trunk/arch/x86/include/asm/delay.h b/trunk/arch/x86/include/asm/delay.h index 9b3b4f2754c7..409a649204aa 100644 --- a/trunk/arch/x86/include/asm/delay.h +++ b/trunk/arch/x86/include/asm/delay.h @@ -1,7 +1,30 @@ #ifndef _ASM_X86_DELAY_H #define _ASM_X86_DELAY_H -#include +/* + * Copyright (C) 1993 Linus Torvalds + * + * Delay routines calling functions in arch/x86/lib/delay.c + */ + +/* Undefined functions to get compile-time errors */ +extern void __bad_udelay(void); +extern void __bad_ndelay(void); + +extern void __udelay(unsigned long usecs); +extern void __ndelay(unsigned long nsecs); +extern void __const_udelay(unsigned long xloops); +extern void __delay(unsigned long loops); + +/* 0x10c7 is 2**32 / 1000000 (rounded up) */ +#define udelay(n) (__builtin_constant_p(n) ? \ + ((n) > 20000 ? __bad_udelay() : __const_udelay((n) * 0x10c7ul)) : \ + __udelay(n)) + +/* 0x5 is 2**32 / 1000000000 (rounded up) */ +#define ndelay(n) (__builtin_constant_p(n) ? \ + ((n) > 20000 ? __bad_ndelay() : __const_udelay((n) * 5ul)) : \ + __ndelay(n)) void use_tsc_delay(void); diff --git a/trunk/arch/x86/include/asm/entry_arch.h b/trunk/arch/x86/include/asm/entry_arch.h index 0baa628e330c..1cd6d26a0a8d 100644 --- a/trunk/arch/x86/include/asm/entry_arch.h +++ b/trunk/arch/x86/include/asm/entry_arch.h @@ -53,4 +53,8 @@ BUILD_INTERRUPT(thermal_interrupt,THERMAL_APIC_VECTOR) BUILD_INTERRUPT(threshold_interrupt,THRESHOLD_APIC_VECTOR) #endif +#ifdef CONFIG_X86_MCE +BUILD_INTERRUPT(mce_self_interrupt,MCE_SELF_VECTOR) +#endif + #endif diff --git a/trunk/arch/x86/include/asm/fixmap.h b/trunk/arch/x86/include/asm/fixmap.h index 460c74e4852c..4729b2b63117 100644 --- a/trunk/arch/x86/include/asm/fixmap.h +++ b/trunk/arch/x86/include/asm/fixmap.h @@ -78,7 +78,6 @@ enum fixed_addresses { VSYSCALL_LAST_PAGE, VSYSCALL_FIRST_PAGE = VSYSCALL_LAST_PAGE + ((VSYSCALL_END-VSYSCALL_START) >> PAGE_SHIFT) - 1, - VVAR_PAGE, VSYSCALL_HPET, #endif FIX_DBGP_BASE, diff --git a/trunk/arch/x86/include/asm/frame.h b/trunk/arch/x86/include/asm/frame.h index 3b629f47eb65..2c6fc9e62812 100644 --- a/trunk/arch/x86/include/asm/frame.h +++ b/trunk/arch/x86/include/asm/frame.h @@ -1,6 +1,5 @@ #ifdef __ASSEMBLY__ -#include #include /* The annotation hides the frame from the unwinder and makes it look @@ -8,13 +7,13 @@ frame pointer later */ #ifdef CONFIG_FRAME_POINTER .macro FRAME - __ASM_SIZE(push,_cfi) %__ASM_REG(bp) - CFI_REL_OFFSET __ASM_REG(bp), 0 - __ASM_SIZE(mov) %__ASM_REG(sp), %__ASM_REG(bp) + pushl_cfi %ebp + CFI_REL_OFFSET ebp,0 + movl %esp,%ebp .endm .macro ENDFRAME - __ASM_SIZE(pop,_cfi) %__ASM_REG(bp) - CFI_RESTORE __ASM_REG(bp) + popl_cfi %ebp + CFI_RESTORE ebp .endm #else .macro FRAME diff --git a/trunk/arch/x86/include/asm/hw_irq.h b/trunk/arch/x86/include/asm/hw_irq.h index 13f5504c76c0..bb9efe8706e2 100644 --- a/trunk/arch/x86/include/asm/hw_irq.h +++ b/trunk/arch/x86/include/asm/hw_irq.h @@ -34,6 +34,7 @@ extern void irq_work_interrupt(void); extern void spurious_interrupt(void); extern void thermal_interrupt(void); extern void reschedule_interrupt(void); +extern void mce_self_interrupt(void); extern void invalidate_interrupt(void); extern void invalidate_interrupt0(void); diff --git a/trunk/arch/x86/include/asm/i8253.h b/trunk/arch/x86/include/asm/i8253.h new file mode 100644 index 000000000000..65aaa91d5850 --- /dev/null +++ b/trunk/arch/x86/include/asm/i8253.h @@ -0,0 +1,20 @@ +#ifndef _ASM_X86_I8253_H +#define _ASM_X86_I8253_H + +/* i8253A PIT registers */ +#define PIT_MODE 0x43 +#define PIT_CH0 0x40 +#define PIT_CH2 0x42 + +#define PIT_LATCH LATCH + +extern raw_spinlock_t i8253_lock; + +extern struct clock_event_device *global_clock_event; + +extern void setup_pit_timer(void); + +#define inb_pit inb_p +#define outb_pit outb_p + +#endif /* _ASM_X86_I8253_H */ diff --git a/trunk/arch/x86/include/asm/irq_vectors.h b/trunk/arch/x86/include/asm/irq_vectors.h index f9a320984a10..6e976ee3b3ef 100644 --- a/trunk/arch/x86/include/asm/irq_vectors.h +++ b/trunk/arch/x86/include/asm/irq_vectors.h @@ -17,8 +17,7 @@ * Vectors 0 ... 31 : system traps and exceptions - hardcoded events * Vectors 32 ... 127 : device interrupts * Vector 128 : legacy int80 syscall interface - * Vector 204 : legacy x86_64 vsyscall emulation - * Vectors 129 ... INVALIDATE_TLB_VECTOR_START-1 except 204 : device interrupts + * Vectors 129 ... INVALIDATE_TLB_VECTOR_START-1 : device interrupts * Vectors INVALIDATE_TLB_VECTOR_START ... 255 : special interrupts * * 64-bit x86 has per CPU IDT tables, 32-bit has one shared IDT table. @@ -51,9 +50,6 @@ #ifdef CONFIG_X86_32 # define SYSCALL_VECTOR 0x80 #endif -#ifdef CONFIG_X86_64 -# define VSYSCALL_EMU_VECTOR 0xcc -#endif /* * Vectors 0x30-0x3f are used for ISA interrupts. @@ -113,6 +109,11 @@ #define UV_BAU_MESSAGE 0xf5 +/* + * Self IPI vector for machine checks + */ +#define MCE_SELF_VECTOR 0xf4 + /* Xen vector callback to receive events in a HVM domain */ #define XEN_HVM_EVTCHN_CALLBACK 0xf3 diff --git a/trunk/arch/x86/include/asm/irqflags.h b/trunk/arch/x86/include/asm/irqflags.h index bba3cf88e624..5745ce8bf108 100644 --- a/trunk/arch/x86/include/asm/irqflags.h +++ b/trunk/arch/x86/include/asm/irqflags.h @@ -60,24 +60,23 @@ static inline void native_halt(void) #include #else #ifndef __ASSEMBLY__ -#include -static inline notrace unsigned long arch_local_save_flags(void) +static inline unsigned long arch_local_save_flags(void) { return native_save_fl(); } -static inline notrace void arch_local_irq_restore(unsigned long flags) +static inline void arch_local_irq_restore(unsigned long flags) { native_restore_fl(flags); } -static inline notrace void arch_local_irq_disable(void) +static inline void arch_local_irq_disable(void) { native_irq_disable(); } -static inline notrace void arch_local_irq_enable(void) +static inline void arch_local_irq_enable(void) { native_irq_enable(); } @@ -103,7 +102,7 @@ static inline void halt(void) /* * For spinlocks, etc: */ -static inline notrace unsigned long arch_local_irq_save(void) +static inline unsigned long arch_local_irq_save(void) { unsigned long flags = arch_local_save_flags(); arch_local_irq_disable(); diff --git a/trunk/arch/x86/include/asm/kvm_emulate.h b/trunk/arch/x86/include/asm/kvm_emulate.h index 6040d115ef51..0049211959c0 100644 --- a/trunk/arch/x86/include/asm/kvm_emulate.h +++ b/trunk/arch/x86/include/asm/kvm_emulate.h @@ -229,26 +229,7 @@ struct read_cache { unsigned long end; }; -struct x86_emulate_ctxt { - struct x86_emulate_ops *ops; - - /* Register state before/after emulation. */ - unsigned long eflags; - unsigned long eip; /* eip before instruction emulation */ - /* Emulated execution mode, represented by an X86EMUL_MODE value. */ - int mode; - - /* interruptibility state, as a result of execution of STI or MOV SS */ - int interruptibility; - - bool guest_mode; /* guest running a nested guest */ - bool perm_ok; /* do not check permissions if true */ - bool only_vendor_specific_insn; - - bool have_exception; - struct x86_exception exception; - - /* decode cache */ +struct decode_cache { u8 twobyte; u8 b; u8 intercept; @@ -265,6 +246,8 @@ struct x86_emulate_ctxt { unsigned int d; int (*execute)(struct x86_emulate_ctxt *ctxt); int (*check_perm)(struct x86_emulate_ctxt *ctxt); + unsigned long regs[NR_VCPU_REGS]; + unsigned long eip; /* modrm */ u8 modrm; u8 modrm_mod; @@ -272,14 +255,34 @@ struct x86_emulate_ctxt { u8 modrm_rm; u8 modrm_seg; bool rip_relative; - unsigned long _eip; - /* Fields above regs are cleared together. */ - unsigned long regs[NR_VCPU_REGS]; struct fetch_cache fetch; struct read_cache io_read; struct read_cache mem_read; }; +struct x86_emulate_ctxt { + struct x86_emulate_ops *ops; + + /* Register state before/after emulation. */ + unsigned long eflags; + unsigned long eip; /* eip before instruction emulation */ + /* Emulated execution mode, represented by an X86EMUL_MODE value. */ + int mode; + + /* interruptibility state, as a result of execution of STI or MOV SS */ + int interruptibility; + + bool guest_mode; /* guest running a nested guest */ + bool perm_ok; /* do not check permissions if true */ + bool only_vendor_specific_insn; + + bool have_exception; + struct x86_exception exception; + + /* decode cache */ + struct decode_cache decode; +}; + /* Repeat String Operation Prefix */ #define REPE_PREFIX 0xf3 #define REPNE_PREFIX 0xf2 @@ -370,5 +373,6 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt); int emulator_task_switch(struct x86_emulate_ctxt *ctxt, u16 tss_selector, int reason, bool has_error_code, u32 error_code); -int emulate_int_real(struct x86_emulate_ctxt *ctxt, int irq); +int emulate_int_real(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, int irq); #endif /* _ASM_X86_KVM_X86_EMULATE_H */ diff --git a/trunk/arch/x86/include/asm/kvm_host.h b/trunk/arch/x86/include/asm/kvm_host.h index dd51c83aa5de..d2ac8e2ee897 100644 --- a/trunk/arch/x86/include/asm/kvm_host.h +++ b/trunk/arch/x86/include/asm/kvm_host.h @@ -48,7 +48,7 @@ (~(unsigned long)(X86_CR4_VME | X86_CR4_PVI | X86_CR4_TSD | X86_CR4_DE\ | X86_CR4_PSE | X86_CR4_PAE | X86_CR4_MCE \ | X86_CR4_PGE | X86_CR4_PCE | X86_CR4_OSFXSR \ - | X86_CR4_OSXSAVE | X86_CR4_SMEP | X86_CR4_RDWRGSFS \ + | X86_CR4_OSXSAVE \ | X86_CR4_OSXMMEXCPT | X86_CR4_VMXE)) #define CR8_RESERVED_BITS (~(unsigned long)X86_CR8_TPR) @@ -205,7 +205,6 @@ union kvm_mmu_page_role { unsigned invalid:1; unsigned nxe:1; unsigned cr0_wp:1; - unsigned smep_andnot_wp:1; }; }; @@ -228,17 +227,15 @@ struct kvm_mmu_page { * in this shadow page. */ DECLARE_BITMAP(slot_bitmap, KVM_MEMORY_SLOTS + KVM_PRIVATE_MEM_SLOTS); + bool multimapped; /* More than one parent_pte? */ bool unsync; int root_count; /* Currently serving as active root */ unsigned int unsync_children; - unsigned long parent_ptes; /* Reverse mapping for parent_pte */ + union { + u64 *parent_pte; /* !multimapped */ + struct hlist_head parent_ptes; /* multimapped, kvm_pte_chain */ + }; DECLARE_BITMAP(unsync_child_bitmap, 512); - -#ifdef CONFIG_X86_32 - int clear_spte_count; -#endif - - struct rcu_head rcu; }; struct kvm_pv_mmu_op_buffer { @@ -272,6 +269,8 @@ struct kvm_mmu { gpa_t (*gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t gva, u32 access, struct x86_exception *exception); gpa_t (*translate_gpa)(struct kvm_vcpu *vcpu, gpa_t gpa, u32 access); + void (*prefetch_page)(struct kvm_vcpu *vcpu, + struct kvm_mmu_page *page); int (*sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp); void (*invlpg)(struct kvm_vcpu *vcpu, gva_t gva); @@ -347,7 +346,8 @@ struct kvm_vcpu_arch { * put it here to avoid allocation */ struct kvm_pv_mmu_op_buffer mmu_op_buffer; - struct kvm_mmu_memory_cache mmu_pte_list_desc_cache; + struct kvm_mmu_memory_cache mmu_pte_chain_cache; + struct kvm_mmu_memory_cache mmu_rmap_desc_cache; struct kvm_mmu_memory_cache mmu_page_cache; struct kvm_mmu_memory_cache mmu_page_header_cache; @@ -393,15 +393,6 @@ struct kvm_vcpu_arch { unsigned int hw_tsc_khz; unsigned int time_offset; struct page *time_page; - - struct { - u64 msr_val; - u64 last_steal; - u64 accum_steal; - struct gfn_to_hva_cache stime; - struct kvm_steal_time steal; - } st; - u64 last_guest_tsc; u64 last_kernel_ns; u64 last_tsc_nsec; @@ -428,11 +419,6 @@ struct kvm_vcpu_arch { u64 mcg_ctl; u64 *mce_banks; - /* Cache MMIO info */ - u64 mmio_gva; - unsigned access; - gfn_t mmio_gfn; - /* used for guest single stepping over the given code position */ unsigned long singlestep_rip; @@ -455,7 +441,6 @@ struct kvm_arch { unsigned int n_used_mmu_pages; unsigned int n_requested_mmu_pages; unsigned int n_max_mmu_pages; - unsigned int indirect_shadow_pages; atomic_t invlpg_counter; struct hlist_head mmu_page_hash[KVM_NUM_MMU_PAGES]; /* @@ -492,8 +477,6 @@ struct kvm_arch { u64 hv_guest_os_id; u64 hv_hypercall; - atomic_t reader_counter; - #ifdef CONFIG_KVM_MMU_AUDIT int audit_point; #endif @@ -576,7 +559,7 @@ struct kvm_x86_ops { void (*decache_cr4_guest_bits)(struct kvm_vcpu *vcpu); void (*set_cr0)(struct kvm_vcpu *vcpu, unsigned long cr0); void (*set_cr3)(struct kvm_vcpu *vcpu, unsigned long cr3); - int (*set_cr4)(struct kvm_vcpu *vcpu, unsigned long cr4); + void (*set_cr4)(struct kvm_vcpu *vcpu, unsigned long cr4); void (*set_efer)(struct kvm_vcpu *vcpu, u64 efer); void (*get_idt)(struct kvm_vcpu *vcpu, struct desc_ptr *dt); void (*set_idt)(struct kvm_vcpu *vcpu, struct desc_ptr *dt); @@ -653,6 +636,7 @@ void kvm_mmu_module_exit(void); void kvm_mmu_destroy(struct kvm_vcpu *vcpu); int kvm_mmu_create(struct kvm_vcpu *vcpu); int kvm_mmu_setup(struct kvm_vcpu *vcpu); +void kvm_mmu_set_nonpresent_ptes(u64 trap_pte, u64 notrap_pte); void kvm_mmu_set_mask_ptes(u64 user_mask, u64 accessed_mask, u64 dirty_mask, u64 nx_mask, u64 x_mask); @@ -846,12 +830,11 @@ enum { asmlinkage void kvm_spurious_fault(void); extern bool kvm_rebooting; -#define ____kvm_handle_fault_on_reboot(insn, cleanup_insn) \ +#define __kvm_handle_fault_on_reboot(insn) \ "666: " insn "\n\t" \ "668: \n\t" \ ".pushsection .fixup, \"ax\" \n" \ "667: \n\t" \ - cleanup_insn "\n\t" \ "cmpb $0, kvm_rebooting \n\t" \ "jne 668b \n\t" \ __ASM_SIZE(push) " $666b \n\t" \ @@ -861,9 +844,6 @@ extern bool kvm_rebooting; _ASM_PTR " 666b, 667b \n\t" \ ".popsection" -#define __kvm_handle_fault_on_reboot(insn) \ - ____kvm_handle_fault_on_reboot(insn, "") - #define KVM_ARCH_WANT_MMU_NOTIFIER int kvm_unmap_hva(struct kvm *kvm, unsigned long hva); int kvm_age_hva(struct kvm *kvm, unsigned long hva); diff --git a/trunk/arch/x86/include/asm/kvm_para.h b/trunk/arch/x86/include/asm/kvm_para.h index 734c3767cfac..a427bf77a93d 100644 --- a/trunk/arch/x86/include/asm/kvm_para.h +++ b/trunk/arch/x86/include/asm/kvm_para.h @@ -21,7 +21,6 @@ */ #define KVM_FEATURE_CLOCKSOURCE2 3 #define KVM_FEATURE_ASYNC_PF 4 -#define KVM_FEATURE_STEAL_TIME 5 /* The last 8 bits are used to indicate how to interpret the flags field * in pvclock structure. If no bits are set, all flags are ignored. @@ -31,23 +30,10 @@ #define MSR_KVM_WALL_CLOCK 0x11 #define MSR_KVM_SYSTEM_TIME 0x12 -#define KVM_MSR_ENABLED 1 /* Custom MSRs falls in the range 0x4b564d00-0x4b564dff */ #define MSR_KVM_WALL_CLOCK_NEW 0x4b564d00 #define MSR_KVM_SYSTEM_TIME_NEW 0x4b564d01 #define MSR_KVM_ASYNC_PF_EN 0x4b564d02 -#define MSR_KVM_STEAL_TIME 0x4b564d03 - -struct kvm_steal_time { - __u64 steal; - __u32 version; - __u32 flags; - __u32 pad[12]; -}; - -#define KVM_STEAL_ALIGNMENT_BITS 5 -#define KVM_STEAL_VALID_BITS ((-1ULL << (KVM_STEAL_ALIGNMENT_BITS + 1))) -#define KVM_STEAL_RESERVED_MASK (((1 << KVM_STEAL_ALIGNMENT_BITS) - 1 ) << 1) #define KVM_MAX_MMU_OP_BATCH 32 @@ -192,7 +178,6 @@ void __init kvm_guest_init(void); void kvm_async_pf_task_wait(u32 token); void kvm_async_pf_task_wake(u32 token); u32 kvm_read_and_reset_pf_reason(void); -extern void kvm_disable_steal_time(void); #else #define kvm_guest_init() do { } while (0) #define kvm_async_pf_task_wait(T) do {} while(0) @@ -201,11 +186,6 @@ static inline u32 kvm_read_and_reset_pf_reason(void) { return 0; } - -static inline void kvm_disable_steal_time(void) -{ - return; -} #endif #endif /* __KERNEL__ */ diff --git a/trunk/arch/x86/include/asm/mce.h b/trunk/arch/x86/include/asm/mce.h index 716b48af7863..021979a6e23f 100644 --- a/trunk/arch/x86/include/asm/mce.h +++ b/trunk/arch/x86/include/asm/mce.h @@ -8,7 +8,6 @@ * Machine Check support for x86 */ -/* MCG_CAP register defines */ #define MCG_BANKCNT_MASK 0xff /* Number of Banks */ #define MCG_CTL_P (1ULL<<8) /* MCG_CTL register available */ #define MCG_EXT_P (1ULL<<9) /* Extended registers available */ @@ -18,12 +17,10 @@ #define MCG_EXT_CNT(c) (((c) & MCG_EXT_CNT_MASK) >> MCG_EXT_CNT_SHIFT) #define MCG_SER_P (1ULL<<24) /* MCA recovery/new status bits */ -/* MCG_STATUS register defines */ #define MCG_STATUS_RIPV (1ULL<<0) /* restart ip valid */ #define MCG_STATUS_EIPV (1ULL<<1) /* ip points to correct instruction */ #define MCG_STATUS_MCIP (1ULL<<2) /* machine check in progress */ -/* MCi_STATUS register defines */ #define MCI_STATUS_VAL (1ULL<<63) /* valid error */ #define MCI_STATUS_OVER (1ULL<<62) /* previous errors lost */ #define MCI_STATUS_UC (1ULL<<61) /* uncorrected error */ @@ -34,14 +31,12 @@ #define MCI_STATUS_S (1ULL<<56) /* Signaled machine check */ #define MCI_STATUS_AR (1ULL<<55) /* Action required */ -/* MCi_MISC register defines */ -#define MCI_MISC_ADDR_LSB(m) ((m) & 0x3f) -#define MCI_MISC_ADDR_MODE(m) (((m) >> 6) & 7) -#define MCI_MISC_ADDR_SEGOFF 0 /* segment offset */ -#define MCI_MISC_ADDR_LINEAR 1 /* linear address */ -#define MCI_MISC_ADDR_PHYS 2 /* physical address */ -#define MCI_MISC_ADDR_MEM 3 /* memory address */ -#define MCI_MISC_ADDR_GENERIC 7 /* generic */ +/* MISC register defines */ +#define MCM_ADDR_SEGOFF 0 /* segment offset */ +#define MCM_ADDR_LINEAR 1 /* linear address */ +#define MCM_ADDR_PHYS 2 /* physical address */ +#define MCM_ADDR_MEM 3 /* memory address */ +#define MCM_ADDR_GENERIC 7 /* generic */ /* CTL2 register defines */ #define MCI_CTL2_CMCI_EN (1ULL << 30) @@ -149,7 +144,7 @@ static inline void enable_p5_mce(void) {} void mce_setup(struct mce *m); void mce_log(struct mce *m); -DECLARE_PER_CPU(struct sys_device, mce_sysdev); +DECLARE_PER_CPU(struct sys_device, mce_dev); /* * Maximum banks number. diff --git a/trunk/arch/x86/include/asm/mmzone_32.h b/trunk/arch/x86/include/asm/mmzone_32.h index 55728e121473..ffa037f28d39 100644 --- a/trunk/arch/x86/include/asm/mmzone_32.h +++ b/trunk/arch/x86/include/asm/mmzone_32.h @@ -34,15 +34,15 @@ static inline void resume_map_numa_kva(pgd_t *pgd) {} * 64Gb / 4096bytes/page = 16777216 pages */ #define MAX_NR_PAGES 16777216 -#define MAX_SECTIONS 1024 -#define PAGES_PER_SECTION (MAX_NR_PAGES/MAX_SECTIONS) +#define MAX_ELEMENTS 1024 +#define PAGES_PER_ELEMENT (MAX_NR_PAGES/MAX_ELEMENTS) extern s8 physnode_map[]; static inline int pfn_to_nid(unsigned long pfn) { #ifdef CONFIG_NUMA - return((int) physnode_map[(pfn) / PAGES_PER_SECTION]); + return((int) physnode_map[(pfn) / PAGES_PER_ELEMENT]); #else return 0; #endif diff --git a/trunk/arch/x86/include/asm/msr-index.h b/trunk/arch/x86/include/asm/msr-index.h index d52609aeeab8..485b4f1f079b 100644 --- a/trunk/arch/x86/include/asm/msr-index.h +++ b/trunk/arch/x86/include/asm/msr-index.h @@ -259,9 +259,6 @@ #define MSR_IA32_TEMPERATURE_TARGET 0x000001a2 #define MSR_IA32_ENERGY_PERF_BIAS 0x000001b0 -#define ENERGY_PERF_BIAS_PERFORMANCE 0 -#define ENERGY_PERF_BIAS_NORMAL 6 -#define ENERGY_PERF_BIAS_POWERSAVE 15 #define MSR_IA32_PACKAGE_THERM_STATUS 0x000001b1 @@ -441,18 +438,6 @@ #define MSR_IA32_VMX_VMCS_ENUM 0x0000048a #define MSR_IA32_VMX_PROCBASED_CTLS2 0x0000048b #define MSR_IA32_VMX_EPT_VPID_CAP 0x0000048c -#define MSR_IA32_VMX_TRUE_PINBASED_CTLS 0x0000048d -#define MSR_IA32_VMX_TRUE_PROCBASED_CTLS 0x0000048e -#define MSR_IA32_VMX_TRUE_EXIT_CTLS 0x0000048f -#define MSR_IA32_VMX_TRUE_ENTRY_CTLS 0x00000490 - -/* VMX_BASIC bits and bitmasks */ -#define VMX_BASIC_VMCS_SIZE_SHIFT 32 -#define VMX_BASIC_64 0x0001000000000000LLU -#define VMX_BASIC_MEM_TYPE_SHIFT 50 -#define VMX_BASIC_MEM_TYPE_MASK 0x003c000000000000LLU -#define VMX_BASIC_MEM_TYPE_WB 6LLU -#define VMX_BASIC_INOUT 0x0040000000000000LLU /* AMD-V MSRs */ diff --git a/trunk/arch/x86/include/asm/paravirt.h b/trunk/arch/x86/include/asm/paravirt.h index a7d2db9a74fb..ebbc4d8ab170 100644 --- a/trunk/arch/x86/include/asm/paravirt.h +++ b/trunk/arch/x86/include/asm/paravirt.h @@ -230,15 +230,6 @@ static inline unsigned long long paravirt_sched_clock(void) return PVOP_CALL0(unsigned long long, pv_time_ops.sched_clock); } -struct jump_label_key; -extern struct jump_label_key paravirt_steal_enabled; -extern struct jump_label_key paravirt_steal_rq_enabled; - -static inline u64 paravirt_steal_clock(int cpu) -{ - return PVOP_CALL1(u64, pv_time_ops.steal_clock, cpu); -} - static inline unsigned long long paravirt_read_pmc(int counter) { return PVOP_CALL1(u64, pv_cpu_ops.read_pmc, counter); diff --git a/trunk/arch/x86/include/asm/paravirt_types.h b/trunk/arch/x86/include/asm/paravirt_types.h index 2c7652163111..82885099c869 100644 --- a/trunk/arch/x86/include/asm/paravirt_types.h +++ b/trunk/arch/x86/include/asm/paravirt_types.h @@ -89,7 +89,6 @@ struct pv_lazy_ops { struct pv_time_ops { unsigned long long (*sched_clock)(void); - unsigned long long (*steal_clock)(int cpu); unsigned long (*get_tsc_khz)(void); }; diff --git a/trunk/arch/x86/include/asm/perf_event.h b/trunk/arch/x86/include/asm/perf_event.h index 094fb30817ab..d9d4dae305f6 100644 --- a/trunk/arch/x86/include/asm/perf_event.h +++ b/trunk/arch/x86/include/asm/perf_event.h @@ -152,11 +152,6 @@ extern unsigned long perf_misc_flags(struct pt_regs *regs); (regs)->bp = caller_frame_pointer(); \ (regs)->cs = __KERNEL_CS; \ regs->flags = 0; \ - asm volatile( \ - _ASM_MOV "%%"_ASM_SP ", %0\n" \ - : "=m" ((regs)->sp) \ - :: "memory" \ - ); \ } #else diff --git a/trunk/arch/x86/include/asm/perf_event_p4.h b/trunk/arch/x86/include/asm/perf_event_p4.h index 4f7e67e2345e..56fd9e3abbda 100644 --- a/trunk/arch/x86/include/asm/perf_event_p4.h +++ b/trunk/arch/x86/include/asm/perf_event_p4.h @@ -101,14 +101,6 @@ #define P4_CONFIG_HT_SHIFT 63 #define P4_CONFIG_HT (1ULL << P4_CONFIG_HT_SHIFT) -/* - * If an event has alias it should be marked - * with a special bit. (Don't forget to check - * P4_PEBS_CONFIG_MASK and related bits on - * modification.) - */ -#define P4_CONFIG_ALIASABLE (1 << 9) - /* * The bits we allow to pass for RAW events */ @@ -131,31 +123,6 @@ (p4_config_pack_escr(P4_CONFIG_MASK_ESCR)) | \ (p4_config_pack_cccr(P4_CONFIG_MASK_CCCR)) -/* - * In case of event aliasing we need to preserve some - * caller bits, otherwise the mapping won't be complete. - */ -#define P4_CONFIG_EVENT_ALIAS_MASK \ - (p4_config_pack_escr(P4_CONFIG_MASK_ESCR) | \ - p4_config_pack_cccr(P4_CCCR_EDGE | \ - P4_CCCR_THRESHOLD_MASK | \ - P4_CCCR_COMPLEMENT | \ - P4_CCCR_COMPARE)) - -#define P4_CONFIG_EVENT_ALIAS_IMMUTABLE_BITS \ - ((P4_CONFIG_HT) | \ - p4_config_pack_escr(P4_ESCR_T0_OS | \ - P4_ESCR_T0_USR | \ - P4_ESCR_T1_OS | \ - P4_ESCR_T1_USR) | \ - p4_config_pack_cccr(P4_CCCR_OVF | \ - P4_CCCR_CASCADE | \ - P4_CCCR_FORCE_OVF | \ - P4_CCCR_THREAD_ANY | \ - P4_CCCR_OVF_PMI_T0 | \ - P4_CCCR_OVF_PMI_T1 | \ - P4_CONFIG_ALIASABLE)) - static inline bool p4_is_event_cascaded(u64 config) { u32 cccr = p4_config_unpack_cccr(config); diff --git a/trunk/arch/x86/include/asm/pgtable_types.h b/trunk/arch/x86/include/asm/pgtable_types.h index 013286a10c2c..d56187c6b838 100644 --- a/trunk/arch/x86/include/asm/pgtable_types.h +++ b/trunk/arch/x86/include/asm/pgtable_types.h @@ -107,8 +107,7 @@ #define __PAGE_KERNEL_NOCACHE (__PAGE_KERNEL | _PAGE_PCD | _PAGE_PWT) #define __PAGE_KERNEL_UC_MINUS (__PAGE_KERNEL | _PAGE_PCD) #define __PAGE_KERNEL_VSYSCALL (__PAGE_KERNEL_RX | _PAGE_USER) -#define __PAGE_KERNEL_VVAR (__PAGE_KERNEL_RO | _PAGE_USER) -#define __PAGE_KERNEL_VVAR_NOCACHE (__PAGE_KERNEL_VVAR | _PAGE_PCD | _PAGE_PWT) +#define __PAGE_KERNEL_VSYSCALL_NOCACHE (__PAGE_KERNEL_VSYSCALL | _PAGE_PCD | _PAGE_PWT) #define __PAGE_KERNEL_LARGE (__PAGE_KERNEL | _PAGE_PSE) #define __PAGE_KERNEL_LARGE_NOCACHE (__PAGE_KERNEL | _PAGE_CACHE_UC | _PAGE_PSE) #define __PAGE_KERNEL_LARGE_EXEC (__PAGE_KERNEL_EXEC | _PAGE_PSE) @@ -130,8 +129,7 @@ #define PAGE_KERNEL_LARGE_NOCACHE __pgprot(__PAGE_KERNEL_LARGE_NOCACHE) #define PAGE_KERNEL_LARGE_EXEC __pgprot(__PAGE_KERNEL_LARGE_EXEC) #define PAGE_KERNEL_VSYSCALL __pgprot(__PAGE_KERNEL_VSYSCALL) -#define PAGE_KERNEL_VVAR __pgprot(__PAGE_KERNEL_VVAR) -#define PAGE_KERNEL_VVAR_NOCACHE __pgprot(__PAGE_KERNEL_VVAR_NOCACHE) +#define PAGE_KERNEL_VSYSCALL_NOCACHE __pgprot(__PAGE_KERNEL_VSYSCALL_NOCACHE) #define PAGE_KERNEL_IO __pgprot(__PAGE_KERNEL_IO) #define PAGE_KERNEL_IO_NOCACHE __pgprot(__PAGE_KERNEL_IO_NOCACHE) diff --git a/trunk/arch/x86/include/asm/processor-flags.h b/trunk/arch/x86/include/asm/processor-flags.h index 2dddb317bb39..59ab4dffa377 100644 --- a/trunk/arch/x86/include/asm/processor-flags.h +++ b/trunk/arch/x86/include/asm/processor-flags.h @@ -59,7 +59,6 @@ #define X86_CR4_OSFXSR 0x00000200 /* enable fast FPU save and restore */ #define X86_CR4_OSXMMEXCPT 0x00000400 /* enable unmasked SSE exceptions */ #define X86_CR4_VMXE 0x00002000 /* enable VMX virtualization */ -#define X86_CR4_RDWRGSFS 0x00010000 /* enable RDWRGSFS support */ #define X86_CR4_OSXSAVE 0x00040000 /* enable xsave and xrestore */ #define X86_CR4_SMEP 0x00100000 /* enable SMEP support */ diff --git a/trunk/arch/x86/include/asm/rwlock.h b/trunk/arch/x86/include/asm/rwlock.h index a5370a03d90c..6a8c0d645108 100644 --- a/trunk/arch/x86/include/asm/rwlock.h +++ b/trunk/arch/x86/include/asm/rwlock.h @@ -1,48 +1,7 @@ #ifndef _ASM_X86_RWLOCK_H #define _ASM_X86_RWLOCK_H -#include - -#if CONFIG_NR_CPUS <= 2048 - -#ifndef __ASSEMBLY__ -typedef union { - s32 lock; - s32 write; -} arch_rwlock_t; -#endif - -#define RW_LOCK_BIAS 0x00100000 -#define READ_LOCK_SIZE(insn) __ASM_FORM(insn##l) -#define READ_LOCK_ATOMIC(n) atomic_##n -#define WRITE_LOCK_ADD(n) __ASM_FORM_COMMA(addl n) -#define WRITE_LOCK_SUB(n) __ASM_FORM_COMMA(subl n) -#define WRITE_LOCK_CMP RW_LOCK_BIAS - -#else /* CONFIG_NR_CPUS > 2048 */ - -#include - -#ifndef __ASSEMBLY__ -typedef union { - s64 lock; - struct { - u32 read; - s32 write; - }; -} arch_rwlock_t; -#endif - -#define RW_LOCK_BIAS (_AC(1,L) << 32) -#define READ_LOCK_SIZE(insn) __ASM_FORM(insn##q) -#define READ_LOCK_ATOMIC(n) atomic64_##n -#define WRITE_LOCK_ADD(n) __ASM_FORM(incl) -#define WRITE_LOCK_SUB(n) __ASM_FORM(decl) -#define WRITE_LOCK_CMP 1 - -#endif /* CONFIG_NR_CPUS */ - -#define __ARCH_RW_LOCK_UNLOCKED { RW_LOCK_BIAS } +#define RW_LOCK_BIAS 0x01000000 /* Actual code is in asm/spinlock.h or in arch/x86/lib/rwlock.S */ diff --git a/trunk/arch/x86/include/asm/segment.h b/trunk/arch/x86/include/asm/segment.h index 5e641715c3fe..cd84f7208f76 100644 --- a/trunk/arch/x86/include/asm/segment.h +++ b/trunk/arch/x86/include/asm/segment.h @@ -162,7 +162,7 @@ #define GDT_ENTRY_DEFAULT_USER32_CS 4 #define GDT_ENTRY_DEFAULT_USER_DS 5 #define GDT_ENTRY_DEFAULT_USER_CS 6 -#define __USER32_CS (GDT_ENTRY_DEFAULT_USER32_CS*8+3) +#define __USER32_CS (GDT_ENTRY_DEFAULT_USER32_CS * 8 + 3) #define __USER32_DS __USER_DS #define GDT_ENTRY_TSS 8 /* needs two entries */ diff --git a/trunk/arch/x86/include/asm/smpboot_hooks.h b/trunk/arch/x86/include/asm/smpboot_hooks.h index 49adfd7bb4a4..725b77831993 100644 --- a/trunk/arch/x86/include/asm/smpboot_hooks.h +++ b/trunk/arch/x86/include/asm/smpboot_hooks.h @@ -10,11 +10,7 @@ static inline void smpboot_clear_io_apic_irqs(void) static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip) { - unsigned long flags; - - spin_lock_irqsave(&rtc_lock, flags); CMOS_WRITE(0xa, 0xf); - spin_unlock_irqrestore(&rtc_lock, flags); local_flush_tlb(); pr_debug("1.\n"); *((volatile unsigned short *)phys_to_virt(apic->trampoline_phys_high)) = @@ -27,8 +23,6 @@ static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip) static inline void smpboot_restore_warm_reset_vector(void) { - unsigned long flags; - /* * Install writable page 0 entry to set BIOS data area. */ @@ -38,9 +32,7 @@ static inline void smpboot_restore_warm_reset_vector(void) * Paranoid: Set warm reset code and vector here back * to default values. */ - spin_lock_irqsave(&rtc_lock, flags); CMOS_WRITE(0, 0xf); - spin_unlock_irqrestore(&rtc_lock, flags); *((volatile u32 *)phys_to_virt(apic->trampoline_phys_low)) = 0; } diff --git a/trunk/arch/x86/include/asm/spinlock.h b/trunk/arch/x86/include/asm/spinlock.h index e9e51f710e6c..3089f70c0c52 100644 --- a/trunk/arch/x86/include/asm/spinlock.h +++ b/trunk/arch/x86/include/asm/spinlock.h @@ -2,6 +2,7 @@ #define _ASM_X86_SPINLOCK_H #include +#include #include #include #include @@ -233,7 +234,7 @@ static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) */ static inline int arch_read_can_lock(arch_rwlock_t *lock) { - return lock->lock > 0; + return (int)(lock)->lock > 0; } /** @@ -242,12 +243,12 @@ static inline int arch_read_can_lock(arch_rwlock_t *lock) */ static inline int arch_write_can_lock(arch_rwlock_t *lock) { - return lock->write == WRITE_LOCK_CMP; + return (lock)->lock == RW_LOCK_BIAS; } static inline void arch_read_lock(arch_rwlock_t *rw) { - asm volatile(LOCK_PREFIX READ_LOCK_SIZE(dec) " (%0)\n\t" + asm volatile(LOCK_PREFIX " subl $1,(%0)\n\t" "jns 1f\n" "call __read_lock_failed\n\t" "1:\n" @@ -256,55 +257,47 @@ static inline void arch_read_lock(arch_rwlock_t *rw) static inline void arch_write_lock(arch_rwlock_t *rw) { - asm volatile(LOCK_PREFIX WRITE_LOCK_SUB(%1) "(%0)\n\t" + asm volatile(LOCK_PREFIX " subl %1,(%0)\n\t" "jz 1f\n" "call __write_lock_failed\n\t" "1:\n" - ::LOCK_PTR_REG (&rw->write), "i" (RW_LOCK_BIAS) - : "memory"); + ::LOCK_PTR_REG (rw), "i" (RW_LOCK_BIAS) : "memory"); } static inline int arch_read_trylock(arch_rwlock_t *lock) { - READ_LOCK_ATOMIC(t) *count = (READ_LOCK_ATOMIC(t) *)lock; + atomic_t *count = (atomic_t *)lock; - if (READ_LOCK_ATOMIC(dec_return)(count) >= 0) + if (atomic_dec_return(count) >= 0) return 1; - READ_LOCK_ATOMIC(inc)(count); + atomic_inc(count); return 0; } static inline int arch_write_trylock(arch_rwlock_t *lock) { - atomic_t *count = (atomic_t *)&lock->write; + atomic_t *count = (atomic_t *)lock; - if (atomic_sub_and_test(WRITE_LOCK_CMP, count)) + if (atomic_sub_and_test(RW_LOCK_BIAS, count)) return 1; - atomic_add(WRITE_LOCK_CMP, count); + atomic_add(RW_LOCK_BIAS, count); return 0; } static inline void arch_read_unlock(arch_rwlock_t *rw) { - asm volatile(LOCK_PREFIX READ_LOCK_SIZE(inc) " %0" - :"+m" (rw->lock) : : "memory"); + asm volatile(LOCK_PREFIX "incl %0" :"+m" (rw->lock) : : "memory"); } static inline void arch_write_unlock(arch_rwlock_t *rw) { - asm volatile(LOCK_PREFIX WRITE_LOCK_ADD(%1) "%0" - : "+m" (rw->write) : "i" (RW_LOCK_BIAS) : "memory"); + asm volatile(LOCK_PREFIX "addl %1, %0" + : "+m" (rw->lock) : "i" (RW_LOCK_BIAS) : "memory"); } #define arch_read_lock_flags(lock, flags) arch_read_lock(lock) #define arch_write_lock_flags(lock, flags) arch_write_lock(lock) -#undef READ_LOCK_SIZE -#undef READ_LOCK_ATOMIC -#undef WRITE_LOCK_ADD -#undef WRITE_LOCK_SUB -#undef WRITE_LOCK_CMP - #define arch_spin_relax(lock) cpu_relax() #define arch_read_relax(lock) cpu_relax() #define arch_write_relax(lock) cpu_relax() diff --git a/trunk/arch/x86/include/asm/spinlock_types.h b/trunk/arch/x86/include/asm/spinlock_types.h index 7c7a486fcb68..dcb48b2edc11 100644 --- a/trunk/arch/x86/include/asm/spinlock_types.h +++ b/trunk/arch/x86/include/asm/spinlock_types.h @@ -11,6 +11,10 @@ typedef struct arch_spinlock { #define __ARCH_SPIN_LOCK_UNLOCKED { 0 } -#include +typedef struct { + unsigned int lock; +} arch_rwlock_t; + +#define __ARCH_RW_LOCK_UNLOCKED { RW_LOCK_BIAS } #endif /* _ASM_X86_SPINLOCK_TYPES_H */ diff --git a/trunk/arch/x86/include/asm/time.h b/trunk/arch/x86/include/asm/time.h index 92b8aec06970..7bdec4e9b739 100644 --- a/trunk/arch/x86/include/asm/time.h +++ b/trunk/arch/x86/include/asm/time.h @@ -1,12 +1,10 @@ #ifndef _ASM_X86_TIME_H #define _ASM_X86_TIME_H -#include +extern void hpet_time_init(void); + #include -extern void hpet_time_init(void); extern void time_init(void); -extern struct clock_event_device *global_clock_event; - #endif /* _ASM_X86_TIME_H */ diff --git a/trunk/arch/x86/include/asm/traps.h b/trunk/arch/x86/include/asm/traps.h index 2bae0a513b40..0310da67307f 100644 --- a/trunk/arch/x86/include/asm/traps.h +++ b/trunk/arch/x86/include/asm/traps.h @@ -1,8 +1,6 @@ #ifndef _ASM_X86_TRAPS_H #define _ASM_X86_TRAPS_H -#include - #include #include /* TRAP_TRACE, ... */ @@ -40,7 +38,6 @@ asmlinkage void alignment_check(void); asmlinkage void machine_check(void); #endif /* CONFIG_X86_MCE */ asmlinkage void simd_coprocessor_error(void); -asmlinkage void emulate_vsyscall(void); dotraplinkage void do_divide_error(struct pt_regs *, long); dotraplinkage void do_debug(struct pt_regs *, long); @@ -67,7 +64,6 @@ dotraplinkage void do_alignment_check(struct pt_regs *, long); dotraplinkage void do_machine_check(struct pt_regs *, long); #endif dotraplinkage void do_simd_coprocessor_error(struct pt_regs *, long); -dotraplinkage void do_emulate_vsyscall(struct pt_regs *, long); #ifdef CONFIG_X86_32 dotraplinkage void do_iret_error(struct pt_regs *, long); #endif diff --git a/trunk/arch/x86/include/asm/tsc.h b/trunk/arch/x86/include/asm/tsc.h index 83e2efd181e2..9db5583b6d38 100644 --- a/trunk/arch/x86/include/asm/tsc.h +++ b/trunk/arch/x86/include/asm/tsc.h @@ -51,6 +51,10 @@ extern int unsynchronized_tsc(void); extern int check_tsc_unstable(void); extern unsigned long native_calibrate_tsc(void); +#ifdef CONFIG_X86_64 +extern cycles_t vread_tsc(void); +#endif + /* * Boot-time check whether the TSCs are synchronized across * all CPUs/cores: diff --git a/trunk/arch/x86/include/asm/uaccess.h b/trunk/arch/x86/include/asm/uaccess.h index 36361bf6fdd1..99ddd148a760 100644 --- a/trunk/arch/x86/include/asm/uaccess.h +++ b/trunk/arch/x86/include/asm/uaccess.h @@ -555,9 +555,6 @@ struct __large_struct { unsigned long buf[100]; }; #endif /* CONFIG_X86_WP_WORKS_OK */ -extern unsigned long -copy_from_user_nmi(void *to, const void __user *from, unsigned long n); - /* * movsl can be slow when source and dest are not both 8-byte aligned */ diff --git a/trunk/arch/x86/include/asm/uv/uv_bau.h b/trunk/arch/x86/include/asm/uv/uv_bau.h index 37d369859c8e..a291c40efd43 100644 --- a/trunk/arch/x86/include/asm/uv/uv_bau.h +++ b/trunk/arch/x86/include/asm/uv/uv_bau.h @@ -67,7 +67,7 @@ * we're using 655us, similar to UV1: 65 units of 10us */ #define UV1_INTD_SOFT_ACK_TIMEOUT_PERIOD (9UL) -#define UV2_INTD_SOFT_ACK_TIMEOUT_PERIOD (15UL) +#define UV2_INTD_SOFT_ACK_TIMEOUT_PERIOD (65*10UL) #define UV_INTD_SOFT_ACK_TIMEOUT_PERIOD (is_uv1_hub() ? \ UV1_INTD_SOFT_ACK_TIMEOUT_PERIOD : \ @@ -106,20 +106,12 @@ #define DS_SOURCE_TIMEOUT 3 /* * bits put together from HRP_LB_BAU_SB_ACTIVATION_STATUS_0/1/2 - * values 1 and 3 will not occur - * Decoded meaning ERROR BUSY AUX ERR - * ------------------------------- ---- ----- ------- - * IDLE 0 0 0 - * BUSY (active) 0 1 0 - * SW Ack Timeout (destination) 1 0 0 - * SW Ack INTD rejected (strong NACK) 1 0 1 - * Source Side Time Out Detected 1 1 0 - * Destination Side PUT Failed 1 1 1 + * values 1 and 5 will not occur */ #define UV2H_DESC_IDLE 0 -#define UV2H_DESC_BUSY 2 -#define UV2H_DESC_DEST_TIMEOUT 4 -#define UV2H_DESC_DEST_STRONG_NACK 5 +#define UV2H_DESC_DEST_TIMEOUT 2 +#define UV2H_DESC_DEST_STRONG_NACK 3 +#define UV2H_DESC_BUSY 4 #define UV2H_DESC_SOURCE_TIMEOUT 6 #define UV2H_DESC_DEST_PUT_ERR 7 @@ -191,7 +183,7 @@ * 'base_dest_nasid' field of the header corresponds to the * destination nodeID associated with that specified bit. */ -struct pnmask { +struct bau_targ_hubmask { unsigned long bits[BITS_TO_LONGS(UV_DISTRIBUTION_SIZE)]; }; @@ -322,7 +314,7 @@ struct bau_msg_header { * Should be 64 bytes */ struct bau_desc { - struct pnmask distribution; + struct bau_targ_hubmask distribution; /* * message template, consisting of header and payload: */ @@ -496,7 +488,6 @@ struct bau_control { struct bau_control *uvhub_master; struct bau_control *socket_master; struct ptc_stats *statp; - cpumask_t *cpumask; unsigned long timeout_interval; unsigned long set_bau_on_time; atomic_t active_descriptor_count; @@ -535,90 +526,90 @@ struct bau_control { struct hub_and_pnode *thp; }; -static inline unsigned long read_mmr_uv2_status(void) +static unsigned long read_mmr_uv2_status(void) { return read_lmmr(UV2H_LB_BAU_SB_ACTIVATION_STATUS_2); } -static inline void write_mmr_data_broadcast(int pnode, unsigned long mmr_image) +static void write_mmr_data_broadcast(int pnode, unsigned long mmr_image) { write_gmmr(pnode, UVH_BAU_DATA_BROADCAST, mmr_image); } -static inline void write_mmr_descriptor_base(int pnode, unsigned long mmr_image) +static void write_mmr_descriptor_base(int pnode, unsigned long mmr_image) { write_gmmr(pnode, UVH_LB_BAU_SB_DESCRIPTOR_BASE, mmr_image); } -static inline void write_mmr_activation(unsigned long index) +static void write_mmr_activation(unsigned long index) { write_lmmr(UVH_LB_BAU_SB_ACTIVATION_CONTROL, index); } -static inline void write_gmmr_activation(int pnode, unsigned long mmr_image) +static void write_gmmr_activation(int pnode, unsigned long mmr_image) { write_gmmr(pnode, UVH_LB_BAU_SB_ACTIVATION_CONTROL, mmr_image); } -static inline void write_mmr_payload_first(int pnode, unsigned long mmr_image) +static void write_mmr_payload_first(int pnode, unsigned long mmr_image) { write_gmmr(pnode, UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST, mmr_image); } -static inline void write_mmr_payload_tail(int pnode, unsigned long mmr_image) +static void write_mmr_payload_tail(int pnode, unsigned long mmr_image) { write_gmmr(pnode, UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL, mmr_image); } -static inline void write_mmr_payload_last(int pnode, unsigned long mmr_image) +static void write_mmr_payload_last(int pnode, unsigned long mmr_image) { write_gmmr(pnode, UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST, mmr_image); } -static inline void write_mmr_misc_control(int pnode, unsigned long mmr_image) +static void write_mmr_misc_control(int pnode, unsigned long mmr_image) { write_gmmr(pnode, UVH_LB_BAU_MISC_CONTROL, mmr_image); } -static inline unsigned long read_mmr_misc_control(int pnode) +static unsigned long read_mmr_misc_control(int pnode) { return read_gmmr(pnode, UVH_LB_BAU_MISC_CONTROL); } -static inline void write_mmr_sw_ack(unsigned long mr) +static void write_mmr_sw_ack(unsigned long mr) { uv_write_local_mmr(UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS, mr); } -static inline unsigned long read_mmr_sw_ack(void) +static unsigned long read_mmr_sw_ack(void) { return read_lmmr(UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE); } -static inline unsigned long read_gmmr_sw_ack(int pnode) +static unsigned long read_gmmr_sw_ack(int pnode) { return read_gmmr(pnode, UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE); } -static inline void write_mmr_data_config(int pnode, unsigned long mr) +static void write_mmr_data_config(int pnode, unsigned long mr) { uv_write_global_mmr64(pnode, UVH_BAU_DATA_CONFIG, mr); } -static inline int bau_uvhub_isset(int uvhub, struct pnmask *dstp) +static inline int bau_uvhub_isset(int uvhub, struct bau_targ_hubmask *dstp) { return constant_test_bit(uvhub, &dstp->bits[0]); } -static inline void bau_uvhub_set(int pnode, struct pnmask *dstp) +static inline void bau_uvhub_set(int pnode, struct bau_targ_hubmask *dstp) { __set_bit(pnode, &dstp->bits[0]); } -static inline void bau_uvhubs_clear(struct pnmask *dstp, +static inline void bau_uvhubs_clear(struct bau_targ_hubmask *dstp, int nbits) { bitmap_zero(&dstp->bits[0], nbits); } -static inline int bau_uvhub_weight(struct pnmask *dstp) +static inline int bau_uvhub_weight(struct bau_targ_hubmask *dstp) { return bitmap_weight((unsigned long *)&dstp->bits[0], UV_DISTRIBUTION_SIZE); diff --git a/trunk/arch/x86/include/asm/uv/uv_mmrs.h b/trunk/arch/x86/include/asm/uv/uv_mmrs.h index 10474fb1185d..4be52c863448 100644 --- a/trunk/arch/x86/include/asm/uv/uv_mmrs.h +++ b/trunk/arch/x86/include/asm/uv/uv_mmrs.h @@ -61,2016 +61,1689 @@ /* Compat: if this #define is present, UV headers support UV2 */ #define UV2_HUB_IS_SUPPORTED 1 +/* KABI compat: if this #define is present, KABI hacks are present */ +#define UV2_HUB_KABI_HACKS 1 + /* ========================================================================= */ /* UVH_BAU_DATA_BROADCAST */ /* ========================================================================= */ -#define UVH_BAU_DATA_BROADCAST 0x61688UL -#define UVH_BAU_DATA_BROADCAST_32 0x440 +#define UVH_BAU_DATA_BROADCAST 0x61688UL +#define UVH_BAU_DATA_BROADCAST_32 0x440 -#define UVH_BAU_DATA_BROADCAST_ENABLE_SHFT 0 -#define UVH_BAU_DATA_BROADCAST_ENABLE_MASK 0x0000000000000001UL +#define UVH_BAU_DATA_BROADCAST_ENABLE_SHFT 0 +#define UVH_BAU_DATA_BROADCAST_ENABLE_MASK 0x0000000000000001UL union uvh_bau_data_broadcast_u { - unsigned long v; - struct uvh_bau_data_broadcast_s { - unsigned long enable:1; /* RW */ - unsigned long rsvd_1_63:63; - } s; + unsigned long v; + struct uvh_bau_data_broadcast_s { + unsigned long enable : 1; /* RW */ + unsigned long rsvd_1_63: 63; /* */ + } s; }; /* ========================================================================= */ /* UVH_BAU_DATA_CONFIG */ /* ========================================================================= */ -#define UVH_BAU_DATA_CONFIG 0x61680UL -#define UVH_BAU_DATA_CONFIG_32 0x438 - -#define UVH_BAU_DATA_CONFIG_VECTOR_SHFT 0 -#define UVH_BAU_DATA_CONFIG_DM_SHFT 8 -#define UVH_BAU_DATA_CONFIG_DESTMODE_SHFT 11 -#define UVH_BAU_DATA_CONFIG_STATUS_SHFT 12 -#define UVH_BAU_DATA_CONFIG_P_SHFT 13 -#define UVH_BAU_DATA_CONFIG_T_SHFT 15 -#define UVH_BAU_DATA_CONFIG_M_SHFT 16 -#define UVH_BAU_DATA_CONFIG_APIC_ID_SHFT 32 -#define UVH_BAU_DATA_CONFIG_VECTOR_MASK 0x00000000000000ffUL -#define UVH_BAU_DATA_CONFIG_DM_MASK 0x0000000000000700UL -#define UVH_BAU_DATA_CONFIG_DESTMODE_MASK 0x0000000000000800UL -#define UVH_BAU_DATA_CONFIG_STATUS_MASK 0x0000000000001000UL -#define UVH_BAU_DATA_CONFIG_P_MASK 0x0000000000002000UL -#define UVH_BAU_DATA_CONFIG_T_MASK 0x0000000000008000UL -#define UVH_BAU_DATA_CONFIG_M_MASK 0x0000000000010000UL -#define UVH_BAU_DATA_CONFIG_APIC_ID_MASK 0xffffffff00000000UL +#define UVH_BAU_DATA_CONFIG 0x61680UL +#define UVH_BAU_DATA_CONFIG_32 0x438 + +#define UVH_BAU_DATA_CONFIG_VECTOR_SHFT 0 +#define UVH_BAU_DATA_CONFIG_VECTOR_MASK 0x00000000000000ffUL +#define UVH_BAU_DATA_CONFIG_DM_SHFT 8 +#define UVH_BAU_DATA_CONFIG_DM_MASK 0x0000000000000700UL +#define UVH_BAU_DATA_CONFIG_DESTMODE_SHFT 11 +#define UVH_BAU_DATA_CONFIG_DESTMODE_MASK 0x0000000000000800UL +#define UVH_BAU_DATA_CONFIG_STATUS_SHFT 12 +#define UVH_BAU_DATA_CONFIG_STATUS_MASK 0x0000000000001000UL +#define UVH_BAU_DATA_CONFIG_P_SHFT 13 +#define UVH_BAU_DATA_CONFIG_P_MASK 0x0000000000002000UL +#define UVH_BAU_DATA_CONFIG_T_SHFT 15 +#define UVH_BAU_DATA_CONFIG_T_MASK 0x0000000000008000UL +#define UVH_BAU_DATA_CONFIG_M_SHFT 16 +#define UVH_BAU_DATA_CONFIG_M_MASK 0x0000000000010000UL +#define UVH_BAU_DATA_CONFIG_APIC_ID_SHFT 32 +#define UVH_BAU_DATA_CONFIG_APIC_ID_MASK 0xffffffff00000000UL union uvh_bau_data_config_u { - unsigned long v; - struct uvh_bau_data_config_s { - unsigned long vector_:8; /* RW */ - unsigned long dm:3; /* RW */ - unsigned long destmode:1; /* RW */ - unsigned long status:1; /* RO */ - unsigned long p:1; /* RO */ - unsigned long rsvd_14:1; - unsigned long t:1; /* RO */ - unsigned long m:1; /* RW */ - unsigned long rsvd_17_31:15; - unsigned long apic_id:32; /* RW */ - } s; + unsigned long v; + struct uvh_bau_data_config_s { + unsigned long vector_ : 8; /* RW */ + unsigned long dm : 3; /* RW */ + unsigned long destmode : 1; /* RW */ + unsigned long status : 1; /* RO */ + unsigned long p : 1; /* RO */ + unsigned long rsvd_14 : 1; /* */ + unsigned long t : 1; /* RO */ + unsigned long m : 1; /* RW */ + unsigned long rsvd_17_31: 15; /* */ + unsigned long apic_id : 32; /* RW */ + } s; }; /* ========================================================================= */ /* UVH_EVENT_OCCURRED0 */ /* ========================================================================= */ -#define UVH_EVENT_OCCURRED0 0x70000UL -#define UVH_EVENT_OCCURRED0_32 0x5e8 - -#define UV1H_EVENT_OCCURRED0_LB_HCERR_SHFT 0 -#define UV1H_EVENT_OCCURRED0_GR0_HCERR_SHFT 1 -#define UV1H_EVENT_OCCURRED0_GR1_HCERR_SHFT 2 -#define UV1H_EVENT_OCCURRED0_LH_HCERR_SHFT 3 -#define UV1H_EVENT_OCCURRED0_RH_HCERR_SHFT 4 -#define UV1H_EVENT_OCCURRED0_XN_HCERR_SHFT 5 -#define UV1H_EVENT_OCCURRED0_SI_HCERR_SHFT 6 -#define UV1H_EVENT_OCCURRED0_LB_AOERR0_SHFT 7 -#define UV1H_EVENT_OCCURRED0_GR0_AOERR0_SHFT 8 -#define UV1H_EVENT_OCCURRED0_GR1_AOERR0_SHFT 9 -#define UV1H_EVENT_OCCURRED0_LH_AOERR0_SHFT 10 -#define UV1H_EVENT_OCCURRED0_RH_AOERR0_SHFT 11 -#define UV1H_EVENT_OCCURRED0_XN_AOERR0_SHFT 12 -#define UV1H_EVENT_OCCURRED0_SI_AOERR0_SHFT 13 -#define UV1H_EVENT_OCCURRED0_LB_AOERR1_SHFT 14 -#define UV1H_EVENT_OCCURRED0_GR0_AOERR1_SHFT 15 -#define UV1H_EVENT_OCCURRED0_GR1_AOERR1_SHFT 16 -#define UV1H_EVENT_OCCURRED0_LH_AOERR1_SHFT 17 -#define UV1H_EVENT_OCCURRED0_RH_AOERR1_SHFT 18 -#define UV1H_EVENT_OCCURRED0_XN_AOERR1_SHFT 19 -#define UV1H_EVENT_OCCURRED0_SI_AOERR1_SHFT 20 -#define UV1H_EVENT_OCCURRED0_RH_VPI_INT_SHFT 21 -#define UV1H_EVENT_OCCURRED0_SYSTEM_SHUTDOWN_INT_SHFT 22 -#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_0_SHFT 23 -#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_1_SHFT 24 -#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_2_SHFT 25 -#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_3_SHFT 26 -#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_4_SHFT 27 -#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_5_SHFT 28 -#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_6_SHFT 29 -#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_7_SHFT 30 -#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_8_SHFT 31 -#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_9_SHFT 32 -#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_10_SHFT 33 -#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_11_SHFT 34 -#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_12_SHFT 35 -#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_13_SHFT 36 -#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_14_SHFT 37 -#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_15_SHFT 38 -#define UV1H_EVENT_OCCURRED0_L1_NMI_INT_SHFT 39 -#define UV1H_EVENT_OCCURRED0_STOP_CLOCK_SHFT 40 -#define UV1H_EVENT_OCCURRED0_ASIC_TO_L1_SHFT 41 -#define UV1H_EVENT_OCCURRED0_L1_TO_ASIC_SHFT 42 -#define UV1H_EVENT_OCCURRED0_LTC_INT_SHFT 43 -#define UV1H_EVENT_OCCURRED0_LA_SEQ_TRIGGER_SHFT 44 -#define UV1H_EVENT_OCCURRED0_IPI_INT_SHFT 45 -#define UV1H_EVENT_OCCURRED0_EXTIO_INT0_SHFT 46 -#define UV1H_EVENT_OCCURRED0_EXTIO_INT1_SHFT 47 -#define UV1H_EVENT_OCCURRED0_EXTIO_INT2_SHFT 48 -#define UV1H_EVENT_OCCURRED0_EXTIO_INT3_SHFT 49 -#define UV1H_EVENT_OCCURRED0_PROFILE_INT_SHFT 50 -#define UV1H_EVENT_OCCURRED0_RTC0_SHFT 51 -#define UV1H_EVENT_OCCURRED0_RTC1_SHFT 52 -#define UV1H_EVENT_OCCURRED0_RTC2_SHFT 53 -#define UV1H_EVENT_OCCURRED0_RTC3_SHFT 54 -#define UV1H_EVENT_OCCURRED0_BAU_DATA_SHFT 55 -#define UV1H_EVENT_OCCURRED0_POWER_MANAGEMENT_REQ_SHFT 56 -#define UV1H_EVENT_OCCURRED0_LB_HCERR_MASK 0x0000000000000001UL -#define UV1H_EVENT_OCCURRED0_GR0_HCERR_MASK 0x0000000000000002UL -#define UV1H_EVENT_OCCURRED0_GR1_HCERR_MASK 0x0000000000000004UL -#define UV1H_EVENT_OCCURRED0_LH_HCERR_MASK 0x0000000000000008UL -#define UV1H_EVENT_OCCURRED0_RH_HCERR_MASK 0x0000000000000010UL -#define UV1H_EVENT_OCCURRED0_XN_HCERR_MASK 0x0000000000000020UL -#define UV1H_EVENT_OCCURRED0_SI_HCERR_MASK 0x0000000000000040UL -#define UV1H_EVENT_OCCURRED0_LB_AOERR0_MASK 0x0000000000000080UL -#define UV1H_EVENT_OCCURRED0_GR0_AOERR0_MASK 0x0000000000000100UL -#define UV1H_EVENT_OCCURRED0_GR1_AOERR0_MASK 0x0000000000000200UL -#define UV1H_EVENT_OCCURRED0_LH_AOERR0_MASK 0x0000000000000400UL -#define UV1H_EVENT_OCCURRED0_RH_AOERR0_MASK 0x0000000000000800UL -#define UV1H_EVENT_OCCURRED0_XN_AOERR0_MASK 0x0000000000001000UL -#define UV1H_EVENT_OCCURRED0_SI_AOERR0_MASK 0x0000000000002000UL -#define UV1H_EVENT_OCCURRED0_LB_AOERR1_MASK 0x0000000000004000UL -#define UV1H_EVENT_OCCURRED0_GR0_AOERR1_MASK 0x0000000000008000UL -#define UV1H_EVENT_OCCURRED0_GR1_AOERR1_MASK 0x0000000000010000UL -#define UV1H_EVENT_OCCURRED0_LH_AOERR1_MASK 0x0000000000020000UL -#define UV1H_EVENT_OCCURRED0_RH_AOERR1_MASK 0x0000000000040000UL -#define UV1H_EVENT_OCCURRED0_XN_AOERR1_MASK 0x0000000000080000UL -#define UV1H_EVENT_OCCURRED0_SI_AOERR1_MASK 0x0000000000100000UL -#define UV1H_EVENT_OCCURRED0_RH_VPI_INT_MASK 0x0000000000200000UL -#define UV1H_EVENT_OCCURRED0_SYSTEM_SHUTDOWN_INT_MASK 0x0000000000400000UL -#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_0_MASK 0x0000000000800000UL -#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_1_MASK 0x0000000001000000UL -#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_2_MASK 0x0000000002000000UL -#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_3_MASK 0x0000000004000000UL -#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_4_MASK 0x0000000008000000UL -#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_5_MASK 0x0000000010000000UL -#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_6_MASK 0x0000000020000000UL -#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_7_MASK 0x0000000040000000UL -#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_8_MASK 0x0000000080000000UL -#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_9_MASK 0x0000000100000000UL -#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_10_MASK 0x0000000200000000UL -#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_11_MASK 0x0000000400000000UL -#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_12_MASK 0x0000000800000000UL -#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_13_MASK 0x0000001000000000UL -#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_14_MASK 0x0000002000000000UL -#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_15_MASK 0x0000004000000000UL -#define UV1H_EVENT_OCCURRED0_L1_NMI_INT_MASK 0x0000008000000000UL -#define UV1H_EVENT_OCCURRED0_STOP_CLOCK_MASK 0x0000010000000000UL -#define UV1H_EVENT_OCCURRED0_ASIC_TO_L1_MASK 0x0000020000000000UL -#define UV1H_EVENT_OCCURRED0_L1_TO_ASIC_MASK 0x0000040000000000UL -#define UV1H_EVENT_OCCURRED0_LTC_INT_MASK 0x0000080000000000UL -#define UV1H_EVENT_OCCURRED0_LA_SEQ_TRIGGER_MASK 0x0000100000000000UL -#define UV1H_EVENT_OCCURRED0_IPI_INT_MASK 0x0000200000000000UL -#define UV1H_EVENT_OCCURRED0_EXTIO_INT0_MASK 0x0000400000000000UL -#define UV1H_EVENT_OCCURRED0_EXTIO_INT1_MASK 0x0000800000000000UL -#define UV1H_EVENT_OCCURRED0_EXTIO_INT2_MASK 0x0001000000000000UL -#define UV1H_EVENT_OCCURRED0_EXTIO_INT3_MASK 0x0002000000000000UL -#define UV1H_EVENT_OCCURRED0_PROFILE_INT_MASK 0x0004000000000000UL -#define UV1H_EVENT_OCCURRED0_RTC0_MASK 0x0008000000000000UL -#define UV1H_EVENT_OCCURRED0_RTC1_MASK 0x0010000000000000UL -#define UV1H_EVENT_OCCURRED0_RTC2_MASK 0x0020000000000000UL -#define UV1H_EVENT_OCCURRED0_RTC3_MASK 0x0040000000000000UL -#define UV1H_EVENT_OCCURRED0_BAU_DATA_MASK 0x0080000000000000UL -#define UV1H_EVENT_OCCURRED0_POWER_MANAGEMENT_REQ_MASK 0x0100000000000000UL - -#define UV2H_EVENT_OCCURRED0_LB_HCERR_SHFT 0 -#define UV2H_EVENT_OCCURRED0_QP_HCERR_SHFT 1 -#define UV2H_EVENT_OCCURRED0_RH_HCERR_SHFT 2 -#define UV2H_EVENT_OCCURRED0_LH0_HCERR_SHFT 3 -#define UV2H_EVENT_OCCURRED0_LH1_HCERR_SHFT 4 -#define UV2H_EVENT_OCCURRED0_GR0_HCERR_SHFT 5 -#define UV2H_EVENT_OCCURRED0_GR1_HCERR_SHFT 6 -#define UV2H_EVENT_OCCURRED0_NI0_HCERR_SHFT 7 -#define UV2H_EVENT_OCCURRED0_NI1_HCERR_SHFT 8 -#define UV2H_EVENT_OCCURRED0_LB_AOERR0_SHFT 9 -#define UV2H_EVENT_OCCURRED0_QP_AOERR0_SHFT 10 -#define UV2H_EVENT_OCCURRED0_RH_AOERR0_SHFT 11 -#define UV2H_EVENT_OCCURRED0_LH0_AOERR0_SHFT 12 -#define UV2H_EVENT_OCCURRED0_LH1_AOERR0_SHFT 13 -#define UV2H_EVENT_OCCURRED0_GR0_AOERR0_SHFT 14 -#define UV2H_EVENT_OCCURRED0_GR1_AOERR0_SHFT 15 -#define UV2H_EVENT_OCCURRED0_XB_AOERR0_SHFT 16 -#define UV2H_EVENT_OCCURRED0_RT_AOERR0_SHFT 17 -#define UV2H_EVENT_OCCURRED0_NI0_AOERR0_SHFT 18 -#define UV2H_EVENT_OCCURRED0_NI1_AOERR0_SHFT 19 -#define UV2H_EVENT_OCCURRED0_LB_AOERR1_SHFT 20 -#define UV2H_EVENT_OCCURRED0_QP_AOERR1_SHFT 21 -#define UV2H_EVENT_OCCURRED0_RH_AOERR1_SHFT 22 -#define UV2H_EVENT_OCCURRED0_LH0_AOERR1_SHFT 23 -#define UV2H_EVENT_OCCURRED0_LH1_AOERR1_SHFT 24 -#define UV2H_EVENT_OCCURRED0_GR0_AOERR1_SHFT 25 -#define UV2H_EVENT_OCCURRED0_GR1_AOERR1_SHFT 26 -#define UV2H_EVENT_OCCURRED0_XB_AOERR1_SHFT 27 -#define UV2H_EVENT_OCCURRED0_RT_AOERR1_SHFT 28 -#define UV2H_EVENT_OCCURRED0_NI0_AOERR1_SHFT 29 -#define UV2H_EVENT_OCCURRED0_NI1_AOERR1_SHFT 30 -#define UV2H_EVENT_OCCURRED0_SYSTEM_SHUTDOWN_INT_SHFT 31 -#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_0_SHFT 32 -#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_1_SHFT 33 -#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_2_SHFT 34 -#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_3_SHFT 35 -#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_4_SHFT 36 -#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_5_SHFT 37 -#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_6_SHFT 38 -#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_7_SHFT 39 -#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_8_SHFT 40 -#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_9_SHFT 41 -#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_10_SHFT 42 -#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_11_SHFT 43 -#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_12_SHFT 44 -#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_13_SHFT 45 -#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_14_SHFT 46 -#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_15_SHFT 47 -#define UV2H_EVENT_OCCURRED0_L1_NMI_INT_SHFT 48 -#define UV2H_EVENT_OCCURRED0_STOP_CLOCK_SHFT 49 -#define UV2H_EVENT_OCCURRED0_ASIC_TO_L1_SHFT 50 -#define UV2H_EVENT_OCCURRED0_L1_TO_ASIC_SHFT 51 -#define UV2H_EVENT_OCCURRED0_LA_SEQ_TRIGGER_SHFT 52 -#define UV2H_EVENT_OCCURRED0_IPI_INT_SHFT 53 -#define UV2H_EVENT_OCCURRED0_EXTIO_INT0_SHFT 54 -#define UV2H_EVENT_OCCURRED0_EXTIO_INT1_SHFT 55 -#define UV2H_EVENT_OCCURRED0_EXTIO_INT2_SHFT 56 -#define UV2H_EVENT_OCCURRED0_EXTIO_INT3_SHFT 57 -#define UV2H_EVENT_OCCURRED0_PROFILE_INT_SHFT 58 -#define UV2H_EVENT_OCCURRED0_LB_HCERR_MASK 0x0000000000000001UL -#define UV2H_EVENT_OCCURRED0_QP_HCERR_MASK 0x0000000000000002UL -#define UV2H_EVENT_OCCURRED0_RH_HCERR_MASK 0x0000000000000004UL -#define UV2H_EVENT_OCCURRED0_LH0_HCERR_MASK 0x0000000000000008UL -#define UV2H_EVENT_OCCURRED0_LH1_HCERR_MASK 0x0000000000000010UL -#define UV2H_EVENT_OCCURRED0_GR0_HCERR_MASK 0x0000000000000020UL -#define UV2H_EVENT_OCCURRED0_GR1_HCERR_MASK 0x0000000000000040UL -#define UV2H_EVENT_OCCURRED0_NI0_HCERR_MASK 0x0000000000000080UL -#define UV2H_EVENT_OCCURRED0_NI1_HCERR_MASK 0x0000000000000100UL -#define UV2H_EVENT_OCCURRED0_LB_AOERR0_MASK 0x0000000000000200UL -#define UV2H_EVENT_OCCURRED0_QP_AOERR0_MASK 0x0000000000000400UL -#define UV2H_EVENT_OCCURRED0_RH_AOERR0_MASK 0x0000000000000800UL -#define UV2H_EVENT_OCCURRED0_LH0_AOERR0_MASK 0x0000000000001000UL -#define UV2H_EVENT_OCCURRED0_LH1_AOERR0_MASK 0x0000000000002000UL -#define UV2H_EVENT_OCCURRED0_GR0_AOERR0_MASK 0x0000000000004000UL -#define UV2H_EVENT_OCCURRED0_GR1_AOERR0_MASK 0x0000000000008000UL -#define UV2H_EVENT_OCCURRED0_XB_AOERR0_MASK 0x0000000000010000UL -#define UV2H_EVENT_OCCURRED0_RT_AOERR0_MASK 0x0000000000020000UL -#define UV2H_EVENT_OCCURRED0_NI0_AOERR0_MASK 0x0000000000040000UL -#define UV2H_EVENT_OCCURRED0_NI1_AOERR0_MASK 0x0000000000080000UL -#define UV2H_EVENT_OCCURRED0_LB_AOERR1_MASK 0x0000000000100000UL -#define UV2H_EVENT_OCCURRED0_QP_AOERR1_MASK 0x0000000000200000UL -#define UV2H_EVENT_OCCURRED0_RH_AOERR1_MASK 0x0000000000400000UL -#define UV2H_EVENT_OCCURRED0_LH0_AOERR1_MASK 0x0000000000800000UL -#define UV2H_EVENT_OCCURRED0_LH1_AOERR1_MASK 0x0000000001000000UL -#define UV2H_EVENT_OCCURRED0_GR0_AOERR1_MASK 0x0000000002000000UL -#define UV2H_EVENT_OCCURRED0_GR1_AOERR1_MASK 0x0000000004000000UL -#define UV2H_EVENT_OCCURRED0_XB_AOERR1_MASK 0x0000000008000000UL -#define UV2H_EVENT_OCCURRED0_RT_AOERR1_MASK 0x0000000010000000UL -#define UV2H_EVENT_OCCURRED0_NI0_AOERR1_MASK 0x0000000020000000UL -#define UV2H_EVENT_OCCURRED0_NI1_AOERR1_MASK 0x0000000040000000UL -#define UV2H_EVENT_OCCURRED0_SYSTEM_SHUTDOWN_INT_MASK 0x0000000080000000UL -#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_0_MASK 0x0000000100000000UL -#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_1_MASK 0x0000000200000000UL -#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_2_MASK 0x0000000400000000UL -#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_3_MASK 0x0000000800000000UL -#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_4_MASK 0x0000001000000000UL -#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_5_MASK 0x0000002000000000UL -#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_6_MASK 0x0000004000000000UL -#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_7_MASK 0x0000008000000000UL -#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_8_MASK 0x0000010000000000UL -#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_9_MASK 0x0000020000000000UL -#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_10_MASK 0x0000040000000000UL -#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_11_MASK 0x0000080000000000UL -#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_12_MASK 0x0000100000000000UL -#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_13_MASK 0x0000200000000000UL -#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_14_MASK 0x0000400000000000UL -#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_15_MASK 0x0000800000000000UL -#define UV2H_EVENT_OCCURRED0_L1_NMI_INT_MASK 0x0001000000000000UL -#define UV2H_EVENT_OCCURRED0_STOP_CLOCK_MASK 0x0002000000000000UL -#define UV2H_EVENT_OCCURRED0_ASIC_TO_L1_MASK 0x0004000000000000UL -#define UV2H_EVENT_OCCURRED0_L1_TO_ASIC_MASK 0x0008000000000000UL -#define UV2H_EVENT_OCCURRED0_LA_SEQ_TRIGGER_MASK 0x0010000000000000UL -#define UV2H_EVENT_OCCURRED0_IPI_INT_MASK 0x0020000000000000UL -#define UV2H_EVENT_OCCURRED0_EXTIO_INT0_MASK 0x0040000000000000UL -#define UV2H_EVENT_OCCURRED0_EXTIO_INT1_MASK 0x0080000000000000UL -#define UV2H_EVENT_OCCURRED0_EXTIO_INT2_MASK 0x0100000000000000UL -#define UV2H_EVENT_OCCURRED0_EXTIO_INT3_MASK 0x0200000000000000UL -#define UV2H_EVENT_OCCURRED0_PROFILE_INT_MASK 0x0400000000000000UL +#define UVH_EVENT_OCCURRED0 0x70000UL +#define UVH_EVENT_OCCURRED0_32 0x5e8 + +#define UV1H_EVENT_OCCURRED0_LB_HCERR_SHFT 0 +#define UV1H_EVENT_OCCURRED0_LB_HCERR_MASK 0x0000000000000001UL +#define UV1H_EVENT_OCCURRED0_GR0_HCERR_SHFT 1 +#define UV1H_EVENT_OCCURRED0_GR0_HCERR_MASK 0x0000000000000002UL +#define UV1H_EVENT_OCCURRED0_GR1_HCERR_SHFT 2 +#define UV1H_EVENT_OCCURRED0_GR1_HCERR_MASK 0x0000000000000004UL +#define UV1H_EVENT_OCCURRED0_LH_HCERR_SHFT 3 +#define UV1H_EVENT_OCCURRED0_LH_HCERR_MASK 0x0000000000000008UL +#define UV1H_EVENT_OCCURRED0_RH_HCERR_SHFT 4 +#define UV1H_EVENT_OCCURRED0_RH_HCERR_MASK 0x0000000000000010UL +#define UV1H_EVENT_OCCURRED0_XN_HCERR_SHFT 5 +#define UV1H_EVENT_OCCURRED0_XN_HCERR_MASK 0x0000000000000020UL +#define UV1H_EVENT_OCCURRED0_SI_HCERR_SHFT 6 +#define UV1H_EVENT_OCCURRED0_SI_HCERR_MASK 0x0000000000000040UL +#define UV1H_EVENT_OCCURRED0_LB_AOERR0_SHFT 7 +#define UV1H_EVENT_OCCURRED0_LB_AOERR0_MASK 0x0000000000000080UL +#define UV1H_EVENT_OCCURRED0_GR0_AOERR0_SHFT 8 +#define UV1H_EVENT_OCCURRED0_GR0_AOERR0_MASK 0x0000000000000100UL +#define UV1H_EVENT_OCCURRED0_GR1_AOERR0_SHFT 9 +#define UV1H_EVENT_OCCURRED0_GR1_AOERR0_MASK 0x0000000000000200UL +#define UV1H_EVENT_OCCURRED0_LH_AOERR0_SHFT 10 +#define UV1H_EVENT_OCCURRED0_LH_AOERR0_MASK 0x0000000000000400UL +#define UV1H_EVENT_OCCURRED0_RH_AOERR0_SHFT 11 +#define UV1H_EVENT_OCCURRED0_RH_AOERR0_MASK 0x0000000000000800UL +#define UV1H_EVENT_OCCURRED0_XN_AOERR0_SHFT 12 +#define UV1H_EVENT_OCCURRED0_XN_AOERR0_MASK 0x0000000000001000UL +#define UV1H_EVENT_OCCURRED0_SI_AOERR0_SHFT 13 +#define UV1H_EVENT_OCCURRED0_SI_AOERR0_MASK 0x0000000000002000UL +#define UV1H_EVENT_OCCURRED0_LB_AOERR1_SHFT 14 +#define UV1H_EVENT_OCCURRED0_LB_AOERR1_MASK 0x0000000000004000UL +#define UV1H_EVENT_OCCURRED0_GR0_AOERR1_SHFT 15 +#define UV1H_EVENT_OCCURRED0_GR0_AOERR1_MASK 0x0000000000008000UL +#define UV1H_EVENT_OCCURRED0_GR1_AOERR1_SHFT 16 +#define UV1H_EVENT_OCCURRED0_GR1_AOERR1_MASK 0x0000000000010000UL +#define UV1H_EVENT_OCCURRED0_LH_AOERR1_SHFT 17 +#define UV1H_EVENT_OCCURRED0_LH_AOERR1_MASK 0x0000000000020000UL +#define UV1H_EVENT_OCCURRED0_RH_AOERR1_SHFT 18 +#define UV1H_EVENT_OCCURRED0_RH_AOERR1_MASK 0x0000000000040000UL +#define UV1H_EVENT_OCCURRED0_XN_AOERR1_SHFT 19 +#define UV1H_EVENT_OCCURRED0_XN_AOERR1_MASK 0x0000000000080000UL +#define UV1H_EVENT_OCCURRED0_SI_AOERR1_SHFT 20 +#define UV1H_EVENT_OCCURRED0_SI_AOERR1_MASK 0x0000000000100000UL +#define UV1H_EVENT_OCCURRED0_RH_VPI_INT_SHFT 21 +#define UV1H_EVENT_OCCURRED0_RH_VPI_INT_MASK 0x0000000000200000UL +#define UV1H_EVENT_OCCURRED0_SYSTEM_SHUTDOWN_INT_SHFT 22 +#define UV1H_EVENT_OCCURRED0_SYSTEM_SHUTDOWN_INT_MASK 0x0000000000400000UL +#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_0_SHFT 23 +#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_0_MASK 0x0000000000800000UL +#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_1_SHFT 24 +#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_1_MASK 0x0000000001000000UL +#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_2_SHFT 25 +#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_2_MASK 0x0000000002000000UL +#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_3_SHFT 26 +#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_3_MASK 0x0000000004000000UL +#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_4_SHFT 27 +#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_4_MASK 0x0000000008000000UL +#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_5_SHFT 28 +#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_5_MASK 0x0000000010000000UL +#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_6_SHFT 29 +#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_6_MASK 0x0000000020000000UL +#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_7_SHFT 30 +#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_7_MASK 0x0000000040000000UL +#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_8_SHFT 31 +#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_8_MASK 0x0000000080000000UL +#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_9_SHFT 32 +#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_9_MASK 0x0000000100000000UL +#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_10_SHFT 33 +#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_10_MASK 0x0000000200000000UL +#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_11_SHFT 34 +#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_11_MASK 0x0000000400000000UL +#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_12_SHFT 35 +#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_12_MASK 0x0000000800000000UL +#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_13_SHFT 36 +#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_13_MASK 0x0000001000000000UL +#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_14_SHFT 37 +#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_14_MASK 0x0000002000000000UL +#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_15_SHFT 38 +#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_15_MASK 0x0000004000000000UL +#define UV1H_EVENT_OCCURRED0_L1_NMI_INT_SHFT 39 +#define UV1H_EVENT_OCCURRED0_L1_NMI_INT_MASK 0x0000008000000000UL +#define UV1H_EVENT_OCCURRED0_STOP_CLOCK_SHFT 40 +#define UV1H_EVENT_OCCURRED0_STOP_CLOCK_MASK 0x0000010000000000UL +#define UV1H_EVENT_OCCURRED0_ASIC_TO_L1_SHFT 41 +#define UV1H_EVENT_OCCURRED0_ASIC_TO_L1_MASK 0x0000020000000000UL +#define UV1H_EVENT_OCCURRED0_L1_TO_ASIC_SHFT 42 +#define UV1H_EVENT_OCCURRED0_L1_TO_ASIC_MASK 0x0000040000000000UL +#define UV1H_EVENT_OCCURRED0_LTC_INT_SHFT 43 +#define UV1H_EVENT_OCCURRED0_LTC_INT_MASK 0x0000080000000000UL +#define UV1H_EVENT_OCCURRED0_LA_SEQ_TRIGGER_SHFT 44 +#define UV1H_EVENT_OCCURRED0_LA_SEQ_TRIGGER_MASK 0x0000100000000000UL +#define UV1H_EVENT_OCCURRED0_IPI_INT_SHFT 45 +#define UV1H_EVENT_OCCURRED0_IPI_INT_MASK 0x0000200000000000UL +#define UV1H_EVENT_OCCURRED0_EXTIO_INT0_SHFT 46 +#define UV1H_EVENT_OCCURRED0_EXTIO_INT0_MASK 0x0000400000000000UL +#define UV1H_EVENT_OCCURRED0_EXTIO_INT1_SHFT 47 +#define UV1H_EVENT_OCCURRED0_EXTIO_INT1_MASK 0x0000800000000000UL +#define UV1H_EVENT_OCCURRED0_EXTIO_INT2_SHFT 48 +#define UV1H_EVENT_OCCURRED0_EXTIO_INT2_MASK 0x0001000000000000UL +#define UV1H_EVENT_OCCURRED0_EXTIO_INT3_SHFT 49 +#define UV1H_EVENT_OCCURRED0_EXTIO_INT3_MASK 0x0002000000000000UL +#define UV1H_EVENT_OCCURRED0_PROFILE_INT_SHFT 50 +#define UV1H_EVENT_OCCURRED0_PROFILE_INT_MASK 0x0004000000000000UL +#define UV1H_EVENT_OCCURRED0_RTC0_SHFT 51 +#define UV1H_EVENT_OCCURRED0_RTC0_MASK 0x0008000000000000UL +#define UV1H_EVENT_OCCURRED0_RTC1_SHFT 52 +#define UV1H_EVENT_OCCURRED0_RTC1_MASK 0x0010000000000000UL +#define UV1H_EVENT_OCCURRED0_RTC2_SHFT 53 +#define UV1H_EVENT_OCCURRED0_RTC2_MASK 0x0020000000000000UL +#define UV1H_EVENT_OCCURRED0_RTC3_SHFT 54 +#define UV1H_EVENT_OCCURRED0_RTC3_MASK 0x0040000000000000UL +#define UV1H_EVENT_OCCURRED0_BAU_DATA_SHFT 55 +#define UV1H_EVENT_OCCURRED0_BAU_DATA_MASK 0x0080000000000000UL +#define UV1H_EVENT_OCCURRED0_POWER_MANAGEMENT_REQ_SHFT 56 +#define UV1H_EVENT_OCCURRED0_POWER_MANAGEMENT_REQ_MASK 0x0100000000000000UL + +#define UV2H_EVENT_OCCURRED0_LB_HCERR_SHFT 0 +#define UV2H_EVENT_OCCURRED0_LB_HCERR_MASK 0x0000000000000001UL +#define UV2H_EVENT_OCCURRED0_QP_HCERR_SHFT 1 +#define UV2H_EVENT_OCCURRED0_QP_HCERR_MASK 0x0000000000000002UL +#define UV2H_EVENT_OCCURRED0_RH_HCERR_SHFT 2 +#define UV2H_EVENT_OCCURRED0_RH_HCERR_MASK 0x0000000000000004UL +#define UV2H_EVENT_OCCURRED0_LH0_HCERR_SHFT 3 +#define UV2H_EVENT_OCCURRED0_LH0_HCERR_MASK 0x0000000000000008UL +#define UV2H_EVENT_OCCURRED0_LH1_HCERR_SHFT 4 +#define UV2H_EVENT_OCCURRED0_LH1_HCERR_MASK 0x0000000000000010UL +#define UV2H_EVENT_OCCURRED0_GR0_HCERR_SHFT 5 +#define UV2H_EVENT_OCCURRED0_GR0_HCERR_MASK 0x0000000000000020UL +#define UV2H_EVENT_OCCURRED0_GR1_HCERR_SHFT 6 +#define UV2H_EVENT_OCCURRED0_GR1_HCERR_MASK 0x0000000000000040UL +#define UV2H_EVENT_OCCURRED0_NI0_HCERR_SHFT 7 +#define UV2H_EVENT_OCCURRED0_NI0_HCERR_MASK 0x0000000000000080UL +#define UV2H_EVENT_OCCURRED0_NI1_HCERR_SHFT 8 +#define UV2H_EVENT_OCCURRED0_NI1_HCERR_MASK 0x0000000000000100UL +#define UV2H_EVENT_OCCURRED0_LB_AOERR0_SHFT 9 +#define UV2H_EVENT_OCCURRED0_LB_AOERR0_MASK 0x0000000000000200UL +#define UV2H_EVENT_OCCURRED0_QP_AOERR0_SHFT 10 +#define UV2H_EVENT_OCCURRED0_QP_AOERR0_MASK 0x0000000000000400UL +#define UV2H_EVENT_OCCURRED0_RH_AOERR0_SHFT 11 +#define UV2H_EVENT_OCCURRED0_RH_AOERR0_MASK 0x0000000000000800UL +#define UV2H_EVENT_OCCURRED0_LH0_AOERR0_SHFT 12 +#define UV2H_EVENT_OCCURRED0_LH0_AOERR0_MASK 0x0000000000001000UL +#define UV2H_EVENT_OCCURRED0_LH1_AOERR0_SHFT 13 +#define UV2H_EVENT_OCCURRED0_LH1_AOERR0_MASK 0x0000000000002000UL +#define UV2H_EVENT_OCCURRED0_GR0_AOERR0_SHFT 14 +#define UV2H_EVENT_OCCURRED0_GR0_AOERR0_MASK 0x0000000000004000UL +#define UV2H_EVENT_OCCURRED0_GR1_AOERR0_SHFT 15 +#define UV2H_EVENT_OCCURRED0_GR1_AOERR0_MASK 0x0000000000008000UL +#define UV2H_EVENT_OCCURRED0_XB_AOERR0_SHFT 16 +#define UV2H_EVENT_OCCURRED0_XB_AOERR0_MASK 0x0000000000010000UL +#define UV2H_EVENT_OCCURRED0_RT_AOERR0_SHFT 17 +#define UV2H_EVENT_OCCURRED0_RT_AOERR0_MASK 0x0000000000020000UL +#define UV2H_EVENT_OCCURRED0_NI0_AOERR0_SHFT 18 +#define UV2H_EVENT_OCCURRED0_NI0_AOERR0_MASK 0x0000000000040000UL +#define UV2H_EVENT_OCCURRED0_NI1_AOERR0_SHFT 19 +#define UV2H_EVENT_OCCURRED0_NI1_AOERR0_MASK 0x0000000000080000UL +#define UV2H_EVENT_OCCURRED0_LB_AOERR1_SHFT 20 +#define UV2H_EVENT_OCCURRED0_LB_AOERR1_MASK 0x0000000000100000UL +#define UV2H_EVENT_OCCURRED0_QP_AOERR1_SHFT 21 +#define UV2H_EVENT_OCCURRED0_QP_AOERR1_MASK 0x0000000000200000UL +#define UV2H_EVENT_OCCURRED0_RH_AOERR1_SHFT 22 +#define UV2H_EVENT_OCCURRED0_RH_AOERR1_MASK 0x0000000000400000UL +#define UV2H_EVENT_OCCURRED0_LH0_AOERR1_SHFT 23 +#define UV2H_EVENT_OCCURRED0_LH0_AOERR1_MASK 0x0000000000800000UL +#define UV2H_EVENT_OCCURRED0_LH1_AOERR1_SHFT 24 +#define UV2H_EVENT_OCCURRED0_LH1_AOERR1_MASK 0x0000000001000000UL +#define UV2H_EVENT_OCCURRED0_GR0_AOERR1_SHFT 25 +#define UV2H_EVENT_OCCURRED0_GR0_AOERR1_MASK 0x0000000002000000UL +#define UV2H_EVENT_OCCURRED0_GR1_AOERR1_SHFT 26 +#define UV2H_EVENT_OCCURRED0_GR1_AOERR1_MASK 0x0000000004000000UL +#define UV2H_EVENT_OCCURRED0_XB_AOERR1_SHFT 27 +#define UV2H_EVENT_OCCURRED0_XB_AOERR1_MASK 0x0000000008000000UL +#define UV2H_EVENT_OCCURRED0_RT_AOERR1_SHFT 28 +#define UV2H_EVENT_OCCURRED0_RT_AOERR1_MASK 0x0000000010000000UL +#define UV2H_EVENT_OCCURRED0_NI0_AOERR1_SHFT 29 +#define UV2H_EVENT_OCCURRED0_NI0_AOERR1_MASK 0x0000000020000000UL +#define UV2H_EVENT_OCCURRED0_NI1_AOERR1_SHFT 30 +#define UV2H_EVENT_OCCURRED0_NI1_AOERR1_MASK 0x0000000040000000UL +#define UV2H_EVENT_OCCURRED0_SYSTEM_SHUTDOWN_INT_SHFT 31 +#define UV2H_EVENT_OCCURRED0_SYSTEM_SHUTDOWN_INT_MASK 0x0000000080000000UL +#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_0_SHFT 32 +#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_0_MASK 0x0000000100000000UL +#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_1_SHFT 33 +#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_1_MASK 0x0000000200000000UL +#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_2_SHFT 34 +#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_2_MASK 0x0000000400000000UL +#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_3_SHFT 35 +#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_3_MASK 0x0000000800000000UL +#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_4_SHFT 36 +#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_4_MASK 0x0000001000000000UL +#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_5_SHFT 37 +#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_5_MASK 0x0000002000000000UL +#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_6_SHFT 38 +#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_6_MASK 0x0000004000000000UL +#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_7_SHFT 39 +#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_7_MASK 0x0000008000000000UL +#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_8_SHFT 40 +#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_8_MASK 0x0000010000000000UL +#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_9_SHFT 41 +#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_9_MASK 0x0000020000000000UL +#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_10_SHFT 42 +#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_10_MASK 0x0000040000000000UL +#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_11_SHFT 43 +#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_11_MASK 0x0000080000000000UL +#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_12_SHFT 44 +#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_12_MASK 0x0000100000000000UL +#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_13_SHFT 45 +#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_13_MASK 0x0000200000000000UL +#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_14_SHFT 46 +#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_14_MASK 0x0000400000000000UL +#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_15_SHFT 47 +#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_15_MASK 0x0000800000000000UL +#define UV2H_EVENT_OCCURRED0_L1_NMI_INT_SHFT 48 +#define UV2H_EVENT_OCCURRED0_L1_NMI_INT_MASK 0x0001000000000000UL +#define UV2H_EVENT_OCCURRED0_STOP_CLOCK_SHFT 49 +#define UV2H_EVENT_OCCURRED0_STOP_CLOCK_MASK 0x0002000000000000UL +#define UV2H_EVENT_OCCURRED0_ASIC_TO_L1_SHFT 50 +#define UV2H_EVENT_OCCURRED0_ASIC_TO_L1_MASK 0x0004000000000000UL +#define UV2H_EVENT_OCCURRED0_L1_TO_ASIC_SHFT 51 +#define UV2H_EVENT_OCCURRED0_L1_TO_ASIC_MASK 0x0008000000000000UL +#define UV2H_EVENT_OCCURRED0_LA_SEQ_TRIGGER_SHFT 52 +#define UV2H_EVENT_OCCURRED0_LA_SEQ_TRIGGER_MASK 0x0010000000000000UL +#define UV2H_EVENT_OCCURRED0_IPI_INT_SHFT 53 +#define UV2H_EVENT_OCCURRED0_IPI_INT_MASK 0x0020000000000000UL +#define UV2H_EVENT_OCCURRED0_EXTIO_INT0_SHFT 54 +#define UV2H_EVENT_OCCURRED0_EXTIO_INT0_MASK 0x0040000000000000UL +#define UV2H_EVENT_OCCURRED0_EXTIO_INT1_SHFT 55 +#define UV2H_EVENT_OCCURRED0_EXTIO_INT1_MASK 0x0080000000000000UL +#define UV2H_EVENT_OCCURRED0_EXTIO_INT2_SHFT 56 +#define UV2H_EVENT_OCCURRED0_EXTIO_INT2_MASK 0x0100000000000000UL +#define UV2H_EVENT_OCCURRED0_EXTIO_INT3_SHFT 57 +#define UV2H_EVENT_OCCURRED0_EXTIO_INT3_MASK 0x0200000000000000UL +#define UV2H_EVENT_OCCURRED0_PROFILE_INT_SHFT 58 +#define UV2H_EVENT_OCCURRED0_PROFILE_INT_MASK 0x0400000000000000UL union uvh_event_occurred0_u { - unsigned long v; - struct uv1h_event_occurred0_s { - unsigned long lb_hcerr:1; /* RW, W1C */ - unsigned long gr0_hcerr:1; /* RW, W1C */ - unsigned long gr1_hcerr:1; /* RW, W1C */ - unsigned long lh_hcerr:1; /* RW, W1C */ - unsigned long rh_hcerr:1; /* RW, W1C */ - unsigned long xn_hcerr:1; /* RW, W1C */ - unsigned long si_hcerr:1; /* RW, W1C */ - unsigned long lb_aoerr0:1; /* RW, W1C */ - unsigned long gr0_aoerr0:1; /* RW, W1C */ - unsigned long gr1_aoerr0:1; /* RW, W1C */ - unsigned long lh_aoerr0:1; /* RW, W1C */ - unsigned long rh_aoerr0:1; /* RW, W1C */ - unsigned long xn_aoerr0:1; /* RW, W1C */ - unsigned long si_aoerr0:1; /* RW, W1C */ - unsigned long lb_aoerr1:1; /* RW, W1C */ - unsigned long gr0_aoerr1:1; /* RW, W1C */ - unsigned long gr1_aoerr1:1; /* RW, W1C */ - unsigned long lh_aoerr1:1; /* RW, W1C */ - unsigned long rh_aoerr1:1; /* RW, W1C */ - unsigned long xn_aoerr1:1; /* RW, W1C */ - unsigned long si_aoerr1:1; /* RW, W1C */ - unsigned long rh_vpi_int:1; /* RW, W1C */ - unsigned long system_shutdown_int:1; /* RW, W1C */ - unsigned long lb_irq_int_0:1; /* RW, W1C */ - unsigned long lb_irq_int_1:1; /* RW, W1C */ - unsigned long lb_irq_int_2:1; /* RW, W1C */ - unsigned long lb_irq_int_3:1; /* RW, W1C */ - unsigned long lb_irq_int_4:1; /* RW, W1C */ - unsigned long lb_irq_int_5:1; /* RW, W1C */ - unsigned long lb_irq_int_6:1; /* RW, W1C */ - unsigned long lb_irq_int_7:1; /* RW, W1C */ - unsigned long lb_irq_int_8:1; /* RW, W1C */ - unsigned long lb_irq_int_9:1; /* RW, W1C */ - unsigned long lb_irq_int_10:1; /* RW, W1C */ - unsigned long lb_irq_int_11:1; /* RW, W1C */ - unsigned long lb_irq_int_12:1; /* RW, W1C */ - unsigned long lb_irq_int_13:1; /* RW, W1C */ - unsigned long lb_irq_int_14:1; /* RW, W1C */ - unsigned long lb_irq_int_15:1; /* RW, W1C */ - unsigned long l1_nmi_int:1; /* RW, W1C */ - unsigned long stop_clock:1; /* RW, W1C */ - unsigned long asic_to_l1:1; /* RW, W1C */ - unsigned long l1_to_asic:1; /* RW, W1C */ - unsigned long ltc_int:1; /* RW, W1C */ - unsigned long la_seq_trigger:1; /* RW, W1C */ - unsigned long ipi_int:1; /* RW, W1C */ - unsigned long extio_int0:1; /* RW, W1C */ - unsigned long extio_int1:1; /* RW, W1C */ - unsigned long extio_int2:1; /* RW, W1C */ - unsigned long extio_int3:1; /* RW, W1C */ - unsigned long profile_int:1; /* RW, W1C */ - unsigned long rtc0:1; /* RW, W1C */ - unsigned long rtc1:1; /* RW, W1C */ - unsigned long rtc2:1; /* RW, W1C */ - unsigned long rtc3:1; /* RW, W1C */ - unsigned long bau_data:1; /* RW, W1C */ - unsigned long power_management_req:1; /* RW, W1C */ - unsigned long rsvd_57_63:7; - } s1; - struct uv2h_event_occurred0_s { - unsigned long lb_hcerr:1; /* RW */ - unsigned long qp_hcerr:1; /* RW */ - unsigned long rh_hcerr:1; /* RW */ - unsigned long lh0_hcerr:1; /* RW */ - unsigned long lh1_hcerr:1; /* RW */ - unsigned long gr0_hcerr:1; /* RW */ - unsigned long gr1_hcerr:1; /* RW */ - unsigned long ni0_hcerr:1; /* RW */ - unsigned long ni1_hcerr:1; /* RW */ - unsigned long lb_aoerr0:1; /* RW */ - unsigned long qp_aoerr0:1; /* RW */ - unsigned long rh_aoerr0:1; /* RW */ - unsigned long lh0_aoerr0:1; /* RW */ - unsigned long lh1_aoerr0:1; /* RW */ - unsigned long gr0_aoerr0:1; /* RW */ - unsigned long gr1_aoerr0:1; /* RW */ - unsigned long xb_aoerr0:1; /* RW */ - unsigned long rt_aoerr0:1; /* RW */ - unsigned long ni0_aoerr0:1; /* RW */ - unsigned long ni1_aoerr0:1; /* RW */ - unsigned long lb_aoerr1:1; /* RW */ - unsigned long qp_aoerr1:1; /* RW */ - unsigned long rh_aoerr1:1; /* RW */ - unsigned long lh0_aoerr1:1; /* RW */ - unsigned long lh1_aoerr1:1; /* RW */ - unsigned long gr0_aoerr1:1; /* RW */ - unsigned long gr1_aoerr1:1; /* RW */ - unsigned long xb_aoerr1:1; /* RW */ - unsigned long rt_aoerr1:1; /* RW */ - unsigned long ni0_aoerr1:1; /* RW */ - unsigned long ni1_aoerr1:1; /* RW */ - unsigned long system_shutdown_int:1; /* RW */ - unsigned long lb_irq_int_0:1; /* RW */ - unsigned long lb_irq_int_1:1; /* RW */ - unsigned long lb_irq_int_2:1; /* RW */ - unsigned long lb_irq_int_3:1; /* RW */ - unsigned long lb_irq_int_4:1; /* RW */ - unsigned long lb_irq_int_5:1; /* RW */ - unsigned long lb_irq_int_6:1; /* RW */ - unsigned long lb_irq_int_7:1; /* RW */ - unsigned long lb_irq_int_8:1; /* RW */ - unsigned long lb_irq_int_9:1; /* RW */ - unsigned long lb_irq_int_10:1; /* RW */ - unsigned long lb_irq_int_11:1; /* RW */ - unsigned long lb_irq_int_12:1; /* RW */ - unsigned long lb_irq_int_13:1; /* RW */ - unsigned long lb_irq_int_14:1; /* RW */ - unsigned long lb_irq_int_15:1; /* RW */ - unsigned long l1_nmi_int:1; /* RW */ - unsigned long stop_clock:1; /* RW */ - unsigned long asic_to_l1:1; /* RW */ - unsigned long l1_to_asic:1; /* RW */ - unsigned long la_seq_trigger:1; /* RW */ - unsigned long ipi_int:1; /* RW */ - unsigned long extio_int0:1; /* RW */ - unsigned long extio_int1:1; /* RW */ - unsigned long extio_int2:1; /* RW */ - unsigned long extio_int3:1; /* RW */ - unsigned long profile_int:1; /* RW */ - unsigned long rsvd_59_63:5; - } s2; + unsigned long v; + struct uv1h_event_occurred0_s { + unsigned long lb_hcerr : 1; /* RW, W1C */ + unsigned long gr0_hcerr : 1; /* RW, W1C */ + unsigned long gr1_hcerr : 1; /* RW, W1C */ + unsigned long lh_hcerr : 1; /* RW, W1C */ + unsigned long rh_hcerr : 1; /* RW, W1C */ + unsigned long xn_hcerr : 1; /* RW, W1C */ + unsigned long si_hcerr : 1; /* RW, W1C */ + unsigned long lb_aoerr0 : 1; /* RW, W1C */ + unsigned long gr0_aoerr0 : 1; /* RW, W1C */ + unsigned long gr1_aoerr0 : 1; /* RW, W1C */ + unsigned long lh_aoerr0 : 1; /* RW, W1C */ + unsigned long rh_aoerr0 : 1; /* RW, W1C */ + unsigned long xn_aoerr0 : 1; /* RW, W1C */ + unsigned long si_aoerr0 : 1; /* RW, W1C */ + unsigned long lb_aoerr1 : 1; /* RW, W1C */ + unsigned long gr0_aoerr1 : 1; /* RW, W1C */ + unsigned long gr1_aoerr1 : 1; /* RW, W1C */ + unsigned long lh_aoerr1 : 1; /* RW, W1C */ + unsigned long rh_aoerr1 : 1; /* RW, W1C */ + unsigned long xn_aoerr1 : 1; /* RW, W1C */ + unsigned long si_aoerr1 : 1; /* RW, W1C */ + unsigned long rh_vpi_int : 1; /* RW, W1C */ + unsigned long system_shutdown_int : 1; /* RW, W1C */ + unsigned long lb_irq_int_0 : 1; /* RW, W1C */ + unsigned long lb_irq_int_1 : 1; /* RW, W1C */ + unsigned long lb_irq_int_2 : 1; /* RW, W1C */ + unsigned long lb_irq_int_3 : 1; /* RW, W1C */ + unsigned long lb_irq_int_4 : 1; /* RW, W1C */ + unsigned long lb_irq_int_5 : 1; /* RW, W1C */ + unsigned long lb_irq_int_6 : 1; /* RW, W1C */ + unsigned long lb_irq_int_7 : 1; /* RW, W1C */ + unsigned long lb_irq_int_8 : 1; /* RW, W1C */ + unsigned long lb_irq_int_9 : 1; /* RW, W1C */ + unsigned long lb_irq_int_10 : 1; /* RW, W1C */ + unsigned long lb_irq_int_11 : 1; /* RW, W1C */ + unsigned long lb_irq_int_12 : 1; /* RW, W1C */ + unsigned long lb_irq_int_13 : 1; /* RW, W1C */ + unsigned long lb_irq_int_14 : 1; /* RW, W1C */ + unsigned long lb_irq_int_15 : 1; /* RW, W1C */ + unsigned long l1_nmi_int : 1; /* RW, W1C */ + unsigned long stop_clock : 1; /* RW, W1C */ + unsigned long asic_to_l1 : 1; /* RW, W1C */ + unsigned long l1_to_asic : 1; /* RW, W1C */ + unsigned long ltc_int : 1; /* RW, W1C */ + unsigned long la_seq_trigger : 1; /* RW, W1C */ + unsigned long ipi_int : 1; /* RW, W1C */ + unsigned long extio_int0 : 1; /* RW, W1C */ + unsigned long extio_int1 : 1; /* RW, W1C */ + unsigned long extio_int2 : 1; /* RW, W1C */ + unsigned long extio_int3 : 1; /* RW, W1C */ + unsigned long profile_int : 1; /* RW, W1C */ + unsigned long rtc0 : 1; /* RW, W1C */ + unsigned long rtc1 : 1; /* RW, W1C */ + unsigned long rtc2 : 1; /* RW, W1C */ + unsigned long rtc3 : 1; /* RW, W1C */ + unsigned long bau_data : 1; /* RW, W1C */ + unsigned long power_management_req : 1; /* RW, W1C */ + unsigned long rsvd_57_63 : 7; /* */ + } s1; + struct uv2h_event_occurred0_s { + unsigned long lb_hcerr : 1; /* RW */ + unsigned long qp_hcerr : 1; /* RW */ + unsigned long rh_hcerr : 1; /* RW */ + unsigned long lh0_hcerr : 1; /* RW */ + unsigned long lh1_hcerr : 1; /* RW */ + unsigned long gr0_hcerr : 1; /* RW */ + unsigned long gr1_hcerr : 1; /* RW */ + unsigned long ni0_hcerr : 1; /* RW */ + unsigned long ni1_hcerr : 1; /* RW */ + unsigned long lb_aoerr0 : 1; /* RW */ + unsigned long qp_aoerr0 : 1; /* RW */ + unsigned long rh_aoerr0 : 1; /* RW */ + unsigned long lh0_aoerr0 : 1; /* RW */ + unsigned long lh1_aoerr0 : 1; /* RW */ + unsigned long gr0_aoerr0 : 1; /* RW */ + unsigned long gr1_aoerr0 : 1; /* RW */ + unsigned long xb_aoerr0 : 1; /* RW */ + unsigned long rt_aoerr0 : 1; /* RW */ + unsigned long ni0_aoerr0 : 1; /* RW */ + unsigned long ni1_aoerr0 : 1; /* RW */ + unsigned long lb_aoerr1 : 1; /* RW */ + unsigned long qp_aoerr1 : 1; /* RW */ + unsigned long rh_aoerr1 : 1; /* RW */ + unsigned long lh0_aoerr1 : 1; /* RW */ + unsigned long lh1_aoerr1 : 1; /* RW */ + unsigned long gr0_aoerr1 : 1; /* RW */ + unsigned long gr1_aoerr1 : 1; /* RW */ + unsigned long xb_aoerr1 : 1; /* RW */ + unsigned long rt_aoerr1 : 1; /* RW */ + unsigned long ni0_aoerr1 : 1; /* RW */ + unsigned long ni1_aoerr1 : 1; /* RW */ + unsigned long system_shutdown_int : 1; /* RW */ + unsigned long lb_irq_int_0 : 1; /* RW */ + unsigned long lb_irq_int_1 : 1; /* RW */ + unsigned long lb_irq_int_2 : 1; /* RW */ + unsigned long lb_irq_int_3 : 1; /* RW */ + unsigned long lb_irq_int_4 : 1; /* RW */ + unsigned long lb_irq_int_5 : 1; /* RW */ + unsigned long lb_irq_int_6 : 1; /* RW */ + unsigned long lb_irq_int_7 : 1; /* RW */ + unsigned long lb_irq_int_8 : 1; /* RW */ + unsigned long lb_irq_int_9 : 1; /* RW */ + unsigned long lb_irq_int_10 : 1; /* RW */ + unsigned long lb_irq_int_11 : 1; /* RW */ + unsigned long lb_irq_int_12 : 1; /* RW */ + unsigned long lb_irq_int_13 : 1; /* RW */ + unsigned long lb_irq_int_14 : 1; /* RW */ + unsigned long lb_irq_int_15 : 1; /* RW */ + unsigned long l1_nmi_int : 1; /* RW */ + unsigned long stop_clock : 1; /* RW */ + unsigned long asic_to_l1 : 1; /* RW */ + unsigned long l1_to_asic : 1; /* RW */ + unsigned long la_seq_trigger : 1; /* RW */ + unsigned long ipi_int : 1; /* RW */ + unsigned long extio_int0 : 1; /* RW */ + unsigned long extio_int1 : 1; /* RW */ + unsigned long extio_int2 : 1; /* RW */ + unsigned long extio_int3 : 1; /* RW */ + unsigned long profile_int : 1; /* RW */ + unsigned long rsvd_59_63 : 5; /* */ + } s2; }; /* ========================================================================= */ /* UVH_EVENT_OCCURRED0_ALIAS */ /* ========================================================================= */ -#define UVH_EVENT_OCCURRED0_ALIAS 0x0000000000070008UL -#define UVH_EVENT_OCCURRED0_ALIAS_32 0x5f0 +#define UVH_EVENT_OCCURRED0_ALIAS 0x0000000000070008UL +#define UVH_EVENT_OCCURRED0_ALIAS_32 0x5f0 /* ========================================================================= */ /* UVH_GR0_TLB_INT0_CONFIG */ /* ========================================================================= */ -#define UVH_GR0_TLB_INT0_CONFIG 0x61b00UL - -#define UVH_GR0_TLB_INT0_CONFIG_VECTOR_SHFT 0 -#define UVH_GR0_TLB_INT0_CONFIG_DM_SHFT 8 -#define UVH_GR0_TLB_INT0_CONFIG_DESTMODE_SHFT 11 -#define UVH_GR0_TLB_INT0_CONFIG_STATUS_SHFT 12 -#define UVH_GR0_TLB_INT0_CONFIG_P_SHFT 13 -#define UVH_GR0_TLB_INT0_CONFIG_T_SHFT 15 -#define UVH_GR0_TLB_INT0_CONFIG_M_SHFT 16 -#define UVH_GR0_TLB_INT0_CONFIG_APIC_ID_SHFT 32 -#define UVH_GR0_TLB_INT0_CONFIG_VECTOR_MASK 0x00000000000000ffUL -#define UVH_GR0_TLB_INT0_CONFIG_DM_MASK 0x0000000000000700UL -#define UVH_GR0_TLB_INT0_CONFIG_DESTMODE_MASK 0x0000000000000800UL -#define UVH_GR0_TLB_INT0_CONFIG_STATUS_MASK 0x0000000000001000UL -#define UVH_GR0_TLB_INT0_CONFIG_P_MASK 0x0000000000002000UL -#define UVH_GR0_TLB_INT0_CONFIG_T_MASK 0x0000000000008000UL -#define UVH_GR0_TLB_INT0_CONFIG_M_MASK 0x0000000000010000UL -#define UVH_GR0_TLB_INT0_CONFIG_APIC_ID_MASK 0xffffffff00000000UL +#define UVH_GR0_TLB_INT0_CONFIG 0x61b00UL + +#define UVH_GR0_TLB_INT0_CONFIG_VECTOR_SHFT 0 +#define UVH_GR0_TLB_INT0_CONFIG_VECTOR_MASK 0x00000000000000ffUL +#define UVH_GR0_TLB_INT0_CONFIG_DM_SHFT 8 +#define UVH_GR0_TLB_INT0_CONFIG_DM_MASK 0x0000000000000700UL +#define UVH_GR0_TLB_INT0_CONFIG_DESTMODE_SHFT 11 +#define UVH_GR0_TLB_INT0_CONFIG_DESTMODE_MASK 0x0000000000000800UL +#define UVH_GR0_TLB_INT0_CONFIG_STATUS_SHFT 12 +#define UVH_GR0_TLB_INT0_CONFIG_STATUS_MASK 0x0000000000001000UL +#define UVH_GR0_TLB_INT0_CONFIG_P_SHFT 13 +#define UVH_GR0_TLB_INT0_CONFIG_P_MASK 0x0000000000002000UL +#define UVH_GR0_TLB_INT0_CONFIG_T_SHFT 15 +#define UVH_GR0_TLB_INT0_CONFIG_T_MASK 0x0000000000008000UL +#define UVH_GR0_TLB_INT0_CONFIG_M_SHFT 16 +#define UVH_GR0_TLB_INT0_CONFIG_M_MASK 0x0000000000010000UL +#define UVH_GR0_TLB_INT0_CONFIG_APIC_ID_SHFT 32 +#define UVH_GR0_TLB_INT0_CONFIG_APIC_ID_MASK 0xffffffff00000000UL union uvh_gr0_tlb_int0_config_u { - unsigned long v; - struct uvh_gr0_tlb_int0_config_s { - unsigned long vector_:8; /* RW */ - unsigned long dm:3; /* RW */ - unsigned long destmode:1; /* RW */ - unsigned long status:1; /* RO */ - unsigned long p:1; /* RO */ - unsigned long rsvd_14:1; - unsigned long t:1; /* RO */ - unsigned long m:1; /* RW */ - unsigned long rsvd_17_31:15; - unsigned long apic_id:32; /* RW */ - } s; + unsigned long v; + struct uvh_gr0_tlb_int0_config_s { + unsigned long vector_ : 8; /* RW */ + unsigned long dm : 3; /* RW */ + unsigned long destmode : 1; /* RW */ + unsigned long status : 1; /* RO */ + unsigned long p : 1; /* RO */ + unsigned long rsvd_14 : 1; /* */ + unsigned long t : 1; /* RO */ + unsigned long m : 1; /* RW */ + unsigned long rsvd_17_31: 15; /* */ + unsigned long apic_id : 32; /* RW */ + } s; }; /* ========================================================================= */ /* UVH_GR0_TLB_INT1_CONFIG */ /* ========================================================================= */ -#define UVH_GR0_TLB_INT1_CONFIG 0x61b40UL - -#define UVH_GR0_TLB_INT1_CONFIG_VECTOR_SHFT 0 -#define UVH_GR0_TLB_INT1_CONFIG_DM_SHFT 8 -#define UVH_GR0_TLB_INT1_CONFIG_DESTMODE_SHFT 11 -#define UVH_GR0_TLB_INT1_CONFIG_STATUS_SHFT 12 -#define UVH_GR0_TLB_INT1_CONFIG_P_SHFT 13 -#define UVH_GR0_TLB_INT1_CONFIG_T_SHFT 15 -#define UVH_GR0_TLB_INT1_CONFIG_M_SHFT 16 -#define UVH_GR0_TLB_INT1_CONFIG_APIC_ID_SHFT 32 -#define UVH_GR0_TLB_INT1_CONFIG_VECTOR_MASK 0x00000000000000ffUL -#define UVH_GR0_TLB_INT1_CONFIG_DM_MASK 0x0000000000000700UL -#define UVH_GR0_TLB_INT1_CONFIG_DESTMODE_MASK 0x0000000000000800UL -#define UVH_GR0_TLB_INT1_CONFIG_STATUS_MASK 0x0000000000001000UL -#define UVH_GR0_TLB_INT1_CONFIG_P_MASK 0x0000000000002000UL -#define UVH_GR0_TLB_INT1_CONFIG_T_MASK 0x0000000000008000UL -#define UVH_GR0_TLB_INT1_CONFIG_M_MASK 0x0000000000010000UL -#define UVH_GR0_TLB_INT1_CONFIG_APIC_ID_MASK 0xffffffff00000000UL +#define UVH_GR0_TLB_INT1_CONFIG 0x61b40UL + +#define UVH_GR0_TLB_INT1_CONFIG_VECTOR_SHFT 0 +#define UVH_GR0_TLB_INT1_CONFIG_VECTOR_MASK 0x00000000000000ffUL +#define UVH_GR0_TLB_INT1_CONFIG_DM_SHFT 8 +#define UVH_GR0_TLB_INT1_CONFIG_DM_MASK 0x0000000000000700UL +#define UVH_GR0_TLB_INT1_CONFIG_DESTMODE_SHFT 11 +#define UVH_GR0_TLB_INT1_CONFIG_DESTMODE_MASK 0x0000000000000800UL +#define UVH_GR0_TLB_INT1_CONFIG_STATUS_SHFT 12 +#define UVH_GR0_TLB_INT1_CONFIG_STATUS_MASK 0x0000000000001000UL +#define UVH_GR0_TLB_INT1_CONFIG_P_SHFT 13 +#define UVH_GR0_TLB_INT1_CONFIG_P_MASK 0x0000000000002000UL +#define UVH_GR0_TLB_INT1_CONFIG_T_SHFT 15 +#define UVH_GR0_TLB_INT1_CONFIG_T_MASK 0x0000000000008000UL +#define UVH_GR0_TLB_INT1_CONFIG_M_SHFT 16 +#define UVH_GR0_TLB_INT1_CONFIG_M_MASK 0x0000000000010000UL +#define UVH_GR0_TLB_INT1_CONFIG_APIC_ID_SHFT 32 +#define UVH_GR0_TLB_INT1_CONFIG_APIC_ID_MASK 0xffffffff00000000UL union uvh_gr0_tlb_int1_config_u { - unsigned long v; - struct uvh_gr0_tlb_int1_config_s { - unsigned long vector_:8; /* RW */ - unsigned long dm:3; /* RW */ - unsigned long destmode:1; /* RW */ - unsigned long status:1; /* RO */ - unsigned long p:1; /* RO */ - unsigned long rsvd_14:1; - unsigned long t:1; /* RO */ - unsigned long m:1; /* RW */ - unsigned long rsvd_17_31:15; - unsigned long apic_id:32; /* RW */ - } s; -}; - -/* ========================================================================= */ -/* UVH_GR0_TLB_MMR_CONTROL */ -/* ========================================================================= */ -#define UV1H_GR0_TLB_MMR_CONTROL 0x401080UL -#define UV2H_GR0_TLB_MMR_CONTROL 0xc01080UL -#define UVH_GR0_TLB_MMR_CONTROL (is_uv1_hub() ? \ - UV1H_GR0_TLB_MMR_CONTROL : \ - UV2H_GR0_TLB_MMR_CONTROL) - -#define UVH_GR0_TLB_MMR_CONTROL_INDEX_SHFT 0 -#define UVH_GR0_TLB_MMR_CONTROL_MEM_SEL_SHFT 12 -#define UVH_GR0_TLB_MMR_CONTROL_AUTO_VALID_EN_SHFT 16 -#define UVH_GR0_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_SHFT 20 -#define UVH_GR0_TLB_MMR_CONTROL_MMR_WRITE_SHFT 30 -#define UVH_GR0_TLB_MMR_CONTROL_MMR_READ_SHFT 31 -#define UVH_GR0_TLB_MMR_CONTROL_INDEX_MASK 0x0000000000000fffUL -#define UVH_GR0_TLB_MMR_CONTROL_MEM_SEL_MASK 0x0000000000003000UL -#define UVH_GR0_TLB_MMR_CONTROL_AUTO_VALID_EN_MASK 0x0000000000010000UL -#define UVH_GR0_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_MASK 0x0000000000100000UL -#define UVH_GR0_TLB_MMR_CONTROL_MMR_WRITE_MASK 0x0000000040000000UL -#define UVH_GR0_TLB_MMR_CONTROL_MMR_READ_MASK 0x0000000080000000UL - -#define UV1H_GR0_TLB_MMR_CONTROL_INDEX_SHFT 0 -#define UV1H_GR0_TLB_MMR_CONTROL_MEM_SEL_SHFT 12 -#define UV1H_GR0_TLB_MMR_CONTROL_AUTO_VALID_EN_SHFT 16 -#define UV1H_GR0_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_SHFT 20 -#define UV1H_GR0_TLB_MMR_CONTROL_MMR_WRITE_SHFT 30 -#define UV1H_GR0_TLB_MMR_CONTROL_MMR_READ_SHFT 31 -#define UV1H_GR0_TLB_MMR_CONTROL_MMR_INJ_CON_SHFT 48 -#define UV1H_GR0_TLB_MMR_CONTROL_MMR_INJ_TLBRAM_SHFT 52 -#define UV1H_GR0_TLB_MMR_CONTROL_MMR_INJ_TLBPGSIZE_SHFT 54 -#define UV1H_GR0_TLB_MMR_CONTROL_MMR_INJ_TLBRREG_SHFT 56 -#define UV1H_GR0_TLB_MMR_CONTROL_MMR_INJ_TLBLRUV_SHFT 60 -#define UV1H_GR0_TLB_MMR_CONTROL_INDEX_MASK 0x0000000000000fffUL -#define UV1H_GR0_TLB_MMR_CONTROL_MEM_SEL_MASK 0x0000000000003000UL -#define UV1H_GR0_TLB_MMR_CONTROL_AUTO_VALID_EN_MASK 0x0000000000010000UL -#define UV1H_GR0_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_MASK 0x0000000000100000UL -#define UV1H_GR0_TLB_MMR_CONTROL_MMR_WRITE_MASK 0x0000000040000000UL -#define UV1H_GR0_TLB_MMR_CONTROL_MMR_READ_MASK 0x0000000080000000UL -#define UV1H_GR0_TLB_MMR_CONTROL_MMR_INJ_CON_MASK 0x0001000000000000UL -#define UV1H_GR0_TLB_MMR_CONTROL_MMR_INJ_TLBRAM_MASK 0x0010000000000000UL -#define UV1H_GR0_TLB_MMR_CONTROL_MMR_INJ_TLBPGSIZE_MASK 0x0040000000000000UL -#define UV1H_GR0_TLB_MMR_CONTROL_MMR_INJ_TLBRREG_MASK 0x0100000000000000UL -#define UV1H_GR0_TLB_MMR_CONTROL_MMR_INJ_TLBLRUV_MASK 0x1000000000000000UL - -#define UV2H_GR0_TLB_MMR_CONTROL_INDEX_SHFT 0 -#define UV2H_GR0_TLB_MMR_CONTROL_MEM_SEL_SHFT 12 -#define UV2H_GR0_TLB_MMR_CONTROL_AUTO_VALID_EN_SHFT 16 -#define UV2H_GR0_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_SHFT 20 -#define UV2H_GR0_TLB_MMR_CONTROL_MMR_WRITE_SHFT 30 -#define UV2H_GR0_TLB_MMR_CONTROL_MMR_READ_SHFT 31 -#define UV2H_GR0_TLB_MMR_CONTROL_MMR_OP_DONE_SHFT 32 -#define UV2H_GR0_TLB_MMR_CONTROL_MMR_INJ_CON_SHFT 48 -#define UV2H_GR0_TLB_MMR_CONTROL_MMR_INJ_TLBRAM_SHFT 52 -#define UV2H_GR0_TLB_MMR_CONTROL_INDEX_MASK 0x0000000000000fffUL -#define UV2H_GR0_TLB_MMR_CONTROL_MEM_SEL_MASK 0x0000000000003000UL -#define UV2H_GR0_TLB_MMR_CONTROL_AUTO_VALID_EN_MASK 0x0000000000010000UL -#define UV2H_GR0_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_MASK 0x0000000000100000UL -#define UV2H_GR0_TLB_MMR_CONTROL_MMR_WRITE_MASK 0x0000000040000000UL -#define UV2H_GR0_TLB_MMR_CONTROL_MMR_READ_MASK 0x0000000080000000UL -#define UV2H_GR0_TLB_MMR_CONTROL_MMR_OP_DONE_MASK 0x0000000100000000UL -#define UV2H_GR0_TLB_MMR_CONTROL_MMR_INJ_CON_MASK 0x0001000000000000UL -#define UV2H_GR0_TLB_MMR_CONTROL_MMR_INJ_TLBRAM_MASK 0x0010000000000000UL - -union uvh_gr0_tlb_mmr_control_u { - unsigned long v; - struct uvh_gr0_tlb_mmr_control_s { - unsigned long index:12; /* RW */ - unsigned long mem_sel:2; /* RW */ - unsigned long rsvd_14_15:2; - unsigned long auto_valid_en:1; /* RW */ - unsigned long rsvd_17_19:3; - unsigned long mmr_hash_index_en:1; /* RW */ - unsigned long rsvd_21_29:9; - unsigned long mmr_write:1; /* WP */ - unsigned long mmr_read:1; /* WP */ - unsigned long rsvd_32_63:32; - } s; - struct uv1h_gr0_tlb_mmr_control_s { - unsigned long index:12; /* RW */ - unsigned long mem_sel:2; /* RW */ - unsigned long rsvd_14_15:2; - unsigned long auto_valid_en:1; /* RW */ - unsigned long rsvd_17_19:3; - unsigned long mmr_hash_index_en:1; /* RW */ - unsigned long rsvd_21_29:9; - unsigned long mmr_write:1; /* WP */ - unsigned long mmr_read:1; /* WP */ - unsigned long rsvd_32_47:16; - unsigned long mmr_inj_con:1; /* RW */ - unsigned long rsvd_49_51:3; - unsigned long mmr_inj_tlbram:1; /* RW */ - unsigned long rsvd_53:1; - unsigned long mmr_inj_tlbpgsize:1; /* RW */ - unsigned long rsvd_55:1; - unsigned long mmr_inj_tlbrreg:1; /* RW */ - unsigned long rsvd_57_59:3; - unsigned long mmr_inj_tlblruv:1; /* RW */ - unsigned long rsvd_61_63:3; - } s1; - struct uv2h_gr0_tlb_mmr_control_s { - unsigned long index:12; /* RW */ - unsigned long mem_sel:2; /* RW */ - unsigned long rsvd_14_15:2; - unsigned long auto_valid_en:1; /* RW */ - unsigned long rsvd_17_19:3; - unsigned long mmr_hash_index_en:1; /* RW */ - unsigned long rsvd_21_29:9; - unsigned long mmr_write:1; /* WP */ - unsigned long mmr_read:1; /* WP */ - unsigned long mmr_op_done:1; /* RW */ - unsigned long rsvd_33_47:15; - unsigned long mmr_inj_con:1; /* RW */ - unsigned long rsvd_49_51:3; - unsigned long mmr_inj_tlbram:1; /* RW */ - unsigned long rsvd_53_63:11; - } s2; -}; - -/* ========================================================================= */ -/* UVH_GR0_TLB_MMR_READ_DATA_HI */ -/* ========================================================================= */ -#define UV1H_GR0_TLB_MMR_READ_DATA_HI 0x4010a0UL -#define UV2H_GR0_TLB_MMR_READ_DATA_HI 0xc010a0UL -#define UVH_GR0_TLB_MMR_READ_DATA_HI (is_uv1_hub() ? \ - UV1H_GR0_TLB_MMR_READ_DATA_HI : \ - UV2H_GR0_TLB_MMR_READ_DATA_HI) - -#define UVH_GR0_TLB_MMR_READ_DATA_HI_PFN_SHFT 0 -#define UVH_GR0_TLB_MMR_READ_DATA_HI_GAA_SHFT 41 -#define UVH_GR0_TLB_MMR_READ_DATA_HI_DIRTY_SHFT 43 -#define UVH_GR0_TLB_MMR_READ_DATA_HI_LARGER_SHFT 44 -#define UVH_GR0_TLB_MMR_READ_DATA_HI_PFN_MASK 0x000001ffffffffffUL -#define UVH_GR0_TLB_MMR_READ_DATA_HI_GAA_MASK 0x0000060000000000UL -#define UVH_GR0_TLB_MMR_READ_DATA_HI_DIRTY_MASK 0x0000080000000000UL -#define UVH_GR0_TLB_MMR_READ_DATA_HI_LARGER_MASK 0x0000100000000000UL - -union uvh_gr0_tlb_mmr_read_data_hi_u { - unsigned long v; - struct uvh_gr0_tlb_mmr_read_data_hi_s { - unsigned long pfn:41; /* RO */ - unsigned long gaa:2; /* RO */ - unsigned long dirty:1; /* RO */ - unsigned long larger:1; /* RO */ - unsigned long rsvd_45_63:19; - } s; -}; - -/* ========================================================================= */ -/* UVH_GR0_TLB_MMR_READ_DATA_LO */ -/* ========================================================================= */ -#define UV1H_GR0_TLB_MMR_READ_DATA_LO 0x4010a8UL -#define UV2H_GR0_TLB_MMR_READ_DATA_LO 0xc010a8UL -#define UVH_GR0_TLB_MMR_READ_DATA_LO (is_uv1_hub() ? \ - UV1H_GR0_TLB_MMR_READ_DATA_LO : \ - UV2H_GR0_TLB_MMR_READ_DATA_LO) - -#define UVH_GR0_TLB_MMR_READ_DATA_LO_VPN_SHFT 0 -#define UVH_GR0_TLB_MMR_READ_DATA_LO_ASID_SHFT 39 -#define UVH_GR0_TLB_MMR_READ_DATA_LO_VALID_SHFT 63 -#define UVH_GR0_TLB_MMR_READ_DATA_LO_VPN_MASK 0x0000007fffffffffUL -#define UVH_GR0_TLB_MMR_READ_DATA_LO_ASID_MASK 0x7fffff8000000000UL -#define UVH_GR0_TLB_MMR_READ_DATA_LO_VALID_MASK 0x8000000000000000UL - -union uvh_gr0_tlb_mmr_read_data_lo_u { - unsigned long v; - struct uvh_gr0_tlb_mmr_read_data_lo_s { - unsigned long vpn:39; /* RO */ - unsigned long asid:24; /* RO */ - unsigned long valid:1; /* RO */ - } s; + unsigned long v; + struct uvh_gr0_tlb_int1_config_s { + unsigned long vector_ : 8; /* RW */ + unsigned long dm : 3; /* RW */ + unsigned long destmode : 1; /* RW */ + unsigned long status : 1; /* RO */ + unsigned long p : 1; /* RO */ + unsigned long rsvd_14 : 1; /* */ + unsigned long t : 1; /* RO */ + unsigned long m : 1; /* RW */ + unsigned long rsvd_17_31: 15; /* */ + unsigned long apic_id : 32; /* RW */ + } s; }; /* ========================================================================= */ /* UVH_GR1_TLB_INT0_CONFIG */ /* ========================================================================= */ -#define UVH_GR1_TLB_INT0_CONFIG 0x61f00UL - -#define UVH_GR1_TLB_INT0_CONFIG_VECTOR_SHFT 0 -#define UVH_GR1_TLB_INT0_CONFIG_DM_SHFT 8 -#define UVH_GR1_TLB_INT0_CONFIG_DESTMODE_SHFT 11 -#define UVH_GR1_TLB_INT0_CONFIG_STATUS_SHFT 12 -#define UVH_GR1_TLB_INT0_CONFIG_P_SHFT 13 -#define UVH_GR1_TLB_INT0_CONFIG_T_SHFT 15 -#define UVH_GR1_TLB_INT0_CONFIG_M_SHFT 16 -#define UVH_GR1_TLB_INT0_CONFIG_APIC_ID_SHFT 32 -#define UVH_GR1_TLB_INT0_CONFIG_VECTOR_MASK 0x00000000000000ffUL -#define UVH_GR1_TLB_INT0_CONFIG_DM_MASK 0x0000000000000700UL -#define UVH_GR1_TLB_INT0_CONFIG_DESTMODE_MASK 0x0000000000000800UL -#define UVH_GR1_TLB_INT0_CONFIG_STATUS_MASK 0x0000000000001000UL -#define UVH_GR1_TLB_INT0_CONFIG_P_MASK 0x0000000000002000UL -#define UVH_GR1_TLB_INT0_CONFIG_T_MASK 0x0000000000008000UL -#define UVH_GR1_TLB_INT0_CONFIG_M_MASK 0x0000000000010000UL -#define UVH_GR1_TLB_INT0_CONFIG_APIC_ID_MASK 0xffffffff00000000UL +#define UVH_GR1_TLB_INT0_CONFIG 0x61f00UL + +#define UVH_GR1_TLB_INT0_CONFIG_VECTOR_SHFT 0 +#define UVH_GR1_TLB_INT0_CONFIG_VECTOR_MASK 0x00000000000000ffUL +#define UVH_GR1_TLB_INT0_CONFIG_DM_SHFT 8 +#define UVH_GR1_TLB_INT0_CONFIG_DM_MASK 0x0000000000000700UL +#define UVH_GR1_TLB_INT0_CONFIG_DESTMODE_SHFT 11 +#define UVH_GR1_TLB_INT0_CONFIG_DESTMODE_MASK 0x0000000000000800UL +#define UVH_GR1_TLB_INT0_CONFIG_STATUS_SHFT 12 +#define UVH_GR1_TLB_INT0_CONFIG_STATUS_MASK 0x0000000000001000UL +#define UVH_GR1_TLB_INT0_CONFIG_P_SHFT 13 +#define UVH_GR1_TLB_INT0_CONFIG_P_MASK 0x0000000000002000UL +#define UVH_GR1_TLB_INT0_CONFIG_T_SHFT 15 +#define UVH_GR1_TLB_INT0_CONFIG_T_MASK 0x0000000000008000UL +#define UVH_GR1_TLB_INT0_CONFIG_M_SHFT 16 +#define UVH_GR1_TLB_INT0_CONFIG_M_MASK 0x0000000000010000UL +#define UVH_GR1_TLB_INT0_CONFIG_APIC_ID_SHFT 32 +#define UVH_GR1_TLB_INT0_CONFIG_APIC_ID_MASK 0xffffffff00000000UL union uvh_gr1_tlb_int0_config_u { - unsigned long v; - struct uvh_gr1_tlb_int0_config_s { - unsigned long vector_:8; /* RW */ - unsigned long dm:3; /* RW */ - unsigned long destmode:1; /* RW */ - unsigned long status:1; /* RO */ - unsigned long p:1; /* RO */ - unsigned long rsvd_14:1; - unsigned long t:1; /* RO */ - unsigned long m:1; /* RW */ - unsigned long rsvd_17_31:15; - unsigned long apic_id:32; /* RW */ - } s; + unsigned long v; + struct uvh_gr1_tlb_int0_config_s { + unsigned long vector_ : 8; /* RW */ + unsigned long dm : 3; /* RW */ + unsigned long destmode : 1; /* RW */ + unsigned long status : 1; /* RO */ + unsigned long p : 1; /* RO */ + unsigned long rsvd_14 : 1; /* */ + unsigned long t : 1; /* RO */ + unsigned long m : 1; /* RW */ + unsigned long rsvd_17_31: 15; /* */ + unsigned long apic_id : 32; /* RW */ + } s; }; /* ========================================================================= */ /* UVH_GR1_TLB_INT1_CONFIG */ /* ========================================================================= */ -#define UVH_GR1_TLB_INT1_CONFIG 0x61f40UL - -#define UVH_GR1_TLB_INT1_CONFIG_VECTOR_SHFT 0 -#define UVH_GR1_TLB_INT1_CONFIG_DM_SHFT 8 -#define UVH_GR1_TLB_INT1_CONFIG_DESTMODE_SHFT 11 -#define UVH_GR1_TLB_INT1_CONFIG_STATUS_SHFT 12 -#define UVH_GR1_TLB_INT1_CONFIG_P_SHFT 13 -#define UVH_GR1_TLB_INT1_CONFIG_T_SHFT 15 -#define UVH_GR1_TLB_INT1_CONFIG_M_SHFT 16 -#define UVH_GR1_TLB_INT1_CONFIG_APIC_ID_SHFT 32 -#define UVH_GR1_TLB_INT1_CONFIG_VECTOR_MASK 0x00000000000000ffUL -#define UVH_GR1_TLB_INT1_CONFIG_DM_MASK 0x0000000000000700UL -#define UVH_GR1_TLB_INT1_CONFIG_DESTMODE_MASK 0x0000000000000800UL -#define UVH_GR1_TLB_INT1_CONFIG_STATUS_MASK 0x0000000000001000UL -#define UVH_GR1_TLB_INT1_CONFIG_P_MASK 0x0000000000002000UL -#define UVH_GR1_TLB_INT1_CONFIG_T_MASK 0x0000000000008000UL -#define UVH_GR1_TLB_INT1_CONFIG_M_MASK 0x0000000000010000UL -#define UVH_GR1_TLB_INT1_CONFIG_APIC_ID_MASK 0xffffffff00000000UL +#define UVH_GR1_TLB_INT1_CONFIG 0x61f40UL + +#define UVH_GR1_TLB_INT1_CONFIG_VECTOR_SHFT 0 +#define UVH_GR1_TLB_INT1_CONFIG_VECTOR_MASK 0x00000000000000ffUL +#define UVH_GR1_TLB_INT1_CONFIG_DM_SHFT 8 +#define UVH_GR1_TLB_INT1_CONFIG_DM_MASK 0x0000000000000700UL +#define UVH_GR1_TLB_INT1_CONFIG_DESTMODE_SHFT 11 +#define UVH_GR1_TLB_INT1_CONFIG_DESTMODE_MASK 0x0000000000000800UL +#define UVH_GR1_TLB_INT1_CONFIG_STATUS_SHFT 12 +#define UVH_GR1_TLB_INT1_CONFIG_STATUS_MASK 0x0000000000001000UL +#define UVH_GR1_TLB_INT1_CONFIG_P_SHFT 13 +#define UVH_GR1_TLB_INT1_CONFIG_P_MASK 0x0000000000002000UL +#define UVH_GR1_TLB_INT1_CONFIG_T_SHFT 15 +#define UVH_GR1_TLB_INT1_CONFIG_T_MASK 0x0000000000008000UL +#define UVH_GR1_TLB_INT1_CONFIG_M_SHFT 16 +#define UVH_GR1_TLB_INT1_CONFIG_M_MASK 0x0000000000010000UL +#define UVH_GR1_TLB_INT1_CONFIG_APIC_ID_SHFT 32 +#define UVH_GR1_TLB_INT1_CONFIG_APIC_ID_MASK 0xffffffff00000000UL union uvh_gr1_tlb_int1_config_u { - unsigned long v; - struct uvh_gr1_tlb_int1_config_s { - unsigned long vector_:8; /* RW */ - unsigned long dm:3; /* RW */ - unsigned long destmode:1; /* RW */ - unsigned long status:1; /* RO */ - unsigned long p:1; /* RO */ - unsigned long rsvd_14:1; - unsigned long t:1; /* RO */ - unsigned long m:1; /* RW */ - unsigned long rsvd_17_31:15; - unsigned long apic_id:32; /* RW */ - } s; -}; - -/* ========================================================================= */ -/* UVH_GR1_TLB_MMR_CONTROL */ -/* ========================================================================= */ -#define UV1H_GR1_TLB_MMR_CONTROL 0x801080UL -#define UV2H_GR1_TLB_MMR_CONTROL 0x1001080UL -#define UVH_GR1_TLB_MMR_CONTROL (is_uv1_hub() ? \ - UV1H_GR1_TLB_MMR_CONTROL : \ - UV2H_GR1_TLB_MMR_CONTROL) - -#define UVH_GR1_TLB_MMR_CONTROL_INDEX_SHFT 0 -#define UVH_GR1_TLB_MMR_CONTROL_MEM_SEL_SHFT 12 -#define UVH_GR1_TLB_MMR_CONTROL_AUTO_VALID_EN_SHFT 16 -#define UVH_GR1_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_SHFT 20 -#define UVH_GR1_TLB_MMR_CONTROL_MMR_WRITE_SHFT 30 -#define UVH_GR1_TLB_MMR_CONTROL_MMR_READ_SHFT 31 -#define UVH_GR1_TLB_MMR_CONTROL_INDEX_MASK 0x0000000000000fffUL -#define UVH_GR1_TLB_MMR_CONTROL_MEM_SEL_MASK 0x0000000000003000UL -#define UVH_GR1_TLB_MMR_CONTROL_AUTO_VALID_EN_MASK 0x0000000000010000UL -#define UVH_GR1_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_MASK 0x0000000000100000UL -#define UVH_GR1_TLB_MMR_CONTROL_MMR_WRITE_MASK 0x0000000040000000UL -#define UVH_GR1_TLB_MMR_CONTROL_MMR_READ_MASK 0x0000000080000000UL - -#define UV1H_GR1_TLB_MMR_CONTROL_INDEX_SHFT 0 -#define UV1H_GR1_TLB_MMR_CONTROL_MEM_SEL_SHFT 12 -#define UV1H_GR1_TLB_MMR_CONTROL_AUTO_VALID_EN_SHFT 16 -#define UV1H_GR1_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_SHFT 20 -#define UV1H_GR1_TLB_MMR_CONTROL_MMR_WRITE_SHFT 30 -#define UV1H_GR1_TLB_MMR_CONTROL_MMR_READ_SHFT 31 -#define UV1H_GR1_TLB_MMR_CONTROL_MMR_INJ_CON_SHFT 48 -#define UV1H_GR1_TLB_MMR_CONTROL_MMR_INJ_TLBRAM_SHFT 52 -#define UV1H_GR1_TLB_MMR_CONTROL_MMR_INJ_TLBPGSIZE_SHFT 54 -#define UV1H_GR1_TLB_MMR_CONTROL_MMR_INJ_TLBRREG_SHFT 56 -#define UV1H_GR1_TLB_MMR_CONTROL_MMR_INJ_TLBLRUV_SHFT 60 -#define UV1H_GR1_TLB_MMR_CONTROL_INDEX_MASK 0x0000000000000fffUL -#define UV1H_GR1_TLB_MMR_CONTROL_MEM_SEL_MASK 0x0000000000003000UL -#define UV1H_GR1_TLB_MMR_CONTROL_AUTO_VALID_EN_MASK 0x0000000000010000UL -#define UV1H_GR1_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_MASK 0x0000000000100000UL -#define UV1H_GR1_TLB_MMR_CONTROL_MMR_WRITE_MASK 0x0000000040000000UL -#define UV1H_GR1_TLB_MMR_CONTROL_MMR_READ_MASK 0x0000000080000000UL -#define UV1H_GR1_TLB_MMR_CONTROL_MMR_INJ_CON_MASK 0x0001000000000000UL -#define UV1H_GR1_TLB_MMR_CONTROL_MMR_INJ_TLBRAM_MASK 0x0010000000000000UL -#define UV1H_GR1_TLB_MMR_CONTROL_MMR_INJ_TLBPGSIZE_MASK 0x0040000000000000UL -#define UV1H_GR1_TLB_MMR_CONTROL_MMR_INJ_TLBRREG_MASK 0x0100000000000000UL -#define UV1H_GR1_TLB_MMR_CONTROL_MMR_INJ_TLBLRUV_MASK 0x1000000000000000UL - -#define UV2H_GR1_TLB_MMR_CONTROL_INDEX_SHFT 0 -#define UV2H_GR1_TLB_MMR_CONTROL_MEM_SEL_SHFT 12 -#define UV2H_GR1_TLB_MMR_CONTROL_AUTO_VALID_EN_SHFT 16 -#define UV2H_GR1_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_SHFT 20 -#define UV2H_GR1_TLB_MMR_CONTROL_MMR_WRITE_SHFT 30 -#define UV2H_GR1_TLB_MMR_CONTROL_MMR_READ_SHFT 31 -#define UV2H_GR1_TLB_MMR_CONTROL_MMR_OP_DONE_SHFT 32 -#define UV2H_GR1_TLB_MMR_CONTROL_MMR_INJ_CON_SHFT 48 -#define UV2H_GR1_TLB_MMR_CONTROL_MMR_INJ_TLBRAM_SHFT 52 -#define UV2H_GR1_TLB_MMR_CONTROL_INDEX_MASK 0x0000000000000fffUL -#define UV2H_GR1_TLB_MMR_CONTROL_MEM_SEL_MASK 0x0000000000003000UL -#define UV2H_GR1_TLB_MMR_CONTROL_AUTO_VALID_EN_MASK 0x0000000000010000UL -#define UV2H_GR1_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_MASK 0x0000000000100000UL -#define UV2H_GR1_TLB_MMR_CONTROL_MMR_WRITE_MASK 0x0000000040000000UL -#define UV2H_GR1_TLB_MMR_CONTROL_MMR_READ_MASK 0x0000000080000000UL -#define UV2H_GR1_TLB_MMR_CONTROL_MMR_OP_DONE_MASK 0x0000000100000000UL -#define UV2H_GR1_TLB_MMR_CONTROL_MMR_INJ_CON_MASK 0x0001000000000000UL -#define UV2H_GR1_TLB_MMR_CONTROL_MMR_INJ_TLBRAM_MASK 0x0010000000000000UL - -union uvh_gr1_tlb_mmr_control_u { - unsigned long v; - struct uvh_gr1_tlb_mmr_control_s { - unsigned long index:12; /* RW */ - unsigned long mem_sel:2; /* RW */ - unsigned long rsvd_14_15:2; - unsigned long auto_valid_en:1; /* RW */ - unsigned long rsvd_17_19:3; - unsigned long mmr_hash_index_en:1; /* RW */ - unsigned long rsvd_21_29:9; - unsigned long mmr_write:1; /* WP */ - unsigned long mmr_read:1; /* WP */ - unsigned long rsvd_32_63:32; - } s; - struct uv1h_gr1_tlb_mmr_control_s { - unsigned long index:12; /* RW */ - unsigned long mem_sel:2; /* RW */ - unsigned long rsvd_14_15:2; - unsigned long auto_valid_en:1; /* RW */ - unsigned long rsvd_17_19:3; - unsigned long mmr_hash_index_en:1; /* RW */ - unsigned long rsvd_21_29:9; - unsigned long mmr_write:1; /* WP */ - unsigned long mmr_read:1; /* WP */ - unsigned long rsvd_32_47:16; - unsigned long mmr_inj_con:1; /* RW */ - unsigned long rsvd_49_51:3; - unsigned long mmr_inj_tlbram:1; /* RW */ - unsigned long rsvd_53:1; - unsigned long mmr_inj_tlbpgsize:1; /* RW */ - unsigned long rsvd_55:1; - unsigned long mmr_inj_tlbrreg:1; /* RW */ - unsigned long rsvd_57_59:3; - unsigned long mmr_inj_tlblruv:1; /* RW */ - unsigned long rsvd_61_63:3; - } s1; - struct uv2h_gr1_tlb_mmr_control_s { - unsigned long index:12; /* RW */ - unsigned long mem_sel:2; /* RW */ - unsigned long rsvd_14_15:2; - unsigned long auto_valid_en:1; /* RW */ - unsigned long rsvd_17_19:3; - unsigned long mmr_hash_index_en:1; /* RW */ - unsigned long rsvd_21_29:9; - unsigned long mmr_write:1; /* WP */ - unsigned long mmr_read:1; /* WP */ - unsigned long mmr_op_done:1; /* RW */ - unsigned long rsvd_33_47:15; - unsigned long mmr_inj_con:1; /* RW */ - unsigned long rsvd_49_51:3; - unsigned long mmr_inj_tlbram:1; /* RW */ - unsigned long rsvd_53_63:11; - } s2; -}; - -/* ========================================================================= */ -/* UVH_GR1_TLB_MMR_READ_DATA_HI */ -/* ========================================================================= */ -#define UV1H_GR1_TLB_MMR_READ_DATA_HI 0x8010a0UL -#define UV2H_GR1_TLB_MMR_READ_DATA_HI 0x10010a0UL -#define UVH_GR1_TLB_MMR_READ_DATA_HI (is_uv1_hub() ? \ - UV1H_GR1_TLB_MMR_READ_DATA_HI : \ - UV2H_GR1_TLB_MMR_READ_DATA_HI) - -#define UVH_GR1_TLB_MMR_READ_DATA_HI_PFN_SHFT 0 -#define UVH_GR1_TLB_MMR_READ_DATA_HI_GAA_SHFT 41 -#define UVH_GR1_TLB_MMR_READ_DATA_HI_DIRTY_SHFT 43 -#define UVH_GR1_TLB_MMR_READ_DATA_HI_LARGER_SHFT 44 -#define UVH_GR1_TLB_MMR_READ_DATA_HI_PFN_MASK 0x000001ffffffffffUL -#define UVH_GR1_TLB_MMR_READ_DATA_HI_GAA_MASK 0x0000060000000000UL -#define UVH_GR1_TLB_MMR_READ_DATA_HI_DIRTY_MASK 0x0000080000000000UL -#define UVH_GR1_TLB_MMR_READ_DATA_HI_LARGER_MASK 0x0000100000000000UL - -union uvh_gr1_tlb_mmr_read_data_hi_u { - unsigned long v; - struct uvh_gr1_tlb_mmr_read_data_hi_s { - unsigned long pfn:41; /* RO */ - unsigned long gaa:2; /* RO */ - unsigned long dirty:1; /* RO */ - unsigned long larger:1; /* RO */ - unsigned long rsvd_45_63:19; - } s; -}; - -/* ========================================================================= */ -/* UVH_GR1_TLB_MMR_READ_DATA_LO */ -/* ========================================================================= */ -#define UV1H_GR1_TLB_MMR_READ_DATA_LO 0x8010a8UL -#define UV2H_GR1_TLB_MMR_READ_DATA_LO 0x10010a8UL -#define UVH_GR1_TLB_MMR_READ_DATA_LO (is_uv1_hub() ? \ - UV1H_GR1_TLB_MMR_READ_DATA_LO : \ - UV2H_GR1_TLB_MMR_READ_DATA_LO) - -#define UVH_GR1_TLB_MMR_READ_DATA_LO_VPN_SHFT 0 -#define UVH_GR1_TLB_MMR_READ_DATA_LO_ASID_SHFT 39 -#define UVH_GR1_TLB_MMR_READ_DATA_LO_VALID_SHFT 63 -#define UVH_GR1_TLB_MMR_READ_DATA_LO_VPN_MASK 0x0000007fffffffffUL -#define UVH_GR1_TLB_MMR_READ_DATA_LO_ASID_MASK 0x7fffff8000000000UL -#define UVH_GR1_TLB_MMR_READ_DATA_LO_VALID_MASK 0x8000000000000000UL - -union uvh_gr1_tlb_mmr_read_data_lo_u { - unsigned long v; - struct uvh_gr1_tlb_mmr_read_data_lo_s { - unsigned long vpn:39; /* RO */ - unsigned long asid:24; /* RO */ - unsigned long valid:1; /* RO */ - } s; + unsigned long v; + struct uvh_gr1_tlb_int1_config_s { + unsigned long vector_ : 8; /* RW */ + unsigned long dm : 3; /* RW */ + unsigned long destmode : 1; /* RW */ + unsigned long status : 1; /* RO */ + unsigned long p : 1; /* RO */ + unsigned long rsvd_14 : 1; /* */ + unsigned long t : 1; /* RO */ + unsigned long m : 1; /* RW */ + unsigned long rsvd_17_31: 15; /* */ + unsigned long apic_id : 32; /* RW */ + } s; }; /* ========================================================================= */ /* UVH_INT_CMPB */ /* ========================================================================= */ -#define UVH_INT_CMPB 0x22080UL +#define UVH_INT_CMPB 0x22080UL -#define UVH_INT_CMPB_REAL_TIME_CMPB_SHFT 0 -#define UVH_INT_CMPB_REAL_TIME_CMPB_MASK 0x00ffffffffffffffUL +#define UVH_INT_CMPB_REAL_TIME_CMPB_SHFT 0 +#define UVH_INT_CMPB_REAL_TIME_CMPB_MASK 0x00ffffffffffffffUL union uvh_int_cmpb_u { - unsigned long v; - struct uvh_int_cmpb_s { - unsigned long real_time_cmpb:56; /* RW */ - unsigned long rsvd_56_63:8; - } s; + unsigned long v; + struct uvh_int_cmpb_s { + unsigned long real_time_cmpb : 56; /* RW */ + unsigned long rsvd_56_63 : 8; /* */ + } s; }; /* ========================================================================= */ /* UVH_INT_CMPC */ /* ========================================================================= */ -#define UVH_INT_CMPC 0x22100UL +#define UVH_INT_CMPC 0x22100UL -#define UVH_INT_CMPC_REAL_TIME_CMPC_SHFT 0 -#define UVH_INT_CMPC_REAL_TIME_CMPC_MASK 0xffffffffffffffUL +#define UV1H_INT_CMPC_REAL_TIME_CMPC_SHFT 0 +#define UV2H_INT_CMPC_REAL_TIME_CMPC_SHFT 0 +#define UVH_INT_CMPC_REAL_TIME_CMPC_SHFT (is_uv1_hub() ? \ + UV1H_INT_CMPC_REAL_TIME_CMPC_SHFT : \ + UV2H_INT_CMPC_REAL_TIME_CMPC_SHFT) +#define UV1H_INT_CMPC_REAL_TIME_CMPC_MASK 0xffffffffffffffUL +#define UV2H_INT_CMPC_REAL_TIME_CMPC_MASK 0xffffffffffffffUL +#define UVH_INT_CMPC_REAL_TIME_CMPC_MASK (is_uv1_hub() ? \ + UV1H_INT_CMPC_REAL_TIME_CMPC_MASK : \ + UV2H_INT_CMPC_REAL_TIME_CMPC_MASK) union uvh_int_cmpc_u { - unsigned long v; - struct uvh_int_cmpc_s { - unsigned long real_time_cmpc:56; /* RW */ - unsigned long rsvd_56_63:8; - } s; + unsigned long v; + struct uvh_int_cmpc_s { + unsigned long real_time_cmpc : 56; /* RW */ + unsigned long rsvd_56_63 : 8; /* */ + } s; }; /* ========================================================================= */ /* UVH_INT_CMPD */ /* ========================================================================= */ -#define UVH_INT_CMPD 0x22180UL +#define UVH_INT_CMPD 0x22180UL -#define UVH_INT_CMPD_REAL_TIME_CMPD_SHFT 0 -#define UVH_INT_CMPD_REAL_TIME_CMPD_MASK 0xffffffffffffffUL +#define UV1H_INT_CMPD_REAL_TIME_CMPD_SHFT 0 +#define UV2H_INT_CMPD_REAL_TIME_CMPD_SHFT 0 +#define UVH_INT_CMPD_REAL_TIME_CMPD_SHFT (is_uv1_hub() ? \ + UV1H_INT_CMPD_REAL_TIME_CMPD_SHFT : \ + UV2H_INT_CMPD_REAL_TIME_CMPD_SHFT) +#define UV1H_INT_CMPD_REAL_TIME_CMPD_MASK 0xffffffffffffffUL +#define UV2H_INT_CMPD_REAL_TIME_CMPD_MASK 0xffffffffffffffUL +#define UVH_INT_CMPD_REAL_TIME_CMPD_MASK (is_uv1_hub() ? \ + UV1H_INT_CMPD_REAL_TIME_CMPD_MASK : \ + UV2H_INT_CMPD_REAL_TIME_CMPD_MASK) union uvh_int_cmpd_u { - unsigned long v; - struct uvh_int_cmpd_s { - unsigned long real_time_cmpd:56; /* RW */ - unsigned long rsvd_56_63:8; - } s; + unsigned long v; + struct uvh_int_cmpd_s { + unsigned long real_time_cmpd : 56; /* RW */ + unsigned long rsvd_56_63 : 8; /* */ + } s; }; /* ========================================================================= */ /* UVH_IPI_INT */ /* ========================================================================= */ -#define UVH_IPI_INT 0x60500UL -#define UVH_IPI_INT_32 0x348 +#define UVH_IPI_INT 0x60500UL +#define UVH_IPI_INT_32 0x348 -#define UVH_IPI_INT_VECTOR_SHFT 0 -#define UVH_IPI_INT_DELIVERY_MODE_SHFT 8 -#define UVH_IPI_INT_DESTMODE_SHFT 11 -#define UVH_IPI_INT_APIC_ID_SHFT 16 -#define UVH_IPI_INT_SEND_SHFT 63 -#define UVH_IPI_INT_VECTOR_MASK 0x00000000000000ffUL -#define UVH_IPI_INT_DELIVERY_MODE_MASK 0x0000000000000700UL -#define UVH_IPI_INT_DESTMODE_MASK 0x0000000000000800UL -#define UVH_IPI_INT_APIC_ID_MASK 0x0000ffffffff0000UL -#define UVH_IPI_INT_SEND_MASK 0x8000000000000000UL +#define UVH_IPI_INT_VECTOR_SHFT 0 +#define UVH_IPI_INT_VECTOR_MASK 0x00000000000000ffUL +#define UVH_IPI_INT_DELIVERY_MODE_SHFT 8 +#define UVH_IPI_INT_DELIVERY_MODE_MASK 0x0000000000000700UL +#define UVH_IPI_INT_DESTMODE_SHFT 11 +#define UVH_IPI_INT_DESTMODE_MASK 0x0000000000000800UL +#define UVH_IPI_INT_APIC_ID_SHFT 16 +#define UVH_IPI_INT_APIC_ID_MASK 0x0000ffffffff0000UL +#define UVH_IPI_INT_SEND_SHFT 63 +#define UVH_IPI_INT_SEND_MASK 0x8000000000000000UL union uvh_ipi_int_u { - unsigned long v; - struct uvh_ipi_int_s { - unsigned long vector_:8; /* RW */ - unsigned long delivery_mode:3; /* RW */ - unsigned long destmode:1; /* RW */ - unsigned long rsvd_12_15:4; - unsigned long apic_id:32; /* RW */ - unsigned long rsvd_48_62:15; - unsigned long send:1; /* WP */ - } s; + unsigned long v; + struct uvh_ipi_int_s { + unsigned long vector_ : 8; /* RW */ + unsigned long delivery_mode : 3; /* RW */ + unsigned long destmode : 1; /* RW */ + unsigned long rsvd_12_15 : 4; /* */ + unsigned long apic_id : 32; /* RW */ + unsigned long rsvd_48_62 : 15; /* */ + unsigned long send : 1; /* WP */ + } s; }; /* ========================================================================= */ /* UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST */ /* ========================================================================= */ -#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST 0x320050UL -#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST_32 0x9c0 +#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST 0x320050UL +#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST_32 0x9c0 #define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST_ADDRESS_SHFT 4 -#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST_NODE_ID_SHFT 49 #define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST_ADDRESS_MASK 0x000007fffffffff0UL +#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST_NODE_ID_SHFT 49 #define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST_NODE_ID_MASK 0x7ffe000000000000UL union uvh_lb_bau_intd_payload_queue_first_u { - unsigned long v; - struct uvh_lb_bau_intd_payload_queue_first_s { - unsigned long rsvd_0_3:4; - unsigned long address:39; /* RW */ - unsigned long rsvd_43_48:6; - unsigned long node_id:14; /* RW */ - unsigned long rsvd_63:1; - } s; + unsigned long v; + struct uvh_lb_bau_intd_payload_queue_first_s { + unsigned long rsvd_0_3: 4; /* */ + unsigned long address : 39; /* RW */ + unsigned long rsvd_43_48: 6; /* */ + unsigned long node_id : 14; /* RW */ + unsigned long rsvd_63 : 1; /* */ + } s; }; /* ========================================================================= */ /* UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST */ /* ========================================================================= */ -#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST 0x320060UL -#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST_32 0x9c8 +#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST 0x320060UL +#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST_32 0x9c8 -#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST_ADDRESS_SHFT 4 -#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST_ADDRESS_MASK 0x000007fffffffff0UL +#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST_ADDRESS_SHFT 4 +#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST_ADDRESS_MASK 0x000007fffffffff0UL union uvh_lb_bau_intd_payload_queue_last_u { - unsigned long v; - struct uvh_lb_bau_intd_payload_queue_last_s { - unsigned long rsvd_0_3:4; - unsigned long address:39; /* RW */ - unsigned long rsvd_43_63:21; - } s; + unsigned long v; + struct uvh_lb_bau_intd_payload_queue_last_s { + unsigned long rsvd_0_3: 4; /* */ + unsigned long address : 39; /* RW */ + unsigned long rsvd_43_63: 21; /* */ + } s; }; /* ========================================================================= */ /* UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL */ /* ========================================================================= */ -#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL 0x320070UL -#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL_32 0x9d0 +#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL 0x320070UL +#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL_32 0x9d0 -#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL_ADDRESS_SHFT 4 -#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL_ADDRESS_MASK 0x000007fffffffff0UL +#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL_ADDRESS_SHFT 4 +#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL_ADDRESS_MASK 0x000007fffffffff0UL union uvh_lb_bau_intd_payload_queue_tail_u { - unsigned long v; - struct uvh_lb_bau_intd_payload_queue_tail_s { - unsigned long rsvd_0_3:4; - unsigned long address:39; /* RW */ - unsigned long rsvd_43_63:21; - } s; + unsigned long v; + struct uvh_lb_bau_intd_payload_queue_tail_s { + unsigned long rsvd_0_3: 4; /* */ + unsigned long address : 39; /* RW */ + unsigned long rsvd_43_63: 21; /* */ + } s; }; /* ========================================================================= */ /* UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE */ /* ========================================================================= */ -#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE 0x320080UL -#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_32 0xa68 +#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE 0x320080UL +#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_32 0xa68 #define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_0_SHFT 0 -#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_1_SHFT 1 -#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_2_SHFT 2 -#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_3_SHFT 3 -#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_4_SHFT 4 -#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_5_SHFT 5 -#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_6_SHFT 6 -#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_7_SHFT 7 -#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_0_SHFT 8 -#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_1_SHFT 9 -#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_2_SHFT 10 -#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_3_SHFT 11 -#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_4_SHFT 12 -#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_5_SHFT 13 -#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_6_SHFT 14 -#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_7_SHFT 15 #define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_0_MASK 0x0000000000000001UL +#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_1_SHFT 1 #define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_1_MASK 0x0000000000000002UL +#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_2_SHFT 2 #define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_2_MASK 0x0000000000000004UL +#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_3_SHFT 3 #define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_3_MASK 0x0000000000000008UL +#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_4_SHFT 4 #define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_4_MASK 0x0000000000000010UL +#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_5_SHFT 5 #define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_5_MASK 0x0000000000000020UL +#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_6_SHFT 6 #define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_6_MASK 0x0000000000000040UL +#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_7_SHFT 7 #define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_7_MASK 0x0000000000000080UL +#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_0_SHFT 8 #define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_0_MASK 0x0000000000000100UL +#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_1_SHFT 9 #define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_1_MASK 0x0000000000000200UL +#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_2_SHFT 10 #define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_2_MASK 0x0000000000000400UL +#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_3_SHFT 11 #define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_3_MASK 0x0000000000000800UL +#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_4_SHFT 12 #define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_4_MASK 0x0000000000001000UL +#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_5_SHFT 13 #define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_5_MASK 0x0000000000002000UL +#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_6_SHFT 14 #define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_6_MASK 0x0000000000004000UL +#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_7_SHFT 15 #define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_7_MASK 0x0000000000008000UL union uvh_lb_bau_intd_software_acknowledge_u { - unsigned long v; - struct uvh_lb_bau_intd_software_acknowledge_s { - unsigned long pending_0:1; /* RW, W1C */ - unsigned long pending_1:1; /* RW, W1C */ - unsigned long pending_2:1; /* RW, W1C */ - unsigned long pending_3:1; /* RW, W1C */ - unsigned long pending_4:1; /* RW, W1C */ - unsigned long pending_5:1; /* RW, W1C */ - unsigned long pending_6:1; /* RW, W1C */ - unsigned long pending_7:1; /* RW, W1C */ - unsigned long timeout_0:1; /* RW, W1C */ - unsigned long timeout_1:1; /* RW, W1C */ - unsigned long timeout_2:1; /* RW, W1C */ - unsigned long timeout_3:1; /* RW, W1C */ - unsigned long timeout_4:1; /* RW, W1C */ - unsigned long timeout_5:1; /* RW, W1C */ - unsigned long timeout_6:1; /* RW, W1C */ - unsigned long timeout_7:1; /* RW, W1C */ - unsigned long rsvd_16_63:48; - } s; + unsigned long v; + struct uvh_lb_bau_intd_software_acknowledge_s { + unsigned long pending_0 : 1; /* RW, W1C */ + unsigned long pending_1 : 1; /* RW, W1C */ + unsigned long pending_2 : 1; /* RW, W1C */ + unsigned long pending_3 : 1; /* RW, W1C */ + unsigned long pending_4 : 1; /* RW, W1C */ + unsigned long pending_5 : 1; /* RW, W1C */ + unsigned long pending_6 : 1; /* RW, W1C */ + unsigned long pending_7 : 1; /* RW, W1C */ + unsigned long timeout_0 : 1; /* RW, W1C */ + unsigned long timeout_1 : 1; /* RW, W1C */ + unsigned long timeout_2 : 1; /* RW, W1C */ + unsigned long timeout_3 : 1; /* RW, W1C */ + unsigned long timeout_4 : 1; /* RW, W1C */ + unsigned long timeout_5 : 1; /* RW, W1C */ + unsigned long timeout_6 : 1; /* RW, W1C */ + unsigned long timeout_7 : 1; /* RW, W1C */ + unsigned long rsvd_16_63: 48; /* */ + } s; }; /* ========================================================================= */ /* UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS */ /* ========================================================================= */ -#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS 0x0000000000320088UL -#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS_32 0xa70 +#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS 0x0000000000320088UL +#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS_32 0xa70 /* ========================================================================= */ /* UVH_LB_BAU_MISC_CONTROL */ /* ========================================================================= */ -#define UVH_LB_BAU_MISC_CONTROL 0x320170UL -#define UVH_LB_BAU_MISC_CONTROL_32 0xa10 - -#define UVH_LB_BAU_MISC_CONTROL_REJECTION_DELAY_SHFT 0 -#define UVH_LB_BAU_MISC_CONTROL_APIC_MODE_SHFT 8 -#define UVH_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_SHFT 9 -#define UVH_LB_BAU_MISC_CONTROL_FORCE_LOCK_NOP_SHFT 10 +#define UVH_LB_BAU_MISC_CONTROL 0x320170UL +#define UVH_LB_BAU_MISC_CONTROL_32 0xa10 + +#define UVH_LB_BAU_MISC_CONTROL_REJECTION_DELAY_SHFT 0 +#define UVH_LB_BAU_MISC_CONTROL_REJECTION_DELAY_MASK 0x00000000000000ffUL +#define UVH_LB_BAU_MISC_CONTROL_APIC_MODE_SHFT 8 +#define UVH_LB_BAU_MISC_CONTROL_APIC_MODE_MASK 0x0000000000000100UL +#define UVH_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_SHFT 9 +#define UVH_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_MASK 0x0000000000000200UL +#define UVH_LB_BAU_MISC_CONTROL_FORCE_LOCK_NOP_SHFT 10 +#define UVH_LB_BAU_MISC_CONTROL_FORCE_LOCK_NOP_MASK 0x0000000000000400UL #define UVH_LB_BAU_MISC_CONTROL_QPI_AGENT_PRESENCE_VECTOR_SHFT 11 -#define UVH_LB_BAU_MISC_CONTROL_DESCRIPTOR_FETCH_MODE_SHFT 14 -#define UVH_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_SHFT 15 -#define UVH_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_SHFT 16 -#define UVH_LB_BAU_MISC_CONTROL_ENABLE_DUAL_MAPPING_MODE_SHFT 20 -#define UVH_LB_BAU_MISC_CONTROL_VGA_IO_PORT_DECODE_ENABLE_SHFT 21 -#define UVH_LB_BAU_MISC_CONTROL_VGA_IO_PORT_16_BIT_DECODE_SHFT 22 -#define UVH_LB_BAU_MISC_CONTROL_SUPPRESS_DEST_REGISTRATION_SHFT 23 -#define UVH_LB_BAU_MISC_CONTROL_PROGRAMMED_INITIAL_PRIORITY_SHFT 24 -#define UVH_LB_BAU_MISC_CONTROL_USE_INCOMING_PRIORITY_SHFT 27 -#define UVH_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_SHFT 28 -#define UVH_LB_BAU_MISC_CONTROL_REJECTION_DELAY_MASK 0x00000000000000ffUL -#define UVH_LB_BAU_MISC_CONTROL_APIC_MODE_MASK 0x0000000000000100UL -#define UVH_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_MASK 0x0000000000000200UL -#define UVH_LB_BAU_MISC_CONTROL_FORCE_LOCK_NOP_MASK 0x0000000000000400UL #define UVH_LB_BAU_MISC_CONTROL_QPI_AGENT_PRESENCE_VECTOR_MASK 0x0000000000003800UL +#define UVH_LB_BAU_MISC_CONTROL_DESCRIPTOR_FETCH_MODE_SHFT 14 #define UVH_LB_BAU_MISC_CONTROL_DESCRIPTOR_FETCH_MODE_MASK 0x0000000000004000UL +#define UVH_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_SHFT 15 #define UVH_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_MASK 0x0000000000008000UL +#define UVH_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_SHFT 16 #define UVH_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_MASK 0x00000000000f0000UL +#define UVH_LB_BAU_MISC_CONTROL_ENABLE_DUAL_MAPPING_MODE_SHFT 20 #define UVH_LB_BAU_MISC_CONTROL_ENABLE_DUAL_MAPPING_MODE_MASK 0x0000000000100000UL +#define UVH_LB_BAU_MISC_CONTROL_VGA_IO_PORT_DECODE_ENABLE_SHFT 21 #define UVH_LB_BAU_MISC_CONTROL_VGA_IO_PORT_DECODE_ENABLE_MASK 0x0000000000200000UL +#define UVH_LB_BAU_MISC_CONTROL_VGA_IO_PORT_16_BIT_DECODE_SHFT 22 #define UVH_LB_BAU_MISC_CONTROL_VGA_IO_PORT_16_BIT_DECODE_MASK 0x0000000000400000UL +#define UVH_LB_BAU_MISC_CONTROL_SUPPRESS_DEST_REGISTRATION_SHFT 23 #define UVH_LB_BAU_MISC_CONTROL_SUPPRESS_DEST_REGISTRATION_MASK 0x0000000000800000UL +#define UVH_LB_BAU_MISC_CONTROL_PROGRAMMED_INITIAL_PRIORITY_SHFT 24 #define UVH_LB_BAU_MISC_CONTROL_PROGRAMMED_INITIAL_PRIORITY_MASK 0x0000000007000000UL +#define UVH_LB_BAU_MISC_CONTROL_USE_INCOMING_PRIORITY_SHFT 27 #define UVH_LB_BAU_MISC_CONTROL_USE_INCOMING_PRIORITY_MASK 0x0000000008000000UL +#define UVH_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_SHFT 28 #define UVH_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_MASK 0x0000000010000000UL -#define UV1H_LB_BAU_MISC_CONTROL_REJECTION_DELAY_SHFT 0 -#define UV1H_LB_BAU_MISC_CONTROL_APIC_MODE_SHFT 8 -#define UV1H_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_SHFT 9 -#define UV1H_LB_BAU_MISC_CONTROL_FORCE_LOCK_NOP_SHFT 10 +#define UV1H_LB_BAU_MISC_CONTROL_REJECTION_DELAY_SHFT 0 +#define UV1H_LB_BAU_MISC_CONTROL_REJECTION_DELAY_MASK 0x00000000000000ffUL +#define UV1H_LB_BAU_MISC_CONTROL_APIC_MODE_SHFT 8 +#define UV1H_LB_BAU_MISC_CONTROL_APIC_MODE_MASK 0x0000000000000100UL +#define UV1H_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_SHFT 9 +#define UV1H_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_MASK 0x0000000000000200UL +#define UV1H_LB_BAU_MISC_CONTROL_FORCE_LOCK_NOP_SHFT 10 +#define UV1H_LB_BAU_MISC_CONTROL_FORCE_LOCK_NOP_MASK 0x0000000000000400UL #define UV1H_LB_BAU_MISC_CONTROL_QPI_AGENT_PRESENCE_VECTOR_SHFT 11 -#define UV1H_LB_BAU_MISC_CONTROL_DESCRIPTOR_FETCH_MODE_SHFT 14 -#define UV1H_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_SHFT 15 -#define UV1H_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_SHFT 16 -#define UV1H_LB_BAU_MISC_CONTROL_ENABLE_DUAL_MAPPING_MODE_SHFT 20 -#define UV1H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_DECODE_ENABLE_SHFT 21 -#define UV1H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_16_BIT_DECODE_SHFT 22 -#define UV1H_LB_BAU_MISC_CONTROL_SUPPRESS_DEST_REGISTRATION_SHFT 23 -#define UV1H_LB_BAU_MISC_CONTROL_PROGRAMMED_INITIAL_PRIORITY_SHFT 24 -#define UV1H_LB_BAU_MISC_CONTROL_USE_INCOMING_PRIORITY_SHFT 27 -#define UV1H_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_SHFT 28 -#define UV1H_LB_BAU_MISC_CONTROL_FUN_SHFT 48 -#define UV1H_LB_BAU_MISC_CONTROL_REJECTION_DELAY_MASK 0x00000000000000ffUL -#define UV1H_LB_BAU_MISC_CONTROL_APIC_MODE_MASK 0x0000000000000100UL -#define UV1H_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_MASK 0x0000000000000200UL -#define UV1H_LB_BAU_MISC_CONTROL_FORCE_LOCK_NOP_MASK 0x0000000000000400UL #define UV1H_LB_BAU_MISC_CONTROL_QPI_AGENT_PRESENCE_VECTOR_MASK 0x0000000000003800UL +#define UV1H_LB_BAU_MISC_CONTROL_DESCRIPTOR_FETCH_MODE_SHFT 14 #define UV1H_LB_BAU_MISC_CONTROL_DESCRIPTOR_FETCH_MODE_MASK 0x0000000000004000UL +#define UV1H_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_SHFT 15 #define UV1H_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_MASK 0x0000000000008000UL +#define UV1H_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_SHFT 16 #define UV1H_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_MASK 0x00000000000f0000UL +#define UV1H_LB_BAU_MISC_CONTROL_ENABLE_DUAL_MAPPING_MODE_SHFT 20 #define UV1H_LB_BAU_MISC_CONTROL_ENABLE_DUAL_MAPPING_MODE_MASK 0x0000000000100000UL +#define UV1H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_DECODE_ENABLE_SHFT 21 #define UV1H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_DECODE_ENABLE_MASK 0x0000000000200000UL +#define UV1H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_16_BIT_DECODE_SHFT 22 #define UV1H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_16_BIT_DECODE_MASK 0x0000000000400000UL +#define UV1H_LB_BAU_MISC_CONTROL_SUPPRESS_DEST_REGISTRATION_SHFT 23 #define UV1H_LB_BAU_MISC_CONTROL_SUPPRESS_DEST_REGISTRATION_MASK 0x0000000000800000UL +#define UV1H_LB_BAU_MISC_CONTROL_PROGRAMMED_INITIAL_PRIORITY_SHFT 24 #define UV1H_LB_BAU_MISC_CONTROL_PROGRAMMED_INITIAL_PRIORITY_MASK 0x0000000007000000UL +#define UV1H_LB_BAU_MISC_CONTROL_USE_INCOMING_PRIORITY_SHFT 27 #define UV1H_LB_BAU_MISC_CONTROL_USE_INCOMING_PRIORITY_MASK 0x0000000008000000UL +#define UV1H_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_SHFT 28 #define UV1H_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_MASK 0x0000000010000000UL -#define UV1H_LB_BAU_MISC_CONTROL_FUN_MASK 0xffff000000000000UL - -#define UV2H_LB_BAU_MISC_CONTROL_REJECTION_DELAY_SHFT 0 -#define UV2H_LB_BAU_MISC_CONTROL_APIC_MODE_SHFT 8 -#define UV2H_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_SHFT 9 -#define UV2H_LB_BAU_MISC_CONTROL_FORCE_LOCK_NOP_SHFT 10 +#define UV1H_LB_BAU_MISC_CONTROL_FUN_SHFT 48 +#define UV1H_LB_BAU_MISC_CONTROL_FUN_MASK 0xffff000000000000UL + +#define UV2H_LB_BAU_MISC_CONTROL_REJECTION_DELAY_SHFT 0 +#define UV2H_LB_BAU_MISC_CONTROL_REJECTION_DELAY_MASK 0x00000000000000ffUL +#define UV2H_LB_BAU_MISC_CONTROL_APIC_MODE_SHFT 8 +#define UV2H_LB_BAU_MISC_CONTROL_APIC_MODE_MASK 0x0000000000000100UL +#define UV2H_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_SHFT 9 +#define UV2H_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_MASK 0x0000000000000200UL +#define UV2H_LB_BAU_MISC_CONTROL_FORCE_LOCK_NOP_SHFT 10 +#define UV2H_LB_BAU_MISC_CONTROL_FORCE_LOCK_NOP_MASK 0x0000000000000400UL #define UV2H_LB_BAU_MISC_CONTROL_QPI_AGENT_PRESENCE_VECTOR_SHFT 11 -#define UV2H_LB_BAU_MISC_CONTROL_DESCRIPTOR_FETCH_MODE_SHFT 14 -#define UV2H_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_SHFT 15 -#define UV2H_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_SHFT 16 -#define UV2H_LB_BAU_MISC_CONTROL_ENABLE_DUAL_MAPPING_MODE_SHFT 20 -#define UV2H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_DECODE_ENABLE_SHFT 21 -#define UV2H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_16_BIT_DECODE_SHFT 22 -#define UV2H_LB_BAU_MISC_CONTROL_SUPPRESS_DEST_REGISTRATION_SHFT 23 -#define UV2H_LB_BAU_MISC_CONTROL_PROGRAMMED_INITIAL_PRIORITY_SHFT 24 -#define UV2H_LB_BAU_MISC_CONTROL_USE_INCOMING_PRIORITY_SHFT 27 -#define UV2H_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_SHFT 28 -#define UV2H_LB_BAU_MISC_CONTROL_ENABLE_AUTOMATIC_APIC_MODE_SELECTION_SHFT 29 -#define UV2H_LB_BAU_MISC_CONTROL_APIC_MODE_STATUS_SHFT 30 -#define UV2H_LB_BAU_MISC_CONTROL_SUPPRESS_INTERRUPTS_TO_SELF_SHFT 31 -#define UV2H_LB_BAU_MISC_CONTROL_ENABLE_LOCK_BASED_SYSTEM_FLUSH_SHFT 32 -#define UV2H_LB_BAU_MISC_CONTROL_ENABLE_EXTENDED_SB_STATUS_SHFT 33 -#define UV2H_LB_BAU_MISC_CONTROL_SUPPRESS_INT_PRIO_UDT_TO_SELF_SHFT 34 -#define UV2H_LB_BAU_MISC_CONTROL_USE_LEGACY_DESCRIPTOR_FORMATS_SHFT 35 -#define UV2H_LB_BAU_MISC_CONTROL_FUN_SHFT 48 -#define UV2H_LB_BAU_MISC_CONTROL_REJECTION_DELAY_MASK 0x00000000000000ffUL -#define UV2H_LB_BAU_MISC_CONTROL_APIC_MODE_MASK 0x0000000000000100UL -#define UV2H_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_MASK 0x0000000000000200UL -#define UV2H_LB_BAU_MISC_CONTROL_FORCE_LOCK_NOP_MASK 0x0000000000000400UL #define UV2H_LB_BAU_MISC_CONTROL_QPI_AGENT_PRESENCE_VECTOR_MASK 0x0000000000003800UL +#define UV2H_LB_BAU_MISC_CONTROL_DESCRIPTOR_FETCH_MODE_SHFT 14 #define UV2H_LB_BAU_MISC_CONTROL_DESCRIPTOR_FETCH_MODE_MASK 0x0000000000004000UL +#define UV2H_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_SHFT 15 #define UV2H_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_MASK 0x0000000000008000UL +#define UV2H_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_SHFT 16 #define UV2H_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_MASK 0x00000000000f0000UL +#define UV2H_LB_BAU_MISC_CONTROL_ENABLE_DUAL_MAPPING_MODE_SHFT 20 #define UV2H_LB_BAU_MISC_CONTROL_ENABLE_DUAL_MAPPING_MODE_MASK 0x0000000000100000UL +#define UV2H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_DECODE_ENABLE_SHFT 21 #define UV2H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_DECODE_ENABLE_MASK 0x0000000000200000UL +#define UV2H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_16_BIT_DECODE_SHFT 22 #define UV2H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_16_BIT_DECODE_MASK 0x0000000000400000UL +#define UV2H_LB_BAU_MISC_CONTROL_SUPPRESS_DEST_REGISTRATION_SHFT 23 #define UV2H_LB_BAU_MISC_CONTROL_SUPPRESS_DEST_REGISTRATION_MASK 0x0000000000800000UL +#define UV2H_LB_BAU_MISC_CONTROL_PROGRAMMED_INITIAL_PRIORITY_SHFT 24 #define UV2H_LB_BAU_MISC_CONTROL_PROGRAMMED_INITIAL_PRIORITY_MASK 0x0000000007000000UL +#define UV2H_LB_BAU_MISC_CONTROL_USE_INCOMING_PRIORITY_SHFT 27 #define UV2H_LB_BAU_MISC_CONTROL_USE_INCOMING_PRIORITY_MASK 0x0000000008000000UL +#define UV2H_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_SHFT 28 #define UV2H_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_MASK 0x0000000010000000UL +#define UV2H_LB_BAU_MISC_CONTROL_ENABLE_AUTOMATIC_APIC_MODE_SELECTION_SHFT 29 #define UV2H_LB_BAU_MISC_CONTROL_ENABLE_AUTOMATIC_APIC_MODE_SELECTION_MASK 0x0000000020000000UL -#define UV2H_LB_BAU_MISC_CONTROL_APIC_MODE_STATUS_MASK 0x0000000040000000UL +#define UV2H_LB_BAU_MISC_CONTROL_APIC_MODE_STATUS_SHFT 30 +#define UV2H_LB_BAU_MISC_CONTROL_APIC_MODE_STATUS_MASK 0x0000000040000000UL +#define UV2H_LB_BAU_MISC_CONTROL_SUPPRESS_INTERRUPTS_TO_SELF_SHFT 31 #define UV2H_LB_BAU_MISC_CONTROL_SUPPRESS_INTERRUPTS_TO_SELF_MASK 0x0000000080000000UL +#define UV2H_LB_BAU_MISC_CONTROL_ENABLE_LOCK_BASED_SYSTEM_FLUSH_SHFT 32 #define UV2H_LB_BAU_MISC_CONTROL_ENABLE_LOCK_BASED_SYSTEM_FLUSH_MASK 0x0000000100000000UL +#define UV2H_LB_BAU_MISC_CONTROL_ENABLE_EXTENDED_SB_STATUS_SHFT 33 #define UV2H_LB_BAU_MISC_CONTROL_ENABLE_EXTENDED_SB_STATUS_MASK 0x0000000200000000UL +#define UV2H_LB_BAU_MISC_CONTROL_SUPPRESS_INT_PRIO_UDT_TO_SELF_SHFT 34 #define UV2H_LB_BAU_MISC_CONTROL_SUPPRESS_INT_PRIO_UDT_TO_SELF_MASK 0x0000000400000000UL +#define UV2H_LB_BAU_MISC_CONTROL_USE_LEGACY_DESCRIPTOR_FORMATS_SHFT 35 #define UV2H_LB_BAU_MISC_CONTROL_USE_LEGACY_DESCRIPTOR_FORMATS_MASK 0x0000000800000000UL -#define UV2H_LB_BAU_MISC_CONTROL_FUN_MASK 0xffff000000000000UL +#define UV2H_LB_BAU_MISC_CONTROL_FUN_SHFT 48 +#define UV2H_LB_BAU_MISC_CONTROL_FUN_MASK 0xffff000000000000UL union uvh_lb_bau_misc_control_u { - unsigned long v; - struct uvh_lb_bau_misc_control_s { - unsigned long rejection_delay:8; /* RW */ - unsigned long apic_mode:1; /* RW */ - unsigned long force_broadcast:1; /* RW */ - unsigned long force_lock_nop:1; /* RW */ - unsigned long qpi_agent_presence_vector:3; /* RW */ - unsigned long descriptor_fetch_mode:1; /* RW */ - unsigned long enable_intd_soft_ack_mode:1; /* RW */ - unsigned long intd_soft_ack_timeout_period:4; /* RW */ - unsigned long enable_dual_mapping_mode:1; /* RW */ - unsigned long vga_io_port_decode_enable:1; /* RW */ - unsigned long vga_io_port_16_bit_decode:1; /* RW */ - unsigned long suppress_dest_registration:1; /* RW */ - unsigned long programmed_initial_priority:3; /* RW */ - unsigned long use_incoming_priority:1; /* RW */ - unsigned long enable_programmed_initial_priority:1;/* RW */ - unsigned long rsvd_29_63:35; - } s; - struct uv1h_lb_bau_misc_control_s { - unsigned long rejection_delay:8; /* RW */ - unsigned long apic_mode:1; /* RW */ - unsigned long force_broadcast:1; /* RW */ - unsigned long force_lock_nop:1; /* RW */ - unsigned long qpi_agent_presence_vector:3; /* RW */ - unsigned long descriptor_fetch_mode:1; /* RW */ - unsigned long enable_intd_soft_ack_mode:1; /* RW */ - unsigned long intd_soft_ack_timeout_period:4; /* RW */ - unsigned long enable_dual_mapping_mode:1; /* RW */ - unsigned long vga_io_port_decode_enable:1; /* RW */ - unsigned long vga_io_port_16_bit_decode:1; /* RW */ - unsigned long suppress_dest_registration:1; /* RW */ - unsigned long programmed_initial_priority:3; /* RW */ - unsigned long use_incoming_priority:1; /* RW */ - unsigned long enable_programmed_initial_priority:1;/* RW */ - unsigned long rsvd_29_47:19; - unsigned long fun:16; /* RW */ - } s1; - struct uv2h_lb_bau_misc_control_s { - unsigned long rejection_delay:8; /* RW */ - unsigned long apic_mode:1; /* RW */ - unsigned long force_broadcast:1; /* RW */ - unsigned long force_lock_nop:1; /* RW */ - unsigned long qpi_agent_presence_vector:3; /* RW */ - unsigned long descriptor_fetch_mode:1; /* RW */ - unsigned long enable_intd_soft_ack_mode:1; /* RW */ - unsigned long intd_soft_ack_timeout_period:4; /* RW */ - unsigned long enable_dual_mapping_mode:1; /* RW */ - unsigned long vga_io_port_decode_enable:1; /* RW */ - unsigned long vga_io_port_16_bit_decode:1; /* RW */ - unsigned long suppress_dest_registration:1; /* RW */ - unsigned long programmed_initial_priority:3; /* RW */ - unsigned long use_incoming_priority:1; /* RW */ - unsigned long enable_programmed_initial_priority:1;/* RW */ - unsigned long enable_automatic_apic_mode_selection:1;/* RW */ - unsigned long apic_mode_status:1; /* RO */ - unsigned long suppress_interrupts_to_self:1; /* RW */ - unsigned long enable_lock_based_system_flush:1;/* RW */ - unsigned long enable_extended_sb_status:1; /* RW */ - unsigned long suppress_int_prio_udt_to_self:1;/* RW */ - unsigned long use_legacy_descriptor_formats:1;/* RW */ - unsigned long rsvd_36_47:12; - unsigned long fun:16; /* RW */ - } s2; + unsigned long v; + struct uvh_lb_bau_misc_control_s { + unsigned long rejection_delay : 8; /* RW */ + unsigned long apic_mode : 1; /* RW */ + unsigned long force_broadcast : 1; /* RW */ + unsigned long force_lock_nop : 1; /* RW */ + unsigned long qpi_agent_presence_vector : 3; /* RW */ + unsigned long descriptor_fetch_mode : 1; /* RW */ + unsigned long enable_intd_soft_ack_mode : 1; /* RW */ + unsigned long intd_soft_ack_timeout_period : 4; /* RW */ + unsigned long enable_dual_mapping_mode : 1; /* RW */ + unsigned long vga_io_port_decode_enable : 1; /* RW */ + unsigned long vga_io_port_16_bit_decode : 1; /* RW */ + unsigned long suppress_dest_registration : 1; /* RW */ + unsigned long programmed_initial_priority : 3; /* RW */ + unsigned long use_incoming_priority : 1; /* RW */ + unsigned long enable_programmed_initial_priority : 1; /* RW */ + unsigned long rsvd_29_63 : 35; + } s; + struct uv1h_lb_bau_misc_control_s { + unsigned long rejection_delay : 8; /* RW */ + unsigned long apic_mode : 1; /* RW */ + unsigned long force_broadcast : 1; /* RW */ + unsigned long force_lock_nop : 1; /* RW */ + unsigned long qpi_agent_presence_vector : 3; /* RW */ + unsigned long descriptor_fetch_mode : 1; /* RW */ + unsigned long enable_intd_soft_ack_mode : 1; /* RW */ + unsigned long intd_soft_ack_timeout_period : 4; /* RW */ + unsigned long enable_dual_mapping_mode : 1; /* RW */ + unsigned long vga_io_port_decode_enable : 1; /* RW */ + unsigned long vga_io_port_16_bit_decode : 1; /* RW */ + unsigned long suppress_dest_registration : 1; /* RW */ + unsigned long programmed_initial_priority : 3; /* RW */ + unsigned long use_incoming_priority : 1; /* RW */ + unsigned long enable_programmed_initial_priority : 1; /* RW */ + unsigned long rsvd_29_47 : 19; /* */ + unsigned long fun : 16; /* RW */ + } s1; + struct uv2h_lb_bau_misc_control_s { + unsigned long rejection_delay : 8; /* RW */ + unsigned long apic_mode : 1; /* RW */ + unsigned long force_broadcast : 1; /* RW */ + unsigned long force_lock_nop : 1; /* RW */ + unsigned long qpi_agent_presence_vector : 3; /* RW */ + unsigned long descriptor_fetch_mode : 1; /* RW */ + unsigned long enable_intd_soft_ack_mode : 1; /* RW */ + unsigned long intd_soft_ack_timeout_period : 4; /* RW */ + unsigned long enable_dual_mapping_mode : 1; /* RW */ + unsigned long vga_io_port_decode_enable : 1; /* RW */ + unsigned long vga_io_port_16_bit_decode : 1; /* RW */ + unsigned long suppress_dest_registration : 1; /* RW */ + unsigned long programmed_initial_priority : 3; /* RW */ + unsigned long use_incoming_priority : 1; /* RW */ + unsigned long enable_programmed_initial_priority : 1; /* RW */ + unsigned long enable_automatic_apic_mode_selection : 1; /* RW */ + unsigned long apic_mode_status : 1; /* RO */ + unsigned long suppress_interrupts_to_self : 1; /* RW */ + unsigned long enable_lock_based_system_flush : 1; /* RW */ + unsigned long enable_extended_sb_status : 1; /* RW */ + unsigned long suppress_int_prio_udt_to_self : 1; /* RW */ + unsigned long use_legacy_descriptor_formats : 1; /* RW */ + unsigned long rsvd_36_47 : 12; /* */ + unsigned long fun : 16; /* RW */ + } s2; }; /* ========================================================================= */ /* UVH_LB_BAU_SB_ACTIVATION_CONTROL */ /* ========================================================================= */ -#define UVH_LB_BAU_SB_ACTIVATION_CONTROL 0x320020UL -#define UVH_LB_BAU_SB_ACTIVATION_CONTROL_32 0x9a8 +#define UVH_LB_BAU_SB_ACTIVATION_CONTROL 0x320020UL +#define UVH_LB_BAU_SB_ACTIVATION_CONTROL_32 0x9a8 -#define UVH_LB_BAU_SB_ACTIVATION_CONTROL_INDEX_SHFT 0 -#define UVH_LB_BAU_SB_ACTIVATION_CONTROL_PUSH_SHFT 62 -#define UVH_LB_BAU_SB_ACTIVATION_CONTROL_INIT_SHFT 63 -#define UVH_LB_BAU_SB_ACTIVATION_CONTROL_INDEX_MASK 0x000000000000003fUL -#define UVH_LB_BAU_SB_ACTIVATION_CONTROL_PUSH_MASK 0x4000000000000000UL -#define UVH_LB_BAU_SB_ACTIVATION_CONTROL_INIT_MASK 0x8000000000000000UL +#define UVH_LB_BAU_SB_ACTIVATION_CONTROL_INDEX_SHFT 0 +#define UVH_LB_BAU_SB_ACTIVATION_CONTROL_INDEX_MASK 0x000000000000003fUL +#define UVH_LB_BAU_SB_ACTIVATION_CONTROL_PUSH_SHFT 62 +#define UVH_LB_BAU_SB_ACTIVATION_CONTROL_PUSH_MASK 0x4000000000000000UL +#define UVH_LB_BAU_SB_ACTIVATION_CONTROL_INIT_SHFT 63 +#define UVH_LB_BAU_SB_ACTIVATION_CONTROL_INIT_MASK 0x8000000000000000UL union uvh_lb_bau_sb_activation_control_u { - unsigned long v; - struct uvh_lb_bau_sb_activation_control_s { - unsigned long index:6; /* RW */ - unsigned long rsvd_6_61:56; - unsigned long push:1; /* WP */ - unsigned long init:1; /* WP */ - } s; + unsigned long v; + struct uvh_lb_bau_sb_activation_control_s { + unsigned long index : 6; /* RW */ + unsigned long rsvd_6_61: 56; /* */ + unsigned long push : 1; /* WP */ + unsigned long init : 1; /* WP */ + } s; }; /* ========================================================================= */ /* UVH_LB_BAU_SB_ACTIVATION_STATUS_0 */ /* ========================================================================= */ -#define UVH_LB_BAU_SB_ACTIVATION_STATUS_0 0x320030UL -#define UVH_LB_BAU_SB_ACTIVATION_STATUS_0_32 0x9b0 +#define UVH_LB_BAU_SB_ACTIVATION_STATUS_0 0x320030UL +#define UVH_LB_BAU_SB_ACTIVATION_STATUS_0_32 0x9b0 -#define UVH_LB_BAU_SB_ACTIVATION_STATUS_0_STATUS_SHFT 0 -#define UVH_LB_BAU_SB_ACTIVATION_STATUS_0_STATUS_MASK 0xffffffffffffffffUL +#define UVH_LB_BAU_SB_ACTIVATION_STATUS_0_STATUS_SHFT 0 +#define UVH_LB_BAU_SB_ACTIVATION_STATUS_0_STATUS_MASK 0xffffffffffffffffUL union uvh_lb_bau_sb_activation_status_0_u { - unsigned long v; - struct uvh_lb_bau_sb_activation_status_0_s { - unsigned long status:64; /* RW */ - } s; + unsigned long v; + struct uvh_lb_bau_sb_activation_status_0_s { + unsigned long status : 64; /* RW */ + } s; }; /* ========================================================================= */ /* UVH_LB_BAU_SB_ACTIVATION_STATUS_1 */ /* ========================================================================= */ -#define UVH_LB_BAU_SB_ACTIVATION_STATUS_1 0x320040UL -#define UVH_LB_BAU_SB_ACTIVATION_STATUS_1_32 0x9b8 +#define UVH_LB_BAU_SB_ACTIVATION_STATUS_1 0x320040UL +#define UVH_LB_BAU_SB_ACTIVATION_STATUS_1_32 0x9b8 -#define UVH_LB_BAU_SB_ACTIVATION_STATUS_1_STATUS_SHFT 0 -#define UVH_LB_BAU_SB_ACTIVATION_STATUS_1_STATUS_MASK 0xffffffffffffffffUL +#define UVH_LB_BAU_SB_ACTIVATION_STATUS_1_STATUS_SHFT 0 +#define UVH_LB_BAU_SB_ACTIVATION_STATUS_1_STATUS_MASK 0xffffffffffffffffUL union uvh_lb_bau_sb_activation_status_1_u { - unsigned long v; - struct uvh_lb_bau_sb_activation_status_1_s { - unsigned long status:64; /* RW */ - } s; + unsigned long v; + struct uvh_lb_bau_sb_activation_status_1_s { + unsigned long status : 64; /* RW */ + } s; }; /* ========================================================================= */ /* UVH_LB_BAU_SB_DESCRIPTOR_BASE */ /* ========================================================================= */ -#define UVH_LB_BAU_SB_DESCRIPTOR_BASE 0x320010UL -#define UVH_LB_BAU_SB_DESCRIPTOR_BASE_32 0x9a0 +#define UVH_LB_BAU_SB_DESCRIPTOR_BASE 0x320010UL +#define UVH_LB_BAU_SB_DESCRIPTOR_BASE_32 0x9a0 -#define UVH_LB_BAU_SB_DESCRIPTOR_BASE_PAGE_ADDRESS_SHFT 12 -#define UVH_LB_BAU_SB_DESCRIPTOR_BASE_NODE_ID_SHFT 49 -#define UVH_LB_BAU_SB_DESCRIPTOR_BASE_PAGE_ADDRESS_MASK 0x000007fffffff000UL -#define UVH_LB_BAU_SB_DESCRIPTOR_BASE_NODE_ID_MASK 0x7ffe000000000000UL +#define UVH_LB_BAU_SB_DESCRIPTOR_BASE_PAGE_ADDRESS_SHFT 12 +#define UVH_LB_BAU_SB_DESCRIPTOR_BASE_PAGE_ADDRESS_MASK 0x000007fffffff000UL +#define UVH_LB_BAU_SB_DESCRIPTOR_BASE_NODE_ID_SHFT 49 +#define UVH_LB_BAU_SB_DESCRIPTOR_BASE_NODE_ID_MASK 0x7ffe000000000000UL union uvh_lb_bau_sb_descriptor_base_u { - unsigned long v; - struct uvh_lb_bau_sb_descriptor_base_s { - unsigned long rsvd_0_11:12; - unsigned long page_address:31; /* RW */ - unsigned long rsvd_43_48:6; - unsigned long node_id:14; /* RW */ - unsigned long rsvd_63:1; - } s; + unsigned long v; + struct uvh_lb_bau_sb_descriptor_base_s { + unsigned long rsvd_0_11 : 12; /* */ + unsigned long page_address : 31; /* RW */ + unsigned long rsvd_43_48 : 6; /* */ + unsigned long node_id : 14; /* RW */ + unsigned long rsvd_63 : 1; /* */ + } s; }; /* ========================================================================= */ /* UVH_NODE_ID */ /* ========================================================================= */ -#define UVH_NODE_ID 0x0UL - -#define UVH_NODE_ID_FORCE1_SHFT 0 -#define UVH_NODE_ID_MANUFACTURER_SHFT 1 -#define UVH_NODE_ID_PART_NUMBER_SHFT 12 -#define UVH_NODE_ID_REVISION_SHFT 28 -#define UVH_NODE_ID_NODE_ID_SHFT 32 -#define UVH_NODE_ID_FORCE1_MASK 0x0000000000000001UL -#define UVH_NODE_ID_MANUFACTURER_MASK 0x0000000000000ffeUL -#define UVH_NODE_ID_PART_NUMBER_MASK 0x000000000ffff000UL -#define UVH_NODE_ID_REVISION_MASK 0x00000000f0000000UL -#define UVH_NODE_ID_NODE_ID_MASK 0x00007fff00000000UL - -#define UV1H_NODE_ID_FORCE1_SHFT 0 -#define UV1H_NODE_ID_MANUFACTURER_SHFT 1 -#define UV1H_NODE_ID_PART_NUMBER_SHFT 12 -#define UV1H_NODE_ID_REVISION_SHFT 28 -#define UV1H_NODE_ID_NODE_ID_SHFT 32 -#define UV1H_NODE_ID_NODES_PER_BIT_SHFT 48 -#define UV1H_NODE_ID_NI_PORT_SHFT 56 -#define UV1H_NODE_ID_FORCE1_MASK 0x0000000000000001UL -#define UV1H_NODE_ID_MANUFACTURER_MASK 0x0000000000000ffeUL -#define UV1H_NODE_ID_PART_NUMBER_MASK 0x000000000ffff000UL -#define UV1H_NODE_ID_REVISION_MASK 0x00000000f0000000UL -#define UV1H_NODE_ID_NODE_ID_MASK 0x00007fff00000000UL -#define UV1H_NODE_ID_NODES_PER_BIT_MASK 0x007f000000000000UL -#define UV1H_NODE_ID_NI_PORT_MASK 0x0f00000000000000UL - -#define UV2H_NODE_ID_FORCE1_SHFT 0 -#define UV2H_NODE_ID_MANUFACTURER_SHFT 1 -#define UV2H_NODE_ID_PART_NUMBER_SHFT 12 -#define UV2H_NODE_ID_REVISION_SHFT 28 -#define UV2H_NODE_ID_NODE_ID_SHFT 32 -#define UV2H_NODE_ID_NODES_PER_BIT_SHFT 50 -#define UV2H_NODE_ID_NI_PORT_SHFT 57 -#define UV2H_NODE_ID_FORCE1_MASK 0x0000000000000001UL -#define UV2H_NODE_ID_MANUFACTURER_MASK 0x0000000000000ffeUL -#define UV2H_NODE_ID_PART_NUMBER_MASK 0x000000000ffff000UL -#define UV2H_NODE_ID_REVISION_MASK 0x00000000f0000000UL -#define UV2H_NODE_ID_NODE_ID_MASK 0x00007fff00000000UL -#define UV2H_NODE_ID_NODES_PER_BIT_MASK 0x01fc000000000000UL -#define UV2H_NODE_ID_NI_PORT_MASK 0x3e00000000000000UL +#define UVH_NODE_ID 0x0UL + +#define UVH_NODE_ID_FORCE1_SHFT 0 +#define UVH_NODE_ID_FORCE1_MASK 0x0000000000000001UL +#define UVH_NODE_ID_MANUFACTURER_SHFT 1 +#define UVH_NODE_ID_MANUFACTURER_MASK 0x0000000000000ffeUL +#define UVH_NODE_ID_PART_NUMBER_SHFT 12 +#define UVH_NODE_ID_PART_NUMBER_MASK 0x000000000ffff000UL +#define UVH_NODE_ID_REVISION_SHFT 28 +#define UVH_NODE_ID_REVISION_MASK 0x00000000f0000000UL +#define UVH_NODE_ID_NODE_ID_SHFT 32 +#define UVH_NODE_ID_NODE_ID_MASK 0x00007fff00000000UL + +#define UV1H_NODE_ID_FORCE1_SHFT 0 +#define UV1H_NODE_ID_FORCE1_MASK 0x0000000000000001UL +#define UV1H_NODE_ID_MANUFACTURER_SHFT 1 +#define UV1H_NODE_ID_MANUFACTURER_MASK 0x0000000000000ffeUL +#define UV1H_NODE_ID_PART_NUMBER_SHFT 12 +#define UV1H_NODE_ID_PART_NUMBER_MASK 0x000000000ffff000UL +#define UV1H_NODE_ID_REVISION_SHFT 28 +#define UV1H_NODE_ID_REVISION_MASK 0x00000000f0000000UL +#define UV1H_NODE_ID_NODE_ID_SHFT 32 +#define UV1H_NODE_ID_NODE_ID_MASK 0x00007fff00000000UL +#define UV1H_NODE_ID_NODES_PER_BIT_SHFT 48 +#define UV1H_NODE_ID_NODES_PER_BIT_MASK 0x007f000000000000UL +#define UV1H_NODE_ID_NI_PORT_SHFT 56 +#define UV1H_NODE_ID_NI_PORT_MASK 0x0f00000000000000UL + +#define UV2H_NODE_ID_FORCE1_SHFT 0 +#define UV2H_NODE_ID_FORCE1_MASK 0x0000000000000001UL +#define UV2H_NODE_ID_MANUFACTURER_SHFT 1 +#define UV2H_NODE_ID_MANUFACTURER_MASK 0x0000000000000ffeUL +#define UV2H_NODE_ID_PART_NUMBER_SHFT 12 +#define UV2H_NODE_ID_PART_NUMBER_MASK 0x000000000ffff000UL +#define UV2H_NODE_ID_REVISION_SHFT 28 +#define UV2H_NODE_ID_REVISION_MASK 0x00000000f0000000UL +#define UV2H_NODE_ID_NODE_ID_SHFT 32 +#define UV2H_NODE_ID_NODE_ID_MASK 0x00007fff00000000UL +#define UV2H_NODE_ID_NODES_PER_BIT_SHFT 50 +#define UV2H_NODE_ID_NODES_PER_BIT_MASK 0x01fc000000000000UL +#define UV2H_NODE_ID_NI_PORT_SHFT 57 +#define UV2H_NODE_ID_NI_PORT_MASK 0x3e00000000000000UL union uvh_node_id_u { - unsigned long v; - struct uvh_node_id_s { - unsigned long force1:1; /* RO */ - unsigned long manufacturer:11; /* RO */ - unsigned long part_number:16; /* RO */ - unsigned long revision:4; /* RO */ - unsigned long node_id:15; /* RW */ - unsigned long rsvd_47_63:17; - } s; - struct uv1h_node_id_s { - unsigned long force1:1; /* RO */ - unsigned long manufacturer:11; /* RO */ - unsigned long part_number:16; /* RO */ - unsigned long revision:4; /* RO */ - unsigned long node_id:15; /* RW */ - unsigned long rsvd_47:1; - unsigned long nodes_per_bit:7; /* RW */ - unsigned long rsvd_55:1; - unsigned long ni_port:4; /* RO */ - unsigned long rsvd_60_63:4; - } s1; - struct uv2h_node_id_s { - unsigned long force1:1; /* RO */ - unsigned long manufacturer:11; /* RO */ - unsigned long part_number:16; /* RO */ - unsigned long revision:4; /* RO */ - unsigned long node_id:15; /* RW */ - unsigned long rsvd_47_49:3; - unsigned long nodes_per_bit:7; /* RO */ - unsigned long ni_port:5; /* RO */ - unsigned long rsvd_62_63:2; - } s2; + unsigned long v; + struct uvh_node_id_s { + unsigned long force1 : 1; /* RO */ + unsigned long manufacturer : 11; /* RO */ + unsigned long part_number : 16; /* RO */ + unsigned long revision : 4; /* RO */ + unsigned long node_id : 15; /* RW */ + unsigned long rsvd_47_63 : 17; + } s; + struct uv1h_node_id_s { + unsigned long force1 : 1; /* RO */ + unsigned long manufacturer : 11; /* RO */ + unsigned long part_number : 16; /* RO */ + unsigned long revision : 4; /* RO */ + unsigned long node_id : 15; /* RW */ + unsigned long rsvd_47 : 1; /* */ + unsigned long nodes_per_bit : 7; /* RW */ + unsigned long rsvd_55 : 1; /* */ + unsigned long ni_port : 4; /* RO */ + unsigned long rsvd_60_63 : 4; /* */ + } s1; + struct uv2h_node_id_s { + unsigned long force1 : 1; /* RO */ + unsigned long manufacturer : 11; /* RO */ + unsigned long part_number : 16; /* RO */ + unsigned long revision : 4; /* RO */ + unsigned long node_id : 15; /* RW */ + unsigned long rsvd_47_49 : 3; /* */ + unsigned long nodes_per_bit : 7; /* RO */ + unsigned long ni_port : 5; /* RO */ + unsigned long rsvd_62_63 : 2; /* */ + } s2; }; /* ========================================================================= */ /* UVH_NODE_PRESENT_TABLE */ /* ========================================================================= */ -#define UVH_NODE_PRESENT_TABLE 0x1400UL -#define UVH_NODE_PRESENT_TABLE_DEPTH 16 +#define UVH_NODE_PRESENT_TABLE 0x1400UL +#define UVH_NODE_PRESENT_TABLE_DEPTH 16 -#define UVH_NODE_PRESENT_TABLE_NODES_SHFT 0 -#define UVH_NODE_PRESENT_TABLE_NODES_MASK 0xffffffffffffffffUL +#define UVH_NODE_PRESENT_TABLE_NODES_SHFT 0 +#define UVH_NODE_PRESENT_TABLE_NODES_MASK 0xffffffffffffffffUL union uvh_node_present_table_u { - unsigned long v; - struct uvh_node_present_table_s { - unsigned long nodes:64; /* RW */ - } s; + unsigned long v; + struct uvh_node_present_table_s { + unsigned long nodes : 64; /* RW */ + } s; }; /* ========================================================================= */ /* UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR */ /* ========================================================================= */ -#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR 0x16000c8UL +#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR 0x16000c8UL #define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_BASE_SHFT 24 -#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_M_ALIAS_SHFT 48 -#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_ENABLE_SHFT 63 #define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_BASE_MASK 0x00000000ff000000UL +#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_M_ALIAS_SHFT 48 #define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_M_ALIAS_MASK 0x001f000000000000UL +#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_ENABLE_SHFT 63 #define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_ENABLE_MASK 0x8000000000000000UL union uvh_rh_gam_alias210_overlay_config_0_mmr_u { - unsigned long v; - struct uvh_rh_gam_alias210_overlay_config_0_mmr_s { - unsigned long rsvd_0_23:24; - unsigned long base:8; /* RW */ - unsigned long rsvd_32_47:16; - unsigned long m_alias:5; /* RW */ - unsigned long rsvd_53_62:10; - unsigned long enable:1; /* RW */ - } s; + unsigned long v; + struct uvh_rh_gam_alias210_overlay_config_0_mmr_s { + unsigned long rsvd_0_23: 24; /* */ + unsigned long base : 8; /* RW */ + unsigned long rsvd_32_47: 16; /* */ + unsigned long m_alias : 5; /* RW */ + unsigned long rsvd_53_62: 10; /* */ + unsigned long enable : 1; /* RW */ + } s; }; /* ========================================================================= */ /* UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR */ /* ========================================================================= */ -#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR 0x16000d8UL +#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR 0x16000d8UL #define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_BASE_SHFT 24 -#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_M_ALIAS_SHFT 48 -#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_ENABLE_SHFT 63 #define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_BASE_MASK 0x00000000ff000000UL +#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_M_ALIAS_SHFT 48 #define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_M_ALIAS_MASK 0x001f000000000000UL +#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_ENABLE_SHFT 63 #define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_ENABLE_MASK 0x8000000000000000UL union uvh_rh_gam_alias210_overlay_config_1_mmr_u { - unsigned long v; - struct uvh_rh_gam_alias210_overlay_config_1_mmr_s { - unsigned long rsvd_0_23:24; - unsigned long base:8; /* RW */ - unsigned long rsvd_32_47:16; - unsigned long m_alias:5; /* RW */ - unsigned long rsvd_53_62:10; - unsigned long enable:1; /* RW */ - } s; + unsigned long v; + struct uvh_rh_gam_alias210_overlay_config_1_mmr_s { + unsigned long rsvd_0_23: 24; /* */ + unsigned long base : 8; /* RW */ + unsigned long rsvd_32_47: 16; /* */ + unsigned long m_alias : 5; /* RW */ + unsigned long rsvd_53_62: 10; /* */ + unsigned long enable : 1; /* RW */ + } s; }; /* ========================================================================= */ /* UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR */ /* ========================================================================= */ -#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR 0x16000e8UL +#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR 0x16000e8UL #define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_BASE_SHFT 24 -#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_M_ALIAS_SHFT 48 -#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_ENABLE_SHFT 63 #define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_BASE_MASK 0x00000000ff000000UL +#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_M_ALIAS_SHFT 48 #define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_M_ALIAS_MASK 0x001f000000000000UL +#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_ENABLE_SHFT 63 #define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_ENABLE_MASK 0x8000000000000000UL union uvh_rh_gam_alias210_overlay_config_2_mmr_u { - unsigned long v; - struct uvh_rh_gam_alias210_overlay_config_2_mmr_s { - unsigned long rsvd_0_23:24; - unsigned long base:8; /* RW */ - unsigned long rsvd_32_47:16; - unsigned long m_alias:5; /* RW */ - unsigned long rsvd_53_62:10; - unsigned long enable:1; /* RW */ - } s; + unsigned long v; + struct uvh_rh_gam_alias210_overlay_config_2_mmr_s { + unsigned long rsvd_0_23: 24; /* */ + unsigned long base : 8; /* RW */ + unsigned long rsvd_32_47: 16; /* */ + unsigned long m_alias : 5; /* RW */ + unsigned long rsvd_53_62: 10; /* */ + unsigned long enable : 1; /* RW */ + } s; }; /* ========================================================================= */ /* UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR */ /* ========================================================================= */ -#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR 0x16000d0UL +#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR 0x16000d0UL #define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR_DEST_BASE_SHFT 24 #define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR_DEST_BASE_MASK 0x00003fffff000000UL union uvh_rh_gam_alias210_redirect_config_0_mmr_u { - unsigned long v; - struct uvh_rh_gam_alias210_redirect_config_0_mmr_s { - unsigned long rsvd_0_23:24; - unsigned long dest_base:22; /* RW */ - unsigned long rsvd_46_63:18; - } s; + unsigned long v; + struct uvh_rh_gam_alias210_redirect_config_0_mmr_s { + unsigned long rsvd_0_23 : 24; /* */ + unsigned long dest_base : 22; /* RW */ + unsigned long rsvd_46_63: 18; /* */ + } s; }; /* ========================================================================= */ /* UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR */ /* ========================================================================= */ -#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR 0x16000e0UL +#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR 0x16000e0UL #define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR_DEST_BASE_SHFT 24 #define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR_DEST_BASE_MASK 0x00003fffff000000UL union uvh_rh_gam_alias210_redirect_config_1_mmr_u { - unsigned long v; - struct uvh_rh_gam_alias210_redirect_config_1_mmr_s { - unsigned long rsvd_0_23:24; - unsigned long dest_base:22; /* RW */ - unsigned long rsvd_46_63:18; - } s; + unsigned long v; + struct uvh_rh_gam_alias210_redirect_config_1_mmr_s { + unsigned long rsvd_0_23 : 24; /* */ + unsigned long dest_base : 22; /* RW */ + unsigned long rsvd_46_63: 18; /* */ + } s; }; /* ========================================================================= */ /* UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR */ /* ========================================================================= */ -#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR 0x16000f0UL +#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR 0x16000f0UL #define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR_DEST_BASE_SHFT 24 #define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR_DEST_BASE_MASK 0x00003fffff000000UL union uvh_rh_gam_alias210_redirect_config_2_mmr_u { - unsigned long v; - struct uvh_rh_gam_alias210_redirect_config_2_mmr_s { - unsigned long rsvd_0_23:24; - unsigned long dest_base:22; /* RW */ - unsigned long rsvd_46_63:18; - } s; + unsigned long v; + struct uvh_rh_gam_alias210_redirect_config_2_mmr_s { + unsigned long rsvd_0_23 : 24; /* */ + unsigned long dest_base : 22; /* RW */ + unsigned long rsvd_46_63: 18; /* */ + } s; }; /* ========================================================================= */ /* UVH_RH_GAM_CONFIG_MMR */ /* ========================================================================= */ -#define UVH_RH_GAM_CONFIG_MMR 0x1600000UL +#define UVH_RH_GAM_CONFIG_MMR 0x1600000UL -#define UVH_RH_GAM_CONFIG_MMR_M_SKT_SHFT 0 -#define UVH_RH_GAM_CONFIG_MMR_N_SKT_SHFT 6 -#define UVH_RH_GAM_CONFIG_MMR_M_SKT_MASK 0x000000000000003fUL -#define UVH_RH_GAM_CONFIG_MMR_N_SKT_MASK 0x00000000000003c0UL +#define UVH_RH_GAM_CONFIG_MMR_M_SKT_SHFT 0 +#define UVH_RH_GAM_CONFIG_MMR_M_SKT_MASK 0x000000000000003fUL +#define UVH_RH_GAM_CONFIG_MMR_N_SKT_SHFT 6 +#define UVH_RH_GAM_CONFIG_MMR_N_SKT_MASK 0x00000000000003c0UL -#define UV1H_RH_GAM_CONFIG_MMR_M_SKT_SHFT 0 -#define UV1H_RH_GAM_CONFIG_MMR_N_SKT_SHFT 6 -#define UV1H_RH_GAM_CONFIG_MMR_MMIOL_CFG_SHFT 12 -#define UV1H_RH_GAM_CONFIG_MMR_M_SKT_MASK 0x000000000000003fUL -#define UV1H_RH_GAM_CONFIG_MMR_N_SKT_MASK 0x00000000000003c0UL -#define UV1H_RH_GAM_CONFIG_MMR_MMIOL_CFG_MASK 0x0000000000001000UL +#define UV1H_RH_GAM_CONFIG_MMR_M_SKT_SHFT 0 +#define UV1H_RH_GAM_CONFIG_MMR_M_SKT_MASK 0x000000000000003fUL +#define UV1H_RH_GAM_CONFIG_MMR_N_SKT_SHFT 6 +#define UV1H_RH_GAM_CONFIG_MMR_N_SKT_MASK 0x00000000000003c0UL +#define UV1H_RH_GAM_CONFIG_MMR_MMIOL_CFG_SHFT 12 +#define UV1H_RH_GAM_CONFIG_MMR_MMIOL_CFG_MASK 0x0000000000001000UL -#define UV2H_RH_GAM_CONFIG_MMR_M_SKT_SHFT 0 -#define UV2H_RH_GAM_CONFIG_MMR_N_SKT_SHFT 6 -#define UV2H_RH_GAM_CONFIG_MMR_M_SKT_MASK 0x000000000000003fUL -#define UV2H_RH_GAM_CONFIG_MMR_N_SKT_MASK 0x00000000000003c0UL +#define UV2H_RH_GAM_CONFIG_MMR_M_SKT_SHFT 0 +#define UV2H_RH_GAM_CONFIG_MMR_M_SKT_MASK 0x000000000000003fUL +#define UV2H_RH_GAM_CONFIG_MMR_N_SKT_SHFT 6 +#define UV2H_RH_GAM_CONFIG_MMR_N_SKT_MASK 0x00000000000003c0UL union uvh_rh_gam_config_mmr_u { - unsigned long v; - struct uvh_rh_gam_config_mmr_s { - unsigned long m_skt:6; /* RW */ - unsigned long n_skt:4; /* RW */ - unsigned long rsvd_10_63:54; - } s; - struct uv1h_rh_gam_config_mmr_s { - unsigned long m_skt:6; /* RW */ - unsigned long n_skt:4; /* RW */ - unsigned long rsvd_10_11:2; - unsigned long mmiol_cfg:1; /* RW */ - unsigned long rsvd_13_63:51; - } s1; - struct uv2h_rh_gam_config_mmr_s { - unsigned long m_skt:6; /* RW */ - unsigned long n_skt:4; /* RW */ - unsigned long rsvd_10_63:54; - } s2; + unsigned long v; + struct uvh_rh_gam_config_mmr_s { + unsigned long m_skt : 6; /* RW */ + unsigned long n_skt : 4; /* RW */ + unsigned long rsvd_10_63 : 54; + } s; + struct uv1h_rh_gam_config_mmr_s { + unsigned long m_skt : 6; /* RW */ + unsigned long n_skt : 4; /* RW */ + unsigned long rsvd_10_11: 2; /* */ + unsigned long mmiol_cfg : 1; /* RW */ + unsigned long rsvd_13_63: 51; /* */ + } s1; + struct uv2h_rh_gam_config_mmr_s { + unsigned long m_skt : 6; /* RW */ + unsigned long n_skt : 4; /* RW */ + unsigned long rsvd_10_63: 54; /* */ + } s2; }; /* ========================================================================= */ /* UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR */ /* ========================================================================= */ -#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR 0x1600010UL +#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR 0x1600010UL -#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_SHFT 28 -#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_MASK 0x00003ffff0000000UL +#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_SHFT 28 +#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_MASK 0x00003ffff0000000UL -#define UV1H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_SHFT 28 -#define UV1H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_GR4_SHFT 48 -#define UV1H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_SHFT 52 -#define UV1H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63 -#define UV1H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_MASK 0x00003ffff0000000UL -#define UV1H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_GR4_MASK 0x0001000000000000UL -#define UV1H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_MASK 0x00f0000000000000UL -#define UV1H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL +#define UV1H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_SHFT 28 +#define UV1H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_MASK 0x00003ffff0000000UL +#define UV1H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_GR4_SHFT 48 +#define UV1H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_GR4_MASK 0x0001000000000000UL +#define UV1H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_SHFT 52 +#define UV1H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_MASK 0x00f0000000000000UL +#define UV1H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63 +#define UV1H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL -#define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_SHFT 28 -#define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_SHFT 52 -#define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63 -#define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_MASK 0x00003ffff0000000UL -#define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_MASK 0x00f0000000000000UL -#define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL +#define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_SHFT 28 +#define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_MASK 0x00003ffff0000000UL +#define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_SHFT 52 +#define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_MASK 0x00f0000000000000UL +#define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63 +#define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL union uvh_rh_gam_gru_overlay_config_mmr_u { - unsigned long v; - struct uvh_rh_gam_gru_overlay_config_mmr_s { - unsigned long rsvd_0_27:28; - unsigned long base:18; /* RW */ - unsigned long rsvd_46_62:17; - unsigned long enable:1; /* RW */ - } s; - struct uv1h_rh_gam_gru_overlay_config_mmr_s { - unsigned long rsvd_0_27:28; - unsigned long base:18; /* RW */ - unsigned long rsvd_46_47:2; - unsigned long gr4:1; /* RW */ - unsigned long rsvd_49_51:3; - unsigned long n_gru:4; /* RW */ - unsigned long rsvd_56_62:7; - unsigned long enable:1; /* RW */ - } s1; - struct uv2h_rh_gam_gru_overlay_config_mmr_s { - unsigned long rsvd_0_27:28; - unsigned long base:18; /* RW */ - unsigned long rsvd_46_51:6; - unsigned long n_gru:4; /* RW */ - unsigned long rsvd_56_62:7; - unsigned long enable:1; /* RW */ - } s2; + unsigned long v; + struct uvh_rh_gam_gru_overlay_config_mmr_s { + unsigned long rsvd_0_27: 28; /* */ + unsigned long base : 18; /* RW */ + unsigned long rsvd_46_62 : 17; + unsigned long enable : 1; /* RW */ + } s; + struct uv1h_rh_gam_gru_overlay_config_mmr_s { + unsigned long rsvd_0_27: 28; /* */ + unsigned long base : 18; /* RW */ + unsigned long rsvd_46_47: 2; /* */ + unsigned long gr4 : 1; /* RW */ + unsigned long rsvd_49_51: 3; /* */ + unsigned long n_gru : 4; /* RW */ + unsigned long rsvd_56_62: 7; /* */ + unsigned long enable : 1; /* RW */ + } s1; + struct uv2h_rh_gam_gru_overlay_config_mmr_s { + unsigned long rsvd_0_27: 28; /* */ + unsigned long base : 18; /* RW */ + unsigned long rsvd_46_51: 6; /* */ + unsigned long n_gru : 4; /* RW */ + unsigned long rsvd_56_62: 7; /* */ + unsigned long enable : 1; /* RW */ + } s2; }; /* ========================================================================= */ /* UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR */ /* ========================================================================= */ -#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR 0x1600030UL +#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR 0x1600030UL -#define UV1H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_BASE_SHFT 30 -#define UV1H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_M_IO_SHFT 46 -#define UV1H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_N_IO_SHFT 52 +#define UV1H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_BASE_SHFT 30 +#define UV1H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_BASE_MASK 0x00003fffc0000000UL +#define UV1H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_M_IO_SHFT 46 +#define UV1H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_M_IO_MASK 0x000fc00000000000UL +#define UV1H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_N_IO_SHFT 52 +#define UV1H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_N_IO_MASK 0x00f0000000000000UL #define UV1H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63 -#define UV1H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_BASE_MASK 0x00003fffc0000000UL -#define UV1H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_M_IO_MASK 0x000fc00000000000UL -#define UV1H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_N_IO_MASK 0x00f0000000000000UL #define UV1H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL -#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_BASE_SHFT 27 -#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_M_IO_SHFT 46 -#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_N_IO_SHFT 52 +#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_BASE_SHFT 27 +#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_BASE_MASK 0x00003ffff8000000UL +#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_M_IO_SHFT 46 +#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_M_IO_MASK 0x000fc00000000000UL +#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_N_IO_SHFT 52 +#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_N_IO_MASK 0x00f0000000000000UL #define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63 -#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_BASE_MASK 0x00003ffff8000000UL -#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_M_IO_MASK 0x000fc00000000000UL -#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_N_IO_MASK 0x00f0000000000000UL #define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL union uvh_rh_gam_mmioh_overlay_config_mmr_u { - unsigned long v; - struct uv1h_rh_gam_mmioh_overlay_config_mmr_s { - unsigned long rsvd_0_29:30; - unsigned long base:16; /* RW */ - unsigned long m_io:6; /* RW */ - unsigned long n_io:4; /* RW */ - unsigned long rsvd_56_62:7; - unsigned long enable:1; /* RW */ - } s1; - struct uv2h_rh_gam_mmioh_overlay_config_mmr_s { - unsigned long rsvd_0_26:27; - unsigned long base:19; /* RW */ - unsigned long m_io:6; /* RW */ - unsigned long n_io:4; /* RW */ - unsigned long rsvd_56_62:7; - unsigned long enable:1; /* RW */ - } s2; + unsigned long v; + struct uv1h_rh_gam_mmioh_overlay_config_mmr_s { + unsigned long rsvd_0_29: 30; /* */ + unsigned long base : 16; /* RW */ + unsigned long m_io : 6; /* RW */ + unsigned long n_io : 4; /* RW */ + unsigned long rsvd_56_62: 7; /* */ + unsigned long enable : 1; /* RW */ + } s1; + struct uv2h_rh_gam_mmioh_overlay_config_mmr_s { + unsigned long rsvd_0_26: 27; /* */ + unsigned long base : 19; /* RW */ + unsigned long m_io : 6; /* RW */ + unsigned long n_io : 4; /* RW */ + unsigned long rsvd_56_62: 7; /* */ + unsigned long enable : 1; /* RW */ + } s2; }; /* ========================================================================= */ /* UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR */ /* ========================================================================= */ -#define UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR 0x1600028UL +#define UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR 0x1600028UL -#define UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_SHFT 26 -#define UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_MASK 0x00003ffffc000000UL +#define UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_SHFT 26 +#define UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_MASK 0x00003ffffc000000UL -#define UV1H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_SHFT 26 +#define UV1H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_SHFT 26 +#define UV1H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_MASK 0x00003ffffc000000UL #define UV1H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_DUAL_HUB_SHFT 46 -#define UV1H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63 -#define UV1H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_MASK 0x00003ffffc000000UL #define UV1H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_DUAL_HUB_MASK 0x0000400000000000UL -#define UV1H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL +#define UV1H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63 +#define UV1H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL -#define UV2H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_SHFT 26 -#define UV2H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63 -#define UV2H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_MASK 0x00003ffffc000000UL -#define UV2H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL +#define UV2H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_SHFT 26 +#define UV2H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_MASK 0x00003ffffc000000UL +#define UV2H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63 +#define UV2H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL union uvh_rh_gam_mmr_overlay_config_mmr_u { - unsigned long v; - struct uvh_rh_gam_mmr_overlay_config_mmr_s { - unsigned long rsvd_0_25:26; - unsigned long base:20; /* RW */ - unsigned long rsvd_46_62:17; - unsigned long enable:1; /* RW */ - } s; - struct uv1h_rh_gam_mmr_overlay_config_mmr_s { - unsigned long rsvd_0_25:26; - unsigned long base:20; /* RW */ - unsigned long dual_hub:1; /* RW */ - unsigned long rsvd_47_62:16; - unsigned long enable:1; /* RW */ - } s1; - struct uv2h_rh_gam_mmr_overlay_config_mmr_s { - unsigned long rsvd_0_25:26; - unsigned long base:20; /* RW */ - unsigned long rsvd_46_62:17; - unsigned long enable:1; /* RW */ - } s2; + unsigned long v; + struct uvh_rh_gam_mmr_overlay_config_mmr_s { + unsigned long rsvd_0_25: 26; /* */ + unsigned long base : 20; /* RW */ + unsigned long rsvd_46_62 : 17; + unsigned long enable : 1; /* RW */ + } s; + struct uv1h_rh_gam_mmr_overlay_config_mmr_s { + unsigned long rsvd_0_25: 26; /* */ + unsigned long base : 20; /* RW */ + unsigned long dual_hub : 1; /* RW */ + unsigned long rsvd_47_62: 16; /* */ + unsigned long enable : 1; /* RW */ + } s1; + struct uv2h_rh_gam_mmr_overlay_config_mmr_s { + unsigned long rsvd_0_25: 26; /* */ + unsigned long base : 20; /* RW */ + unsigned long rsvd_46_62: 17; /* */ + unsigned long enable : 1; /* RW */ + } s2; }; /* ========================================================================= */ /* UVH_RTC */ /* ========================================================================= */ -#define UVH_RTC 0x340000UL +#define UVH_RTC 0x340000UL -#define UVH_RTC_REAL_TIME_CLOCK_SHFT 0 -#define UVH_RTC_REAL_TIME_CLOCK_MASK 0x00ffffffffffffffUL +#define UVH_RTC_REAL_TIME_CLOCK_SHFT 0 +#define UVH_RTC_REAL_TIME_CLOCK_MASK 0x00ffffffffffffffUL union uvh_rtc_u { - unsigned long v; - struct uvh_rtc_s { - unsigned long real_time_clock:56; /* RW */ - unsigned long rsvd_56_63:8; - } s; + unsigned long v; + struct uvh_rtc_s { + unsigned long real_time_clock : 56; /* RW */ + unsigned long rsvd_56_63 : 8; /* */ + } s; }; /* ========================================================================= */ /* UVH_RTC1_INT_CONFIG */ /* ========================================================================= */ -#define UVH_RTC1_INT_CONFIG 0x615c0UL - -#define UVH_RTC1_INT_CONFIG_VECTOR_SHFT 0 -#define UVH_RTC1_INT_CONFIG_DM_SHFT 8 -#define UVH_RTC1_INT_CONFIG_DESTMODE_SHFT 11 -#define UVH_RTC1_INT_CONFIG_STATUS_SHFT 12 -#define UVH_RTC1_INT_CONFIG_P_SHFT 13 -#define UVH_RTC1_INT_CONFIG_T_SHFT 15 -#define UVH_RTC1_INT_CONFIG_M_SHFT 16 -#define UVH_RTC1_INT_CONFIG_APIC_ID_SHFT 32 -#define UVH_RTC1_INT_CONFIG_VECTOR_MASK 0x00000000000000ffUL -#define UVH_RTC1_INT_CONFIG_DM_MASK 0x0000000000000700UL -#define UVH_RTC1_INT_CONFIG_DESTMODE_MASK 0x0000000000000800UL -#define UVH_RTC1_INT_CONFIG_STATUS_MASK 0x0000000000001000UL -#define UVH_RTC1_INT_CONFIG_P_MASK 0x0000000000002000UL -#define UVH_RTC1_INT_CONFIG_T_MASK 0x0000000000008000UL -#define UVH_RTC1_INT_CONFIG_M_MASK 0x0000000000010000UL -#define UVH_RTC1_INT_CONFIG_APIC_ID_MASK 0xffffffff00000000UL +#define UVH_RTC1_INT_CONFIG 0x615c0UL + +#define UVH_RTC1_INT_CONFIG_VECTOR_SHFT 0 +#define UVH_RTC1_INT_CONFIG_VECTOR_MASK 0x00000000000000ffUL +#define UVH_RTC1_INT_CONFIG_DM_SHFT 8 +#define UVH_RTC1_INT_CONFIG_DM_MASK 0x0000000000000700UL +#define UVH_RTC1_INT_CONFIG_DESTMODE_SHFT 11 +#define UVH_RTC1_INT_CONFIG_DESTMODE_MASK 0x0000000000000800UL +#define UVH_RTC1_INT_CONFIG_STATUS_SHFT 12 +#define UVH_RTC1_INT_CONFIG_STATUS_MASK 0x0000000000001000UL +#define UVH_RTC1_INT_CONFIG_P_SHFT 13 +#define UVH_RTC1_INT_CONFIG_P_MASK 0x0000000000002000UL +#define UVH_RTC1_INT_CONFIG_T_SHFT 15 +#define UVH_RTC1_INT_CONFIG_T_MASK 0x0000000000008000UL +#define UVH_RTC1_INT_CONFIG_M_SHFT 16 +#define UVH_RTC1_INT_CONFIG_M_MASK 0x0000000000010000UL +#define UVH_RTC1_INT_CONFIG_APIC_ID_SHFT 32 +#define UVH_RTC1_INT_CONFIG_APIC_ID_MASK 0xffffffff00000000UL union uvh_rtc1_int_config_u { - unsigned long v; - struct uvh_rtc1_int_config_s { - unsigned long vector_:8; /* RW */ - unsigned long dm:3; /* RW */ - unsigned long destmode:1; /* RW */ - unsigned long status:1; /* RO */ - unsigned long p:1; /* RO */ - unsigned long rsvd_14:1; - unsigned long t:1; /* RO */ - unsigned long m:1; /* RW */ - unsigned long rsvd_17_31:15; - unsigned long apic_id:32; /* RW */ - } s; + unsigned long v; + struct uvh_rtc1_int_config_s { + unsigned long vector_ : 8; /* RW */ + unsigned long dm : 3; /* RW */ + unsigned long destmode : 1; /* RW */ + unsigned long status : 1; /* RO */ + unsigned long p : 1; /* RO */ + unsigned long rsvd_14 : 1; /* */ + unsigned long t : 1; /* RO */ + unsigned long m : 1; /* RW */ + unsigned long rsvd_17_31: 15; /* */ + unsigned long apic_id : 32; /* RW */ + } s; }; /* ========================================================================= */ /* UVH_SCRATCH5 */ /* ========================================================================= */ -#define UVH_SCRATCH5 0x2d0200UL -#define UVH_SCRATCH5_32 0x778 +#define UVH_SCRATCH5 0x2d0200UL +#define UVH_SCRATCH5_32 0x778 -#define UVH_SCRATCH5_SCRATCH5_SHFT 0 -#define UVH_SCRATCH5_SCRATCH5_MASK 0xffffffffffffffffUL +#define UVH_SCRATCH5_SCRATCH5_SHFT 0 +#define UVH_SCRATCH5_SCRATCH5_MASK 0xffffffffffffffffUL union uvh_scratch5_u { - unsigned long v; - struct uvh_scratch5_s { - unsigned long scratch5:64; /* RW, W1CS */ - } s; + unsigned long v; + struct uvh_scratch5_s { + unsigned long scratch5 : 64; /* RW, W1CS */ + } s; }; /* ========================================================================= */ /* UV2H_EVENT_OCCURRED2 */ /* ========================================================================= */ -#define UV2H_EVENT_OCCURRED2 0x70100UL -#define UV2H_EVENT_OCCURRED2_32 0xb68 - -#define UV2H_EVENT_OCCURRED2_RTC_0_SHFT 0 -#define UV2H_EVENT_OCCURRED2_RTC_1_SHFT 1 -#define UV2H_EVENT_OCCURRED2_RTC_2_SHFT 2 -#define UV2H_EVENT_OCCURRED2_RTC_3_SHFT 3 -#define UV2H_EVENT_OCCURRED2_RTC_4_SHFT 4 -#define UV2H_EVENT_OCCURRED2_RTC_5_SHFT 5 -#define UV2H_EVENT_OCCURRED2_RTC_6_SHFT 6 -#define UV2H_EVENT_OCCURRED2_RTC_7_SHFT 7 -#define UV2H_EVENT_OCCURRED2_RTC_8_SHFT 8 -#define UV2H_EVENT_OCCURRED2_RTC_9_SHFT 9 -#define UV2H_EVENT_OCCURRED2_RTC_10_SHFT 10 -#define UV2H_EVENT_OCCURRED2_RTC_11_SHFT 11 -#define UV2H_EVENT_OCCURRED2_RTC_12_SHFT 12 -#define UV2H_EVENT_OCCURRED2_RTC_13_SHFT 13 -#define UV2H_EVENT_OCCURRED2_RTC_14_SHFT 14 -#define UV2H_EVENT_OCCURRED2_RTC_15_SHFT 15 -#define UV2H_EVENT_OCCURRED2_RTC_16_SHFT 16 -#define UV2H_EVENT_OCCURRED2_RTC_17_SHFT 17 -#define UV2H_EVENT_OCCURRED2_RTC_18_SHFT 18 -#define UV2H_EVENT_OCCURRED2_RTC_19_SHFT 19 -#define UV2H_EVENT_OCCURRED2_RTC_20_SHFT 20 -#define UV2H_EVENT_OCCURRED2_RTC_21_SHFT 21 -#define UV2H_EVENT_OCCURRED2_RTC_22_SHFT 22 -#define UV2H_EVENT_OCCURRED2_RTC_23_SHFT 23 -#define UV2H_EVENT_OCCURRED2_RTC_24_SHFT 24 -#define UV2H_EVENT_OCCURRED2_RTC_25_SHFT 25 -#define UV2H_EVENT_OCCURRED2_RTC_26_SHFT 26 -#define UV2H_EVENT_OCCURRED2_RTC_27_SHFT 27 -#define UV2H_EVENT_OCCURRED2_RTC_28_SHFT 28 -#define UV2H_EVENT_OCCURRED2_RTC_29_SHFT 29 -#define UV2H_EVENT_OCCURRED2_RTC_30_SHFT 30 -#define UV2H_EVENT_OCCURRED2_RTC_31_SHFT 31 -#define UV2H_EVENT_OCCURRED2_RTC_0_MASK 0x0000000000000001UL -#define UV2H_EVENT_OCCURRED2_RTC_1_MASK 0x0000000000000002UL -#define UV2H_EVENT_OCCURRED2_RTC_2_MASK 0x0000000000000004UL -#define UV2H_EVENT_OCCURRED2_RTC_3_MASK 0x0000000000000008UL -#define UV2H_EVENT_OCCURRED2_RTC_4_MASK 0x0000000000000010UL -#define UV2H_EVENT_OCCURRED2_RTC_5_MASK 0x0000000000000020UL -#define UV2H_EVENT_OCCURRED2_RTC_6_MASK 0x0000000000000040UL -#define UV2H_EVENT_OCCURRED2_RTC_7_MASK 0x0000000000000080UL -#define UV2H_EVENT_OCCURRED2_RTC_8_MASK 0x0000000000000100UL -#define UV2H_EVENT_OCCURRED2_RTC_9_MASK 0x0000000000000200UL -#define UV2H_EVENT_OCCURRED2_RTC_10_MASK 0x0000000000000400UL -#define UV2H_EVENT_OCCURRED2_RTC_11_MASK 0x0000000000000800UL -#define UV2H_EVENT_OCCURRED2_RTC_12_MASK 0x0000000000001000UL -#define UV2H_EVENT_OCCURRED2_RTC_13_MASK 0x0000000000002000UL -#define UV2H_EVENT_OCCURRED2_RTC_14_MASK 0x0000000000004000UL -#define UV2H_EVENT_OCCURRED2_RTC_15_MASK 0x0000000000008000UL -#define UV2H_EVENT_OCCURRED2_RTC_16_MASK 0x0000000000010000UL -#define UV2H_EVENT_OCCURRED2_RTC_17_MASK 0x0000000000020000UL -#define UV2H_EVENT_OCCURRED2_RTC_18_MASK 0x0000000000040000UL -#define UV2H_EVENT_OCCURRED2_RTC_19_MASK 0x0000000000080000UL -#define UV2H_EVENT_OCCURRED2_RTC_20_MASK 0x0000000000100000UL -#define UV2H_EVENT_OCCURRED2_RTC_21_MASK 0x0000000000200000UL -#define UV2H_EVENT_OCCURRED2_RTC_22_MASK 0x0000000000400000UL -#define UV2H_EVENT_OCCURRED2_RTC_23_MASK 0x0000000000800000UL -#define UV2H_EVENT_OCCURRED2_RTC_24_MASK 0x0000000001000000UL -#define UV2H_EVENT_OCCURRED2_RTC_25_MASK 0x0000000002000000UL -#define UV2H_EVENT_OCCURRED2_RTC_26_MASK 0x0000000004000000UL -#define UV2H_EVENT_OCCURRED2_RTC_27_MASK 0x0000000008000000UL -#define UV2H_EVENT_OCCURRED2_RTC_28_MASK 0x0000000010000000UL -#define UV2H_EVENT_OCCURRED2_RTC_29_MASK 0x0000000020000000UL -#define UV2H_EVENT_OCCURRED2_RTC_30_MASK 0x0000000040000000UL -#define UV2H_EVENT_OCCURRED2_RTC_31_MASK 0x0000000080000000UL +#define UV2H_EVENT_OCCURRED2 0x70100UL +#define UV2H_EVENT_OCCURRED2_32 0xb68 + +#define UV2H_EVENT_OCCURRED2_RTC_0_SHFT 0 +#define UV2H_EVENT_OCCURRED2_RTC_0_MASK 0x0000000000000001UL +#define UV2H_EVENT_OCCURRED2_RTC_1_SHFT 1 +#define UV2H_EVENT_OCCURRED2_RTC_1_MASK 0x0000000000000002UL +#define UV2H_EVENT_OCCURRED2_RTC_2_SHFT 2 +#define UV2H_EVENT_OCCURRED2_RTC_2_MASK 0x0000000000000004UL +#define UV2H_EVENT_OCCURRED2_RTC_3_SHFT 3 +#define UV2H_EVENT_OCCURRED2_RTC_3_MASK 0x0000000000000008UL +#define UV2H_EVENT_OCCURRED2_RTC_4_SHFT 4 +#define UV2H_EVENT_OCCURRED2_RTC_4_MASK 0x0000000000000010UL +#define UV2H_EVENT_OCCURRED2_RTC_5_SHFT 5 +#define UV2H_EVENT_OCCURRED2_RTC_5_MASK 0x0000000000000020UL +#define UV2H_EVENT_OCCURRED2_RTC_6_SHFT 6 +#define UV2H_EVENT_OCCURRED2_RTC_6_MASK 0x0000000000000040UL +#define UV2H_EVENT_OCCURRED2_RTC_7_SHFT 7 +#define UV2H_EVENT_OCCURRED2_RTC_7_MASK 0x0000000000000080UL +#define UV2H_EVENT_OCCURRED2_RTC_8_SHFT 8 +#define UV2H_EVENT_OCCURRED2_RTC_8_MASK 0x0000000000000100UL +#define UV2H_EVENT_OCCURRED2_RTC_9_SHFT 9 +#define UV2H_EVENT_OCCURRED2_RTC_9_MASK 0x0000000000000200UL +#define UV2H_EVENT_OCCURRED2_RTC_10_SHFT 10 +#define UV2H_EVENT_OCCURRED2_RTC_10_MASK 0x0000000000000400UL +#define UV2H_EVENT_OCCURRED2_RTC_11_SHFT 11 +#define UV2H_EVENT_OCCURRED2_RTC_11_MASK 0x0000000000000800UL +#define UV2H_EVENT_OCCURRED2_RTC_12_SHFT 12 +#define UV2H_EVENT_OCCURRED2_RTC_12_MASK 0x0000000000001000UL +#define UV2H_EVENT_OCCURRED2_RTC_13_SHFT 13 +#define UV2H_EVENT_OCCURRED2_RTC_13_MASK 0x0000000000002000UL +#define UV2H_EVENT_OCCURRED2_RTC_14_SHFT 14 +#define UV2H_EVENT_OCCURRED2_RTC_14_MASK 0x0000000000004000UL +#define UV2H_EVENT_OCCURRED2_RTC_15_SHFT 15 +#define UV2H_EVENT_OCCURRED2_RTC_15_MASK 0x0000000000008000UL +#define UV2H_EVENT_OCCURRED2_RTC_16_SHFT 16 +#define UV2H_EVENT_OCCURRED2_RTC_16_MASK 0x0000000000010000UL +#define UV2H_EVENT_OCCURRED2_RTC_17_SHFT 17 +#define UV2H_EVENT_OCCURRED2_RTC_17_MASK 0x0000000000020000UL +#define UV2H_EVENT_OCCURRED2_RTC_18_SHFT 18 +#define UV2H_EVENT_OCCURRED2_RTC_18_MASK 0x0000000000040000UL +#define UV2H_EVENT_OCCURRED2_RTC_19_SHFT 19 +#define UV2H_EVENT_OCCURRED2_RTC_19_MASK 0x0000000000080000UL +#define UV2H_EVENT_OCCURRED2_RTC_20_SHFT 20 +#define UV2H_EVENT_OCCURRED2_RTC_20_MASK 0x0000000000100000UL +#define UV2H_EVENT_OCCURRED2_RTC_21_SHFT 21 +#define UV2H_EVENT_OCCURRED2_RTC_21_MASK 0x0000000000200000UL +#define UV2H_EVENT_OCCURRED2_RTC_22_SHFT 22 +#define UV2H_EVENT_OCCURRED2_RTC_22_MASK 0x0000000000400000UL +#define UV2H_EVENT_OCCURRED2_RTC_23_SHFT 23 +#define UV2H_EVENT_OCCURRED2_RTC_23_MASK 0x0000000000800000UL +#define UV2H_EVENT_OCCURRED2_RTC_24_SHFT 24 +#define UV2H_EVENT_OCCURRED2_RTC_24_MASK 0x0000000001000000UL +#define UV2H_EVENT_OCCURRED2_RTC_25_SHFT 25 +#define UV2H_EVENT_OCCURRED2_RTC_25_MASK 0x0000000002000000UL +#define UV2H_EVENT_OCCURRED2_RTC_26_SHFT 26 +#define UV2H_EVENT_OCCURRED2_RTC_26_MASK 0x0000000004000000UL +#define UV2H_EVENT_OCCURRED2_RTC_27_SHFT 27 +#define UV2H_EVENT_OCCURRED2_RTC_27_MASK 0x0000000008000000UL +#define UV2H_EVENT_OCCURRED2_RTC_28_SHFT 28 +#define UV2H_EVENT_OCCURRED2_RTC_28_MASK 0x0000000010000000UL +#define UV2H_EVENT_OCCURRED2_RTC_29_SHFT 29 +#define UV2H_EVENT_OCCURRED2_RTC_29_MASK 0x0000000020000000UL +#define UV2H_EVENT_OCCURRED2_RTC_30_SHFT 30 +#define UV2H_EVENT_OCCURRED2_RTC_30_MASK 0x0000000040000000UL +#define UV2H_EVENT_OCCURRED2_RTC_31_SHFT 31 +#define UV2H_EVENT_OCCURRED2_RTC_31_MASK 0x0000000080000000UL union uv2h_event_occurred2_u { - unsigned long v; - struct uv2h_event_occurred2_s { - unsigned long rtc_0:1; /* RW */ - unsigned long rtc_1:1; /* RW */ - unsigned long rtc_2:1; /* RW */ - unsigned long rtc_3:1; /* RW */ - unsigned long rtc_4:1; /* RW */ - unsigned long rtc_5:1; /* RW */ - unsigned long rtc_6:1; /* RW */ - unsigned long rtc_7:1; /* RW */ - unsigned long rtc_8:1; /* RW */ - unsigned long rtc_9:1; /* RW */ - unsigned long rtc_10:1; /* RW */ - unsigned long rtc_11:1; /* RW */ - unsigned long rtc_12:1; /* RW */ - unsigned long rtc_13:1; /* RW */ - unsigned long rtc_14:1; /* RW */ - unsigned long rtc_15:1; /* RW */ - unsigned long rtc_16:1; /* RW */ - unsigned long rtc_17:1; /* RW */ - unsigned long rtc_18:1; /* RW */ - unsigned long rtc_19:1; /* RW */ - unsigned long rtc_20:1; /* RW */ - unsigned long rtc_21:1; /* RW */ - unsigned long rtc_22:1; /* RW */ - unsigned long rtc_23:1; /* RW */ - unsigned long rtc_24:1; /* RW */ - unsigned long rtc_25:1; /* RW */ - unsigned long rtc_26:1; /* RW */ - unsigned long rtc_27:1; /* RW */ - unsigned long rtc_28:1; /* RW */ - unsigned long rtc_29:1; /* RW */ - unsigned long rtc_30:1; /* RW */ - unsigned long rtc_31:1; /* RW */ - unsigned long rsvd_32_63:32; - } s1; + unsigned long v; + struct uv2h_event_occurred2_s { + unsigned long rtc_0 : 1; /* RW */ + unsigned long rtc_1 : 1; /* RW */ + unsigned long rtc_2 : 1; /* RW */ + unsigned long rtc_3 : 1; /* RW */ + unsigned long rtc_4 : 1; /* RW */ + unsigned long rtc_5 : 1; /* RW */ + unsigned long rtc_6 : 1; /* RW */ + unsigned long rtc_7 : 1; /* RW */ + unsigned long rtc_8 : 1; /* RW */ + unsigned long rtc_9 : 1; /* RW */ + unsigned long rtc_10 : 1; /* RW */ + unsigned long rtc_11 : 1; /* RW */ + unsigned long rtc_12 : 1; /* RW */ + unsigned long rtc_13 : 1; /* RW */ + unsigned long rtc_14 : 1; /* RW */ + unsigned long rtc_15 : 1; /* RW */ + unsigned long rtc_16 : 1; /* RW */ + unsigned long rtc_17 : 1; /* RW */ + unsigned long rtc_18 : 1; /* RW */ + unsigned long rtc_19 : 1; /* RW */ + unsigned long rtc_20 : 1; /* RW */ + unsigned long rtc_21 : 1; /* RW */ + unsigned long rtc_22 : 1; /* RW */ + unsigned long rtc_23 : 1; /* RW */ + unsigned long rtc_24 : 1; /* RW */ + unsigned long rtc_25 : 1; /* RW */ + unsigned long rtc_26 : 1; /* RW */ + unsigned long rtc_27 : 1; /* RW */ + unsigned long rtc_28 : 1; /* RW */ + unsigned long rtc_29 : 1; /* RW */ + unsigned long rtc_30 : 1; /* RW */ + unsigned long rtc_31 : 1; /* RW */ + unsigned long rsvd_32_63: 32; /* */ + } s1; }; /* ========================================================================= */ /* UV2H_EVENT_OCCURRED2_ALIAS */ /* ========================================================================= */ -#define UV2H_EVENT_OCCURRED2_ALIAS 0x70108UL -#define UV2H_EVENT_OCCURRED2_ALIAS_32 0xb70 +#define UV2H_EVENT_OCCURRED2_ALIAS 0x70108UL +#define UV2H_EVENT_OCCURRED2_ALIAS_32 0xb70 /* ========================================================================= */ /* UV2H_LB_BAU_SB_ACTIVATION_STATUS_2 */ /* ========================================================================= */ -#define UV2H_LB_BAU_SB_ACTIVATION_STATUS_2 0x320130UL -#define UV2H_LB_BAU_SB_ACTIVATION_STATUS_2_32 0x9f0 +#define UV2H_LB_BAU_SB_ACTIVATION_STATUS_2 0x320130UL +#define UV2H_LB_BAU_SB_ACTIVATION_STATUS_2_32 0x9f0 #define UV2H_LB_BAU_SB_ACTIVATION_STATUS_2_AUX_ERROR_SHFT 0 #define UV2H_LB_BAU_SB_ACTIVATION_STATUS_2_AUX_ERROR_MASK 0xffffffffffffffffUL union uv2h_lb_bau_sb_activation_status_2_u { - unsigned long v; - struct uv2h_lb_bau_sb_activation_status_2_s { - unsigned long aux_error:64; /* RW */ - } s1; + unsigned long v; + struct uv2h_lb_bau_sb_activation_status_2_s { + unsigned long aux_error : 64; /* RW */ + } s1; }; /* ========================================================================= */ /* UV1H_LB_TARGET_PHYSICAL_APIC_ID_MASK */ /* ========================================================================= */ -#define UV1H_LB_TARGET_PHYSICAL_APIC_ID_MASK 0x320130UL -#define UV1H_LB_TARGET_PHYSICAL_APIC_ID_MASK_32 0x9f0 +#define UV1H_LB_TARGET_PHYSICAL_APIC_ID_MASK 0x320130UL +#define UV1H_LB_TARGET_PHYSICAL_APIC_ID_MASK_32 0x9f0 #define UV1H_LB_TARGET_PHYSICAL_APIC_ID_MASK_BIT_ENABLES_SHFT 0 #define UV1H_LB_TARGET_PHYSICAL_APIC_ID_MASK_BIT_ENABLES_MASK 0x00000000ffffffffUL union uv1h_lb_target_physical_apic_id_mask_u { - unsigned long v; - struct uv1h_lb_target_physical_apic_id_mask_s { - unsigned long bit_enables:32; /* RW */ - unsigned long rsvd_32_63:32; - } s1; + unsigned long v; + struct uv1h_lb_target_physical_apic_id_mask_s { + unsigned long bit_enables : 32; /* RW */ + unsigned long rsvd_32_63 : 32; /* */ + } s1; }; -#endif /* _ASM_X86_UV_UV_MMRS_H */ +#endif /* __ASM_UV_MMRS_X86_H__ */ diff --git a/trunk/arch/x86/include/asm/vgtod.h b/trunk/arch/x86/include/asm/vgtod.h index 815285bcaceb..646b4c1ca695 100644 --- a/trunk/arch/x86/include/asm/vgtod.h +++ b/trunk/arch/x86/include/asm/vgtod.h @@ -11,9 +11,10 @@ struct vsyscall_gtod_data { time_t wall_time_sec; u32 wall_time_nsec; + int sysctl_enabled; struct timezone sys_tz; struct { /* extract of a clocksource struct */ - int vclock_mode; + cycle_t (*vread)(void); cycle_t cycle_last; cycle_t mask; u32 mult; diff --git a/trunk/arch/x86/include/asm/vmx.h b/trunk/arch/x86/include/asm/vmx.h index 2caf290e9895..84471b810460 100644 --- a/trunk/arch/x86/include/asm/vmx.h +++ b/trunk/arch/x86/include/asm/vmx.h @@ -132,8 +132,6 @@ enum vmcs_field { GUEST_IA32_PAT_HIGH = 0x00002805, GUEST_IA32_EFER = 0x00002806, GUEST_IA32_EFER_HIGH = 0x00002807, - GUEST_IA32_PERF_GLOBAL_CTRL = 0x00002808, - GUEST_IA32_PERF_GLOBAL_CTRL_HIGH= 0x00002809, GUEST_PDPTR0 = 0x0000280a, GUEST_PDPTR0_HIGH = 0x0000280b, GUEST_PDPTR1 = 0x0000280c, @@ -146,8 +144,6 @@ enum vmcs_field { HOST_IA32_PAT_HIGH = 0x00002c01, HOST_IA32_EFER = 0x00002c02, HOST_IA32_EFER_HIGH = 0x00002c03, - HOST_IA32_PERF_GLOBAL_CTRL = 0x00002c04, - HOST_IA32_PERF_GLOBAL_CTRL_HIGH = 0x00002c05, PIN_BASED_VM_EXEC_CONTROL = 0x00004000, CPU_BASED_VM_EXEC_CONTROL = 0x00004002, EXCEPTION_BITMAP = 0x00004004, @@ -430,43 +426,4 @@ struct vmx_msr_entry { u64 value; } __aligned(16); -/* - * Exit Qualifications for entry failure during or after loading guest state - */ -#define ENTRY_FAIL_DEFAULT 0 -#define ENTRY_FAIL_PDPTE 2 -#define ENTRY_FAIL_NMI 3 -#define ENTRY_FAIL_VMCS_LINK_PTR 4 - -/* - * VM-instruction error numbers - */ -enum vm_instruction_error_number { - VMXERR_VMCALL_IN_VMX_ROOT_OPERATION = 1, - VMXERR_VMCLEAR_INVALID_ADDRESS = 2, - VMXERR_VMCLEAR_VMXON_POINTER = 3, - VMXERR_VMLAUNCH_NONCLEAR_VMCS = 4, - VMXERR_VMRESUME_NONLAUNCHED_VMCS = 5, - VMXERR_VMRESUME_AFTER_VMXOFF = 6, - VMXERR_ENTRY_INVALID_CONTROL_FIELD = 7, - VMXERR_ENTRY_INVALID_HOST_STATE_FIELD = 8, - VMXERR_VMPTRLD_INVALID_ADDRESS = 9, - VMXERR_VMPTRLD_VMXON_POINTER = 10, - VMXERR_VMPTRLD_INCORRECT_VMCS_REVISION_ID = 11, - VMXERR_UNSUPPORTED_VMCS_COMPONENT = 12, - VMXERR_VMWRITE_READ_ONLY_VMCS_COMPONENT = 13, - VMXERR_VMXON_IN_VMX_ROOT_OPERATION = 15, - VMXERR_ENTRY_INVALID_EXECUTIVE_VMCS_POINTER = 16, - VMXERR_ENTRY_NONLAUNCHED_EXECUTIVE_VMCS = 17, - VMXERR_ENTRY_EXECUTIVE_VMCS_POINTER_NOT_VMXON_POINTER = 18, - VMXERR_VMCALL_NONCLEAR_VMCS = 19, - VMXERR_VMCALL_INVALID_VM_EXIT_CONTROL_FIELDS = 20, - VMXERR_VMCALL_INCORRECT_MSEG_REVISION_ID = 22, - VMXERR_VMXOFF_UNDER_DUAL_MONITOR_TREATMENT_OF_SMIS_AND_SMM = 23, - VMXERR_VMCALL_INVALID_SMM_MONITOR_FEATURES = 24, - VMXERR_ENTRY_INVALID_VM_EXECUTION_CONTROL_FIELDS_IN_EXECUTIVE_VMCS = 25, - VMXERR_ENTRY_EVENTS_BLOCKED_BY_MOV_SS = 26, - VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID = 28, -}; - #endif diff --git a/trunk/arch/x86/include/asm/vsyscall.h b/trunk/arch/x86/include/asm/vsyscall.h index 60107072c28b..d55597351f6a 100644 --- a/trunk/arch/x86/include/asm/vsyscall.h +++ b/trunk/arch/x86/include/asm/vsyscall.h @@ -16,6 +16,10 @@ enum vsyscall_num { #ifdef __KERNEL__ #include +/* Definitions for CONFIG_GENERIC_TIME definitions */ +#define __vsyscall_fn \ + __attribute__ ((unused, __section__(".vsyscall_fn"))) notrace + #define VGETCPU_RDTSCP 1 #define VGETCPU_LSL 2 diff --git a/trunk/arch/x86/include/asm/vvar.h b/trunk/arch/x86/include/asm/vvar.h index de656ac2af41..341b3559452b 100644 --- a/trunk/arch/x86/include/asm/vvar.h +++ b/trunk/arch/x86/include/asm/vvar.h @@ -10,14 +10,15 @@ * In normal kernel code, they are used like any other variable. * In user code, they are accessed through the VVAR macro. * - * These variables live in a page of kernel data that has an extra RO - * mapping for userspace. Each variable needs a unique offset within - * that page; specify that offset with the DECLARE_VVAR macro. (If - * you mess up, the linker will catch it.) + * Each of these variables lives in the vsyscall page, and each + * one needs a unique offset within the little piece of the page + * reserved for vvars. Specify that offset in DECLARE_VVAR. + * (There are 896 bytes available. If you mess up, the linker will + * catch it.) */ -/* Base address of vvars. This is not ABI. */ -#define VVAR_ADDRESS (-10*1024*1024 - 4096) +/* Offset of vars within vsyscall page */ +#define VSYSCALL_VARS_OFFSET (3072 + 128) #if defined(__VVAR_KERNEL_LDS) @@ -25,17 +26,17 @@ * right place. */ #define DECLARE_VVAR(offset, type, name) \ - EMIT_VVAR(name, offset) + EMIT_VVAR(name, VSYSCALL_VARS_OFFSET + offset) #else #define DECLARE_VVAR(offset, type, name) \ static type const * const vvaraddr_ ## name = \ - (void *)(VVAR_ADDRESS + (offset)); + (void *)(VSYSCALL_START + VSYSCALL_VARS_OFFSET + (offset)); #define DEFINE_VVAR(type, name) \ - type name \ - __attribute__((section(".vvar_" #name), aligned(16))) + type __vvar_ ## name \ + __attribute__((section(".vsyscall_var_" #name), aligned(16))) #define VVAR(name) (*vvaraddr_ ## name) @@ -44,7 +45,8 @@ /* DECLARE_VVAR(offset, type, name) */ DECLARE_VVAR(0, volatile unsigned long, jiffies) -DECLARE_VVAR(16, int, vgetcpu_mode) +DECLARE_VVAR(8, int, vgetcpu_mode) DECLARE_VVAR(128, struct vsyscall_gtod_data, vsyscall_gtod_data) #undef DECLARE_VVAR +#undef VSYSCALL_VARS_OFFSET diff --git a/trunk/arch/x86/include/asm/xen/hypercall.h b/trunk/arch/x86/include/asm/xen/hypercall.h index 417777de5a40..d240ea950519 100644 --- a/trunk/arch/x86/include/asm/xen/hypercall.h +++ b/trunk/arch/x86/include/asm/xen/hypercall.h @@ -39,8 +39,6 @@ #include #include -#include - #include #include @@ -461,8 +459,6 @@ MULTI_fpu_taskswitch(struct multicall_entry *mcl, int set) { mcl->op = __HYPERVISOR_fpu_taskswitch; mcl->args[0] = set; - - trace_xen_mc_entry(mcl, 1); } static inline void @@ -479,8 +475,6 @@ MULTI_update_va_mapping(struct multicall_entry *mcl, unsigned long va, mcl->args[2] = new_val.pte >> 32; mcl->args[3] = flags; } - - trace_xen_mc_entry(mcl, sizeof(new_val) == sizeof(long) ? 3 : 4); } static inline void @@ -491,8 +485,6 @@ MULTI_grant_table_op(struct multicall_entry *mcl, unsigned int cmd, mcl->args[0] = cmd; mcl->args[1] = (unsigned long)uop; mcl->args[2] = count; - - trace_xen_mc_entry(mcl, 3); } static inline void @@ -512,8 +504,6 @@ MULTI_update_va_mapping_otherdomain(struct multicall_entry *mcl, unsigned long v mcl->args[3] = flags; mcl->args[4] = domid; } - - trace_xen_mc_entry(mcl, sizeof(new_val) == sizeof(long) ? 4 : 5); } static inline void @@ -530,8 +520,6 @@ MULTI_update_descriptor(struct multicall_entry *mcl, u64 maddr, mcl->args[2] = desc.a; mcl->args[3] = desc.b; } - - trace_xen_mc_entry(mcl, sizeof(maddr) == sizeof(long) ? 2 : 4); } static inline void @@ -540,8 +528,6 @@ MULTI_memory_op(struct multicall_entry *mcl, unsigned int cmd, void *arg) mcl->op = __HYPERVISOR_memory_op; mcl->args[0] = cmd; mcl->args[1] = (unsigned long)arg; - - trace_xen_mc_entry(mcl, 2); } static inline void @@ -553,8 +539,6 @@ MULTI_mmu_update(struct multicall_entry *mcl, struct mmu_update *req, mcl->args[1] = count; mcl->args[2] = (unsigned long)success_count; mcl->args[3] = domid; - - trace_xen_mc_entry(mcl, 4); } static inline void @@ -566,8 +550,6 @@ MULTI_mmuext_op(struct multicall_entry *mcl, struct mmuext_op *op, int count, mcl->args[1] = count; mcl->args[2] = (unsigned long)success_count; mcl->args[3] = domid; - - trace_xen_mc_entry(mcl, 4); } static inline void @@ -576,8 +558,6 @@ MULTI_set_gdt(struct multicall_entry *mcl, unsigned long *frames, int entries) mcl->op = __HYPERVISOR_set_gdt; mcl->args[0] = (unsigned long)frames; mcl->args[1] = entries; - - trace_xen_mc_entry(mcl, 2); } static inline void @@ -587,8 +567,6 @@ MULTI_stack_switch(struct multicall_entry *mcl, mcl->op = __HYPERVISOR_stack_switch; mcl->args[0] = ss; mcl->args[1] = esp; - - trace_xen_mc_entry(mcl, 2); } #endif /* _ASM_X86_XEN_HYPERCALL_H */ diff --git a/trunk/arch/x86/include/asm/xen/trace_types.h b/trunk/arch/x86/include/asm/xen/trace_types.h deleted file mode 100644 index 21e1874c0a0b..000000000000 --- a/trunk/arch/x86/include/asm/xen/trace_types.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef _ASM_XEN_TRACE_TYPES_H -#define _ASM_XEN_TRACE_TYPES_H - -enum xen_mc_flush_reason { - XEN_MC_FL_NONE, /* explicit flush */ - XEN_MC_FL_BATCH, /* out of hypercall space */ - XEN_MC_FL_ARGS, /* out of argument space */ - XEN_MC_FL_CALLBACK, /* out of callback space */ -}; - -enum xen_mc_extend_args { - XEN_MC_XE_OK, - XEN_MC_XE_BAD_OP, - XEN_MC_XE_NO_SPACE -}; -typedef void (*xen_mc_callback_fn_t)(void *); - -#endif /* _ASM_XEN_TRACE_TYPES_H */ diff --git a/trunk/arch/x86/kernel/Makefile b/trunk/arch/x86/kernel/Makefile index 04105574c8e9..90b06d4daee2 100644 --- a/trunk/arch/x86/kernel/Makefile +++ b/trunk/arch/x86/kernel/Makefile @@ -24,12 +24,17 @@ endif nostackp := $(call cc-option, -fno-stack-protector) CFLAGS_vsyscall_64.o := $(PROFILING) -g0 $(nostackp) CFLAGS_hpet.o := $(nostackp) +CFLAGS_vread_tsc_64.o := $(nostackp) CFLAGS_paravirt.o := $(nostackp) GCOV_PROFILE_vsyscall_64.o := n GCOV_PROFILE_hpet.o := n GCOV_PROFILE_tsc.o := n +GCOV_PROFILE_vread_tsc_64.o := n GCOV_PROFILE_paravirt.o := n +# vread_tsc_64 is hot and should be fully optimized: +CFLAGS_REMOVE_vread_tsc_64.o = -pg -fno-optimize-sibling-calls + obj-y := process_$(BITS).o signal.o entry_$(BITS).o obj-y += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o obj-y += time.o ioport.o ldt.o dumpstack.o @@ -38,8 +43,7 @@ obj-$(CONFIG_IRQ_WORK) += irq_work.o obj-y += probe_roms.o obj-$(CONFIG_X86_32) += sys_i386_32.o i386_ksyms_32.o obj-$(CONFIG_X86_64) += sys_x86_64.o x8664_ksyms_64.o -obj-$(CONFIG_X86_64) += syscall_64.o vsyscall_64.o -obj-$(CONFIG_X86_64) += vsyscall_emu_64.o +obj-$(CONFIG_X86_64) += syscall_64.o vsyscall_64.o vread_tsc_64.o obj-y += bootflag.o e820.o obj-y += pci-dma.o quirks.o topology.o kdebugfs.o obj-y += alternative.o i8253.o pci-nommu.o hw_breakpoint.o @@ -119,6 +123,7 @@ ifeq ($(CONFIG_X86_64),y) obj-$(CONFIG_GART_IOMMU) += amd_gart_64.o aperture_64.o obj-$(CONFIG_CALGARY_IOMMU) += pci-calgary_64.o tce_64.o + obj-$(CONFIG_AMD_IOMMU) += amd_iommu_init.o amd_iommu.o obj-$(CONFIG_PCI_MMCONFIG) += mmconf-fam10h_64.o obj-y += vsmp_64.o diff --git a/trunk/arch/x86/kernel/alternative.c b/trunk/arch/x86/kernel/alternative.c index c63822816249..a81f2d52f869 100644 --- a/trunk/arch/x86/kernel/alternative.c +++ b/trunk/arch/x86/kernel/alternative.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -249,6 +250,7 @@ static void __init_or_module add_nops(void *insns, unsigned int len) extern struct alt_instr __alt_instructions[], __alt_instructions_end[]; extern s32 __smp_locks[], __smp_locks_end[]; +extern char __vsyscall_0; void *text_poke_early(void *addr, const void *opcode, size_t len); /* Replace instructions with better alternatives for this CPU type. @@ -261,7 +263,6 @@ void __init_or_module apply_alternatives(struct alt_instr *start, struct alt_instr *end) { struct alt_instr *a; - u8 *instr, *replacement; u8 insnbuf[MAX_PATCH_LEN]; DPRINTK("%s: alt table %p -> %p\n", __func__, start, end); @@ -275,23 +276,25 @@ void __init_or_module apply_alternatives(struct alt_instr *start, * order. */ for (a = start; a < end; a++) { - instr = (u8 *)&a->instr_offset + a->instr_offset; - replacement = (u8 *)&a->repl_offset + a->repl_offset; + u8 *instr = a->instr; BUG_ON(a->replacementlen > a->instrlen); BUG_ON(a->instrlen > sizeof(insnbuf)); BUG_ON(a->cpuid >= NCAPINTS*32); if (!boot_cpu_has(a->cpuid)) continue; - - memcpy(insnbuf, replacement, a->replacementlen); - - /* 0xe8 is a relative jump; fix the offset. */ +#ifdef CONFIG_X86_64 + /* vsyscall code is not mapped yet. resolve it manually. */ + if (instr >= (u8 *)VSYSCALL_START && instr < (u8*)VSYSCALL_END) { + instr = __va(instr - (u8*)VSYSCALL_START + (u8*)__pa_symbol(&__vsyscall_0)); + DPRINTK("%s: vsyscall fixup: %p => %p\n", + __func__, a->instr, instr); + } +#endif + memcpy(insnbuf, a->replacement, a->replacementlen); if (*insnbuf == 0xe8 && a->replacementlen == 5) - *(s32 *)(insnbuf + 1) += replacement - instr; - + *(s32 *)(insnbuf + 1) += a->replacement - a->instr; add_nops(insnbuf + a->replacementlen, a->instrlen - a->replacementlen); - text_poke_early(instr, insnbuf, a->instrlen); } } diff --git a/trunk/drivers/iommu/amd_iommu.c b/trunk/arch/x86/kernel/amd_iommu.c similarity index 91% rename from trunk/drivers/iommu/amd_iommu.c rename to trunk/arch/x86/kernel/amd_iommu.c index a14f8dc23462..7c3a95e54ec5 100644 --- a/trunk/drivers/iommu/amd_iommu.c +++ b/trunk/arch/x86/kernel/amd_iommu.c @@ -27,15 +27,13 @@ #include #include #include -#include -#include #include #include #include #include - -#include "amd_iommu_proto.h" -#include "amd_iommu_types.h" +#include +#include +#include #define CMD_SET_TYPE(cmd, t) ((cmd)->data[1] |= ((t) << 28)) @@ -47,10 +45,6 @@ static DEFINE_RWLOCK(amd_iommu_devtable_lock); static LIST_HEAD(iommu_pd_list); static DEFINE_SPINLOCK(iommu_pd_list_lock); -/* List of all available dev_data structures */ -static LIST_HEAD(dev_data_list); -static DEFINE_SPINLOCK(dev_data_list_lock); - /* * Domain for untranslated devices - only allocated * if iommu=pt passed on kernel cmd line. @@ -74,67 +68,6 @@ static void update_domain(struct protection_domain *domain); * ****************************************************************************/ -static struct iommu_dev_data *alloc_dev_data(u16 devid) -{ - struct iommu_dev_data *dev_data; - unsigned long flags; - - dev_data = kzalloc(sizeof(*dev_data), GFP_KERNEL); - if (!dev_data) - return NULL; - - dev_data->devid = devid; - atomic_set(&dev_data->bind, 0); - - spin_lock_irqsave(&dev_data_list_lock, flags); - list_add_tail(&dev_data->dev_data_list, &dev_data_list); - spin_unlock_irqrestore(&dev_data_list_lock, flags); - - return dev_data; -} - -static void free_dev_data(struct iommu_dev_data *dev_data) -{ - unsigned long flags; - - spin_lock_irqsave(&dev_data_list_lock, flags); - list_del(&dev_data->dev_data_list); - spin_unlock_irqrestore(&dev_data_list_lock, flags); - - kfree(dev_data); -} - -static struct iommu_dev_data *search_dev_data(u16 devid) -{ - struct iommu_dev_data *dev_data; - unsigned long flags; - - spin_lock_irqsave(&dev_data_list_lock, flags); - list_for_each_entry(dev_data, &dev_data_list, dev_data_list) { - if (dev_data->devid == devid) - goto out_unlock; - } - - dev_data = NULL; - -out_unlock: - spin_unlock_irqrestore(&dev_data_list_lock, flags); - - return dev_data; -} - -static struct iommu_dev_data *find_dev_data(u16 devid) -{ - struct iommu_dev_data *dev_data; - - dev_data = search_dev_data(devid); - - if (dev_data == NULL) - dev_data = alloc_dev_data(devid); - - return dev_data; -} - static inline u16 get_device_id(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); @@ -205,31 +138,33 @@ static bool check_device(struct device *dev) static int iommu_init_device(struct device *dev) { struct iommu_dev_data *dev_data; - u16 alias; + struct pci_dev *pdev; + u16 devid, alias; if (dev->archdata.iommu) return 0; - dev_data = find_dev_data(get_device_id(dev)); + dev_data = kzalloc(sizeof(*dev_data), GFP_KERNEL); if (!dev_data) return -ENOMEM; - alias = amd_iommu_alias_table[dev_data->devid]; - if (alias != dev_data->devid) { - struct iommu_dev_data *alias_data; + dev_data->dev = dev; - alias_data = find_dev_data(alias); - if (alias_data == NULL) { - pr_err("AMD-Vi: Warning: Unhandled device %s\n", - dev_name(dev)); - free_dev_data(dev_data); - return -ENOTSUPP; - } - dev_data->alias_data = alias_data; + devid = get_device_id(dev); + alias = amd_iommu_alias_table[devid]; + pdev = pci_get_bus_and_slot(PCI_BUS(alias), alias & 0xff); + if (pdev) + dev_data->alias = &pdev->dev; + else { + kfree(dev_data); + return -ENOTSUPP; } + atomic_set(&dev_data->bind, 0); + dev->archdata.iommu = dev_data; + return 0; } @@ -249,16 +184,11 @@ static void iommu_ignore_device(struct device *dev) static void iommu_uninit_device(struct device *dev) { - /* - * Nothing to do here - we keep dev_data around for unplugged devices - * and reuse it when the device is re-plugged - not doing so would - * introduce a ton of races. - */ + kfree(dev->archdata.iommu); } void __init amd_iommu_uninit_devices(void) { - struct iommu_dev_data *dev_data, *n; struct pci_dev *pdev = NULL; for_each_pci_dev(pdev) { @@ -268,10 +198,6 @@ void __init amd_iommu_uninit_devices(void) iommu_uninit_device(&pdev->dev); } - - /* Free all of our dev_data structures */ - list_for_each_entry_safe(dev_data, n, &dev_data_list, dev_data_list) - free_dev_data(dev_data); } int __init amd_iommu_init_devices(void) @@ -728,17 +654,19 @@ void iommu_flush_all_caches(struct amd_iommu *iommu) /* * Command send function for flushing on-device TLB */ -static int device_flush_iotlb(struct iommu_dev_data *dev_data, - u64 address, size_t size) +static int device_flush_iotlb(struct device *dev, u64 address, size_t size) { + struct pci_dev *pdev = to_pci_dev(dev); struct amd_iommu *iommu; struct iommu_cmd cmd; + u16 devid; int qdep; - qdep = dev_data->ats.qdep; - iommu = amd_iommu_rlookup_table[dev_data->devid]; + qdep = pci_ats_queue_depth(pdev); + devid = get_device_id(dev); + iommu = amd_iommu_rlookup_table[devid]; - build_inv_iotlb_pages(&cmd, dev_data->devid, qdep, address, size); + build_inv_iotlb_pages(&cmd, devid, qdep, address, size); return iommu_queue_command(iommu, &cmd); } @@ -746,19 +674,23 @@ static int device_flush_iotlb(struct iommu_dev_data *dev_data, /* * Command send function for invalidating a device table entry */ -static int device_flush_dte(struct iommu_dev_data *dev_data) +static int device_flush_dte(struct device *dev) { struct amd_iommu *iommu; + struct pci_dev *pdev; + u16 devid; int ret; - iommu = amd_iommu_rlookup_table[dev_data->devid]; + pdev = to_pci_dev(dev); + devid = get_device_id(dev); + iommu = amd_iommu_rlookup_table[devid]; - ret = iommu_flush_dte(iommu, dev_data->devid); + ret = iommu_flush_dte(iommu, devid); if (ret) return ret; - if (dev_data->ats.enabled) - ret = device_flush_iotlb(dev_data, 0, ~0UL); + if (pci_ats_enabled(pdev)) + ret = device_flush_iotlb(dev, 0, ~0UL); return ret; } @@ -789,11 +721,12 @@ static void __domain_flush_pages(struct protection_domain *domain, } list_for_each_entry(dev_data, &domain->dev_list, list) { + struct pci_dev *pdev = to_pci_dev(dev_data->dev); - if (!dev_data->ats.enabled) + if (!pci_ats_enabled(pdev)) continue; - ret |= device_flush_iotlb(dev_data, address, size); + ret |= device_flush_iotlb(dev_data->dev, address, size); } WARN_ON(ret); @@ -845,7 +778,7 @@ static void domain_flush_devices(struct protection_domain *domain) spin_lock_irqsave(&domain->lock, flags); list_for_each_entry(dev_data, &domain->dev_list, list) - device_flush_dte(dev_data); + device_flush_dte(dev_data->dev); spin_unlock_irqrestore(&domain->lock, flags); } @@ -1203,7 +1136,7 @@ static int alloc_new_range(struct dma_ops_domain *dma_dom, { int index = dma_dom->aperture_size >> APERTURE_RANGE_SHIFT; struct amd_iommu *iommu; - unsigned long i, old_size; + unsigned long i; #ifdef CONFIG_IOMMU_STRESS populate = false; @@ -1239,21 +1172,8 @@ static int alloc_new_range(struct dma_ops_domain *dma_dom, } } - old_size = dma_dom->aperture_size; dma_dom->aperture_size += APERTURE_RANGE_SIZE; - /* Reserve address range used for MSI messages */ - if (old_size < MSI_ADDR_BASE_LO && - dma_dom->aperture_size > MSI_ADDR_BASE_LO) { - unsigned long spage; - int pages; - - pages = iommu_num_pages(MSI_ADDR_BASE_LO, 0x10000, PAGE_SIZE); - spage = MSI_ADDR_BASE_LO >> PAGE_SHIFT; - - dma_ops_reserve_addresses(dma_dom, spage, pages); - } - /* Initialize the exclusion range if necessary */ for_each_iommu(iommu) { if (iommu->exclusion_start && @@ -1606,33 +1526,44 @@ static void clear_dte_entry(u16 devid) amd_iommu_apply_erratum_63(devid); } -static void do_attach(struct iommu_dev_data *dev_data, - struct protection_domain *domain) +static void do_attach(struct device *dev, struct protection_domain *domain) { + struct iommu_dev_data *dev_data; struct amd_iommu *iommu; - bool ats; + struct pci_dev *pdev; + bool ats = false; + u16 devid; - iommu = amd_iommu_rlookup_table[dev_data->devid]; - ats = dev_data->ats.enabled; + devid = get_device_id(dev); + iommu = amd_iommu_rlookup_table[devid]; + dev_data = get_dev_data(dev); + pdev = to_pci_dev(dev); + + if (amd_iommu_iotlb_sup) + ats = pci_ats_enabled(pdev); /* Update data structures */ dev_data->domain = domain; list_add(&dev_data->list, &domain->dev_list); - set_dte_entry(dev_data->devid, domain, ats); + set_dte_entry(devid, domain, ats); /* Do reference counting */ domain->dev_iommu[iommu->index] += 1; domain->dev_cnt += 1; /* Flush the DTE entry */ - device_flush_dte(dev_data); + device_flush_dte(dev); } -static void do_detach(struct iommu_dev_data *dev_data) +static void do_detach(struct device *dev) { + struct iommu_dev_data *dev_data; struct amd_iommu *iommu; + u16 devid; - iommu = amd_iommu_rlookup_table[dev_data->devid]; + devid = get_device_id(dev); + iommu = amd_iommu_rlookup_table[devid]; + dev_data = get_dev_data(dev); /* decrease reference counters */ dev_data->domain->dev_iommu[iommu->index] -= 1; @@ -1641,46 +1572,52 @@ static void do_detach(struct iommu_dev_data *dev_data) /* Update data structures */ dev_data->domain = NULL; list_del(&dev_data->list); - clear_dte_entry(dev_data->devid); + clear_dte_entry(devid); /* Flush the DTE entry */ - device_flush_dte(dev_data); + device_flush_dte(dev); } /* * If a device is not yet associated with a domain, this function does * assigns it visible for the hardware */ -static int __attach_device(struct iommu_dev_data *dev_data, +static int __attach_device(struct device *dev, struct protection_domain *domain) { + struct iommu_dev_data *dev_data, *alias_data; int ret; + dev_data = get_dev_data(dev); + alias_data = get_dev_data(dev_data->alias); + + if (!alias_data) + return -EINVAL; + /* lock domain */ spin_lock(&domain->lock); - if (dev_data->alias_data != NULL) { - struct iommu_dev_data *alias_data = dev_data->alias_data; + /* Some sanity checks */ + ret = -EBUSY; + if (alias_data->domain != NULL && + alias_data->domain != domain) + goto out_unlock; - /* Some sanity checks */ - ret = -EBUSY; - if (alias_data->domain != NULL && - alias_data->domain != domain) - goto out_unlock; + if (dev_data->domain != NULL && + dev_data->domain != domain) + goto out_unlock; - if (dev_data->domain != NULL && - dev_data->domain != domain) - goto out_unlock; - - /* Do real assignment */ + /* Do real assignment */ + if (dev_data->alias != dev) { + alias_data = get_dev_data(dev_data->alias); if (alias_data->domain == NULL) - do_attach(alias_data, domain); + do_attach(dev_data->alias, domain); atomic_inc(&alias_data->bind); } if (dev_data->domain == NULL) - do_attach(dev_data, domain); + do_attach(dev, domain); atomic_inc(&dev_data->bind); @@ -1702,19 +1639,14 @@ static int attach_device(struct device *dev, struct protection_domain *domain) { struct pci_dev *pdev = to_pci_dev(dev); - struct iommu_dev_data *dev_data; unsigned long flags; int ret; - dev_data = get_dev_data(dev); - - if (amd_iommu_iotlb_sup && pci_enable_ats(pdev, PAGE_SHIFT) == 0) { - dev_data->ats.enabled = true; - dev_data->ats.qdep = pci_ats_queue_depth(pdev); - } + if (amd_iommu_iotlb_sup) + pci_enable_ats(pdev, PAGE_SHIFT); write_lock_irqsave(&amd_iommu_devtable_lock, flags); - ret = __attach_device(dev_data, domain); + ret = __attach_device(dev, domain); write_unlock_irqrestore(&amd_iommu_devtable_lock, flags); /* @@ -1730,8 +1662,10 @@ static int attach_device(struct device *dev, /* * Removes a device from a protection domain (unlocked) */ -static void __detach_device(struct iommu_dev_data *dev_data) +static void __detach_device(struct device *dev) { + struct iommu_dev_data *dev_data = get_dev_data(dev); + struct iommu_dev_data *alias_data; struct protection_domain *domain; unsigned long flags; @@ -1741,15 +1675,14 @@ static void __detach_device(struct iommu_dev_data *dev_data) spin_lock_irqsave(&domain->lock, flags); - if (dev_data->alias_data != NULL) { - struct iommu_dev_data *alias_data = dev_data->alias_data; - + if (dev_data->alias != dev) { + alias_data = get_dev_data(dev_data->alias); if (atomic_dec_and_test(&alias_data->bind)) - do_detach(alias_data); + do_detach(dev_data->alias); } if (atomic_dec_and_test(&dev_data->bind)) - do_detach(dev_data); + do_detach(dev); spin_unlock_irqrestore(&domain->lock, flags); @@ -1760,7 +1693,7 @@ static void __detach_device(struct iommu_dev_data *dev_data) */ if (iommu_pass_through && (dev_data->domain == NULL && domain != pt_domain)) - __attach_device(dev_data, pt_domain); + __attach_device(dev, pt_domain); } /* @@ -1768,20 +1701,16 @@ static void __detach_device(struct iommu_dev_data *dev_data) */ static void detach_device(struct device *dev) { - struct iommu_dev_data *dev_data; + struct pci_dev *pdev = to_pci_dev(dev); unsigned long flags; - dev_data = get_dev_data(dev); - /* lock device table */ write_lock_irqsave(&amd_iommu_devtable_lock, flags); - __detach_device(dev_data); + __detach_device(dev); write_unlock_irqrestore(&amd_iommu_devtable_lock, flags); - if (dev_data->ats.enabled) { - pci_disable_ats(to_pci_dev(dev)); - dev_data->ats.enabled = false; - } + if (amd_iommu_iotlb_sup && pci_ats_enabled(pdev)) + pci_disable_ats(pdev); } /* @@ -1790,26 +1719,27 @@ static void detach_device(struct device *dev) */ static struct protection_domain *domain_for_device(struct device *dev) { - struct iommu_dev_data *dev_data; - struct protection_domain *dom = NULL; + struct protection_domain *dom; + struct iommu_dev_data *dev_data, *alias_data; unsigned long flags; + u16 devid; + devid = get_device_id(dev); dev_data = get_dev_data(dev); + alias_data = get_dev_data(dev_data->alias); + if (!alias_data) + return NULL; - if (dev_data->domain) - return dev_data->domain; - - if (dev_data->alias_data != NULL) { - struct iommu_dev_data *alias_data = dev_data->alias_data; - - read_lock_irqsave(&amd_iommu_devtable_lock, flags); - if (alias_data->domain != NULL) { - __attach_device(dev_data, alias_data->domain); - dom = alias_data->domain; - } - read_unlock_irqrestore(&amd_iommu_devtable_lock, flags); + read_lock_irqsave(&amd_iommu_devtable_lock, flags); + dom = dev_data->domain; + if (dom == NULL && + alias_data->domain != NULL) { + __attach_device(dev, alias_data->domain); + dom = alias_data->domain; } + read_unlock_irqrestore(&amd_iommu_devtable_lock, flags); + return dom; } @@ -1868,6 +1798,7 @@ static int device_change_notifier(struct notifier_block *nb, goto out; } + device_flush_dte(dev); iommu_completion_wait(iommu); out: @@ -1927,8 +1858,11 @@ static void update_device_table(struct protection_domain *domain) { struct iommu_dev_data *dev_data; - list_for_each_entry(dev_data, &domain->dev_list, list) - set_dte_entry(dev_data->devid, domain, dev_data->ats.enabled); + list_for_each_entry(dev_data, &domain->dev_list, list) { + struct pci_dev *pdev = to_pci_dev(dev_data->dev); + u16 devid = get_device_id(dev_data->dev); + set_dte_entry(devid, domain, pci_ats_enabled(pdev)); + } } static void update_domain(struct protection_domain *domain) @@ -2563,7 +2497,9 @@ static void cleanup_domain(struct protection_domain *domain) write_lock_irqsave(&amd_iommu_devtable_lock, flags); list_for_each_entry_safe(dev_data, next, &domain->dev_list, list) { - __detach_device(dev_data); + struct device *dev = dev_data->dev; + + __detach_device(dev); atomic_set(&dev_data->bind, 0); } @@ -2669,6 +2605,7 @@ static void amd_iommu_detach_device(struct iommu_domain *dom, if (!iommu) return; + device_flush_dte(dev); iommu_completion_wait(iommu); } @@ -2679,13 +2616,16 @@ static int amd_iommu_attach_device(struct iommu_domain *dom, struct iommu_dev_data *dev_data; struct amd_iommu *iommu; int ret; + u16 devid; if (!check_device(dev)) return -EINVAL; dev_data = dev->archdata.iommu; - iommu = amd_iommu_rlookup_table[dev_data->devid]; + devid = get_device_id(dev); + + iommu = amd_iommu_rlookup_table[devid]; if (!iommu) return -EINVAL; diff --git a/trunk/drivers/iommu/amd_iommu_init.c b/trunk/arch/x86/kernel/amd_iommu_init.c similarity index 99% rename from trunk/drivers/iommu/amd_iommu_init.c rename to trunk/arch/x86/kernel/amd_iommu_init.c index 82d2410f4205..bfc8453bd98d 100644 --- a/trunk/drivers/iommu/amd_iommu_init.c +++ b/trunk/arch/x86/kernel/amd_iommu_init.c @@ -24,16 +24,14 @@ #include #include #include -#include #include +#include +#include +#include #include #include #include #include - -#include "amd_iommu_proto.h" -#include "amd_iommu_types.h" - /* * definitions for the ACPI scanning code */ diff --git a/trunk/arch/x86/kernel/apb_timer.c b/trunk/arch/x86/kernel/apb_timer.c index afdc3f756dea..289e92862fd9 100644 --- a/trunk/arch/x86/kernel/apb_timer.c +++ b/trunk/arch/x86/kernel/apb_timer.c @@ -27,12 +27,15 @@ * timer, but by default APB timer has higher rating than local APIC timers. */ +#include +#include #include -#include #include #include +#include #include #include +#include #include #include #include @@ -41,48 +44,76 @@ #include #include #include -#include +#define APBT_MASK CLOCKSOURCE_MASK(32) +#define APBT_SHIFT 22 #define APBT_CLOCKEVENT_RATING 110 #define APBT_CLOCKSOURCE_RATING 250 +#define APBT_MIN_DELTA_USEC 200 +#define EVT_TO_APBT_DEV(evt) container_of(evt, struct apbt_dev, evt) #define APBT_CLOCKEVENT0_NUM (0) +#define APBT_CLOCKEVENT1_NUM (1) #define APBT_CLOCKSOURCE_NUM (2) -static phys_addr_t apbt_address; +static unsigned long apbt_address; static int apb_timer_block_enabled; static void __iomem *apbt_virt_address; +static int phy_cs_timer_id; /* * Common DW APB timer info */ -static unsigned long apbt_freq; +static uint64_t apbt_freq; + +static void apbt_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt); +static int apbt_next_event(unsigned long delta, + struct clock_event_device *evt); +static cycle_t apbt_read_clocksource(struct clocksource *cs); +static void apbt_restart_clocksource(struct clocksource *cs); struct apbt_dev { - struct dw_apb_clock_event_device *timer; - unsigned int num; - int cpu; - unsigned int irq; - char name[10]; + struct clock_event_device evt; + unsigned int num; + int cpu; + unsigned int irq; + unsigned int tick; + unsigned int count; + unsigned int flags; + char name[10]; }; -static struct dw_apb_clocksource *clocksource_apbt; - -static inline void __iomem *adev_virt_addr(struct apbt_dev *adev) -{ - return apbt_virt_address + adev->num * APBTMRS_REG_SIZE; -} - static DEFINE_PER_CPU(struct apbt_dev, cpu_apbt_dev); #ifdef CONFIG_SMP static unsigned int apbt_num_timers_used; +static struct apbt_dev *apbt_devs; #endif +static inline unsigned long apbt_readl_reg(unsigned long a) +{ + return readl(apbt_virt_address + a); +} + +static inline void apbt_writel_reg(unsigned long d, unsigned long a) +{ + writel(d, apbt_virt_address + a); +} + +static inline unsigned long apbt_readl(int n, unsigned long a) +{ + return readl(apbt_virt_address + a + n * APBTMRS_REG_SIZE); +} + +static inline void apbt_writel(int n, unsigned long d, unsigned long a) +{ + writel(d, apbt_virt_address + a + n * APBTMRS_REG_SIZE); +} + static inline void apbt_set_mapping(void) { struct sfi_timer_table_entry *mtmr; - int phy_cs_timer_id = 0; if (apbt_virt_address) { pr_debug("APBT base already mapped\n"); @@ -94,18 +125,21 @@ static inline void apbt_set_mapping(void) APBT_CLOCKEVENT0_NUM); return; } - apbt_address = (phys_addr_t)mtmr->phys_addr; + apbt_address = (unsigned long)mtmr->phys_addr; if (!apbt_address) { printk(KERN_WARNING "No timer base from SFI, use default\n"); apbt_address = APBT_DEFAULT_BASE; } apbt_virt_address = ioremap_nocache(apbt_address, APBT_MMAP_SIZE); - if (!apbt_virt_address) { - pr_debug("Failed mapping APBT phy address at %lu\n",\ - (unsigned long)apbt_address); + if (apbt_virt_address) { + pr_debug("Mapped APBT physical addr %p at virtual addr %p\n",\ + (void *)apbt_address, (void *)apbt_virt_address); + } else { + pr_debug("Failed mapping APBT phy address at %p\n",\ + (void *)apbt_address); goto panic_noapbt; } - apbt_freq = mtmr->freq_hz; + apbt_freq = mtmr->freq_hz / USEC_PER_SEC; sfi_free_mtmr(mtmr); /* Now figure out the physical timer id for clocksource device */ @@ -114,14 +148,9 @@ static inline void apbt_set_mapping(void) goto panic_noapbt; /* Now figure out the physical timer id */ - pr_debug("Use timer %d for clocksource\n", - (int)(mtmr->phys_addr & 0xff) / APBTMRS_REG_SIZE); - phy_cs_timer_id = (unsigned int)(mtmr->phys_addr & 0xff) / - APBTMRS_REG_SIZE; - - clocksource_apbt = dw_apb_clocksource_init(APBT_CLOCKSOURCE_RATING, - "apbt0", apbt_virt_address + phy_cs_timer_id * - APBTMRS_REG_SIZE, apbt_freq); + phy_cs_timer_id = (unsigned int)(mtmr->phys_addr & 0xff) + / APBTMRS_REG_SIZE; + pr_debug("Use timer %d for clocksource\n", phy_cs_timer_id); return; panic_noapbt: @@ -143,6 +172,82 @@ static inline int is_apbt_capable(void) return apbt_virt_address ? 1 : 0; } +static struct clocksource clocksource_apbt = { + .name = "apbt", + .rating = APBT_CLOCKSOURCE_RATING, + .read = apbt_read_clocksource, + .mask = APBT_MASK, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, + .resume = apbt_restart_clocksource, +}; + +/* boot APB clock event device */ +static struct clock_event_device apbt_clockevent = { + .name = "apbt0", + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .set_mode = apbt_set_mode, + .set_next_event = apbt_next_event, + .shift = APBT_SHIFT, + .irq = 0, + .rating = APBT_CLOCKEVENT_RATING, +}; + +/* + * start count down from 0xffff_ffff. this is done by toggling the enable bit + * then load initial load count to ~0. + */ +static void apbt_start_counter(int n) +{ + unsigned long ctrl = apbt_readl(n, APBTMR_N_CONTROL); + + ctrl &= ~APBTMR_CONTROL_ENABLE; + apbt_writel(n, ctrl, APBTMR_N_CONTROL); + apbt_writel(n, ~0, APBTMR_N_LOAD_COUNT); + /* enable, mask interrupt */ + ctrl &= ~APBTMR_CONTROL_MODE_PERIODIC; + ctrl |= (APBTMR_CONTROL_ENABLE | APBTMR_CONTROL_INT); + apbt_writel(n, ctrl, APBTMR_N_CONTROL); + /* read it once to get cached counter value initialized */ + apbt_read_clocksource(&clocksource_apbt); +} + +static irqreturn_t apbt_interrupt_handler(int irq, void *data) +{ + struct apbt_dev *dev = (struct apbt_dev *)data; + struct clock_event_device *aevt = &dev->evt; + + if (!aevt->event_handler) { + printk(KERN_INFO "Spurious APBT timer interrupt on %d\n", + dev->num); + return IRQ_NONE; + } + aevt->event_handler(aevt); + return IRQ_HANDLED; +} + +static void apbt_restart_clocksource(struct clocksource *cs) +{ + apbt_start_counter(phy_cs_timer_id); +} + +static void apbt_enable_int(int n) +{ + unsigned long ctrl = apbt_readl(n, APBTMR_N_CONTROL); + /* clear pending intr */ + apbt_readl(n, APBTMR_N_EOI); + ctrl &= ~APBTMR_CONTROL_INT; + apbt_writel(n, ctrl, APBTMR_N_CONTROL); +} + +static void apbt_disable_int(int n) +{ + unsigned long ctrl = apbt_readl(n, APBTMR_N_CONTROL); + + ctrl |= APBTMR_CONTROL_INT; + apbt_writel(n, ctrl, APBTMR_N_CONTROL); +} + + static int __init apbt_clockevent_register(void) { struct sfi_timer_table_entry *mtmr; @@ -155,21 +260,45 @@ static int __init apbt_clockevent_register(void) return -ENODEV; } + /* + * We need to calculate the scaled math multiplication factor for + * nanosecond to apbt tick conversion. + * mult = (nsec/cycle)*2^APBT_SHIFT + */ + apbt_clockevent.mult = div_sc((unsigned long) mtmr->freq_hz + , NSEC_PER_SEC, APBT_SHIFT); + + /* Calculate the min / max delta */ + apbt_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF, + &apbt_clockevent); + apbt_clockevent.min_delta_ns = clockevent_delta2ns( + APBT_MIN_DELTA_USEC*apbt_freq, + &apbt_clockevent); + /* + * Start apbt with the boot cpu mask and make it + * global if not used for per cpu timer. + */ + apbt_clockevent.cpumask = cpumask_of(smp_processor_id()); adev->num = smp_processor_id(); - adev->timer = dw_apb_clockevent_init(smp_processor_id(), "apbt0", - mrst_timer_options == MRST_TIMER_LAPIC_APBT ? - APBT_CLOCKEVENT_RATING - 100 : APBT_CLOCKEVENT_RATING, - adev_virt_addr(adev), 0, apbt_freq); - /* Firmware does EOI handling for us. */ - adev->timer->eoi = NULL; + memcpy(&adev->evt, &apbt_clockevent, sizeof(struct clock_event_device)); if (mrst_timer_options == MRST_TIMER_LAPIC_APBT) { - global_clock_event = &adev->timer->ced; + adev->evt.rating = APBT_CLOCKEVENT_RATING - 100; + global_clock_event = &adev->evt; printk(KERN_DEBUG "%s clockevent registered as global\n", global_clock_event->name); } - dw_apb_clockevent_register(adev->timer); + if (request_irq(apbt_clockevent.irq, apbt_interrupt_handler, + IRQF_TIMER | IRQF_DISABLED | IRQF_NOBALANCING, + apbt_clockevent.name, adev)) { + printk(KERN_ERR "Failed request IRQ for APBT%d\n", + apbt_clockevent.irq); + } + + clockevents_register_device(&adev->evt); + /* Start APBT 0 interrupts */ + apbt_enable_int(APBT_CLOCKEVENT0_NUM); sfi_free_mtmr(mtmr); return 0; @@ -187,34 +316,52 @@ static void apbt_setup_irq(struct apbt_dev *adev) irq_set_affinity(adev->irq, cpumask_of(adev->cpu)); /* APB timer irqs are set up as mp_irqs, timer is edge type */ __irq_set_handler(adev->irq, handle_edge_irq, 0, "edge"); + + if (system_state == SYSTEM_BOOTING) { + if (request_irq(adev->irq, apbt_interrupt_handler, + IRQF_TIMER | IRQF_DISABLED | + IRQF_NOBALANCING, + adev->name, adev)) { + printk(KERN_ERR "Failed request IRQ for APBT%d\n", + adev->num); + } + } else + enable_irq(adev->irq); } /* Should be called with per cpu */ void apbt_setup_secondary_clock(void) { struct apbt_dev *adev; + struct clock_event_device *aevt; int cpu; /* Don't register boot CPU clockevent */ cpu = smp_processor_id(); if (!cpu) return; + /* + * We need to calculate the scaled math multiplication factor for + * nanosecond to apbt tick conversion. + * mult = (nsec/cycle)*2^APBT_SHIFT + */ + printk(KERN_INFO "Init per CPU clockevent %d\n", cpu); + adev = &per_cpu(cpu_apbt_dev, cpu); + aevt = &adev->evt; - adev = &__get_cpu_var(cpu_apbt_dev); - if (!adev->timer) { - adev->timer = dw_apb_clockevent_init(cpu, adev->name, - APBT_CLOCKEVENT_RATING, adev_virt_addr(adev), - adev->irq, apbt_freq); - adev->timer->eoi = NULL; - } else { - dw_apb_clockevent_resume(adev->timer); - } + memcpy(aevt, &apbt_clockevent, sizeof(*aevt)); + aevt->cpumask = cpumask_of(cpu); + aevt->name = adev->name; + aevt->mode = CLOCK_EVT_MODE_UNUSED; - printk(KERN_INFO "Registering CPU %d clockevent device %s, cpu %08x\n", - cpu, adev->name, adev->cpu); + printk(KERN_INFO "Registering CPU %d clockevent device %s, mask %08x\n", + cpu, aevt->name, *(u32 *)aevt->cpumask); apbt_setup_irq(adev); - dw_apb_clockevent_register(adev->timer); + + clockevents_register_device(aevt); + + apbt_enable_int(cpu); return; } @@ -237,12 +384,13 @@ static int apbt_cpuhp_notify(struct notifier_block *n, switch (action & 0xf) { case CPU_DEAD: - dw_apb_clockevent_pause(adev->timer); + disable_irq(adev->irq); + apbt_disable_int(cpu); if (system_state == SYSTEM_RUNNING) { pr_debug("skipping APBT CPU %lu offline\n", cpu); } else if (adev) { pr_debug("APBT clockevent for cpu %lu offline\n", cpu); - dw_apb_clockevent_stop(adev->timer); + free_irq(adev->irq, adev); } break; default: @@ -267,16 +415,116 @@ void apbt_setup_secondary_clock(void) {} #endif /* CONFIG_SMP */ +static void apbt_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + unsigned long ctrl; + uint64_t delta; + int timer_num; + struct apbt_dev *adev = EVT_TO_APBT_DEV(evt); + + BUG_ON(!apbt_virt_address); + + timer_num = adev->num; + pr_debug("%s CPU %d timer %d mode=%d\n", + __func__, first_cpu(*evt->cpumask), timer_num, mode); + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + delta = ((uint64_t)(NSEC_PER_SEC/HZ)) * apbt_clockevent.mult; + delta >>= apbt_clockevent.shift; + ctrl = apbt_readl(timer_num, APBTMR_N_CONTROL); + ctrl |= APBTMR_CONTROL_MODE_PERIODIC; + apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); + /* + * DW APB p. 46, have to disable timer before load counter, + * may cause sync problem. + */ + ctrl &= ~APBTMR_CONTROL_ENABLE; + apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); + udelay(1); + pr_debug("Setting clock period %d for HZ %d\n", (int)delta, HZ); + apbt_writel(timer_num, delta, APBTMR_N_LOAD_COUNT); + ctrl |= APBTMR_CONTROL_ENABLE; + apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); + break; + /* APB timer does not have one-shot mode, use free running mode */ + case CLOCK_EVT_MODE_ONESHOT: + ctrl = apbt_readl(timer_num, APBTMR_N_CONTROL); + /* + * set free running mode, this mode will let timer reload max + * timeout which will give time (3min on 25MHz clock) to rearm + * the next event, therefore emulate the one-shot mode. + */ + ctrl &= ~APBTMR_CONTROL_ENABLE; + ctrl &= ~APBTMR_CONTROL_MODE_PERIODIC; + + apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); + /* write again to set free running mode */ + apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); + + /* + * DW APB p. 46, load counter with all 1s before starting free + * running mode. + */ + apbt_writel(timer_num, ~0, APBTMR_N_LOAD_COUNT); + ctrl &= ~APBTMR_CONTROL_INT; + ctrl |= APBTMR_CONTROL_ENABLE; + apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); + break; + + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + apbt_disable_int(timer_num); + ctrl = apbt_readl(timer_num, APBTMR_N_CONTROL); + ctrl &= ~APBTMR_CONTROL_ENABLE; + apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); + break; + + case CLOCK_EVT_MODE_RESUME: + apbt_enable_int(timer_num); + break; + } +} + +static int apbt_next_event(unsigned long delta, + struct clock_event_device *evt) +{ + unsigned long ctrl; + int timer_num; + + struct apbt_dev *adev = EVT_TO_APBT_DEV(evt); + + timer_num = adev->num; + /* Disable timer */ + ctrl = apbt_readl(timer_num, APBTMR_N_CONTROL); + ctrl &= ~APBTMR_CONTROL_ENABLE; + apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); + /* write new count */ + apbt_writel(timer_num, delta, APBTMR_N_LOAD_COUNT); + ctrl |= APBTMR_CONTROL_ENABLE; + apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); + return 0; +} + +static cycle_t apbt_read_clocksource(struct clocksource *cs) +{ + unsigned long current_count; + + current_count = apbt_readl(phy_cs_timer_id, APBTMR_N_CURRENT_VALUE); + return (cycle_t)~current_count; +} + static int apbt_clocksource_register(void) { u64 start, now; cycle_t t1; /* Start the counter, use timer 2 as source, timer 0/1 for event */ - dw_apb_clocksource_start(clocksource_apbt); + apbt_start_counter(phy_cs_timer_id); /* Verify whether apbt counter works */ - t1 = dw_apb_clocksource_read(clocksource_apbt); + t1 = apbt_read_clocksource(&clocksource_apbt); rdtscll(start); /* @@ -291,10 +539,10 @@ static int apbt_clocksource_register(void) } while ((now - start) < 200000UL); /* APBT is the only always on clocksource, it has to work! */ - if (t1 == dw_apb_clocksource_read(clocksource_apbt)) + if (t1 == apbt_read_clocksource(&clocksource_apbt)) panic("APBT counter not counting. APBT disabled\n"); - dw_apb_clocksource_register(clocksource_apbt); + clocksource_register_khz(&clocksource_apbt, (u32)apbt_freq*1000); return 0; } @@ -318,7 +566,10 @@ void __init apbt_time_init(void) if (apb_timer_block_enabled) return; apbt_set_mapping(); - if (!apbt_virt_address) + if (apbt_virt_address) { + pr_debug("Found APBT version 0x%lx\n",\ + apbt_readl_reg(APBTMRS_COMP_VERSION)); + } else goto out_noapbt; /* * Read the frequency and check for a sane value, for ESL model @@ -326,7 +577,7 @@ void __init apbt_time_init(void) */ if (apbt_freq < APBT_MIN_FREQ || apbt_freq > APBT_MAX_FREQ) { - pr_debug("APBT has invalid freq 0x%lx\n", apbt_freq); + pr_debug("APBT has invalid freq 0x%llx\n", apbt_freq); goto out_noapbt; } if (apbt_clocksource_register()) { @@ -352,20 +603,30 @@ void __init apbt_time_init(void) } else { percpu_timer = 0; apbt_num_timers_used = 1; + adev = &per_cpu(cpu_apbt_dev, 0); + adev->flags &= ~APBT_DEV_USED; } pr_debug("%s: %d APB timers used\n", __func__, apbt_num_timers_used); /* here we set up per CPU timer data structure */ + apbt_devs = kzalloc(sizeof(struct apbt_dev) * apbt_num_timers_used, + GFP_KERNEL); + if (!apbt_devs) { + printk(KERN_ERR "Failed to allocate APB timer devices\n"); + return; + } for (i = 0; i < apbt_num_timers_used; i++) { adev = &per_cpu(cpu_apbt_dev, i); adev->num = i; adev->cpu = i; p_mtmr = sfi_get_mtmr(i); - if (p_mtmr) + if (p_mtmr) { + adev->tick = p_mtmr->freq_hz; adev->irq = p_mtmr->irq; - else + } else printk(KERN_ERR "Failed to get timer for cpu %d\n", i); - snprintf(adev->name, sizeof(adev->name) - 1, "apbt%d", i); + adev->count = 0; + sprintf(adev->name, "apbt%d", i); } #endif @@ -377,8 +638,17 @@ void __init apbt_time_init(void) panic("failed to enable APB timer\n"); } +static inline void apbt_disable(int n) +{ + if (is_apbt_capable()) { + unsigned long ctrl = apbt_readl(n, APBTMR_N_CONTROL); + ctrl &= ~APBTMR_CONTROL_ENABLE; + apbt_writel(n, ctrl, APBTMR_N_CONTROL); + } +} + /* called before apb_timer_enable, use early map */ -unsigned long apbt_quick_calibrate(void) +unsigned long apbt_quick_calibrate() { int i, scale; u64 old, new; @@ -387,31 +657,31 @@ unsigned long apbt_quick_calibrate(void) u32 loop, shift; apbt_set_mapping(); - dw_apb_clocksource_start(clocksource_apbt); + apbt_start_counter(phy_cs_timer_id); /* check if the timer can count down, otherwise return */ - old = dw_apb_clocksource_read(clocksource_apbt); + old = apbt_read_clocksource(&clocksource_apbt); i = 10000; while (--i) { - if (old != dw_apb_clocksource_read(clocksource_apbt)) + if (old != apbt_read_clocksource(&clocksource_apbt)) break; } if (!i) goto failed; /* count 16 ms */ - loop = (apbt_freq / 1000) << 4; + loop = (apbt_freq * 1000) << 4; /* restart the timer to ensure it won't get to 0 in the calibration */ - dw_apb_clocksource_start(clocksource_apbt); + apbt_start_counter(phy_cs_timer_id); - old = dw_apb_clocksource_read(clocksource_apbt); + old = apbt_read_clocksource(&clocksource_apbt); old += loop; t1 = __native_read_tsc(); do { - new = dw_apb_clocksource_read(clocksource_apbt); + new = apbt_read_clocksource(&clocksource_apbt); } while (new < old); t2 = __native_read_tsc(); @@ -423,7 +693,7 @@ unsigned long apbt_quick_calibrate(void) return 0; } scale = (int)div_u64((t2 - t1), loop >> shift); - khz = (scale * (apbt_freq / 1000)) >> shift; + khz = (scale * apbt_freq * 1000) >> shift; printk(KERN_INFO "TSC freq calculated by APB timer is %lu khz\n", khz); return khz; failed: diff --git a/trunk/arch/x86/kernel/apic/apic.c b/trunk/arch/x86/kernel/apic/apic.c index b24be38c8cf8..b9338b8cf420 100644 --- a/trunk/arch/x86/kernel/apic/apic.c +++ b/trunk/arch/x86/kernel/apic/apic.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -40,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -48,7 +48,6 @@ #include #include #include -#include #include #include #include @@ -1430,7 +1429,7 @@ void enable_x2apic(void) rdmsr(MSR_IA32_APICBASE, msr, msr2); if (!(msr & X2APIC_ENABLE)) { printk_once(KERN_INFO "Enabling x2apic\n"); - wrmsr(MSR_IA32_APICBASE, msr | X2APIC_ENABLE, msr2); + wrmsr(MSR_IA32_APICBASE, msr | X2APIC_ENABLE, 0); } } #endif /* CONFIG_X86_X2APIC */ @@ -1944,28 +1943,10 @@ void disconnect_bsp_APIC(int virt_wire_setup) void __cpuinit generic_processor_info(int apicid, int version) { - int cpu, max = nr_cpu_ids; - bool boot_cpu_detected = physid_isset(boot_cpu_physical_apicid, - phys_cpu_present_map); - - /* - * If boot cpu has not been detected yet, then only allow upto - * nr_cpu_ids - 1 processors and keep one slot free for boot cpu - */ - if (!boot_cpu_detected && num_processors >= nr_cpu_ids - 1 && - apicid != boot_cpu_physical_apicid) { - int thiscpu = max + disabled_cpus - 1; - - pr_warning( - "ACPI: NR_CPUS/possible_cpus limit of %i almost" - " reached. Keeping one slot for boot cpu." - " Processor %d/0x%x ignored.\n", max, thiscpu, apicid); - - disabled_cpus++; - return; - } + int cpu; if (num_processors >= nr_cpu_ids) { + int max = nr_cpu_ids; int thiscpu = max + disabled_cpus; pr_warning( diff --git a/trunk/arch/x86/kernel/apic/io_apic.c b/trunk/arch/x86/kernel/apic/io_apic.c index 8eb863e27ea6..e5293394b548 100644 --- a/trunk/arch/x86/kernel/apic/io_apic.c +++ b/trunk/arch/x86/kernel/apic/io_apic.c @@ -1295,16 +1295,6 @@ static int setup_ioapic_entry(int apic_id, int irq, * irq handler will do the explicit EOI to the io-apic. */ ir_entry->vector = pin; - - apic_printk(APIC_VERBOSE, KERN_DEBUG "IOAPIC[%d]: " - "Set IRTE entry (P:%d FPD:%d Dst_Mode:%d " - "Redir_hint:%d Trig_Mode:%d Dlvry_Mode:%X " - "Avail:%X Vector:%02X Dest:%08X " - "SID:%04X SQ:%X SVT:%X)\n", - apic_id, irte.present, irte.fpd, irte.dst_mode, - irte.redir_hint, irte.trigger_mode, irte.dlvry_mode, - irte.avail, irte.vector, irte.dest_id, - irte.sid, irte.sq, irte.svt); } else { entry->delivery_mode = apic->irq_delivery_mode; entry->dest_mode = apic->irq_dest_mode; @@ -1347,9 +1337,9 @@ static void setup_ioapic_irq(int apic_id, int pin, unsigned int irq, apic_printk(APIC_VERBOSE,KERN_DEBUG "IOAPIC[%d]: Set routing entry (%d-%d -> 0x%x -> " - "IRQ %d Mode:%i Active:%i Dest:%d)\n", + "IRQ %d Mode:%i Active:%i)\n", apic_id, mpc_ioapic_id(apic_id), pin, cfg->vector, - irq, trigger, polarity, dest); + irq, trigger, polarity); if (setup_ioapic_entry(mpc_ioapic_id(apic_id), irq, &entry, @@ -1532,12 +1522,10 @@ __apicdebuginit(void) print_IO_APIC(void) printk(KERN_DEBUG "....... : LTS : %X\n", reg_00.bits.LTS); printk(KERN_DEBUG ".... register #01: %08X\n", *(int *)®_01); - printk(KERN_DEBUG "....... : max redirection entries: %02X\n", - reg_01.bits.entries); + printk(KERN_DEBUG "....... : max redirection entries: %04X\n", reg_01.bits.entries); printk(KERN_DEBUG "....... : PRQ implemented: %X\n", reg_01.bits.PRQ); - printk(KERN_DEBUG "....... : IO APIC version: %02X\n", - reg_01.bits.version); + printk(KERN_DEBUG "....... : IO APIC version: %04X\n", reg_01.bits.version); /* * Some Intel chipsets with IO APIC VERSION of 0x1? don't have reg_02, @@ -1562,60 +1550,31 @@ __apicdebuginit(void) print_IO_APIC(void) printk(KERN_DEBUG ".... IRQ redirection table:\n"); - if (intr_remapping_enabled) { - printk(KERN_DEBUG " NR Indx Fmt Mask Trig IRR" - " Pol Stat Indx2 Zero Vect:\n"); - } else { - printk(KERN_DEBUG " NR Dst Mask Trig IRR Pol" - " Stat Dmod Deli Vect:\n"); - } + printk(KERN_DEBUG " NR Dst Mask Trig IRR Pol" + " Stat Dmod Deli Vect:\n"); for (i = 0; i <= reg_01.bits.entries; i++) { - if (intr_remapping_enabled) { - struct IO_APIC_route_entry entry; - struct IR_IO_APIC_route_entry *ir_entry; - - entry = ioapic_read_entry(apic, i); - ir_entry = (struct IR_IO_APIC_route_entry *) &entry; - printk(KERN_DEBUG " %02x %04X ", - i, - ir_entry->index - ); - printk("%1d %1d %1d %1d %1d " - "%1d %1d %X %02X\n", - ir_entry->format, - ir_entry->mask, - ir_entry->trigger, - ir_entry->irr, - ir_entry->polarity, - ir_entry->delivery_status, - ir_entry->index2, - ir_entry->zero, - ir_entry->vector - ); - } else { - struct IO_APIC_route_entry entry; + struct IO_APIC_route_entry entry; - entry = ioapic_read_entry(apic, i); - printk(KERN_DEBUG " %02x %02X ", - i, - entry.dest - ); - printk("%1d %1d %1d %1d %1d " - "%1d %1d %02X\n", - entry.mask, - entry.trigger, - entry.irr, - entry.polarity, - entry.delivery_status, - entry.dest_mode, - entry.delivery_mode, - entry.vector - ); - } + entry = ioapic_read_entry(apic, i); + + printk(KERN_DEBUG " %02x %03X ", + i, + entry.dest + ); + + printk("%1d %1d %1d %1d %1d %1d %1d %02X\n", + entry.mask, + entry.trigger, + entry.irr, + entry.polarity, + entry.delivery_status, + entry.dest_mode, + entry.delivery_mode, + entry.vector + ); } } - printk(KERN_DEBUG "IRQ to pin mappings:\n"); for_each_active_irq(irq) { struct irq_pin_list *entry; @@ -1833,7 +1792,7 @@ __apicdebuginit(int) print_ICs(void) return 0; } -late_initcall(print_ICs); +fs_initcall(print_ICs); /* Where if anywhere is the i8259 connect in external int mode */ diff --git a/trunk/arch/x86/kernel/apm_32.c b/trunk/arch/x86/kernel/apm_32.c index 0371c484bb8a..965a7666c283 100644 --- a/trunk/arch/x86/kernel/apm_32.c +++ b/trunk/arch/x86/kernel/apm_32.c @@ -229,11 +229,11 @@ #include #include #include -#include #include #include #include +#include #include #include #include @@ -1220,11 +1220,11 @@ static void reinit_timer(void) raw_spin_lock_irqsave(&i8253_lock, flags); /* set the clock to HZ */ - outb_p(0x34, PIT_MODE); /* binary, mode 2, LSB/MSB, ch 0 */ + outb_pit(0x34, PIT_MODE); /* binary, mode 2, LSB/MSB, ch 0 */ udelay(10); - outb_p(LATCH & 0xff, PIT_CH0); /* LSB */ + outb_pit(LATCH & 0xff, PIT_CH0); /* LSB */ udelay(10); - outb_p(LATCH >> 8, PIT_CH0); /* MSB */ + outb_pit(LATCH >> 8, PIT_CH0); /* MSB */ udelay(10); raw_spin_unlock_irqrestore(&i8253_lock, flags); #endif diff --git a/trunk/arch/x86/kernel/cpu/bugs.c b/trunk/arch/x86/kernel/cpu/bugs.c index 46674fbb62ba..525514cf33c3 100644 --- a/trunk/arch/x86/kernel/cpu/bugs.c +++ b/trunk/arch/x86/kernel/cpu/bugs.c @@ -62,8 +62,6 @@ static void __init check_fpu(void) return; } - kernel_fpu_begin(); - /* * trap_init() enabled FXSR and company _before_ testing for FP * problems here. @@ -82,8 +80,6 @@ static void __init check_fpu(void) : "=m" (*&fdiv_bug) : "m" (*&x), "m" (*&y)); - kernel_fpu_end(); - boot_cpu_data.fdiv_bug = fdiv_bug; if (boot_cpu_data.fdiv_bug) printk(KERN_WARNING "Hmm, FPU with FDIV bug.\n"); diff --git a/trunk/arch/x86/kernel/cpu/hypervisor.c b/trunk/arch/x86/kernel/cpu/hypervisor.c index 755f64fb0743..8095f8611f8a 100644 --- a/trunk/arch/x86/kernel/cpu/hypervisor.c +++ b/trunk/arch/x86/kernel/cpu/hypervisor.c @@ -32,11 +32,11 @@ */ static const __initconst struct hypervisor_x86 * const hypervisors[] = { + &x86_hyper_vmware, + &x86_hyper_ms_hyperv, #ifdef CONFIG_XEN_PVHVM &x86_hyper_xen_hvm, #endif - &x86_hyper_vmware, - &x86_hyper_ms_hyperv, }; const struct hypervisor_x86 *x86_hyper; diff --git a/trunk/arch/x86/kernel/cpu/intel.c b/trunk/arch/x86/kernel/cpu/intel.c index ed6086eedf1d..1edf5ba4fb2b 100644 --- a/trunk/arch/x86/kernel/cpu/intel.c +++ b/trunk/arch/x86/kernel/cpu/intel.c @@ -456,24 +456,6 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c) if (cpu_has(c, X86_FEATURE_VMX)) detect_vmx_virtcap(c); - - /* - * Initialize MSR_IA32_ENERGY_PERF_BIAS if BIOS did not. - * x86_energy_perf_policy(8) is available to change it at run-time - */ - if (cpu_has(c, X86_FEATURE_EPB)) { - u64 epb; - - rdmsrl(MSR_IA32_ENERGY_PERF_BIAS, epb); - if ((epb & 0xF) == ENERGY_PERF_BIAS_PERFORMANCE) { - printk_once(KERN_WARNING "ENERGY_PERF_BIAS:" - " Set to 'normal', was 'performance'\n" - "ENERGY_PERF_BIAS: View and update with" - " x86_energy_perf_policy(8)\n"); - epb = (epb & ~0xF) | ENERGY_PERF_BIAS_NORMAL; - wrmsrl(MSR_IA32_ENERGY_PERF_BIAS, epb); - } - } } #ifdef CONFIG_X86_32 diff --git a/trunk/arch/x86/kernel/cpu/mcheck/mce-severity.c b/trunk/arch/x86/kernel/cpu/mcheck/mce-severity.c index 7395d5f4272d..1e8d66c1336a 100644 --- a/trunk/arch/x86/kernel/cpu/mcheck/mce-severity.c +++ b/trunk/arch/x86/kernel/cpu/mcheck/mce-severity.c @@ -43,105 +43,61 @@ static struct severity { unsigned char covered; char *msg; } severities[] = { -#define MCESEV(s, m, c...) { .sev = MCE_ ## s ## _SEVERITY, .msg = m, ## c } -#define KERNEL .context = IN_KERNEL -#define USER .context = IN_USER -#define SER .ser = SER_REQUIRED -#define NOSER .ser = NO_SER -#define BITCLR(x) .mask = x, .result = 0 -#define BITSET(x) .mask = x, .result = x -#define MCGMASK(x, y) .mcgmask = x, .mcgres = y -#define MASK(x, y) .mask = x, .result = y +#define KERNEL .context = IN_KERNEL +#define USER .context = IN_USER +#define SER .ser = SER_REQUIRED +#define NOSER .ser = NO_SER +#define SEV(s) .sev = MCE_ ## s ## _SEVERITY +#define BITCLR(x, s, m, r...) { .mask = x, .result = 0, SEV(s), .msg = m, ## r } +#define BITSET(x, s, m, r...) { .mask = x, .result = x, SEV(s), .msg = m, ## r } +#define MCGMASK(x, res, s, m, r...) \ + { .mcgmask = x, .mcgres = res, SEV(s), .msg = m, ## r } +#define MASK(x, y, s, m, r...) \ + { .mask = x, .result = y, SEV(s), .msg = m, ## r } #define MCI_UC_S (MCI_STATUS_UC|MCI_STATUS_S) #define MCI_UC_SAR (MCI_STATUS_UC|MCI_STATUS_S|MCI_STATUS_AR) #define MCACOD 0xffff - MCESEV( - NO, "Invalid", - BITCLR(MCI_STATUS_VAL) - ), - MCESEV( - NO, "Not enabled", - BITCLR(MCI_STATUS_EN) - ), - MCESEV( - PANIC, "Processor context corrupt", - BITSET(MCI_STATUS_PCC) - ), + BITCLR(MCI_STATUS_VAL, NO, "Invalid"), + BITCLR(MCI_STATUS_EN, NO, "Not enabled"), + BITSET(MCI_STATUS_PCC, PANIC, "Processor context corrupt"), /* When MCIP is not set something is very confused */ - MCESEV( - PANIC, "MCIP not set in MCA handler", - MCGMASK(MCG_STATUS_MCIP, 0) - ), + MCGMASK(MCG_STATUS_MCIP, 0, PANIC, "MCIP not set in MCA handler"), /* Neither return not error IP -- no chance to recover -> PANIC */ - MCESEV( - PANIC, "Neither restart nor error IP", - MCGMASK(MCG_STATUS_RIPV|MCG_STATUS_EIPV, 0) - ), - MCESEV( - PANIC, "In kernel and no restart IP", - KERNEL, MCGMASK(MCG_STATUS_RIPV, 0) - ), - MCESEV( - KEEP, "Corrected error", - NOSER, BITCLR(MCI_STATUS_UC) - ), + MCGMASK(MCG_STATUS_RIPV|MCG_STATUS_EIPV, 0, PANIC, + "Neither restart nor error IP"), + MCGMASK(MCG_STATUS_RIPV, 0, PANIC, "In kernel and no restart IP", + KERNEL), + BITCLR(MCI_STATUS_UC, KEEP, "Corrected error", NOSER), + MASK(MCI_STATUS_OVER|MCI_STATUS_UC|MCI_STATUS_EN, MCI_STATUS_UC, SOME, + "Spurious not enabled", SER), /* ignore OVER for UCNA */ - MCESEV( - KEEP, "Uncorrected no action required", - SER, MASK(MCI_UC_SAR, MCI_STATUS_UC) - ), - MCESEV( - PANIC, "Illegal combination (UCNA with AR=1)", - SER, - MASK(MCI_STATUS_OVER|MCI_UC_SAR, MCI_STATUS_UC|MCI_STATUS_AR) - ), - MCESEV( - KEEP, "Non signalled machine check", - SER, BITCLR(MCI_STATUS_S) - ), + MASK(MCI_UC_SAR, MCI_STATUS_UC, KEEP, + "Uncorrected no action required", SER), + MASK(MCI_STATUS_OVER|MCI_UC_SAR, MCI_STATUS_UC|MCI_STATUS_AR, PANIC, + "Illegal combination (UCNA with AR=1)", SER), + MASK(MCI_STATUS_S, 0, KEEP, "Non signalled machine check", SER), /* AR add known MCACODs here */ - MCESEV( - PANIC, "Action required with lost events", - SER, BITSET(MCI_STATUS_OVER|MCI_UC_SAR) - ), - MCESEV( - PANIC, "Action required: unknown MCACOD", - SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR, MCI_UC_SAR) - ), + MASK(MCI_STATUS_OVER|MCI_UC_SAR, MCI_STATUS_OVER|MCI_UC_SAR, PANIC, + "Action required with lost events", SER), + MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCACOD, MCI_UC_SAR, PANIC, + "Action required; unknown MCACOD", SER), /* known AO MCACODs: */ - MCESEV( - AO, "Action optional: memory scrubbing error", - SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|0xfff0, MCI_UC_S|0x00c0) - ), - MCESEV( - AO, "Action optional: last level cache writeback error", - SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCACOD, MCI_UC_S|0x017a) - ), - MCESEV( - SOME, "Action optional: unknown MCACOD", - SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR, MCI_UC_S) - ), - MCESEV( - SOME, "Action optional with lost events", - SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR, MCI_STATUS_OVER|MCI_UC_S) - ), - - MCESEV( - PANIC, "Overflowed uncorrected", - BITSET(MCI_STATUS_OVER|MCI_STATUS_UC) - ), - MCESEV( - UC, "Uncorrected", - BITSET(MCI_STATUS_UC) - ), - MCESEV( - SOME, "No match", - BITSET(0) - ) /* always matches. keep at end */ + MASK(MCI_UC_SAR|MCI_STATUS_OVER|0xfff0, MCI_UC_S|0xc0, AO, + "Action optional: memory scrubbing error", SER), + MASK(MCI_UC_SAR|MCI_STATUS_OVER|MCACOD, MCI_UC_S|0x17a, AO, + "Action optional: last level cache writeback error", SER), + + MASK(MCI_STATUS_OVER|MCI_UC_SAR, MCI_UC_S, SOME, + "Action optional unknown MCACOD", SER), + MASK(MCI_STATUS_OVER|MCI_UC_SAR, MCI_UC_S|MCI_STATUS_OVER, SOME, + "Action optional with lost events", SER), + BITSET(MCI_STATUS_UC|MCI_STATUS_OVER, PANIC, "Overflowed uncorrected"), + BITSET(MCI_STATUS_UC, UC, "Uncorrected"), + BITSET(0, SOME, "No match") /* always matches. keep at end */ }; /* @@ -156,15 +112,15 @@ static int error_context(struct mce *m) return IN_KERNEL; } -int mce_severity(struct mce *m, int tolerant, char **msg) +int mce_severity(struct mce *a, int tolerant, char **msg) { - enum context ctx = error_context(m); + enum context ctx = error_context(a); struct severity *s; for (s = severities;; s++) { - if ((m->status & s->mask) != s->result) + if ((a->status & s->mask) != s->result) continue; - if ((m->mcgstatus & s->mcgmask) != s->mcgres) + if ((a->mcgstatus & s->mcgmask) != s->mcgres) continue; if (s->ser == SER_REQUIRED && !mce_ser) continue; @@ -241,15 +197,15 @@ static const struct file_operations severities_coverage_fops = { static int __init severities_debugfs_init(void) { - struct dentry *dmce, *fsev; + struct dentry *dmce = NULL, *fseverities_coverage = NULL; dmce = mce_get_debugfs_dir(); - if (!dmce) + if (dmce == NULL) goto err_out; - - fsev = debugfs_create_file("severities-coverage", 0444, dmce, NULL, - &severities_coverage_fops); - if (!fsev) + fseverities_coverage = debugfs_create_file("severities-coverage", + 0444, dmce, NULL, + &severities_coverage_fops); + if (fseverities_coverage == NULL) goto err_out; return 0; @@ -258,4 +214,4 @@ static int __init severities_debugfs_init(void) return -ENOMEM; } late_initcall(severities_debugfs_init); -#endif /* CONFIG_DEBUG_FS */ +#endif diff --git a/trunk/arch/x86/kernel/cpu/mcheck/mce.c b/trunk/arch/x86/kernel/cpu/mcheck/mce.c index 08363b042122..ff1ae9b6464d 100644 --- a/trunk/arch/x86/kernel/cpu/mcheck/mce.c +++ b/trunk/arch/x86/kernel/cpu/mcheck/mce.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -37,20 +38,23 @@ #include #include #include -#include #include +#include +#include +#include +#include #include #include #include "mce-internal.h" -static DEFINE_MUTEX(mce_chrdev_read_mutex); +static DEFINE_MUTEX(mce_read_mutex); #define rcu_dereference_check_mce(p) \ rcu_dereference_index_check((p), \ rcu_read_lock_sched_held() || \ - lockdep_is_held(&mce_chrdev_read_mutex)) + lockdep_is_held(&mce_read_mutex)) #define CREATE_TRACE_POINTS #include @@ -90,8 +94,7 @@ static unsigned long mce_need_notify; static char mce_helper[128]; static char *mce_helper_argv[2] = { mce_helper, NULL }; -static DECLARE_WAIT_QUEUE_HEAD(mce_chrdev_wait); - +static DECLARE_WAIT_QUEUE_HEAD(mce_wait); static DEFINE_PER_CPU(struct mce, mces_seen); static int cpu_missing; @@ -369,31 +372,6 @@ static void mce_wrmsrl(u32 msr, u64 v) wrmsrl(msr, v); } -/* - * Collect all global (w.r.t. this processor) status about this machine - * check into our "mce" struct so that we can use it later to assess - * the severity of the problem as we read per-bank specific details. - */ -static inline void mce_gather_info(struct mce *m, struct pt_regs *regs) -{ - mce_setup(m); - - m->mcgstatus = mce_rdmsrl(MSR_IA32_MCG_STATUS); - if (regs) { - /* - * Get the address of the instruction at the time of - * the machine check error. - */ - if (m->mcgstatus & (MCG_STATUS_RIPV|MCG_STATUS_EIPV)) { - m->ip = regs->ip; - m->cs = regs->cs; - } - /* Use accurate RIP reporting if available. */ - if (rip_msr) - m->ip = mce_rdmsrl(rip_msr); - } -} - /* * Simple lockless ring to communicate PFNs from the exception handler with the * process context work function. This is vastly simplified because there's @@ -465,13 +443,40 @@ static void mce_schedule_work(void) } } -DEFINE_PER_CPU(struct irq_work, mce_irq_work); +/* + * Get the address of the instruction at the time of the machine check + * error. + */ +static inline void mce_get_rip(struct mce *m, struct pt_regs *regs) +{ + + if (regs && (m->mcgstatus & (MCG_STATUS_RIPV|MCG_STATUS_EIPV))) { + m->ip = regs->ip; + m->cs = regs->cs; + } else { + m->ip = 0; + m->cs = 0; + } + if (rip_msr) + m->ip = mce_rdmsrl(rip_msr); +} -static void mce_irq_work_cb(struct irq_work *entry) +#ifdef CONFIG_X86_LOCAL_APIC +/* + * Called after interrupts have been reenabled again + * when a MCE happened during an interrupts off region + * in the kernel. + */ +asmlinkage void smp_mce_self_interrupt(struct pt_regs *regs) { + ack_APIC_irq(); + exit_idle(); + irq_enter(); mce_notify_irq(); mce_schedule_work(); + irq_exit(); } +#endif static void mce_report_event(struct pt_regs *regs) { @@ -487,7 +492,29 @@ static void mce_report_event(struct pt_regs *regs) return; } - irq_work_queue(&__get_cpu_var(mce_irq_work)); +#ifdef CONFIG_X86_LOCAL_APIC + /* + * Without APIC do not notify. The event will be picked + * up eventually. + */ + if (!cpu_has_apic) + return; + + /* + * When interrupts are disabled we cannot use + * kernel services safely. Trigger an self interrupt + * through the APIC to instead do the notification + * after interrupts are reenabled again. + */ + apic->send_IPI_self(MCE_SELF_VECTOR); + + /* + * Wait for idle afterwards again so that we don't leave the + * APIC in a non idle state because the normal APIC writes + * cannot exclude us. + */ + apic_wait_icr_idle(); +#endif } DEFINE_PER_CPU(unsigned, mce_poll_count); @@ -514,8 +541,9 @@ void machine_check_poll(enum mcp_flags flags, mce_banks_t *b) percpu_inc(mce_poll_count); - mce_gather_info(&m, NULL); + mce_setup(&m); + m.mcgstatus = mce_rdmsrl(MSR_IA32_MCG_STATUS); for (i = 0; i < banks; i++) { if (!mce_banks[i].ctl || !test_bit(i, *b)) continue; @@ -851,9 +879,9 @@ static int mce_usable_address(struct mce *m) { if (!(m->status & MCI_STATUS_MISCV) || !(m->status & MCI_STATUS_ADDRV)) return 0; - if (MCI_MISC_ADDR_LSB(m->misc) > PAGE_SHIFT) + if ((m->misc & 0x3f) > PAGE_SHIFT) return 0; - if (MCI_MISC_ADDR_MODE(m->misc) != MCI_MISC_ADDR_PHYS) + if (((m->misc >> 6) & 7) != MCM_ADDR_PHYS) return 0; return 1; } @@ -914,8 +942,9 @@ void do_machine_check(struct pt_regs *regs, long error_code) if (!banks) goto out; - mce_gather_info(&m, regs); + mce_setup(&m); + m.mcgstatus = mce_rdmsrl(MSR_IA32_MCG_STATUS); final = &__get_cpu_var(mces_seen); *final = m; @@ -999,6 +1028,7 @@ void do_machine_check(struct pt_regs *regs, long error_code) if (severity == MCE_AO_SEVERITY && mce_usable_address(&m)) mce_ring_add(m.addr >> PAGE_SHIFT); + mce_get_rip(&m, regs); mce_log(&m); if (severity > worst) { @@ -1160,8 +1190,7 @@ int mce_notify_irq(void) clear_thread_flag(TIF_MCE_NOTIFY); if (test_and_clear_bit(0, &mce_need_notify)) { - /* wake processes polling /dev/mcelog */ - wake_up_interruptible(&mce_chrdev_wait); + wake_up_interruptible(&mce_wait); /* * There is no risk of missing notifications because @@ -1334,23 +1363,18 @@ static int __cpuinit __mcheck_cpu_apply_quirks(struct cpuinfo_x86 *c) return 0; } -static int __cpuinit __mcheck_cpu_ancient_init(struct cpuinfo_x86 *c) +static void __cpuinit __mcheck_cpu_ancient_init(struct cpuinfo_x86 *c) { if (c->x86 != 5) - return 0; - + return; switch (c->x86_vendor) { case X86_VENDOR_INTEL: intel_p5_mcheck_init(c); - return 1; break; case X86_VENDOR_CENTAUR: winchip_mcheck_init(c); - return 1; break; } - - return 0; } static void __mcheck_cpu_init_vendor(struct cpuinfo_x86 *c) @@ -1404,8 +1428,7 @@ void __cpuinit mcheck_cpu_init(struct cpuinfo_x86 *c) if (mce_disabled) return; - if (__mcheck_cpu_ancient_init(c)) - return; + __mcheck_cpu_ancient_init(c); if (!mce_available(c)) return; @@ -1421,45 +1444,44 @@ void __cpuinit mcheck_cpu_init(struct cpuinfo_x86 *c) __mcheck_cpu_init_vendor(c); __mcheck_cpu_init_timer(); INIT_WORK(&__get_cpu_var(mce_work), mce_process_work); - init_irq_work(&__get_cpu_var(mce_irq_work), &mce_irq_work_cb); + } /* - * mce_chrdev: Character device /dev/mcelog to read and clear the MCE log. + * Character device to read and clear the MCE log. */ -static DEFINE_SPINLOCK(mce_chrdev_state_lock); -static int mce_chrdev_open_count; /* #times opened */ -static int mce_chrdev_open_exclu; /* already open exclusive? */ +static DEFINE_SPINLOCK(mce_state_lock); +static int open_count; /* #times opened */ +static int open_exclu; /* already open exclusive? */ -static int mce_chrdev_open(struct inode *inode, struct file *file) +static int mce_open(struct inode *inode, struct file *file) { - spin_lock(&mce_chrdev_state_lock); + spin_lock(&mce_state_lock); - if (mce_chrdev_open_exclu || - (mce_chrdev_open_count && (file->f_flags & O_EXCL))) { - spin_unlock(&mce_chrdev_state_lock); + if (open_exclu || (open_count && (file->f_flags & O_EXCL))) { + spin_unlock(&mce_state_lock); return -EBUSY; } if (file->f_flags & O_EXCL) - mce_chrdev_open_exclu = 1; - mce_chrdev_open_count++; + open_exclu = 1; + open_count++; - spin_unlock(&mce_chrdev_state_lock); + spin_unlock(&mce_state_lock); return nonseekable_open(inode, file); } -static int mce_chrdev_release(struct inode *inode, struct file *file) +static int mce_release(struct inode *inode, struct file *file) { - spin_lock(&mce_chrdev_state_lock); + spin_lock(&mce_state_lock); - mce_chrdev_open_count--; - mce_chrdev_open_exclu = 0; + open_count--; + open_exclu = 0; - spin_unlock(&mce_chrdev_state_lock); + spin_unlock(&mce_state_lock); return 0; } @@ -1508,8 +1530,8 @@ static int __mce_read_apei(char __user **ubuf, size_t usize) return 0; } -static ssize_t mce_chrdev_read(struct file *filp, char __user *ubuf, - size_t usize, loff_t *off) +static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize, + loff_t *off) { char __user *buf = ubuf; unsigned long *cpu_tsc; @@ -1520,7 +1542,7 @@ static ssize_t mce_chrdev_read(struct file *filp, char __user *ubuf, if (!cpu_tsc) return -ENOMEM; - mutex_lock(&mce_chrdev_read_mutex); + mutex_lock(&mce_read_mutex); if (!mce_apei_read_done) { err = __mce_read_apei(&buf, usize); @@ -1540,18 +1562,19 @@ static ssize_t mce_chrdev_read(struct file *filp, char __user *ubuf, do { for (i = prev; i < next; i++) { unsigned long start = jiffies; - struct mce *m = &mcelog.entry[i]; - while (!m->finished) { + while (!mcelog.entry[i].finished) { if (time_after_eq(jiffies, start + 2)) { - memset(m, 0, sizeof(*m)); + memset(mcelog.entry + i, 0, + sizeof(struct mce)); goto timeout; } cpu_relax(); } smp_rmb(); - err |= copy_to_user(buf, m, sizeof(*m)); - buf += sizeof(*m); + err |= copy_to_user(buf, mcelog.entry + i, + sizeof(struct mce)); + buf += sizeof(struct mce); timeout: ; } @@ -1571,13 +1594,13 @@ static ssize_t mce_chrdev_read(struct file *filp, char __user *ubuf, on_each_cpu(collect_tscs, cpu_tsc, 1); for (i = next; i < MCE_LOG_LEN; i++) { - struct mce *m = &mcelog.entry[i]; - - if (m->finished && m->tsc < cpu_tsc[m->cpu]) { - err |= copy_to_user(buf, m, sizeof(*m)); + if (mcelog.entry[i].finished && + mcelog.entry[i].tsc < cpu_tsc[mcelog.entry[i].cpu]) { + err |= copy_to_user(buf, mcelog.entry+i, + sizeof(struct mce)); smp_rmb(); - buf += sizeof(*m); - memset(m, 0, sizeof(*m)); + buf += sizeof(struct mce); + memset(&mcelog.entry[i], 0, sizeof(struct mce)); } } @@ -1585,15 +1608,15 @@ static ssize_t mce_chrdev_read(struct file *filp, char __user *ubuf, err = -EFAULT; out: - mutex_unlock(&mce_chrdev_read_mutex); + mutex_unlock(&mce_read_mutex); kfree(cpu_tsc); return err ? err : buf - ubuf; } -static unsigned int mce_chrdev_poll(struct file *file, poll_table *wait) +static unsigned int mce_poll(struct file *file, poll_table *wait) { - poll_wait(file, &mce_chrdev_wait, wait); + poll_wait(file, &mce_wait, wait); if (rcu_access_index(mcelog.next)) return POLLIN | POLLRDNORM; if (!mce_apei_read_done && apei_check_mce()) @@ -1601,8 +1624,7 @@ static unsigned int mce_chrdev_poll(struct file *file, poll_table *wait) return 0; } -static long mce_chrdev_ioctl(struct file *f, unsigned int cmd, - unsigned long arg) +static long mce_ioctl(struct file *f, unsigned int cmd, unsigned long arg) { int __user *p = (int __user *)arg; @@ -1630,16 +1652,16 @@ static long mce_chrdev_ioctl(struct file *f, unsigned int cmd, /* Modified in mce-inject.c, so not static or const */ struct file_operations mce_chrdev_ops = { - .open = mce_chrdev_open, - .release = mce_chrdev_release, - .read = mce_chrdev_read, - .poll = mce_chrdev_poll, - .unlocked_ioctl = mce_chrdev_ioctl, - .llseek = no_llseek, + .open = mce_open, + .release = mce_release, + .read = mce_read, + .poll = mce_poll, + .unlocked_ioctl = mce_ioctl, + .llseek = no_llseek, }; EXPORT_SYMBOL_GPL(mce_chrdev_ops); -static struct miscdevice mce_chrdev_device = { +static struct miscdevice mce_log_device = { MISC_MCELOG_MINOR, "mcelog", &mce_chrdev_ops, @@ -1697,7 +1719,7 @@ int __init mcheck_init(void) } /* - * mce_syscore: PM support + * Sysfs support */ /* @@ -1717,12 +1739,12 @@ static int mce_disable_error_reporting(void) return 0; } -static int mce_syscore_suspend(void) +static int mce_suspend(void) { return mce_disable_error_reporting(); } -static void mce_syscore_shutdown(void) +static void mce_shutdown(void) { mce_disable_error_reporting(); } @@ -1732,22 +1754,18 @@ static void mce_syscore_shutdown(void) * Only one CPU is active at this time, the others get re-added later using * CPU hotplug: */ -static void mce_syscore_resume(void) +static void mce_resume(void) { __mcheck_cpu_init_generic(); __mcheck_cpu_init_vendor(__this_cpu_ptr(&cpu_info)); } static struct syscore_ops mce_syscore_ops = { - .suspend = mce_syscore_suspend, - .shutdown = mce_syscore_shutdown, - .resume = mce_syscore_resume, + .suspend = mce_suspend, + .shutdown = mce_shutdown, + .resume = mce_resume, }; -/* - * mce_sysdev: Sysfs support - */ - static void mce_cpu_restart(void *data) { del_timer_sync(&__get_cpu_var(mce_timer)); @@ -1783,11 +1801,11 @@ static void mce_enable_ce(void *all) __mcheck_cpu_init_timer(); } -static struct sysdev_class mce_sysdev_class = { +static struct sysdev_class mce_sysclass = { .name = "machinecheck", }; -DEFINE_PER_CPU(struct sys_device, mce_sysdev); +DEFINE_PER_CPU(struct sys_device, mce_dev); __cpuinitdata void (*threshold_cpu_callback)(unsigned long action, unsigned int cpu); @@ -1916,7 +1934,7 @@ static struct sysdev_ext_attribute attr_cmci_disabled = { &mce_cmci_disabled }; -static struct sysdev_attribute *mce_sysdev_attrs[] = { +static struct sysdev_attribute *mce_attrs[] = { &attr_tolerant.attr, &attr_check_interval.attr, &attr_trigger, @@ -1927,67 +1945,66 @@ static struct sysdev_attribute *mce_sysdev_attrs[] = { NULL }; -static cpumask_var_t mce_sysdev_initialized; +static cpumask_var_t mce_dev_initialized; /* Per cpu sysdev init. All of the cpus still share the same ctrl bank: */ -static __cpuinit int mce_sysdev_create(unsigned int cpu) +static __cpuinit int mce_create_device(unsigned int cpu) { - struct sys_device *sysdev = &per_cpu(mce_sysdev, cpu); int err; int i, j; if (!mce_available(&boot_cpu_data)) return -EIO; - memset(&sysdev->kobj, 0, sizeof(struct kobject)); - sysdev->id = cpu; - sysdev->cls = &mce_sysdev_class; + memset(&per_cpu(mce_dev, cpu).kobj, 0, sizeof(struct kobject)); + per_cpu(mce_dev, cpu).id = cpu; + per_cpu(mce_dev, cpu).cls = &mce_sysclass; - err = sysdev_register(sysdev); + err = sysdev_register(&per_cpu(mce_dev, cpu)); if (err) return err; - for (i = 0; mce_sysdev_attrs[i]; i++) { - err = sysdev_create_file(sysdev, mce_sysdev_attrs[i]); + for (i = 0; mce_attrs[i]; i++) { + err = sysdev_create_file(&per_cpu(mce_dev, cpu), mce_attrs[i]); if (err) goto error; } for (j = 0; j < banks; j++) { - err = sysdev_create_file(sysdev, &mce_banks[j].attr); + err = sysdev_create_file(&per_cpu(mce_dev, cpu), + &mce_banks[j].attr); if (err) goto error2; } - cpumask_set_cpu(cpu, mce_sysdev_initialized); + cpumask_set_cpu(cpu, mce_dev_initialized); return 0; error2: while (--j >= 0) - sysdev_remove_file(sysdev, &mce_banks[j].attr); + sysdev_remove_file(&per_cpu(mce_dev, cpu), &mce_banks[j].attr); error: while (--i >= 0) - sysdev_remove_file(sysdev, mce_sysdev_attrs[i]); + sysdev_remove_file(&per_cpu(mce_dev, cpu), mce_attrs[i]); - sysdev_unregister(sysdev); + sysdev_unregister(&per_cpu(mce_dev, cpu)); return err; } -static __cpuinit void mce_sysdev_remove(unsigned int cpu) +static __cpuinit void mce_remove_device(unsigned int cpu) { - struct sys_device *sysdev = &per_cpu(mce_sysdev, cpu); int i; - if (!cpumask_test_cpu(cpu, mce_sysdev_initialized)) + if (!cpumask_test_cpu(cpu, mce_dev_initialized)) return; - for (i = 0; mce_sysdev_attrs[i]; i++) - sysdev_remove_file(sysdev, mce_sysdev_attrs[i]); + for (i = 0; mce_attrs[i]; i++) + sysdev_remove_file(&per_cpu(mce_dev, cpu), mce_attrs[i]); for (i = 0; i < banks; i++) - sysdev_remove_file(sysdev, &mce_banks[i].attr); + sysdev_remove_file(&per_cpu(mce_dev, cpu), &mce_banks[i].attr); - sysdev_unregister(sysdev); - cpumask_clear_cpu(cpu, mce_sysdev_initialized); + sysdev_unregister(&per_cpu(mce_dev, cpu)); + cpumask_clear_cpu(cpu, mce_dev_initialized); } /* Make sure there are no machine checks on offlined CPUs. */ @@ -2037,7 +2054,7 @@ mce_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) switch (action) { case CPU_ONLINE: case CPU_ONLINE_FROZEN: - mce_sysdev_create(cpu); + mce_create_device(cpu); if (threshold_cpu_callback) threshold_cpu_callback(action, cpu); break; @@ -2045,7 +2062,7 @@ mce_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) case CPU_DEAD_FROZEN: if (threshold_cpu_callback) threshold_cpu_callback(action, cpu); - mce_sysdev_remove(cpu); + mce_remove_device(cpu); break; case CPU_DOWN_PREPARE: case CPU_DOWN_PREPARE_FROZEN: @@ -2099,28 +2116,27 @@ static __init int mcheck_init_device(void) if (!mce_available(&boot_cpu_data)) return -EIO; - zalloc_cpumask_var(&mce_sysdev_initialized, GFP_KERNEL); + zalloc_cpumask_var(&mce_dev_initialized, GFP_KERNEL); mce_init_banks(); - err = sysdev_class_register(&mce_sysdev_class); + err = sysdev_class_register(&mce_sysclass); if (err) return err; for_each_online_cpu(i) { - err = mce_sysdev_create(i); + err = mce_create_device(i); if (err) return err; } register_syscore_ops(&mce_syscore_ops); register_hotcpu_notifier(&mce_cpu_notifier); - - /* register character device /dev/mcelog */ - misc_register(&mce_chrdev_device); + misc_register(&mce_log_device); return err; } + device_initcall(mcheck_init_device); /* diff --git a/trunk/arch/x86/kernel/cpu/mcheck/mce_amd.c b/trunk/arch/x86/kernel/cpu/mcheck/mce_amd.c index f5474218cffe..bb0adad35143 100644 --- a/trunk/arch/x86/kernel/cpu/mcheck/mce_amd.c +++ b/trunk/arch/x86/kernel/cpu/mcheck/mce_amd.c @@ -548,7 +548,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank) if (!b) goto out; - err = sysfs_create_link(&per_cpu(mce_sysdev, cpu).kobj, + err = sysfs_create_link(&per_cpu(mce_dev, cpu).kobj, b->kobj, name); if (err) goto out; @@ -571,7 +571,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank) goto out; } - b->kobj = kobject_create_and_add(name, &per_cpu(mce_sysdev, cpu).kobj); + b->kobj = kobject_create_and_add(name, &per_cpu(mce_dev, cpu).kobj); if (!b->kobj) goto out_free; @@ -591,7 +591,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank) if (i == cpu) continue; - err = sysfs_create_link(&per_cpu(mce_sysdev, i).kobj, + err = sysfs_create_link(&per_cpu(mce_dev, i).kobj, b->kobj, name); if (err) goto out; @@ -669,7 +669,7 @@ static void threshold_remove_bank(unsigned int cpu, int bank) #ifdef CONFIG_SMP /* sibling symlink */ if (shared_bank[bank] && b->blocks->cpu != cpu) { - sysfs_remove_link(&per_cpu(mce_sysdev, cpu).kobj, name); + sysfs_remove_link(&per_cpu(mce_dev, cpu).kobj, name); per_cpu(threshold_banks, cpu)[bank] = NULL; return; @@ -681,7 +681,7 @@ static void threshold_remove_bank(unsigned int cpu, int bank) if (i == cpu) continue; - sysfs_remove_link(&per_cpu(mce_sysdev, i).kobj, name); + sysfs_remove_link(&per_cpu(mce_dev, i).kobj, name); per_cpu(threshold_banks, i)[bank] = NULL; } diff --git a/trunk/arch/x86/kernel/cpu/mtrr/main.c b/trunk/arch/x86/kernel/cpu/mtrr/main.c index 08119a37e53c..929739a653d1 100644 --- a/trunk/arch/x86/kernel/cpu/mtrr/main.c +++ b/trunk/arch/x86/kernel/cpu/mtrr/main.c @@ -79,6 +79,7 @@ void set_mtrr_ops(const struct mtrr_ops *ops) static int have_wrcomb(void) { struct pci_dev *dev; + u8 rev; dev = pci_get_class(PCI_CLASS_BRIDGE_HOST << 8, NULL); if (dev != NULL) { @@ -88,11 +89,13 @@ static int have_wrcomb(void) * chipsets to be tagged */ if (dev->vendor == PCI_VENDOR_ID_SERVERWORKS && - dev->device == PCI_DEVICE_ID_SERVERWORKS_LE && - dev->revision <= 5) { - pr_info("mtrr: Serverworks LE rev < 6 detected. Write-combining disabled.\n"); - pci_dev_put(dev); - return 0; + dev->device == PCI_DEVICE_ID_SERVERWORKS_LE) { + pci_read_config_byte(dev, PCI_CLASS_REVISION, &rev); + if (rev <= 5) { + pr_info("mtrr: Serverworks LE rev < 6 detected. Write-combining disabled.\n"); + pci_dev_put(dev); + return 0; + } } /* * Intel 450NX errata # 23. Non ascending cacheline evictions to @@ -134,43 +137,55 @@ static void __init init_table(void) } struct set_mtrr_data { + atomic_t count; + atomic_t gate; unsigned long smp_base; unsigned long smp_size; unsigned int smp_reg; mtrr_type smp_type; }; +static DEFINE_PER_CPU(struct cpu_stop_work, mtrr_work); + /** - * mtrr_rendezvous_handler - Work done in the synchronization handler. Executed - * by all the CPUs. + * mtrr_work_handler - Synchronisation handler. Executed by "other" CPUs. * @info: pointer to mtrr configuration data * * Returns nothing. */ -static int mtrr_rendezvous_handler(void *info) +static int mtrr_work_handler(void *info) { #ifdef CONFIG_SMP struct set_mtrr_data *data = info; + unsigned long flags; - /* - * We use this same function to initialize the mtrrs during boot, - * resume, runtime cpu online and on an explicit request to set a - * specific MTRR. - * - * During boot or suspend, the state of the boot cpu's mtrrs has been - * saved, and we want to replicate that across all the cpus that come - * online (either at the end of boot or resume or during a runtime cpu - * online). If we're doing that, @reg is set to something special and on - * all the cpu's we do mtrr_if->set_all() (On the logical cpu that - * started the boot/resume sequence, this might be a duplicate - * set_all()). - */ + atomic_dec(&data->count); + while (!atomic_read(&data->gate)) + cpu_relax(); + + local_irq_save(flags); + + atomic_dec(&data->count); + while (atomic_read(&data->gate)) + cpu_relax(); + + /* The master has cleared me to execute */ if (data->smp_reg != ~0U) { mtrr_if->set(data->smp_reg, data->smp_base, data->smp_size, data->smp_type); - } else if (mtrr_aps_delayed_init || !cpu_online(smp_processor_id())) { + } else if (mtrr_aps_delayed_init) { + /* + * Initialize the MTRRs inaddition to the synchronisation. + */ mtrr_if->set_all(); } + + atomic_dec(&data->count); + while (!atomic_read(&data->gate)) + cpu_relax(); + + atomic_dec(&data->count); + local_irq_restore(flags); #endif return 0; } @@ -208,11 +223,20 @@ static inline int types_compatible(mtrr_type type1, mtrr_type type2) * 14. Wait for buddies to catch up * 15. Enable interrupts. * - * What does that mean for us? Well, stop_machine() will ensure that - * the rendezvous handler is started on each CPU. And in lockstep they - * do the state transition of disabling interrupts, updating MTRR's - * (the CPU vendors may each do it differently, so we call mtrr_if->set() - * callback and let them take care of it.) and enabling interrupts. + * What does that mean for us? Well, first we set data.count to the number + * of CPUs. As each CPU announces that it started the rendezvous handler by + * decrementing the count, We reset data.count and set the data.gate flag + * allowing all the cpu's to proceed with the work. As each cpu disables + * interrupts, it'll decrement data.count once. We wait until it hits 0 and + * proceed. We clear the data.gate flag and reset data.count. Meanwhile, they + * are waiting for that flag to be cleared. Once it's cleared, each + * CPU goes through the transition of updating MTRRs. + * The CPU vendors may each do it differently, + * so we call mtrr_if->set() callback and let them take care of it. + * When they're done, they again decrement data->count and wait for data.gate + * to be set. + * When we finish, we wait for data.count to hit 0 and toggle the data.gate flag + * Everyone then enables interrupts and we all continue on. * * Note that the mechanism is the same for UP systems, too; all the SMP stuff * becomes nops. @@ -220,26 +244,92 @@ static inline int types_compatible(mtrr_type type1, mtrr_type type2) static void set_mtrr(unsigned int reg, unsigned long base, unsigned long size, mtrr_type type) { - struct set_mtrr_data data = { .smp_reg = reg, - .smp_base = base, - .smp_size = size, - .smp_type = type - }; + struct set_mtrr_data data; + unsigned long flags; + int cpu; - stop_machine(mtrr_rendezvous_handler, &data, cpu_online_mask); -} + preempt_disable(); -static void set_mtrr_from_inactive_cpu(unsigned int reg, unsigned long base, - unsigned long size, mtrr_type type) -{ - struct set_mtrr_data data = { .smp_reg = reg, - .smp_base = base, - .smp_size = size, - .smp_type = type - }; - - stop_machine_from_inactive_cpu(mtrr_rendezvous_handler, &data, - cpu_callout_mask); + data.smp_reg = reg; + data.smp_base = base; + data.smp_size = size; + data.smp_type = type; + atomic_set(&data.count, num_booting_cpus() - 1); + + /* Make sure data.count is visible before unleashing other CPUs */ + smp_wmb(); + atomic_set(&data.gate, 0); + + /* Start the ball rolling on other CPUs */ + for_each_online_cpu(cpu) { + struct cpu_stop_work *work = &per_cpu(mtrr_work, cpu); + + if (cpu == smp_processor_id()) + continue; + + stop_one_cpu_nowait(cpu, mtrr_work_handler, &data, work); + } + + + while (atomic_read(&data.count)) + cpu_relax(); + + /* Ok, reset count and toggle gate */ + atomic_set(&data.count, num_booting_cpus() - 1); + smp_wmb(); + atomic_set(&data.gate, 1); + + local_irq_save(flags); + + while (atomic_read(&data.count)) + cpu_relax(); + + /* Ok, reset count and toggle gate */ + atomic_set(&data.count, num_booting_cpus() - 1); + smp_wmb(); + atomic_set(&data.gate, 0); + + /* Do our MTRR business */ + + /* + * HACK! + * + * We use this same function to initialize the mtrrs during boot, + * resume, runtime cpu online and on an explicit request to set a + * specific MTRR. + * + * During boot or suspend, the state of the boot cpu's mtrrs has been + * saved, and we want to replicate that across all the cpus that come + * online (either at the end of boot or resume or during a runtime cpu + * online). If we're doing that, @reg is set to something special and on + * this cpu we still do mtrr_if->set_all(). During boot/resume, this + * is unnecessary if at this point we are still on the cpu that started + * the boot/resume sequence. But there is no guarantee that we are still + * on the same cpu. So we do mtrr_if->set_all() on this cpu aswell to be + * sure that we are in sync with everyone else. + */ + if (reg != ~0U) + mtrr_if->set(reg, base, size, type); + else + mtrr_if->set_all(); + + /* Wait for the others */ + while (atomic_read(&data.count)) + cpu_relax(); + + atomic_set(&data.count, num_booting_cpus() - 1); + smp_wmb(); + atomic_set(&data.gate, 1); + + /* + * Wait here for everyone to have seen the gate change + * So we're the last ones to touch 'data' + */ + while (atomic_read(&data.count)) + cpu_relax(); + + local_irq_restore(flags); + preempt_enable(); } /** @@ -693,7 +783,7 @@ void mtrr_ap_init(void) * 2. cpu hotadd time. We let mtrr_add/del_page hold cpuhotplug * lock to prevent mtrr entry changes */ - set_mtrr_from_inactive_cpu(~0U, 0, 0, 0); + set_mtrr(~0U, 0, 0, 0); } /** diff --git a/trunk/arch/x86/kernel/cpu/perf_event.c b/trunk/arch/x86/kernel/cpu/perf_event.c index 4ee3abf20ed6..3a0338b4b179 100644 --- a/trunk/arch/x86/kernel/cpu/perf_event.c +++ b/trunk/arch/x86/kernel/cpu/perf_event.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -44,27 +45,38 @@ do { \ #endif /* - * | NHM/WSM | SNB | - * register ------------------------------- - * | HT | no HT | HT | no HT | - *----------------------------------------- - * offcore | core | core | cpu | core | - * lbr_sel | core | core | cpu | core | - * ld_lat | cpu | core | cpu | core | - *----------------------------------------- - * - * Given that there is a small number of shared regs, - * we can pre-allocate their slot in the per-cpu - * per-core reg tables. + * best effort, GUP based copy_from_user() that assumes IRQ or NMI context */ -enum extra_reg_type { - EXTRA_REG_NONE = -1, /* not used */ +static unsigned long +copy_from_user_nmi(void *to, const void __user *from, unsigned long n) +{ + unsigned long offset, addr = (unsigned long)from; + unsigned long size, len = 0; + struct page *page; + void *map; + int ret; + + do { + ret = __get_user_pages_fast(addr, 1, 0, &page); + if (!ret) + break; - EXTRA_REG_RSP_0 = 0, /* offcore_response_0 */ - EXTRA_REG_RSP_1 = 1, /* offcore_response_1 */ + offset = addr & (PAGE_SIZE - 1); + size = min(PAGE_SIZE - offset, n - len); - EXTRA_REG_MAX /* number of entries needed */ -}; + map = kmap_atomic(page); + memcpy(to, map+offset, size); + kunmap_atomic(map); + put_page(page); + + len += size; + to += size; + addr += size; + + } while (len < n); + + return len; +} struct event_constraint { union { @@ -120,10 +132,11 @@ struct cpu_hw_events { struct perf_branch_entry lbr_entries[MAX_LBR_ENTRIES]; /* - * manage shared (per-core, per-cpu) registers - * used on Intel NHM/WSM/SNB + * Intel percore register state. + * Coordinate shared resources between HT threads. */ - struct intel_shared_regs *shared_regs; + int percore_used; /* Used by this CPU? */ + struct intel_percore *per_core; /* * AMD specific bits @@ -173,46 +186,27 @@ struct cpu_hw_events { #define for_each_event_constraint(e, c) \ for ((e) = (c); (e)->weight; (e)++) -/* - * Per register state. - */ -struct er_account { - raw_spinlock_t lock; /* per-core: protect structure */ - u64 config; /* extra MSR config */ - u64 reg; /* extra MSR number */ - atomic_t ref; /* reference count */ -}; - /* * Extra registers for specific events. - * * Some events need large masks and require external MSRs. - * Those extra MSRs end up being shared for all events on - * a PMU and sometimes between PMU of sibling HT threads. - * In either case, the kernel needs to handle conflicting - * accesses to those extra, shared, regs. The data structure - * to manage those registers is stored in cpu_hw_event. + * Define a mapping to these extra registers. */ struct extra_reg { unsigned int event; unsigned int msr; u64 config_mask; u64 valid_mask; - int idx; /* per_xxx->regs[] reg index */ }; -#define EVENT_EXTRA_REG(e, ms, m, vm, i) { \ +#define EVENT_EXTRA_REG(e, ms, m, vm) { \ .event = (e), \ .msr = (ms), \ .config_mask = (m), \ .valid_mask = (vm), \ - .idx = EXTRA_REG_##i \ } - -#define INTEL_EVENT_EXTRA_REG(event, msr, vm, idx) \ - EVENT_EXTRA_REG(event, msr, ARCH_PERFMON_EVENTSEL_EVENT, vm, idx) - -#define EVENT_EXTRA_END EVENT_EXTRA_REG(0, 0, 0, 0, RSP_0) +#define INTEL_EVENT_EXTRA_REG(event, msr, vm) \ + EVENT_EXTRA_REG(event, msr, ARCH_PERFMON_EVENTSEL_EVENT, vm) +#define EVENT_EXTRA_END EVENT_EXTRA_REG(0, 0, 0, 0) union perf_capabilities { struct { @@ -258,6 +252,7 @@ struct x86_pmu { void (*put_event_constraints)(struct cpu_hw_events *cpuc, struct perf_event *event); struct event_constraint *event_constraints; + struct event_constraint *percore_constraints; void (*quirks)(void); int perfctr_second_write; @@ -291,12 +286,8 @@ struct x86_pmu { * Extra registers for events */ struct extra_reg *extra_regs; - unsigned int er_flags; }; -#define ERF_NO_HT_SHARING 1 -#define ERF_HAS_RSP_1 2 - static struct x86_pmu x86_pmu __read_mostly; static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = { @@ -402,10 +393,10 @@ static inline unsigned int x86_pmu_event_addr(int index) */ static int x86_pmu_extra_regs(u64 config, struct perf_event *event) { - struct hw_perf_event_extra *reg; struct extra_reg *er; - reg = &event->hw.extra_reg; + event->hw.extra_reg = 0; + event->hw.extra_config = 0; if (!x86_pmu.extra_regs) return 0; @@ -415,10 +406,8 @@ static int x86_pmu_extra_regs(u64 config, struct perf_event *event) continue; if (event->attr.config1 & ~er->valid_mask) return -EINVAL; - - reg->idx = er->idx; - reg->config = event->attr.config1; - reg->reg = er->msr; + event->hw.extra_reg = er->msr; + event->hw.extra_config = event->attr.config1; break; } return 0; @@ -717,9 +706,6 @@ static int __x86_pmu_event_init(struct perf_event *event) event->hw.last_cpu = -1; event->hw.last_tag = ~0ULL; - /* mark unused */ - event->hw.extra_reg.idx = EXTRA_REG_NONE; - return x86_pmu.hw_config(event); } @@ -761,8 +747,8 @@ static void x86_pmu_disable(struct pmu *pmu) static inline void __x86_pmu_enable_event(struct hw_perf_event *hwc, u64 enable_mask) { - if (hwc->extra_reg.reg) - wrmsrl(hwc->extra_reg.reg, hwc->extra_reg.config); + if (hwc->extra_reg) + wrmsrl(hwc->extra_reg, hwc->extra_config); wrmsrl(hwc->config_base, hwc->config | enable_mask); } @@ -1346,7 +1332,7 @@ static int x86_pmu_handle_irq(struct pt_regs *regs) if (!x86_perf_event_set_period(event)) continue; - if (perf_event_overflow(event, &data, regs)) + if (perf_event_overflow(event, 1, &data, regs)) x86_pmu_stop(event, 0); } @@ -1651,40 +1637,6 @@ static int x86_pmu_commit_txn(struct pmu *pmu) perf_pmu_enable(pmu); return 0; } -/* - * a fake_cpuc is used to validate event groups. Due to - * the extra reg logic, we need to also allocate a fake - * per_core and per_cpu structure. Otherwise, group events - * using extra reg may conflict without the kernel being - * able to catch this when the last event gets added to - * the group. - */ -static void free_fake_cpuc(struct cpu_hw_events *cpuc) -{ - kfree(cpuc->shared_regs); - kfree(cpuc); -} - -static struct cpu_hw_events *allocate_fake_cpuc(void) -{ - struct cpu_hw_events *cpuc; - int cpu = raw_smp_processor_id(); - - cpuc = kzalloc(sizeof(*cpuc), GFP_KERNEL); - if (!cpuc) - return ERR_PTR(-ENOMEM); - - /* only needed, if we have extra_regs */ - if (x86_pmu.extra_regs) { - cpuc->shared_regs = allocate_shared_regs(cpu); - if (!cpuc->shared_regs) - goto error; - } - return cpuc; -error: - free_fake_cpuc(cpuc); - return ERR_PTR(-ENOMEM); -} /* * validate that we can schedule this event @@ -1695,9 +1647,9 @@ static int validate_event(struct perf_event *event) struct event_constraint *c; int ret = 0; - fake_cpuc = allocate_fake_cpuc(); - if (IS_ERR(fake_cpuc)) - return PTR_ERR(fake_cpuc); + fake_cpuc = kmalloc(sizeof(*fake_cpuc), GFP_KERNEL | __GFP_ZERO); + if (!fake_cpuc) + return -ENOMEM; c = x86_pmu.get_event_constraints(fake_cpuc, event); @@ -1707,7 +1659,7 @@ static int validate_event(struct perf_event *event) if (x86_pmu.put_event_constraints) x86_pmu.put_event_constraints(fake_cpuc, event); - free_fake_cpuc(fake_cpuc); + kfree(fake_cpuc); return ret; } @@ -1727,32 +1679,36 @@ static int validate_group(struct perf_event *event) { struct perf_event *leader = event->group_leader; struct cpu_hw_events *fake_cpuc; - int ret = -ENOSPC, n; + int ret, n; + + ret = -ENOMEM; + fake_cpuc = kmalloc(sizeof(*fake_cpuc), GFP_KERNEL | __GFP_ZERO); + if (!fake_cpuc) + goto out; - fake_cpuc = allocate_fake_cpuc(); - if (IS_ERR(fake_cpuc)) - return PTR_ERR(fake_cpuc); /* * the event is not yet connected with its * siblings therefore we must first collect * existing siblings, then add the new event * before we can simulate the scheduling */ + ret = -ENOSPC; n = collect_events(fake_cpuc, leader, true); if (n < 0) - goto out; + goto out_free; fake_cpuc->n_events = n; n = collect_events(fake_cpuc, event, false); if (n < 0) - goto out; + goto out_free; fake_cpuc->n_events = n; ret = x86_pmu.schedule_events(fake_cpuc, n, NULL); +out_free: + kfree(fake_cpuc); out: - free_fake_cpuc(fake_cpuc); return ret; } diff --git a/trunk/arch/x86/kernel/cpu/perf_event_amd.c b/trunk/arch/x86/kernel/cpu/perf_event_amd.c index 941caa2e449b..fe29c1d2219e 100644 --- a/trunk/arch/x86/kernel/cpu/perf_event_amd.c +++ b/trunk/arch/x86/kernel/cpu/perf_event_amd.c @@ -89,20 +89,6 @@ static __initconst const u64 amd_hw_cache_event_ids [ C(RESULT_MISS) ] = -1, }, }, - [ C(NODE) ] = { - [ C(OP_READ) ] = { - [ C(RESULT_ACCESS) ] = 0xb8e9, /* CPU Request to Memory, l+r */ - [ C(RESULT_MISS) ] = 0x98e9, /* CPU Request to Memory, r */ - }, - [ C(OP_WRITE) ] = { - [ C(RESULT_ACCESS) ] = -1, - [ C(RESULT_MISS) ] = -1, - }, - [ C(OP_PREFETCH) ] = { - [ C(RESULT_ACCESS) ] = -1, - [ C(RESULT_MISS) ] = -1, - }, - }, }; /* diff --git a/trunk/arch/x86/kernel/cpu/perf_event_intel.c b/trunk/arch/x86/kernel/cpu/perf_event_intel.c index 45fbb8f7f549..41178c826c48 100644 --- a/trunk/arch/x86/kernel/cpu/perf_event_intel.c +++ b/trunk/arch/x86/kernel/cpu/perf_event_intel.c @@ -1,15 +1,25 @@ #ifdef CONFIG_CPU_SUP_INTEL +#define MAX_EXTRA_REGS 2 + /* - * Per core/cpu state - * - * Used to coordinate shared registers between HT threads or - * among events on a single PMU. + * Per register state. */ -struct intel_shared_regs { - struct er_account regs[EXTRA_REG_MAX]; - int refcnt; /* per-core: #HT threads */ - unsigned core_id; /* per-core: core id */ +struct er_account { + int ref; /* reference count */ + unsigned int extra_reg; /* extra MSR number */ + u64 extra_config; /* extra MSR config */ +}; + +/* + * Per core state + * This used to coordinate shared registers for HT threads. + */ +struct intel_percore { + raw_spinlock_t lock; /* protect structure */ + struct er_account regs[MAX_EXTRA_REGS]; + int refcnt; /* number of threads */ + unsigned core_id; }; /* @@ -78,10 +88,16 @@ static struct event_constraint intel_nehalem_event_constraints[] __read_mostly = static struct extra_reg intel_nehalem_extra_regs[] __read_mostly = { - INTEL_EVENT_EXTRA_REG(0xb7, MSR_OFFCORE_RSP_0, 0xffff, RSP_0), + INTEL_EVENT_EXTRA_REG(0xb7, MSR_OFFCORE_RSP_0, 0xffff), EVENT_EXTRA_END }; +static struct event_constraint intel_nehalem_percore_constraints[] __read_mostly = +{ + INTEL_EVENT_CONSTRAINT(0xb7, 0), + EVENT_CONSTRAINT_END +}; + static struct event_constraint intel_westmere_event_constraints[] __read_mostly = { FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */ @@ -100,6 +116,8 @@ static struct event_constraint intel_snb_event_constraints[] __read_mostly = FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */ /* FIXED_EVENT_CONSTRAINT(0x013c, 2), CPU_CLK_UNHALTED.REF */ INTEL_EVENT_CONSTRAINT(0x48, 0x4), /* L1D_PEND_MISS.PENDING */ + INTEL_EVENT_CONSTRAINT(0xb7, 0x1), /* OFF_CORE_RESPONSE_0 */ + INTEL_EVENT_CONSTRAINT(0xbb, 0x8), /* OFF_CORE_RESPONSE_1 */ INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PREC_DIST */ INTEL_EVENT_CONSTRAINT(0xcd, 0x8), /* MEM_TRANS_RETIRED.LOAD_LATENCY */ EVENT_CONSTRAINT_END @@ -107,13 +125,15 @@ static struct event_constraint intel_snb_event_constraints[] __read_mostly = static struct extra_reg intel_westmere_extra_regs[] __read_mostly = { - INTEL_EVENT_EXTRA_REG(0xb7, MSR_OFFCORE_RSP_0, 0xffff, RSP_0), - INTEL_EVENT_EXTRA_REG(0xbb, MSR_OFFCORE_RSP_1, 0xffff, RSP_1), + INTEL_EVENT_EXTRA_REG(0xb7, MSR_OFFCORE_RSP_0, 0xffff), + INTEL_EVENT_EXTRA_REG(0xbb, MSR_OFFCORE_RSP_1, 0xffff), EVENT_EXTRA_END }; -static struct event_constraint intel_v1_event_constraints[] __read_mostly = +static struct event_constraint intel_westmere_percore_constraints[] __read_mostly = { + INTEL_EVENT_CONSTRAINT(0xb7, 0), + INTEL_EVENT_CONSTRAINT(0xbb, 0), EVENT_CONSTRAINT_END }; @@ -125,12 +145,6 @@ static struct event_constraint intel_gen_event_constraints[] __read_mostly = EVENT_CONSTRAINT_END }; -static struct extra_reg intel_snb_extra_regs[] __read_mostly = { - INTEL_EVENT_EXTRA_REG(0xb7, MSR_OFFCORE_RSP_0, 0x3fffffffffull, RSP_0), - INTEL_EVENT_EXTRA_REG(0xbb, MSR_OFFCORE_RSP_1, 0x3fffffffffull, RSP_1), - EVENT_EXTRA_END -}; - static u64 intel_pmu_event_map(int hw_event) { return intel_perfmon_event_map[hw_event]; @@ -231,21 +245,6 @@ static __initconst const u64 snb_hw_cache_event_ids [ C(RESULT_MISS) ] = -1, }, }, - [ C(NODE) ] = { - [ C(OP_READ) ] = { - [ C(RESULT_ACCESS) ] = -1, - [ C(RESULT_MISS) ] = -1, - }, - [ C(OP_WRITE) ] = { - [ C(RESULT_ACCESS) ] = -1, - [ C(RESULT_MISS) ] = -1, - }, - [ C(OP_PREFETCH) ] = { - [ C(RESULT_ACCESS) ] = -1, - [ C(RESULT_MISS) ] = -1, - }, - }, - }; static __initconst const u64 westmere_hw_cache_event_ids @@ -347,20 +346,6 @@ static __initconst const u64 westmere_hw_cache_event_ids [ C(RESULT_MISS) ] = -1, }, }, - [ C(NODE) ] = { - [ C(OP_READ) ] = { - [ C(RESULT_ACCESS) ] = 0x01b7, - [ C(RESULT_MISS) ] = 0x01b7, - }, - [ C(OP_WRITE) ] = { - [ C(RESULT_ACCESS) ] = 0x01b7, - [ C(RESULT_MISS) ] = 0x01b7, - }, - [ C(OP_PREFETCH) ] = { - [ C(RESULT_ACCESS) ] = 0x01b7, - [ C(RESULT_MISS) ] = 0x01b7, - }, - }, }; /* @@ -413,21 +398,7 @@ static __initconst const u64 nehalem_hw_cache_extra_regs [ C(RESULT_ACCESS) ] = NHM_DMND_PREFETCH|NHM_L3_ACCESS, [ C(RESULT_MISS) ] = NHM_DMND_PREFETCH|NHM_L3_MISS, }, - }, - [ C(NODE) ] = { - [ C(OP_READ) ] = { - [ C(RESULT_ACCESS) ] = NHM_DMND_READ|NHM_ALL_DRAM, - [ C(RESULT_MISS) ] = NHM_DMND_READ|NHM_REMOTE_DRAM, - }, - [ C(OP_WRITE) ] = { - [ C(RESULT_ACCESS) ] = NHM_DMND_WRITE|NHM_ALL_DRAM, - [ C(RESULT_MISS) ] = NHM_DMND_WRITE|NHM_REMOTE_DRAM, - }, - [ C(OP_PREFETCH) ] = { - [ C(RESULT_ACCESS) ] = NHM_DMND_PREFETCH|NHM_ALL_DRAM, - [ C(RESULT_MISS) ] = NHM_DMND_PREFETCH|NHM_REMOTE_DRAM, - }, - }, + } }; static __initconst const u64 nehalem_hw_cache_event_ids @@ -529,20 +500,6 @@ static __initconst const u64 nehalem_hw_cache_event_ids [ C(RESULT_MISS) ] = -1, }, }, - [ C(NODE) ] = { - [ C(OP_READ) ] = { - [ C(RESULT_ACCESS) ] = 0x01b7, - [ C(RESULT_MISS) ] = 0x01b7, - }, - [ C(OP_WRITE) ] = { - [ C(RESULT_ACCESS) ] = 0x01b7, - [ C(RESULT_MISS) ] = 0x01b7, - }, - [ C(OP_PREFETCH) ] = { - [ C(RESULT_ACCESS) ] = 0x01b7, - [ C(RESULT_MISS) ] = 0x01b7, - }, - }, }; static __initconst const u64 core2_hw_cache_event_ids @@ -1046,7 +1003,7 @@ static int intel_pmu_handle_irq(struct pt_regs *regs) data.period = event->hw.last_period; - if (perf_event_overflow(event, &data, regs)) + if (perf_event_overflow(event, 1, &data, regs)) x86_pmu_stop(event, 0); } @@ -1080,121 +1037,65 @@ intel_bts_constraints(struct perf_event *event) return NULL; } -static bool intel_try_alt_er(struct perf_event *event, int orig_idx) -{ - if (!(x86_pmu.er_flags & ERF_HAS_RSP_1)) - return false; - - if (event->hw.extra_reg.idx == EXTRA_REG_RSP_0) { - event->hw.config &= ~INTEL_ARCH_EVENT_MASK; - event->hw.config |= 0x01bb; - event->hw.extra_reg.idx = EXTRA_REG_RSP_1; - event->hw.extra_reg.reg = MSR_OFFCORE_RSP_1; - } else if (event->hw.extra_reg.idx == EXTRA_REG_RSP_1) { - event->hw.config &= ~INTEL_ARCH_EVENT_MASK; - event->hw.config |= 0x01b7; - event->hw.extra_reg.idx = EXTRA_REG_RSP_0; - event->hw.extra_reg.reg = MSR_OFFCORE_RSP_0; - } - - if (event->hw.extra_reg.idx == orig_idx) - return false; - - return true; -} - -/* - * manage allocation of shared extra msr for certain events - * - * sharing can be: - * per-cpu: to be shared between the various events on a single PMU - * per-core: per-cpu + shared by HT threads - */ static struct event_constraint * -__intel_shared_reg_get_constraints(struct cpu_hw_events *cpuc, - struct perf_event *event) +intel_percore_constraints(struct cpu_hw_events *cpuc, struct perf_event *event) { - struct event_constraint *c = &emptyconstraint; - struct hw_perf_event_extra *reg = &event->hw.extra_reg; + struct hw_perf_event *hwc = &event->hw; + unsigned int e = hwc->config & ARCH_PERFMON_EVENTSEL_EVENT; + struct event_constraint *c; + struct intel_percore *pc; struct er_account *era; - unsigned long flags; - int orig_idx = reg->idx; - - /* already allocated shared msr */ - if (reg->alloc) - return &unconstrained; - -again: - era = &cpuc->shared_regs->regs[reg->idx]; - /* - * we use spin_lock_irqsave() to avoid lockdep issues when - * passing a fake cpuc - */ - raw_spin_lock_irqsave(&era->lock, flags); - - if (!atomic_read(&era->ref) || era->config == reg->config) { - - /* lock in msr value */ - era->config = reg->config; - era->reg = reg->reg; + int i; + int free_slot; + int found; - /* one more user */ - atomic_inc(&era->ref); + if (!x86_pmu.percore_constraints || hwc->extra_alloc) + return NULL; - /* no need to reallocate during incremental event scheduling */ - reg->alloc = 1; + for (c = x86_pmu.percore_constraints; c->cmask; c++) { + if (e != c->code) + continue; /* - * All events using extra_reg are unconstrained. - * Avoids calling x86_get_event_constraints() - * - * Must revisit if extra_reg controlling events - * ever have constraints. Worst case we go through - * the regular event constraint table. + * Allocate resource per core. */ - c = &unconstrained; - } else if (intel_try_alt_er(event, orig_idx)) { - raw_spin_unlock(&era->lock); - goto again; + pc = cpuc->per_core; + if (!pc) + break; + c = &emptyconstraint; + raw_spin_lock(&pc->lock); + free_slot = -1; + found = 0; + for (i = 0; i < MAX_EXTRA_REGS; i++) { + era = &pc->regs[i]; + if (era->ref > 0 && hwc->extra_reg == era->extra_reg) { + /* Allow sharing same config */ + if (hwc->extra_config == era->extra_config) { + era->ref++; + cpuc->percore_used = 1; + hwc->extra_alloc = 1; + c = NULL; + } + /* else conflict */ + found = 1; + break; + } else if (era->ref == 0 && free_slot == -1) + free_slot = i; + } + if (!found && free_slot != -1) { + era = &pc->regs[free_slot]; + era->ref = 1; + era->extra_reg = hwc->extra_reg; + era->extra_config = hwc->extra_config; + cpuc->percore_used = 1; + hwc->extra_alloc = 1; + c = NULL; + } + raw_spin_unlock(&pc->lock); + return c; } - raw_spin_unlock_irqrestore(&era->lock, flags); - - return c; -} - -static void -__intel_shared_reg_put_constraints(struct cpu_hw_events *cpuc, - struct hw_perf_event_extra *reg) -{ - struct er_account *era; - - /* - * only put constraint if extra reg was actually - * allocated. Also takes care of event which do - * not use an extra shared reg - */ - if (!reg->alloc) - return; - - era = &cpuc->shared_regs->regs[reg->idx]; - - /* one fewer user */ - atomic_dec(&era->ref); - - /* allocate again next time */ - reg->alloc = 0; -} - -static struct event_constraint * -intel_shared_regs_constraints(struct cpu_hw_events *cpuc, - struct perf_event *event) -{ - struct event_constraint *c = NULL; - if (event->hw.extra_reg.idx != EXTRA_REG_NONE) - c = __intel_shared_reg_get_constraints(cpuc, event); - - return c; + return NULL; } static struct event_constraint * @@ -1210,28 +1111,49 @@ intel_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event if (c) return c; - c = intel_shared_regs_constraints(cpuc, event); + c = intel_percore_constraints(cpuc, event); if (c) return c; return x86_get_event_constraints(cpuc, event); } -static void -intel_put_shared_regs_event_constraints(struct cpu_hw_events *cpuc, +static void intel_put_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event) { - struct hw_perf_event_extra *reg; + struct extra_reg *er; + struct intel_percore *pc; + struct er_account *era; + struct hw_perf_event *hwc = &event->hw; + int i, allref; - reg = &event->hw.extra_reg; - if (reg->idx != EXTRA_REG_NONE) - __intel_shared_reg_put_constraints(cpuc, reg); -} + if (!cpuc->percore_used) + return; -static void intel_put_event_constraints(struct cpu_hw_events *cpuc, - struct perf_event *event) -{ - intel_put_shared_regs_event_constraints(cpuc, event); + for (er = x86_pmu.extra_regs; er->msr; er++) { + if (er->event != (hwc->config & er->config_mask)) + continue; + + pc = cpuc->per_core; + raw_spin_lock(&pc->lock); + for (i = 0; i < MAX_EXTRA_REGS; i++) { + era = &pc->regs[i]; + if (era->ref > 0 && + era->extra_config == hwc->extra_config && + era->extra_reg == er->msr) { + era->ref--; + hwc->extra_alloc = 0; + break; + } + } + allref = 0; + for (i = 0; i < MAX_EXTRA_REGS; i++) + allref += pc->regs[i].ref; + if (allref == 0) + cpuc->percore_used = 0; + raw_spin_unlock(&pc->lock); + break; + } } static int intel_pmu_hw_config(struct perf_event *event) @@ -1309,36 +1231,20 @@ static __initconst const struct x86_pmu core_pmu = { .event_constraints = intel_core_event_constraints, }; -static struct intel_shared_regs *allocate_shared_regs(int cpu) -{ - struct intel_shared_regs *regs; - int i; - - regs = kzalloc_node(sizeof(struct intel_shared_regs), - GFP_KERNEL, cpu_to_node(cpu)); - if (regs) { - /* - * initialize the locks to keep lockdep happy - */ - for (i = 0; i < EXTRA_REG_MAX; i++) - raw_spin_lock_init(®s->regs[i].lock); - - regs->core_id = -1; - } - return regs; -} - static int intel_pmu_cpu_prepare(int cpu) { struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu); - if (!x86_pmu.extra_regs) + if (!cpu_has_ht_siblings()) return NOTIFY_OK; - cpuc->shared_regs = allocate_shared_regs(cpu); - if (!cpuc->shared_regs) + cpuc->per_core = kzalloc_node(sizeof(struct intel_percore), + GFP_KERNEL, cpu_to_node(cpu)); + if (!cpuc->per_core) return NOTIFY_BAD; + raw_spin_lock_init(&cpuc->per_core->lock); + cpuc->per_core->core_id = -1; return NOTIFY_OK; } @@ -1354,34 +1260,32 @@ static void intel_pmu_cpu_starting(int cpu) */ intel_pmu_lbr_reset(); - if (!cpuc->shared_regs || (x86_pmu.er_flags & ERF_NO_HT_SHARING)) + if (!cpu_has_ht_siblings()) return; for_each_cpu(i, topology_thread_cpumask(cpu)) { - struct intel_shared_regs *pc; + struct intel_percore *pc = per_cpu(cpu_hw_events, i).per_core; - pc = per_cpu(cpu_hw_events, i).shared_regs; if (pc && pc->core_id == core_id) { - kfree(cpuc->shared_regs); - cpuc->shared_regs = pc; + kfree(cpuc->per_core); + cpuc->per_core = pc; break; } } - cpuc->shared_regs->core_id = core_id; - cpuc->shared_regs->refcnt++; + cpuc->per_core->core_id = core_id; + cpuc->per_core->refcnt++; } static void intel_pmu_cpu_dying(int cpu) { struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu); - struct intel_shared_regs *pc; + struct intel_percore *pc = cpuc->per_core; - pc = cpuc->shared_regs; if (pc) { if (pc->core_id == -1 || --pc->refcnt == 0) kfree(pc); - cpuc->shared_regs = NULL; + cpuc->per_core = NULL; } fini_debug_store_on_cpu(cpu); @@ -1532,6 +1436,7 @@ static __init int intel_pmu_init(void) x86_pmu.event_constraints = intel_nehalem_event_constraints; x86_pmu.pebs_constraints = intel_nehalem_pebs_event_constraints; + x86_pmu.percore_constraints = intel_nehalem_percore_constraints; x86_pmu.enable_all = intel_pmu_nhm_enable_all; x86_pmu.extra_regs = intel_nehalem_extra_regs; @@ -1576,10 +1481,10 @@ static __init int intel_pmu_init(void) intel_pmu_lbr_init_nhm(); x86_pmu.event_constraints = intel_westmere_event_constraints; + x86_pmu.percore_constraints = intel_westmere_percore_constraints; x86_pmu.enable_all = intel_pmu_nhm_enable_all; x86_pmu.pebs_constraints = intel_westmere_pebs_event_constraints; x86_pmu.extra_regs = intel_westmere_extra_regs; - x86_pmu.er_flags |= ERF_HAS_RSP_1; /* UOPS_ISSUED.STALLED_CYCLES */ intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 0x180010e; @@ -1597,10 +1502,6 @@ static __init int intel_pmu_init(void) x86_pmu.event_constraints = intel_snb_event_constraints; x86_pmu.pebs_constraints = intel_snb_pebs_events; - x86_pmu.extra_regs = intel_snb_extra_regs; - /* all extra regs are per-cpu when HT is on */ - x86_pmu.er_flags |= ERF_HAS_RSP_1; - x86_pmu.er_flags |= ERF_NO_HT_SHARING; /* UOPS_ISSUED.ANY,c=1,i=1 to count stall cycles */ intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 0x180010e; @@ -1611,19 +1512,11 @@ static __init int intel_pmu_init(void) break; default: - switch (x86_pmu.version) { - case 1: - x86_pmu.event_constraints = intel_v1_event_constraints; - pr_cont("generic architected perfmon v1, "); - break; - default: - /* - * default constraints for v2 and up - */ - x86_pmu.event_constraints = intel_gen_event_constraints; - pr_cont("generic architected perfmon, "); - break; - } + /* + * default constraints for v2 and up + */ + x86_pmu.event_constraints = intel_gen_event_constraints; + pr_cont("generic architected perfmon, "); } return 0; } @@ -1635,8 +1528,4 @@ static int intel_pmu_init(void) return 0; } -static struct intel_shared_regs *allocate_shared_regs(int cpu) -{ - return NULL; -} #endif /* CONFIG_CPU_SUP_INTEL */ diff --git a/trunk/arch/x86/kernel/cpu/perf_event_intel_ds.c b/trunk/arch/x86/kernel/cpu/perf_event_intel_ds.c index 1b1ef3addcfd..bab491b8ee25 100644 --- a/trunk/arch/x86/kernel/cpu/perf_event_intel_ds.c +++ b/trunk/arch/x86/kernel/cpu/perf_event_intel_ds.c @@ -340,7 +340,7 @@ static int intel_pmu_drain_bts_buffer(void) */ perf_prepare_sample(&header, &data, event, ®s); - if (perf_output_begin(&handle, event, header.size * (top - at))) + if (perf_output_begin(&handle, event, header.size * (top - at), 1, 1)) return 1; for (; at < top; at++) { @@ -616,7 +616,7 @@ static void __intel_pmu_pebs_event(struct perf_event *event, else regs.flags &= ~PERF_EFLAGS_EXACT; - if (perf_event_overflow(event, &data, ®s)) + if (perf_event_overflow(event, 1, &data, ®s)) x86_pmu_stop(event, 0); } diff --git a/trunk/arch/x86/kernel/cpu/perf_event_p4.c b/trunk/arch/x86/kernel/cpu/perf_event_p4.c index 7809d2bcb209..ead584fb6a7d 100644 --- a/trunk/arch/x86/kernel/cpu/perf_event_p4.c +++ b/trunk/arch/x86/kernel/cpu/perf_event_p4.c @@ -554,102 +554,13 @@ static __initconst const u64 p4_hw_cache_event_ids [ C(RESULT_MISS) ] = -1, }, }, - [ C(NODE) ] = { - [ C(OP_READ) ] = { - [ C(RESULT_ACCESS) ] = -1, - [ C(RESULT_MISS) ] = -1, - }, - [ C(OP_WRITE) ] = { - [ C(RESULT_ACCESS) ] = -1, - [ C(RESULT_MISS) ] = -1, - }, - [ C(OP_PREFETCH) ] = { - [ C(RESULT_ACCESS) ] = -1, - [ C(RESULT_MISS) ] = -1, - }, - }, }; -/* - * Because of Netburst being quite restricted in how many - * identical events may run simultaneously, we introduce event aliases, - * ie the different events which have the same functionality but - * utilize non-intersected resources (ESCR/CCCR/counter registers). - * - * This allow us to relax restrictions a bit and run two or more - * identical events together. - * - * Never set any custom internal bits such as P4_CONFIG_HT, - * P4_CONFIG_ALIASABLE or bits for P4_PEBS_METRIC, they are - * either up to date automatically or not applicable at all. - */ -struct p4_event_alias { - u64 original; - u64 alternative; -} p4_event_aliases[] = { - { - /* - * Non-halted cycles can be substituted with non-sleeping cycles (see - * Intel SDM Vol3b for details). We need this alias to be able - * to run nmi-watchdog and 'perf top' (or any other user space tool - * which is interested in running PERF_COUNT_HW_CPU_CYCLES) - * simultaneously. - */ - .original = - p4_config_pack_escr(P4_ESCR_EVENT(P4_EVENT_GLOBAL_POWER_EVENTS) | - P4_ESCR_EMASK_BIT(P4_EVENT_GLOBAL_POWER_EVENTS, RUNNING)), - .alternative = - p4_config_pack_escr(P4_ESCR_EVENT(P4_EVENT_EXECUTION_EVENT) | - P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, NBOGUS0)| - P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, NBOGUS1)| - P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, NBOGUS2)| - P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, NBOGUS3)| - P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, BOGUS0) | - P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, BOGUS1) | - P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, BOGUS2) | - P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, BOGUS3))| - p4_config_pack_cccr(P4_CCCR_THRESHOLD(15) | P4_CCCR_COMPLEMENT | - P4_CCCR_COMPARE), - }, -}; - -static u64 p4_get_alias_event(u64 config) -{ - u64 config_match; - int i; - - /* - * Only event with special mark is allowed, - * we're to be sure it didn't come as malformed - * RAW event. - */ - if (!(config & P4_CONFIG_ALIASABLE)) - return 0; - - config_match = config & P4_CONFIG_EVENT_ALIAS_MASK; - - for (i = 0; i < ARRAY_SIZE(p4_event_aliases); i++) { - if (config_match == p4_event_aliases[i].original) { - config_match = p4_event_aliases[i].alternative; - break; - } else if (config_match == p4_event_aliases[i].alternative) { - config_match = p4_event_aliases[i].original; - break; - } - } - - if (i >= ARRAY_SIZE(p4_event_aliases)) - return 0; - - return config_match | (config & P4_CONFIG_EVENT_ALIAS_IMMUTABLE_BITS); -} - static u64 p4_general_events[PERF_COUNT_HW_MAX] = { /* non-halted CPU clocks */ [PERF_COUNT_HW_CPU_CYCLES] = p4_config_pack_escr(P4_ESCR_EVENT(P4_EVENT_GLOBAL_POWER_EVENTS) | - P4_ESCR_EMASK_BIT(P4_EVENT_GLOBAL_POWER_EVENTS, RUNNING)) | - P4_CONFIG_ALIASABLE, + P4_ESCR_EMASK_BIT(P4_EVENT_GLOBAL_POWER_EVENTS, RUNNING)), /* * retired instructions @@ -1034,7 +945,7 @@ static int p4_pmu_handle_irq(struct pt_regs *regs) if (!x86_perf_event_set_period(event)) continue; - if (perf_event_overflow(event, &data, regs)) + if (perf_event_overflow(event, 1, &data, regs)) x86_pmu_stop(event, 0); } @@ -1209,8 +1120,6 @@ static int p4_pmu_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign struct p4_event_bind *bind; unsigned int i, thread, num; int cntr_idx, escr_idx; - u64 config_alias; - int pass; bitmap_zero(used_mask, X86_PMC_IDX_MAX); bitmap_zero(escr_mask, P4_ESCR_MSR_TABLE_SIZE); @@ -1219,17 +1128,6 @@ static int p4_pmu_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign hwc = &cpuc->event_list[i]->hw; thread = p4_ht_thread(cpu); - pass = 0; - -again: - /* - * It's possible to hit a circular lock - * between original and alternative events - * if both are scheduled already. - */ - if (pass > 2) - goto done; - bind = p4_config_get_bind(hwc->config); escr_idx = p4_get_escr_idx(bind->escr_msr[thread]); if (unlikely(escr_idx == -1)) @@ -1243,17 +1141,8 @@ static int p4_pmu_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign } cntr_idx = p4_next_cntr(thread, used_mask, bind); - if (cntr_idx == -1 || test_bit(escr_idx, escr_mask)) { - /* - * Check whether an event alias is still available. - */ - config_alias = p4_get_alias_event(hwc->config); - if (!config_alias) - goto done; - hwc->config = config_alias; - pass++; - goto again; - } + if (cntr_idx == -1 || test_bit(escr_idx, escr_mask)) + goto done; p4_pmu_swap_config_ts(hwc, cpu); if (assign) diff --git a/trunk/arch/x86/kernel/dumpstack_64.c b/trunk/arch/x86/kernel/dumpstack_64.c index 19853ad8afc5..e71c98d3c0d2 100644 --- a/trunk/arch/x86/kernel/dumpstack_64.c +++ b/trunk/arch/x86/kernel/dumpstack_64.c @@ -104,6 +104,34 @@ in_irq_stack(unsigned long *stack, unsigned long *irq_stack, return (stack >= irq_stack && stack < irq_stack_end); } +/* + * We are returning from the irq stack and go to the previous one. + * If the previous stack is also in the irq stack, then bp in the first + * frame of the irq stack points to the previous, interrupted one. + * Otherwise we have another level of indirection: We first save + * the bp of the previous stack, then we switch the stack to the irq one + * and save a new bp that links to the previous one. + * (See save_args()) + */ +static inline unsigned long +fixup_bp_irq_link(unsigned long bp, unsigned long *stack, + unsigned long *irq_stack, unsigned long *irq_stack_end) +{ +#ifdef CONFIG_FRAME_POINTER + struct stack_frame *frame = (struct stack_frame *)bp; + unsigned long next; + + if (!in_irq_stack(stack, irq_stack, irq_stack_end)) { + if (!probe_kernel_address(&frame->next_frame, next)) + return next; + else + WARN_ONCE(1, "Perf: bad frame pointer = %p in " + "callchain\n", &frame->next_frame); + } +#endif + return bp; +} + /* * x86-64 can have up to three kernel stacks: * process stack @@ -127,12 +155,9 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, task = current; if (!stack) { - if (regs) - stack = (unsigned long *)regs->sp; - else if (task && task != current) + stack = &dummy; + if (task && task != current) stack = (unsigned long *)task->thread.sp; - else - stack = &dummy; } if (!bp) @@ -180,6 +205,8 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, * pointer (index -1 to end) in the IRQ stack: */ stack = (unsigned long *) (irq_stack_end[-1]); + bp = fixup_bp_irq_link(bp, stack, irq_stack, + irq_stack_end); irq_stack_end = NULL; ops->stack(data, "EOI"); continue; diff --git a/trunk/arch/x86/kernel/entry_64.S b/trunk/arch/x86/kernel/entry_64.S index e13329d800c8..8a445a0c989e 100644 --- a/trunk/arch/x86/kernel/entry_64.S +++ b/trunk/arch/x86/kernel/entry_64.S @@ -9,8 +9,6 @@ /* * entry.S contains the system-call and fault low-level handling routines. * - * Some of this is documented in Documentation/x86/entry_64.txt - * * NOTE: This code handles signal-recognition, which happens every time * after an interrupt and after each system call. * @@ -299,26 +297,27 @@ ENDPROC(native_usergs_sysret64) .endm /* save partial stack frame */ - .macro SAVE_ARGS_IRQ + .pushsection .kprobes.text, "ax" +ENTRY(save_args) + XCPT_FRAME cld - /* start from rbp in pt_regs and jump over */ - movq_cfi rdi, RDI-RBP - movq_cfi rsi, RSI-RBP - movq_cfi rdx, RDX-RBP - movq_cfi rcx, RCX-RBP - movq_cfi rax, RAX-RBP - movq_cfi r8, R8-RBP - movq_cfi r9, R9-RBP - movq_cfi r10, R10-RBP - movq_cfi r11, R11-RBP - - /* Save rbp so that we can unwind from get_irq_regs() */ - movq_cfi rbp, 0 - - /* Save previous stack value */ - movq %rsp, %rsi - - leaq -RBP(%rsp),%rdi /* arg1 for handler */ + /* + * start from rbp in pt_regs and jump over + * return address. + */ + movq_cfi rdi, RDI+8-RBP + movq_cfi rsi, RSI+8-RBP + movq_cfi rdx, RDX+8-RBP + movq_cfi rcx, RCX+8-RBP + movq_cfi rax, RAX+8-RBP + movq_cfi r8, R8+8-RBP + movq_cfi r9, R9+8-RBP + movq_cfi r10, R10+8-RBP + movq_cfi r11, R11+8-RBP + + leaq -RBP+8(%rsp),%rdi /* arg1 for handler */ + movq_cfi rbp, 8 /* push %rbp */ + leaq 8(%rsp), %rbp /* mov %rsp, %ebp */ testl $3, CS(%rdi) je 1f SWAPGS @@ -330,14 +329,19 @@ ENDPROC(native_usergs_sysret64) */ 1: incl PER_CPU_VAR(irq_count) jne 2f + popq_cfi %rax /* move return address... */ mov PER_CPU_VAR(irq_stack_ptr),%rsp EMPTY_FRAME 0 - -2: /* Store previous stack value */ - pushq %rsi - /* We entered an interrupt context - irqs are off: */ - TRACE_IRQS_OFF - .endm + pushq_cfi %rbp /* backlink for unwinder */ + pushq_cfi %rax /* ... to the new stack */ + /* + * We entered an interrupt context - irqs are off: + */ +2: TRACE_IRQS_OFF + ret + CFI_ENDPROC +END(save_args) + .popsection ENTRY(save_rest) PARTIAL_FRAME 1 REST_SKIP+8 @@ -469,7 +473,7 @@ ENTRY(system_call_after_swapgs) * and short: */ ENABLE_INTERRUPTS(CLBR_NONE) - SAVE_ARGS 8,0 + SAVE_ARGS 8,1 movq %rax,ORIG_RAX-ARGOFFSET(%rsp) movq %rcx,RIP-ARGOFFSET(%rsp) CFI_REL_OFFSET rip,RIP-ARGOFFSET @@ -504,7 +508,7 @@ sysret_check: TRACE_IRQS_ON movq RIP-ARGOFFSET(%rsp),%rcx CFI_REGISTER rip,rcx - RESTORE_ARGS 1,-ARG_SKIP,0 + RESTORE_ARGS 0,-ARG_SKIP,1 /*CFI_REGISTER rflags,r11*/ movq PER_CPU_VAR(old_rsp), %rsp USERGS_SYSRET64 @@ -787,7 +791,7 @@ END(interrupt) /* reserve pt_regs for scratch regs and rbp */ subq $ORIG_RAX-RBP, %rsp CFI_ADJUST_CFA_OFFSET ORIG_RAX-RBP - SAVE_ARGS_IRQ + call save_args PARTIAL_FRAME 0 call \func .endm @@ -810,14 +814,15 @@ ret_from_intr: DISABLE_INTERRUPTS(CLBR_NONE) TRACE_IRQS_OFF decl PER_CPU_VAR(irq_count) + leaveq - /* Restore saved previous stack */ - popq %rsi - leaq 16(%rsi), %rsp - + CFI_RESTORE rbp CFI_DEF_CFA_REGISTER rsp - CFI_ADJUST_CFA_OFFSET -16 + CFI_ADJUST_CFA_OFFSET -8 + /* we did not save rbx, restore only from ARGOFFSET */ + addq $8, %rsp + CFI_ADJUST_CFA_OFFSET -8 exit_intr: GET_THREAD_INFO(%rcx) testl $3,CS-ARGOFFSET(%rsp) @@ -853,7 +858,7 @@ retint_restore_args: /* return to kernel space */ */ TRACE_IRQS_IRETQ restore_args: - RESTORE_ARGS 1,8,1 + RESTORE_ARGS 0,8,0 irq_return: INTERRUPT_RETURN @@ -986,6 +991,11 @@ apicinterrupt THRESHOLD_APIC_VECTOR \ apicinterrupt THERMAL_APIC_VECTOR \ thermal_interrupt smp_thermal_interrupt +#ifdef CONFIG_X86_MCE +apicinterrupt MCE_SELF_VECTOR \ + mce_self_interrupt smp_mce_self_interrupt +#endif + #ifdef CONFIG_SMP apicinterrupt CALL_FUNCTION_SINGLE_VECTOR \ call_function_single_interrupt smp_call_function_single_interrupt @@ -1111,8 +1121,6 @@ zeroentry spurious_interrupt_bug do_spurious_interrupt_bug zeroentry coprocessor_error do_coprocessor_error errorentry alignment_check do_alignment_check zeroentry simd_coprocessor_error do_simd_coprocessor_error -zeroentry emulate_vsyscall do_emulate_vsyscall - /* Reload gs selector with exception handling */ /* edi: new selector */ diff --git a/trunk/arch/x86/kernel/hpet.c b/trunk/arch/x86/kernel/hpet.c index 4aecc54236a9..6781765b3a0d 100644 --- a/trunk/arch/x86/kernel/hpet.c +++ b/trunk/arch/x86/kernel/hpet.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -13,8 +12,8 @@ #include #include +#include #include -#include #define HPET_MASK CLOCKSOURCE_MASK(32) @@ -72,7 +71,7 @@ static inline void hpet_set_mapping(void) { hpet_virt_address = ioremap_nocache(hpet_address, HPET_MMAP_SIZE); #ifdef CONFIG_X86_64 - __set_fixmap(VSYSCALL_HPET, hpet_address, PAGE_KERNEL_VVAR_NOCACHE); + __set_fixmap(VSYSCALL_HPET, hpet_address, PAGE_KERNEL_VSYSCALL_NOCACHE); #endif } @@ -739,6 +738,13 @@ static cycle_t read_hpet(struct clocksource *cs) return (cycle_t)hpet_readl(HPET_COUNTER); } +#ifdef CONFIG_X86_64 +static cycle_t __vsyscall_fn vread_hpet(void) +{ + return readl((const void __iomem *)fix_to_virt(VSYSCALL_HPET) + 0xf0); +} +#endif + static struct clocksource clocksource_hpet = { .name = "hpet", .rating = 250, @@ -747,7 +753,7 @@ static struct clocksource clocksource_hpet = { .flags = CLOCK_SOURCE_IS_CONTINUOUS, .resume = hpet_resume_counter, #ifdef CONFIG_X86_64 - .archdata = { .vclock_mode = VCLOCK_HPET }, + .vread = vread_hpet, #endif }; diff --git a/trunk/arch/x86/kernel/i8253.c b/trunk/arch/x86/kernel/i8253.c index f2b96de3c7c1..fb66dc9e36cb 100644 --- a/trunk/arch/x86/kernel/i8253.c +++ b/trunk/arch/x86/kernel/i8253.c @@ -3,24 +3,113 @@ * */ #include +#include +#include +#include #include #include -#include +#include +#include +#include +#include #include -#include #include +DEFINE_RAW_SPINLOCK(i8253_lock); +EXPORT_SYMBOL(i8253_lock); + /* * HPET replaces the PIT, when enabled. So we need to know, which of * the two timers is used */ struct clock_event_device *global_clock_event; +/* + * Initialize the PIT timer. + * + * This is also called after resume to bring the PIT into operation again. + */ +static void init_pit_timer(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + raw_spin_lock(&i8253_lock); + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + /* binary, mode 2, LSB/MSB, ch 0 */ + outb_pit(0x34, PIT_MODE); + outb_pit(LATCH & 0xff , PIT_CH0); /* LSB */ + outb_pit(LATCH >> 8 , PIT_CH0); /* MSB */ + break; + + case CLOCK_EVT_MODE_SHUTDOWN: + case CLOCK_EVT_MODE_UNUSED: + if (evt->mode == CLOCK_EVT_MODE_PERIODIC || + evt->mode == CLOCK_EVT_MODE_ONESHOT) { + outb_pit(0x30, PIT_MODE); + outb_pit(0, PIT_CH0); + outb_pit(0, PIT_CH0); + } + break; + + case CLOCK_EVT_MODE_ONESHOT: + /* One shot setup */ + outb_pit(0x38, PIT_MODE); + break; + + case CLOCK_EVT_MODE_RESUME: + /* Nothing to do here */ + break; + } + raw_spin_unlock(&i8253_lock); +} + +/* + * Program the next event in oneshot mode + * + * Delta is given in PIT ticks + */ +static int pit_next_event(unsigned long delta, struct clock_event_device *evt) +{ + raw_spin_lock(&i8253_lock); + outb_pit(delta & 0xff , PIT_CH0); /* LSB */ + outb_pit(delta >> 8 , PIT_CH0); /* MSB */ + raw_spin_unlock(&i8253_lock); + + return 0; +} + +/* + * On UP the PIT can serve all of the possible timer functions. On SMP systems + * it can be solely used for the global tick. + * + * The profiling and update capabilities are switched off once the local apic is + * registered. This mechanism replaces the previous #ifdef LOCAL_APIC - + * !using_apic_timer decisions in do_timer_interrupt_hook() + */ +static struct clock_event_device pit_ce = { + .name = "pit", + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .set_mode = init_pit_timer, + .set_next_event = pit_next_event, + .irq = 0, +}; + +/* + * Initialize the conversion factor and the min/max deltas of the clock event + * structure and register the clock event source with the framework. + */ void __init setup_pit_timer(void) { - clockevent_i8253_init(true); - global_clock_event = &i8253_clockevent; + /* + * Start pit with the boot cpu mask and make it global after the + * IO_APIC has been initialized. + */ + pit_ce.cpumask = cpumask_of(smp_processor_id()); + + clockevents_config_and_register(&pit_ce, CLOCK_TICK_RATE, 0xF, 0x7FFF); + global_clock_event = &pit_ce; } #ifndef CONFIG_X86_64 @@ -34,7 +123,7 @@ static int __init init_pit_clocksource(void) * - when local APIC timer is active (PIT is switched off) */ if (num_possible_cpus() > 1 || is_hpet_enabled() || - i8253_clockevent.mode != CLOCK_EVT_MODE_PERIODIC) + pit_ce.mode != CLOCK_EVT_MODE_PERIODIC) return 0; return clocksource_i8253_init(); diff --git a/trunk/arch/x86/kernel/irqinit.c b/trunk/arch/x86/kernel/irqinit.c index f09d4bbe2d2d..f470e4ef993e 100644 --- a/trunk/arch/x86/kernel/irqinit.c +++ b/trunk/arch/x86/kernel/irqinit.c @@ -272,6 +272,9 @@ static void __init apic_intr_init(void) #ifdef CONFIG_X86_MCE_THRESHOLD alloc_intr_gate(THRESHOLD_APIC_VECTOR, threshold_interrupt); #endif +#if defined(CONFIG_X86_MCE) && defined(CONFIG_X86_LOCAL_APIC) + alloc_intr_gate(MCE_SELF_VECTOR, mce_self_interrupt); +#endif #if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC) /* self generated IPI for local APIC timer */ diff --git a/trunk/arch/x86/kernel/kgdb.c b/trunk/arch/x86/kernel/kgdb.c index 00354d4919a9..5f9ecff328b5 100644 --- a/trunk/arch/x86/kernel/kgdb.c +++ b/trunk/arch/x86/kernel/kgdb.c @@ -608,7 +608,7 @@ int kgdb_arch_init(void) return register_die_notifier(&kgdb_notifier); } -static void kgdb_hw_overflow_handler(struct perf_event *event, +static void kgdb_hw_overflow_handler(struct perf_event *event, int nmi, struct perf_sample_data *data, struct pt_regs *regs) { struct task_struct *tsk = current; @@ -638,7 +638,7 @@ void kgdb_arch_late(void) for (i = 0; i < HBP_NUM; i++) { if (breakinfo[i].pev) continue; - breakinfo[i].pev = register_wide_hw_breakpoint(&attr, NULL, NULL); + breakinfo[i].pev = register_wide_hw_breakpoint(&attr, NULL); if (IS_ERR((void * __force)breakinfo[i].pev)) { printk(KERN_ERR "kgdb: Could not allocate hw" "breakpoints\nDisabling the kernel debugger\n"); diff --git a/trunk/arch/x86/kernel/kvm.c b/trunk/arch/x86/kernel/kvm.c index a9c2116001d6..33c07b0b122e 100644 --- a/trunk/arch/x86/kernel/kvm.c +++ b/trunk/arch/x86/kernel/kvm.c @@ -51,15 +51,6 @@ static int parse_no_kvmapf(char *arg) early_param("no-kvmapf", parse_no_kvmapf); -static int steal_acc = 1; -static int parse_no_stealacc(char *arg) -{ - steal_acc = 0; - return 0; -} - -early_param("no-steal-acc", parse_no_stealacc); - struct kvm_para_state { u8 mmu_queue[MMU_QUEUE_SIZE]; int mmu_queue_len; @@ -67,8 +58,6 @@ struct kvm_para_state { static DEFINE_PER_CPU(struct kvm_para_state, para_state); static DEFINE_PER_CPU(struct kvm_vcpu_pv_apf_data, apf_reason) __aligned(64); -static DEFINE_PER_CPU(struct kvm_steal_time, steal_time) __aligned(64); -static int has_steal_clock = 0; static struct kvm_para_state *kvm_para_state(void) { @@ -452,21 +441,6 @@ static void __init paravirt_ops_setup(void) #endif } -static void kvm_register_steal_time(void) -{ - int cpu = smp_processor_id(); - struct kvm_steal_time *st = &per_cpu(steal_time, cpu); - - if (!has_steal_clock) - return; - - memset(st, 0, sizeof(*st)); - - wrmsrl(MSR_KVM_STEAL_TIME, (__pa(st) | KVM_MSR_ENABLED)); - printk(KERN_INFO "kvm-stealtime: cpu %d, msr %lx\n", - cpu, __pa(st)); -} - void __cpuinit kvm_guest_cpu_init(void) { if (!kvm_para_available()) @@ -483,9 +457,6 @@ void __cpuinit kvm_guest_cpu_init(void) printk(KERN_INFO"KVM setup async PF for cpu %d\n", smp_processor_id()); } - - if (has_steal_clock) - kvm_register_steal_time(); } static void kvm_pv_disable_apf(void *unused) @@ -512,31 +483,6 @@ static struct notifier_block kvm_pv_reboot_nb = { .notifier_call = kvm_pv_reboot_notify, }; -static u64 kvm_steal_clock(int cpu) -{ - u64 steal; - struct kvm_steal_time *src; - int version; - - src = &per_cpu(steal_time, cpu); - do { - version = src->version; - rmb(); - steal = src->steal; - rmb(); - } while ((version & 1) || (version != src->version)); - - return steal; -} - -void kvm_disable_steal_time(void) -{ - if (!has_steal_clock) - return; - - wrmsr(MSR_KVM_STEAL_TIME, 0, 0); -} - #ifdef CONFIG_SMP static void __init kvm_smp_prepare_boot_cpu(void) { @@ -554,7 +500,6 @@ static void __cpuinit kvm_guest_cpu_online(void *dummy) static void kvm_guest_cpu_offline(void *dummy) { - kvm_disable_steal_time(); kvm_pv_disable_apf(NULL); apf_task_wake_all(); } @@ -603,11 +548,6 @@ void __init kvm_guest_init(void) if (kvm_para_has_feature(KVM_FEATURE_ASYNC_PF)) x86_init.irqs.trap_init = kvm_apf_trap_init; - if (kvm_para_has_feature(KVM_FEATURE_STEAL_TIME)) { - has_steal_clock = 1; - pv_time_ops.steal_clock = kvm_steal_clock; - } - #ifdef CONFIG_SMP smp_ops.smp_prepare_boot_cpu = kvm_smp_prepare_boot_cpu; register_cpu_notifier(&kvm_cpu_notifier); @@ -615,15 +555,3 @@ void __init kvm_guest_init(void) kvm_guest_cpu_init(); #endif } - -static __init int activate_jump_labels(void) -{ - if (has_steal_clock) { - jump_label_inc(¶virt_steal_enabled); - if (steal_acc) - jump_label_inc(¶virt_steal_rq_enabled); - } - - return 0; -} -arch_initcall(activate_jump_labels); diff --git a/trunk/arch/x86/kernel/kvmclock.c b/trunk/arch/x86/kernel/kvmclock.c index c1a0188e29ae..6389a6bca11b 100644 --- a/trunk/arch/x86/kernel/kvmclock.c +++ b/trunk/arch/x86/kernel/kvmclock.c @@ -160,7 +160,6 @@ static void __cpuinit kvm_setup_secondary_clock(void) static void kvm_crash_shutdown(struct pt_regs *regs) { native_write_msr(msr_kvm_system_time, 0, 0); - kvm_disable_steal_time(); native_machine_crash_shutdown(regs); } #endif @@ -168,7 +167,6 @@ static void kvm_crash_shutdown(struct pt_regs *regs) static void kvm_shutdown(void) { native_write_msr(msr_kvm_system_time, 0, 0); - kvm_disable_steal_time(); native_machine_shutdown(); } diff --git a/trunk/arch/x86/kernel/microcode_amd.c b/trunk/arch/x86/kernel/microcode_amd.c index 591be0ee1934..c5610384ab16 100644 --- a/trunk/arch/x86/kernel/microcode_amd.c +++ b/trunk/arch/x86/kernel/microcode_amd.c @@ -66,8 +66,8 @@ struct microcode_amd { unsigned int mpb[0]; }; -#define SECTION_HDR_SIZE 8 -#define CONTAINER_HDR_SZ 12 +#define UCODE_CONTAINER_SECTION_HDR 8 +#define UCODE_CONTAINER_HEADER_SIZE 12 static struct equiv_cpu_entry *equiv_cpu_table; @@ -157,7 +157,7 @@ static int apply_microcode_amd(int cpu) static unsigned int verify_ucode_size(int cpu, const u8 *buf, unsigned int size) { struct cpuinfo_x86 *c = &cpu_data(cpu); - u32 max_size, actual_size; + unsigned int max_size, actual_size; #define F1XH_MPB_MAX_SIZE 2048 #define F14H_MPB_MAX_SIZE 1824 @@ -175,9 +175,9 @@ static unsigned int verify_ucode_size(int cpu, const u8 *buf, unsigned int size) break; } - actual_size = *(u32 *)(buf + 4); + actual_size = buf[4] + (buf[5] << 8); - if (actual_size + SECTION_HDR_SIZE > size || actual_size > max_size) { + if (actual_size > size || actual_size > max_size) { pr_err("section size mismatch\n"); return 0; } @@ -191,7 +191,7 @@ get_next_ucode(int cpu, const u8 *buf, unsigned int size, unsigned int *mc_size) struct microcode_header_amd *mc = NULL; unsigned int actual_size = 0; - if (*(u32 *)buf != UCODE_UCODE_TYPE) { + if (buf[0] != UCODE_UCODE_TYPE) { pr_err("invalid type field in container file section header\n"); goto out; } @@ -204,8 +204,8 @@ get_next_ucode(int cpu, const u8 *buf, unsigned int size, unsigned int *mc_size) if (!mc) goto out; - get_ucode_data(mc, buf + SECTION_HDR_SIZE, actual_size); - *mc_size = actual_size + SECTION_HDR_SIZE; + get_ucode_data(mc, buf + UCODE_CONTAINER_SECTION_HDR, actual_size); + *mc_size = actual_size + UCODE_CONTAINER_SECTION_HDR; out: return mc; @@ -229,10 +229,9 @@ static int install_equiv_cpu_table(const u8 *buf) return -ENOMEM; } - get_ucode_data(equiv_cpu_table, buf + CONTAINER_HDR_SZ, size); + get_ucode_data(equiv_cpu_table, buf + UCODE_CONTAINER_HEADER_SIZE, size); - /* add header length */ - return size + CONTAINER_HDR_SZ; + return size + UCODE_CONTAINER_HEADER_SIZE; /* add header length */ } static void free_equiv_cpu_table(void) diff --git a/trunk/arch/x86/kernel/module.c b/trunk/arch/x86/kernel/module.c index 925179f871de..52f256f2cc81 100644 --- a/trunk/arch/x86/kernel/module.c +++ b/trunk/arch/x86/kernel/module.c @@ -45,6 +45,21 @@ void *module_alloc(unsigned long size) -1, __builtin_return_address(0)); } +/* Free memory returned from module_alloc */ +void module_free(struct module *mod, void *module_region) +{ + vfree(module_region); +} + +/* We don't need anything special. */ +int module_frob_arch_sections(Elf_Ehdr *hdr, + Elf_Shdr *sechdrs, + char *secstrings, + struct module *mod) +{ + return 0; +} + #ifdef CONFIG_X86_32 int apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, @@ -85,6 +100,17 @@ int apply_relocate(Elf32_Shdr *sechdrs, } return 0; } + +int apply_relocate_add(Elf32_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *me) +{ + printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n", + me->name); + return -ENOEXEC; +} #else /*X86_64*/ int apply_relocate_add(Elf64_Shdr *sechdrs, const char *strtab, @@ -155,6 +181,17 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, me->name); return -ENOEXEC; } + +int apply_relocate(Elf_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *me) +{ + printk(KERN_ERR "non add relocation not supported\n"); + return -ENOSYS; +} + #endif int module_finalize(const Elf_Ehdr *hdr, diff --git a/trunk/arch/x86/kernel/paravirt.c b/trunk/arch/x86/kernel/paravirt.c index 613a7931ecc1..869e1aeeb71b 100644 --- a/trunk/arch/x86/kernel/paravirt.c +++ b/trunk/arch/x86/kernel/paravirt.c @@ -202,14 +202,6 @@ static void native_flush_tlb_single(unsigned long addr) __native_flush_tlb_single(addr); } -struct jump_label_key paravirt_steal_enabled; -struct jump_label_key paravirt_steal_rq_enabled; - -static u64 native_steal_clock(int cpu) -{ - return 0; -} - /* These are in entry.S */ extern void native_iret(void); extern void native_irq_enable_sysexit(void); @@ -315,7 +307,6 @@ struct pv_init_ops pv_init_ops = { struct pv_time_ops pv_time_ops = { .sched_clock = native_sched_clock, - .steal_clock = native_steal_clock, }; struct pv_irq_ops pv_irq_ops = { diff --git a/trunk/arch/x86/kernel/ptrace.c b/trunk/arch/x86/kernel/ptrace.c index 82528799c5de..807c2a2b80f1 100644 --- a/trunk/arch/x86/kernel/ptrace.c +++ b/trunk/arch/x86/kernel/ptrace.c @@ -528,7 +528,7 @@ static int genregs_set(struct task_struct *target, return ret; } -static void ptrace_triggered(struct perf_event *bp, +static void ptrace_triggered(struct perf_event *bp, int nmi, struct perf_sample_data *data, struct pt_regs *regs) { @@ -715,8 +715,7 @@ static int ptrace_set_breakpoint_addr(struct task_struct *tsk, int nr, attr.bp_type = HW_BREAKPOINT_W; attr.disabled = 1; - bp = register_user_hw_breakpoint(&attr, ptrace_triggered, - NULL, tsk); + bp = register_user_hw_breakpoint(&attr, ptrace_triggered, tsk); /* * CHECKME: the previous code returned -EIO if the addr wasn't diff --git a/trunk/arch/x86/kernel/quirks.c b/trunk/arch/x86/kernel/quirks.c index b78643d0f9a5..8bbe8c56916d 100644 --- a/trunk/arch/x86/kernel/quirks.c +++ b/trunk/arch/x86/kernel/quirks.c @@ -10,7 +10,7 @@ static void __devinit quirk_intel_irqbalance(struct pci_dev *dev) { - u8 config; + u8 config, rev; u16 word; /* BIOS may enable hardware IRQ balancing for @@ -18,7 +18,8 @@ static void __devinit quirk_intel_irqbalance(struct pci_dev *dev) * based platforms. * Disable SW irqbalance/affinity on those platforms. */ - if (dev->revision > 0x9) + pci_read_config_byte(dev, PCI_CLASS_REVISION, &rev); + if (rev > 0x9) return; /* enable access to config space*/ diff --git a/trunk/arch/x86/kernel/relocate_kernel_32.S b/trunk/arch/x86/kernel/relocate_kernel_32.S index 36818f8ec2be..41235531b11c 100644 --- a/trunk/arch/x86/kernel/relocate_kernel_32.S +++ b/trunk/arch/x86/kernel/relocate_kernel_32.S @@ -97,8 +97,6 @@ relocate_kernel: ret identity_mapped: - /* set return address to 0 if not preserving context */ - pushl $0 /* store the start address on the stack */ pushl %edx diff --git a/trunk/arch/x86/kernel/relocate_kernel_64.S b/trunk/arch/x86/kernel/relocate_kernel_64.S index 7a6f3b3be3cf..4de8f5b3d476 100644 --- a/trunk/arch/x86/kernel/relocate_kernel_64.S +++ b/trunk/arch/x86/kernel/relocate_kernel_64.S @@ -100,8 +100,6 @@ relocate_kernel: ret identity_mapped: - /* set return address to 0 if not preserving context */ - pushq $0 /* store the start address on the stack */ pushq %rdx diff --git a/trunk/arch/x86/kernel/signal.c b/trunk/arch/x86/kernel/signal.c index 54ddaeb221c1..40a24932a8a1 100644 --- a/trunk/arch/x86/kernel/signal.c +++ b/trunk/arch/x86/kernel/signal.c @@ -485,18 +485,17 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, asmlinkage int sys_sigsuspend(int history0, int history1, old_sigset_t mask) { - sigset_t blocked; - - current->saved_sigmask = current->blocked; - mask &= _BLOCKABLE; - siginitset(&blocked, mask); - set_current_blocked(&blocked); + spin_lock_irq(¤t->sighand->siglock); + current->saved_sigmask = current->blocked; + siginitset(¤t->blocked, mask); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); current->state = TASK_INTERRUPTIBLE; schedule(); - set_restore_sigmask(); + return -ERESTARTNOHAND; } @@ -573,7 +572,10 @@ unsigned long sys_sigreturn(struct pt_regs *regs) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); - set_current_blocked(&set); + spin_lock_irq(¤t->sighand->siglock); + current->blocked = set; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); if (restore_sigcontext(regs, &frame->sc, &ax)) goto badframe; @@ -651,15 +653,11 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, - struct pt_regs *regs) + sigset_t *set, struct pt_regs *regs) { int usig = signr_convert(sig); - sigset_t *set = ¤t->blocked; int ret; - if (current_thread_info()->status & TS_RESTORE_SIGMASK) - set = ¤t->saved_sigmask; - /* Set up the stack frame */ if (is_ia32) { if (ka->sa.sa_flags & SA_SIGINFO) @@ -674,13 +672,12 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, return -EFAULT; } - current_thread_info()->status &= ~TS_RESTORE_SIGMASK; return ret; } static int handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, - struct pt_regs *regs) + sigset_t *oldset, struct pt_regs *regs) { sigset_t blocked; int ret; @@ -715,11 +712,20 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, likely(test_and_clear_thread_flag(TIF_FORCED_TF))) regs->flags &= ~X86_EFLAGS_TF; - ret = setup_rt_frame(sig, ka, info, regs); + ret = setup_rt_frame(sig, ka, info, oldset, regs); if (ret) return ret; +#ifdef CONFIG_X86_64 + /* + * This has nothing to do with segment registers, + * despite the name. This magic affects uaccess.h + * macros' behavior. Reset it to the normal setting. + */ + set_fs(USER_DS); +#endif + /* * Clear the direction flag as per the ABI for function entry. */ @@ -761,6 +767,7 @@ static void do_signal(struct pt_regs *regs) struct k_sigaction ka; siginfo_t info; int signr; + sigset_t *oldset; /* * We want the common case to go fast, which is why we may in certain @@ -772,10 +779,23 @@ static void do_signal(struct pt_regs *regs) if (!user_mode(regs)) return; + if (current_thread_info()->status & TS_RESTORE_SIGMASK) + oldset = ¤t->saved_sigmask; + else + oldset = ¤t->blocked; + signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (signr > 0) { /* Whee! Actually deliver the signal. */ - handle_signal(signr, &info, &ka, regs); + if (handle_signal(signr, &info, &ka, oldset, regs) == 0) { + /* + * A signal was successfully delivered; the saved + * sigmask will have been stored in the signal frame, + * and will be restored by sigreturn, so we can simply + * clear the TS_RESTORE_SIGMASK flag. + */ + current_thread_info()->status &= ~TS_RESTORE_SIGMASK; + } return; } @@ -803,7 +823,7 @@ static void do_signal(struct pt_regs *regs) */ if (current_thread_info()->status & TS_RESTORE_SIGMASK) { current_thread_info()->status &= ~TS_RESTORE_SIGMASK; - set_current_blocked(¤t->saved_sigmask); + sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); } } diff --git a/trunk/arch/x86/kernel/smpboot.c b/trunk/arch/x86/kernel/smpboot.c index 9f548cb4a958..9fd3137230d4 100644 --- a/trunk/arch/x86/kernel/smpboot.c +++ b/trunk/arch/x86/kernel/smpboot.c @@ -438,7 +438,7 @@ static void impress_friends(void) void __inquire_remote_apic(int apicid) { unsigned i, regs[] = { APIC_ID >> 4, APIC_LVR >> 4, APIC_SPIV >> 4 }; - const char * const names[] = { "ID", "VERSION", "SPIV" }; + char *names[] = { "ID", "VERSION", "SPIV" }; int timeout; u32 status; diff --git a/trunk/arch/x86/kernel/stacktrace.c b/trunk/arch/x86/kernel/stacktrace.c index fdd0c6430e5a..55d9bc03f696 100644 --- a/trunk/arch/x86/kernel/stacktrace.c +++ b/trunk/arch/x86/kernel/stacktrace.c @@ -66,7 +66,7 @@ void save_stack_trace(struct stack_trace *trace) } EXPORT_SYMBOL_GPL(save_stack_trace); -void save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace) +void save_stack_trace_regs(struct stack_trace *trace, struct pt_regs *regs) { dump_trace(current, regs, NULL, 0, &save_stack_ops, trace); if (trace->nr_entries < trace->max_entries) diff --git a/trunk/arch/x86/kernel/time.c b/trunk/arch/x86/kernel/time.c index 5a64d057be57..00cbb272627f 100644 --- a/trunk/arch/x86/kernel/time.c +++ b/trunk/arch/x86/kernel/time.c @@ -11,13 +11,13 @@ #include #include -#include #include #include #include #include #include +#include #include #include #include diff --git a/trunk/arch/x86/kernel/traps.c b/trunk/arch/x86/kernel/traps.c index fbc097a085ca..b9b67166f9de 100644 --- a/trunk/arch/x86/kernel/traps.c +++ b/trunk/arch/x86/kernel/traps.c @@ -872,12 +872,6 @@ void __init trap_init(void) set_bit(SYSCALL_VECTOR, used_vectors); #endif -#ifdef CONFIG_X86_64 - BUG_ON(test_bit(VSYSCALL_EMU_VECTOR, used_vectors)); - set_system_intr_gate(VSYSCALL_EMU_VECTOR, &emulate_vsyscall); - set_bit(VSYSCALL_EMU_VECTOR, used_vectors); -#endif - /* * Should be a barrier for any external CPU state: */ diff --git a/trunk/arch/x86/kernel/tsc.c b/trunk/arch/x86/kernel/tsc.c index db483369f10b..6cc6922262af 100644 --- a/trunk/arch/x86/kernel/tsc.c +++ b/trunk/arch/x86/kernel/tsc.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -776,7 +777,7 @@ static struct clocksource clocksource_tsc = { .flags = CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_MUST_VERIFY, #ifdef CONFIG_X86_64 - .archdata = { .vclock_mode = VCLOCK_TSC }, + .vread = vread_tsc, #endif }; @@ -799,6 +800,27 @@ void mark_tsc_unstable(char *reason) EXPORT_SYMBOL_GPL(mark_tsc_unstable); +static int __init dmi_mark_tsc_unstable(const struct dmi_system_id *d) +{ + printk(KERN_NOTICE "%s detected: marking TSC unstable.\n", + d->ident); + tsc_unstable = 1; + return 0; +} + +/* List of systems that have known TSC problems */ +static struct dmi_system_id __initdata bad_tsc_dmi_table[] = { + { + .callback = dmi_mark_tsc_unstable, + .ident = "IBM Thinkpad 380XD", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "IBM"), + DMI_MATCH(DMI_BOARD_NAME, "2635FA0"), + }, + }, + {} +}; + static void __init check_system_tsc_reliable(void) { #ifdef CONFIG_MGEODE_LX @@ -988,6 +1010,8 @@ void __init tsc_init(void) lpj_fine = lpj; use_tsc_delay(); + /* Check and install the TSC clocksource */ + dmi_check_system(bad_tsc_dmi_table); if (unsynchronized_tsc()) mark_tsc_unstable("TSCs unsynchronized"); diff --git a/trunk/arch/x86/kernel/vmlinux.lds.S b/trunk/arch/x86/kernel/vmlinux.lds.S index 4aa9c54a9b76..89aed99aafce 100644 --- a/trunk/arch/x86/kernel/vmlinux.lds.S +++ b/trunk/arch/x86/kernel/vmlinux.lds.S @@ -161,47 +161,50 @@ SECTIONS #define VVIRT_OFFSET (VSYSCALL_ADDR - __vsyscall_0) #define VVIRT(x) (ADDR(x) - VVIRT_OFFSET) +#define EMIT_VVAR(x, offset) .vsyscall_var_ ## x \ + ADDR(.vsyscall_0) + offset \ + : AT(VLOAD(.vsyscall_var_ ## x)) { \ + *(.vsyscall_var_ ## x) \ + } \ + x = VVIRT(.vsyscall_var_ ## x); . = ALIGN(4096); __vsyscall_0 = .; . = VSYSCALL_ADDR; - .vsyscall : AT(VLOAD(.vsyscall)) { + .vsyscall_0 : AT(VLOAD(.vsyscall_0)) { *(.vsyscall_0) + } :user - . = 1024; - *(.vsyscall_1) + . = ALIGN(L1_CACHE_BYTES); + .vsyscall_fn : AT(VLOAD(.vsyscall_fn)) { + *(.vsyscall_fn) + } - . = 2048; + .vsyscall_1 ADDR(.vsyscall_0) + 1024: AT(VLOAD(.vsyscall_1)) { + *(.vsyscall_1) + } + .vsyscall_2 ADDR(.vsyscall_0) + 2048: AT(VLOAD(.vsyscall_2)) { *(.vsyscall_2) + } + + .vsyscall_3 ADDR(.vsyscall_0) + 3072: AT(VLOAD(.vsyscall_3)) { + *(.vsyscall_3) + } + +#define __VVAR_KERNEL_LDS +#include +#undef __VVAR_KERNEL_LDS - . = 4096; /* Pad the whole page. */ - } :user =0xcc - . = ALIGN(__vsyscall_0 + PAGE_SIZE, PAGE_SIZE); + . = __vsyscall_0 + PAGE_SIZE; #undef VSYSCALL_ADDR #undef VLOAD_OFFSET #undef VLOAD #undef VVIRT_OFFSET #undef VVIRT - - __vvar_page = .; - - .vvar : AT(ADDR(.vvar) - LOAD_OFFSET) { - - /* Place all vvars at the offsets in asm/vvar.h. */ -#define EMIT_VVAR(name, offset) \ - . = offset; \ - *(.vvar_ ## name) -#define __VVAR_KERNEL_LDS -#include -#undef __VVAR_KERNEL_LDS #undef EMIT_VVAR - } :data - - . = ALIGN(__vvar_page + PAGE_SIZE, PAGE_SIZE); - #endif /* CONFIG_X86_64 */ /* Init code and data - will be freed after init */ diff --git a/trunk/arch/x86/kernel/vread_tsc_64.c b/trunk/arch/x86/kernel/vread_tsc_64.c new file mode 100644 index 000000000000..a81aa9e9894c --- /dev/null +++ b/trunk/arch/x86/kernel/vread_tsc_64.c @@ -0,0 +1,36 @@ +/* This code runs in userspace. */ + +#define DISABLE_BRANCH_PROFILING +#include + +notrace cycle_t __vsyscall_fn vread_tsc(void) +{ + cycle_t ret; + u64 last; + + /* + * Empirically, a fence (of type that depends on the CPU) + * before rdtsc is enough to ensure that rdtsc is ordered + * with respect to loads. The various CPU manuals are unclear + * as to whether rdtsc can be reordered with later loads, + * but no one has ever seen it happen. + */ + rdtsc_barrier(); + ret = (cycle_t)vget_cycles(); + + last = VVAR(vsyscall_gtod_data).clock.cycle_last; + + if (likely(ret >= last)) + return ret; + + /* + * GCC likes to generate cmov here, but this branch is extremely + * predictable (it's just a funciton of time and the likely is + * very likely) and there's a data dependence, so force GCC + * to generate a branch instead. I don't barrier() because + * we don't actually need a barrier, and if this function + * ever gets inlined it will generate worse code. + */ + asm volatile (""); + return last; +} diff --git a/trunk/arch/x86/kernel/vsyscall_64.c b/trunk/arch/x86/kernel/vsyscall_64.c index dda7dff9cef7..3e682184d76c 100644 --- a/trunk/arch/x86/kernel/vsyscall_64.c +++ b/trunk/arch/x86/kernel/vsyscall_64.c @@ -2,8 +2,6 @@ * Copyright (C) 2001 Andrea Arcangeli SuSE * Copyright 2003 Andi Kleen, SuSE Labs. * - * [ NOTE: this mechanism is now deprecated in favor of the vDSO. ] - * * Thanks to hpa@transmeta.com for some useful hint. * Special thanks to Ingo Molnar for his early experience with * a different vsyscall implementation for Linux/IA32 and for the name. @@ -13,9 +11,10 @@ * vsyscalls. One vsyscall can reserve more than 1 slot to avoid * jumping out of line if necessary. We cannot add more with this * mechanism because older kernels won't return -ENOSYS. + * If we want more than four we need a vDSO. * - * Note: the concept clashes with user mode linux. UML users should - * use the vDSO. + * Note: the concept clashes with user mode linux. If you use UML and + * want per guest time just set the kernel.vsyscall64 sysctl to 0. */ /* Disable profiling for userspace code: */ @@ -33,12 +32,9 @@ #include #include #include -#include -#include #include #include -#include #include #include #include @@ -48,12 +44,16 @@ #include #include #include -#include + +#define __vsyscall(nr) \ + __attribute__ ((unused, __section__(".vsyscall_" #nr))) notrace +#define __syscall_clobber "r11","cx","memory" DEFINE_VVAR(int, vgetcpu_mode); DEFINE_VVAR(struct vsyscall_gtod_data, vsyscall_gtod_data) = { .lock = __SEQLOCK_UNLOCKED(__vsyscall_gtod_data.lock), + .sysctl_enabled = 1, }; void update_vsyscall_tz(void) @@ -72,149 +72,179 @@ void update_vsyscall(struct timespec *wall_time, struct timespec *wtm, unsigned long flags; write_seqlock_irqsave(&vsyscall_gtod_data.lock, flags); - /* copy vsyscall data */ - vsyscall_gtod_data.clock.vclock_mode = clock->archdata.vclock_mode; - vsyscall_gtod_data.clock.cycle_last = clock->cycle_last; - vsyscall_gtod_data.clock.mask = clock->mask; - vsyscall_gtod_data.clock.mult = mult; - vsyscall_gtod_data.clock.shift = clock->shift; - vsyscall_gtod_data.wall_time_sec = wall_time->tv_sec; - vsyscall_gtod_data.wall_time_nsec = wall_time->tv_nsec; - vsyscall_gtod_data.wall_to_monotonic = *wtm; - vsyscall_gtod_data.wall_time_coarse = __current_kernel_time(); - + vsyscall_gtod_data.clock.vread = clock->vread; + vsyscall_gtod_data.clock.cycle_last = clock->cycle_last; + vsyscall_gtod_data.clock.mask = clock->mask; + vsyscall_gtod_data.clock.mult = mult; + vsyscall_gtod_data.clock.shift = clock->shift; + vsyscall_gtod_data.wall_time_sec = wall_time->tv_sec; + vsyscall_gtod_data.wall_time_nsec = wall_time->tv_nsec; + vsyscall_gtod_data.wall_to_monotonic = *wtm; + vsyscall_gtod_data.wall_time_coarse = __current_kernel_time(); write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, flags); } -static void warn_bad_vsyscall(const char *level, struct pt_regs *regs, - const char *message) +/* RED-PEN may want to readd seq locking, but then the variable should be + * write-once. + */ +static __always_inline void do_get_tz(struct timezone * tz) { - static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST); - struct task_struct *tsk; + *tz = VVAR(vsyscall_gtod_data).sys_tz; +} - if (!show_unhandled_signals || !__ratelimit(&rs)) - return; +static __always_inline int gettimeofday(struct timeval *tv, struct timezone *tz) +{ + int ret; + asm volatile("syscall" + : "=a" (ret) + : "0" (__NR_gettimeofday),"D" (tv),"S" (tz) + : __syscall_clobber ); + return ret; +} - tsk = current; +static __always_inline long time_syscall(long *t) +{ + long secs; + asm volatile("syscall" + : "=a" (secs) + : "0" (__NR_time),"D" (t) : __syscall_clobber); + return secs; +} - printk("%s%s[%d] %s ip:%lx cs:%lx sp:%lx ax:%lx si:%lx di:%lx\n", - level, tsk->comm, task_pid_nr(tsk), - message, regs->ip - 2, regs->cs, - regs->sp, regs->ax, regs->si, regs->di); +static __always_inline void do_vgettimeofday(struct timeval * tv) +{ + cycle_t now, base, mask, cycle_delta; + unsigned seq; + unsigned long mult, shift, nsec; + cycle_t (*vread)(void); + do { + seq = read_seqbegin(&VVAR(vsyscall_gtod_data).lock); + + vread = VVAR(vsyscall_gtod_data).clock.vread; + if (unlikely(!VVAR(vsyscall_gtod_data).sysctl_enabled || + !vread)) { + gettimeofday(tv,NULL); + return; + } + + now = vread(); + base = VVAR(vsyscall_gtod_data).clock.cycle_last; + mask = VVAR(vsyscall_gtod_data).clock.mask; + mult = VVAR(vsyscall_gtod_data).clock.mult; + shift = VVAR(vsyscall_gtod_data).clock.shift; + + tv->tv_sec = VVAR(vsyscall_gtod_data).wall_time_sec; + nsec = VVAR(vsyscall_gtod_data).wall_time_nsec; + } while (read_seqretry(&VVAR(vsyscall_gtod_data).lock, seq)); + + /* calculate interval: */ + cycle_delta = (now - base) & mask; + /* convert to nsecs: */ + nsec += (cycle_delta * mult) >> shift; + + while (nsec >= NSEC_PER_SEC) { + tv->tv_sec += 1; + nsec -= NSEC_PER_SEC; + } + tv->tv_usec = nsec / NSEC_PER_USEC; } -static int addr_to_vsyscall_nr(unsigned long addr) +int __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz) { - int nr; + if (tv) + do_vgettimeofday(tv); + if (tz) + do_get_tz(tz); + return 0; +} - if ((addr & ~0xC00UL) != VSYSCALL_START) - return -EINVAL; +/* This will break when the xtime seconds get inaccurate, but that is + * unlikely */ +time_t __vsyscall(1) vtime(time_t *t) +{ + unsigned seq; + time_t result; + if (unlikely(!VVAR(vsyscall_gtod_data).sysctl_enabled)) + return time_syscall(t); - nr = (addr & 0xC00UL) >> 10; - if (nr >= 3) - return -EINVAL; + do { + seq = read_seqbegin(&VVAR(vsyscall_gtod_data).lock); - return nr; -} + result = VVAR(vsyscall_gtod_data).wall_time_sec; -void dotraplinkage do_emulate_vsyscall(struct pt_regs *regs, long error_code) -{ - struct task_struct *tsk; - unsigned long caller; - int vsyscall_nr; - long ret; - - local_irq_enable(); - - /* - * Real 64-bit user mode code has cs == __USER_CS. Anything else - * is bogus. - */ - if (regs->cs != __USER_CS) { - /* - * If we trapped from kernel mode, we might as well OOPS now - * instead of returning to some random address and OOPSing - * then. - */ - BUG_ON(!user_mode(regs)); - - /* Compat mode and non-compat 32-bit CS should both segfault. */ - warn_bad_vsyscall(KERN_WARNING, regs, - "illegal int 0xcc from 32-bit mode"); - goto sigsegv; - } + } while (read_seqretry(&VVAR(vsyscall_gtod_data).lock, seq)); - /* - * x86-ism here: regs->ip points to the instruction after the int 0xcc, - * and int 0xcc is two bytes long. - */ - vsyscall_nr = addr_to_vsyscall_nr(regs->ip - 2); - if (vsyscall_nr < 0) { - warn_bad_vsyscall(KERN_WARNING, regs, - "illegal int 0xcc (exploit attempt?)"); - goto sigsegv; - } + if (t) + *t = result; + return result; +} - if (get_user(caller, (unsigned long __user *)regs->sp) != 0) { - warn_bad_vsyscall(KERN_WARNING, regs, "int 0xcc with bad stack (exploit attempt?)"); - goto sigsegv; - } +/* Fast way to get current CPU and node. + This helps to do per node and per CPU caches in user space. + The result is not guaranteed without CPU affinity, but usually + works out because the scheduler tries to keep a thread on the same + CPU. - tsk = current; - if (seccomp_mode(&tsk->seccomp)) - do_exit(SIGKILL); - - switch (vsyscall_nr) { - case 0: - ret = sys_gettimeofday( - (struct timeval __user *)regs->di, - (struct timezone __user *)regs->si); - break; - - case 1: - ret = sys_time((time_t __user *)regs->di); - break; - - case 2: - ret = sys_getcpu((unsigned __user *)regs->di, - (unsigned __user *)regs->si, - 0); - break; + tcache must point to a two element sized long array. + All arguments can be NULL. */ +long __vsyscall(2) +vgetcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache) +{ + unsigned int p; + unsigned long j = 0; + + /* Fast cache - only recompute value once per jiffies and avoid + relatively costly rdtscp/cpuid otherwise. + This works because the scheduler usually keeps the process + on the same CPU and this syscall doesn't guarantee its + results anyways. + We do this here because otherwise user space would do it on + its own in a likely inferior way (no access to jiffies). + If you don't like it pass NULL. */ + if (tcache && tcache->blob[0] == (j = VVAR(jiffies))) { + p = tcache->blob[1]; + } else if (VVAR(vgetcpu_mode) == VGETCPU_RDTSCP) { + /* Load per CPU data from RDTSCP */ + native_read_tscp(&p); + } else { + /* Load per CPU data from GDT */ + asm("lsl %1,%0" : "=r" (p) : "r" (__PER_CPU_SEG)); } - - if (ret == -EFAULT) { - /* - * Bad news -- userspace fed a bad pointer to a vsyscall. - * - * With a real vsyscall, that would have caused SIGSEGV. - * To make writing reliable exploits using the emulated - * vsyscalls harder, generate SIGSEGV here as well. - */ - warn_bad_vsyscall(KERN_INFO, regs, - "vsyscall fault (exploit attempt?)"); - goto sigsegv; + if (tcache) { + tcache->blob[0] = j; + tcache->blob[1] = p; } + if (cpu) + *cpu = p & 0xfff; + if (node) + *node = p >> 12; + return 0; +} - regs->ax = ret; - - /* Emulate a ret instruction. */ - regs->ip = caller; - regs->sp += 8; +static long __vsyscall(3) venosys_1(void) +{ + return -ENOSYS; +} - local_irq_disable(); - return; +#ifdef CONFIG_SYSCTL +static ctl_table kernel_table2[] = { + { .procname = "vsyscall64", + .data = &vsyscall_gtod_data.sysctl_enabled, .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec }, + {} +}; -sigsegv: - regs->ip -= 2; /* The faulting instruction should be the int 0xcc. */ - force_sig(SIGSEGV, current); - local_irq_disable(); -} +static ctl_table kernel_root_table2[] = { + { .procname = "kernel", .mode = 0555, + .child = kernel_table2 }, + {} +}; +#endif -/* - * Assume __initcall executes before all user space. Hopefully kmod - * doesn't violate that. We'll find out if it does. - */ +/* Assume __initcall executes before all user space. Hopefully kmod + doesn't violate that. We'll find out if it does. */ static void __cpuinit vsyscall_set_cpu(int cpu) { unsigned long d; @@ -225,15 +255,13 @@ static void __cpuinit vsyscall_set_cpu(int cpu) if (cpu_has(&cpu_data(cpu), X86_FEATURE_RDTSCP)) write_rdtscp_aux((node << 12) | cpu); - /* - * Store cpu number in limit so that it can be loaded quickly - * in user space in vgetcpu. (12 bits for the CPU and 8 bits for the node) - */ + /* Store cpu number in limit so that it can be loaded quickly + in user space in vgetcpu. + 12 bits for the CPU and 8 bits for the node. */ d = 0x0f40000000000ULL; d |= cpu; d |= (node & 0xf) << 12; d |= (node >> 4) << 48; - write_gdt_entry(get_cpu_gdt_table(cpu), GDT_ENTRY_PER_CPU, &d, DESCTYPE_S); } @@ -247,10 +275,8 @@ static int __cpuinit cpu_vsyscall_notifier(struct notifier_block *n, unsigned long action, void *arg) { long cpu = (long)arg; - if (action == CPU_ONLINE || action == CPU_ONLINE_FROZEN) smp_call_function_single(cpu, cpu_vsyscall_init, NULL, 1); - return NOTIFY_DONE; } @@ -258,23 +284,25 @@ void __init map_vsyscall(void) { extern char __vsyscall_0; unsigned long physaddr_page0 = __pa_symbol(&__vsyscall_0); - extern char __vvar_page; - unsigned long physaddr_vvar_page = __pa_symbol(&__vvar_page); /* Note that VSYSCALL_MAPPED_PAGES must agree with the code below. */ __set_fixmap(VSYSCALL_FIRST_PAGE, physaddr_page0, PAGE_KERNEL_VSYSCALL); - __set_fixmap(VVAR_PAGE, physaddr_vvar_page, PAGE_KERNEL_VVAR); - BUILD_BUG_ON((unsigned long)__fix_to_virt(VVAR_PAGE) != (unsigned long)VVAR_ADDRESS); } static int __init vsyscall_init(void) { - BUG_ON(VSYSCALL_ADDR(0) != __fix_to_virt(VSYSCALL_FIRST_PAGE)); - + BUG_ON(((unsigned long) &vgettimeofday != + VSYSCALL_ADDR(__NR_vgettimeofday))); + BUG_ON((unsigned long) &vtime != VSYSCALL_ADDR(__NR_vtime)); + BUG_ON((VSYSCALL_ADDR(0) != __fix_to_virt(VSYSCALL_FIRST_PAGE))); + BUG_ON((unsigned long) &vgetcpu != VSYSCALL_ADDR(__NR_vgetcpu)); +#ifdef CONFIG_SYSCTL + register_sysctl_table(kernel_root_table2); +#endif on_each_cpu(cpu_vsyscall_init, NULL, 1); /* notifier priority > KVM */ hotcpu_notifier(cpu_vsyscall_notifier, 30); - return 0; } + __initcall(vsyscall_init); diff --git a/trunk/arch/x86/kernel/vsyscall_emu_64.S b/trunk/arch/x86/kernel/vsyscall_emu_64.S deleted file mode 100644 index ffa845eae5ca..000000000000 --- a/trunk/arch/x86/kernel/vsyscall_emu_64.S +++ /dev/null @@ -1,27 +0,0 @@ -/* - * vsyscall_emu_64.S: Vsyscall emulation page - * - * Copyright (c) 2011 Andy Lutomirski - * - * Subject to the GNU General Public License, version 2 - */ - -#include -#include - -/* The unused parts of the page are filled with 0xcc by the linker script. */ - -.section .vsyscall_0, "a" -ENTRY(vsyscall_0) - int $VSYSCALL_EMU_VECTOR -END(vsyscall_0) - -.section .vsyscall_1, "a" -ENTRY(vsyscall_1) - int $VSYSCALL_EMU_VECTOR -END(vsyscall_1) - -.section .vsyscall_2, "a" -ENTRY(vsyscall_2) - int $VSYSCALL_EMU_VECTOR -END(vsyscall_2) diff --git a/trunk/arch/x86/kvm/Kconfig b/trunk/arch/x86/kvm/Kconfig index 988724b236b6..50f63648ce1b 100644 --- a/trunk/arch/x86/kvm/Kconfig +++ b/trunk/arch/x86/kvm/Kconfig @@ -31,7 +31,6 @@ config KVM select KVM_ASYNC_PF select USER_RETURN_NOTIFIER select KVM_MMIO - select TASK_DELAY_ACCT ---help--- Support hosting fully virtualized guest machines using hardware virtualization extensions. You will need a fairly recent @@ -77,5 +76,6 @@ config KVM_MMU_AUDIT # the virtualization menu. source drivers/vhost/Kconfig source drivers/lguest/Kconfig +source drivers/virtio/Kconfig endif # VIRTUALIZATION diff --git a/trunk/arch/x86/kvm/emulate.c b/trunk/arch/x86/kvm/emulate.c index 6f08bc940fa8..adc98675cda0 100644 --- a/trunk/arch/x86/kvm/emulate.c +++ b/trunk/arch/x86/kvm/emulate.c @@ -407,59 +407,76 @@ struct gprefix { } \ } while (0) +/* Fetch next part of the instruction being emulated. */ +#define insn_fetch(_type, _size, _eip) \ +({ unsigned long _x; \ + rc = do_insn_fetch(ctxt, ops, (_eip), &_x, (_size)); \ + if (rc != X86EMUL_CONTINUE) \ + goto done; \ + (_eip) += (_size); \ + (_type)_x; \ +}) + +#define insn_fetch_arr(_arr, _size, _eip) \ +({ rc = do_insn_fetch(ctxt, ops, (_eip), _arr, (_size)); \ + if (rc != X86EMUL_CONTINUE) \ + goto done; \ + (_eip) += (_size); \ +}) + static int emulator_check_intercept(struct x86_emulate_ctxt *ctxt, enum x86_intercept intercept, enum x86_intercept_stage stage) { struct x86_instruction_info info = { .intercept = intercept, - .rep_prefix = ctxt->rep_prefix, - .modrm_mod = ctxt->modrm_mod, - .modrm_reg = ctxt->modrm_reg, - .modrm_rm = ctxt->modrm_rm, - .src_val = ctxt->src.val64, - .src_bytes = ctxt->src.bytes, - .dst_bytes = ctxt->dst.bytes, - .ad_bytes = ctxt->ad_bytes, + .rep_prefix = ctxt->decode.rep_prefix, + .modrm_mod = ctxt->decode.modrm_mod, + .modrm_reg = ctxt->decode.modrm_reg, + .modrm_rm = ctxt->decode.modrm_rm, + .src_val = ctxt->decode.src.val64, + .src_bytes = ctxt->decode.src.bytes, + .dst_bytes = ctxt->decode.dst.bytes, + .ad_bytes = ctxt->decode.ad_bytes, .next_rip = ctxt->eip, }; return ctxt->ops->intercept(ctxt, &info, stage); } -static inline unsigned long ad_mask(struct x86_emulate_ctxt *ctxt) +static inline unsigned long ad_mask(struct decode_cache *c) { - return (1UL << (ctxt->ad_bytes << 3)) - 1; + return (1UL << (c->ad_bytes << 3)) - 1; } /* Access/update address held in a register, based on addressing mode. */ static inline unsigned long -address_mask(struct x86_emulate_ctxt *ctxt, unsigned long reg) +address_mask(struct decode_cache *c, unsigned long reg) { - if (ctxt->ad_bytes == sizeof(unsigned long)) + if (c->ad_bytes == sizeof(unsigned long)) return reg; else - return reg & ad_mask(ctxt); + return reg & ad_mask(c); } static inline unsigned long -register_address(struct x86_emulate_ctxt *ctxt, unsigned long reg) +register_address(struct decode_cache *c, unsigned long reg) { - return address_mask(ctxt, reg); + return address_mask(c, reg); } static inline void -register_address_increment(struct x86_emulate_ctxt *ctxt, unsigned long *reg, int inc) +register_address_increment(struct decode_cache *c, unsigned long *reg, int inc) { - if (ctxt->ad_bytes == sizeof(unsigned long)) + if (c->ad_bytes == sizeof(unsigned long)) *reg += inc; else - *reg = (*reg & ~ad_mask(ctxt)) | ((*reg + inc) & ad_mask(ctxt)); + *reg = (*reg & ~ad_mask(c)) | ((*reg + inc) & ad_mask(c)); } -static inline void jmp_rel(struct x86_emulate_ctxt *ctxt, int rel) +static inline void jmp_rel(struct decode_cache *c, int rel) { - register_address_increment(ctxt, &ctxt->_eip, rel); + register_address_increment(c, &c->eip, rel); } static u32 desc_limit_scaled(struct desc_struct *desc) @@ -469,26 +486,28 @@ static u32 desc_limit_scaled(struct desc_struct *desc) return desc->g ? (limit << 12) | 0xfff : limit; } -static void set_seg_override(struct x86_emulate_ctxt *ctxt, int seg) +static void set_seg_override(struct decode_cache *c, int seg) { - ctxt->has_seg_override = true; - ctxt->seg_override = seg; + c->has_seg_override = true; + c->seg_override = seg; } -static unsigned long seg_base(struct x86_emulate_ctxt *ctxt, int seg) +static unsigned long seg_base(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, int seg) { if (ctxt->mode == X86EMUL_MODE_PROT64 && seg < VCPU_SREG_FS) return 0; - return ctxt->ops->get_cached_segment_base(ctxt, seg); + return ops->get_cached_segment_base(ctxt, seg); } -static unsigned seg_override(struct x86_emulate_ctxt *ctxt) +static unsigned seg_override(struct x86_emulate_ctxt *ctxt, + struct decode_cache *c) { - if (!ctxt->has_seg_override) + if (!c->has_seg_override) return 0; - return ctxt->seg_override; + return c->seg_override; } static int emulate_exception(struct x86_emulate_ctxt *ctxt, int vec, @@ -560,6 +579,7 @@ static int __linearize(struct x86_emulate_ctxt *ctxt, unsigned size, bool write, bool fetch, ulong *linear) { + struct decode_cache *c = &ctxt->decode; struct desc_struct desc; bool usable; ulong la; @@ -567,7 +587,7 @@ static int __linearize(struct x86_emulate_ctxt *ctxt, u16 sel; unsigned cpl, rpl; - la = seg_base(ctxt, addr.seg) + addr.ea; + la = seg_base(ctxt, ctxt->ops, addr.seg) + addr.ea; switch (ctxt->mode) { case X86EMUL_MODE_REAL: break; @@ -617,7 +637,7 @@ static int __linearize(struct x86_emulate_ctxt *ctxt, } break; } - if (fetch ? ctxt->mode != X86EMUL_MODE_PROT64 : ctxt->ad_bytes != 8) + if (fetch ? ctxt->mode != X86EMUL_MODE_PROT64 : c->ad_bytes != 8) la &= (u32)-1; *linear = la; return X86EMUL_CONTINUE; @@ -651,10 +671,11 @@ static int segmented_read_std(struct x86_emulate_ctxt *ctxt, return ctxt->ops->read_std(ctxt, linear, data, size, &ctxt->exception); } -static int do_insn_fetch_byte(struct x86_emulate_ctxt *ctxt, +static int do_fetch_insn_byte(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, unsigned long eip, u8 *dest) { - struct fetch_cache *fc = &ctxt->fetch; + struct fetch_cache *fc = &ctxt->decode.fetch; int rc; int size, cur_size; @@ -666,8 +687,8 @@ static int do_insn_fetch_byte(struct x86_emulate_ctxt *ctxt, rc = __linearize(ctxt, addr, size, false, true, &linear); if (rc != X86EMUL_CONTINUE) return rc; - rc = ctxt->ops->fetch(ctxt, linear, fc->data + cur_size, - size, &ctxt->exception); + rc = ops->fetch(ctxt, linear, fc->data + cur_size, + size, &ctxt->exception); if (rc != X86EMUL_CONTINUE) return rc; fc->end += size; @@ -677,6 +698,7 @@ static int do_insn_fetch_byte(struct x86_emulate_ctxt *ctxt, } static int do_insn_fetch(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, unsigned long eip, void *dest, unsigned size) { int rc; @@ -685,30 +707,13 @@ static int do_insn_fetch(struct x86_emulate_ctxt *ctxt, if (eip + size - ctxt->eip > 15) return X86EMUL_UNHANDLEABLE; while (size--) { - rc = do_insn_fetch_byte(ctxt, eip++, dest++); + rc = do_fetch_insn_byte(ctxt, ops, eip++, dest++); if (rc != X86EMUL_CONTINUE) return rc; } return X86EMUL_CONTINUE; } -/* Fetch next part of the instruction being emulated. */ -#define insn_fetch(_type, _size, _eip) \ -({ unsigned long _x; \ - rc = do_insn_fetch(ctxt, (_eip), &_x, (_size)); \ - if (rc != X86EMUL_CONTINUE) \ - goto done; \ - (_eip) += (_size); \ - (_type)_x; \ -}) - -#define insn_fetch_arr(_arr, _size, _eip) \ -({ rc = do_insn_fetch(ctxt, (_eip), _arr, (_size)); \ - if (rc != X86EMUL_CONTINUE) \ - goto done; \ - (_eip) += (_size); \ -}) - /* * Given the 'reg' portion of a ModRM byte, and a register block, return a * pointer into the block that addresses the relevant register. @@ -852,15 +857,16 @@ static void write_sse_reg(struct x86_emulate_ctxt *ctxt, sse128_t *data, static void decode_register_operand(struct x86_emulate_ctxt *ctxt, struct operand *op, + struct decode_cache *c, int inhibit_bytereg) { - unsigned reg = ctxt->modrm_reg; - int highbyte_regs = ctxt->rex_prefix == 0; + unsigned reg = c->modrm_reg; + int highbyte_regs = c->rex_prefix == 0; - if (!(ctxt->d & ModRM)) - reg = (ctxt->b & 7) | ((ctxt->rex_prefix & 1) << 3); + if (!(c->d & ModRM)) + reg = (c->b & 7) | ((c->rex_prefix & 1) << 3); - if (ctxt->d & Sse) { + if (c->d & Sse) { op->type = OP_XMM; op->bytes = 16; op->addr.xmm = reg; @@ -869,47 +875,49 @@ static void decode_register_operand(struct x86_emulate_ctxt *ctxt, } op->type = OP_REG; - if ((ctxt->d & ByteOp) && !inhibit_bytereg) { - op->addr.reg = decode_register(reg, ctxt->regs, highbyte_regs); + if ((c->d & ByteOp) && !inhibit_bytereg) { + op->addr.reg = decode_register(reg, c->regs, highbyte_regs); op->bytes = 1; } else { - op->addr.reg = decode_register(reg, ctxt->regs, 0); - op->bytes = ctxt->op_bytes; + op->addr.reg = decode_register(reg, c->regs, 0); + op->bytes = c->op_bytes; } fetch_register_operand(op); op->orig_val = op->val; } static int decode_modrm(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, struct operand *op) { + struct decode_cache *c = &ctxt->decode; u8 sib; int index_reg = 0, base_reg = 0, scale; int rc = X86EMUL_CONTINUE; ulong modrm_ea = 0; - if (ctxt->rex_prefix) { - ctxt->modrm_reg = (ctxt->rex_prefix & 4) << 1; /* REX.R */ - index_reg = (ctxt->rex_prefix & 2) << 2; /* REX.X */ - ctxt->modrm_rm = base_reg = (ctxt->rex_prefix & 1) << 3; /* REG.B */ + if (c->rex_prefix) { + c->modrm_reg = (c->rex_prefix & 4) << 1; /* REX.R */ + index_reg = (c->rex_prefix & 2) << 2; /* REX.X */ + c->modrm_rm = base_reg = (c->rex_prefix & 1) << 3; /* REG.B */ } - ctxt->modrm = insn_fetch(u8, 1, ctxt->_eip); - ctxt->modrm_mod |= (ctxt->modrm & 0xc0) >> 6; - ctxt->modrm_reg |= (ctxt->modrm & 0x38) >> 3; - ctxt->modrm_rm |= (ctxt->modrm & 0x07); - ctxt->modrm_seg = VCPU_SREG_DS; + c->modrm = insn_fetch(u8, 1, c->eip); + c->modrm_mod |= (c->modrm & 0xc0) >> 6; + c->modrm_reg |= (c->modrm & 0x38) >> 3; + c->modrm_rm |= (c->modrm & 0x07); + c->modrm_seg = VCPU_SREG_DS; - if (ctxt->modrm_mod == 3) { + if (c->modrm_mod == 3) { op->type = OP_REG; - op->bytes = (ctxt->d & ByteOp) ? 1 : ctxt->op_bytes; - op->addr.reg = decode_register(ctxt->modrm_rm, - ctxt->regs, ctxt->d & ByteOp); - if (ctxt->d & Sse) { + op->bytes = (c->d & ByteOp) ? 1 : c->op_bytes; + op->addr.reg = decode_register(c->modrm_rm, + c->regs, c->d & ByteOp); + if (c->d & Sse) { op->type = OP_XMM; op->bytes = 16; - op->addr.xmm = ctxt->modrm_rm; - read_sse_reg(ctxt, &op->vec_val, ctxt->modrm_rm); + op->addr.xmm = c->modrm_rm; + read_sse_reg(ctxt, &op->vec_val, c->modrm_rm); return rc; } fetch_register_operand(op); @@ -918,26 +926,26 @@ static int decode_modrm(struct x86_emulate_ctxt *ctxt, op->type = OP_MEM; - if (ctxt->ad_bytes == 2) { - unsigned bx = ctxt->regs[VCPU_REGS_RBX]; - unsigned bp = ctxt->regs[VCPU_REGS_RBP]; - unsigned si = ctxt->regs[VCPU_REGS_RSI]; - unsigned di = ctxt->regs[VCPU_REGS_RDI]; + if (c->ad_bytes == 2) { + unsigned bx = c->regs[VCPU_REGS_RBX]; + unsigned bp = c->regs[VCPU_REGS_RBP]; + unsigned si = c->regs[VCPU_REGS_RSI]; + unsigned di = c->regs[VCPU_REGS_RDI]; /* 16-bit ModR/M decode. */ - switch (ctxt->modrm_mod) { + switch (c->modrm_mod) { case 0: - if (ctxt->modrm_rm == 6) - modrm_ea += insn_fetch(u16, 2, ctxt->_eip); + if (c->modrm_rm == 6) + modrm_ea += insn_fetch(u16, 2, c->eip); break; case 1: - modrm_ea += insn_fetch(s8, 1, ctxt->_eip); + modrm_ea += insn_fetch(s8, 1, c->eip); break; case 2: - modrm_ea += insn_fetch(u16, 2, ctxt->_eip); + modrm_ea += insn_fetch(u16, 2, c->eip); break; } - switch (ctxt->modrm_rm) { + switch (c->modrm_rm) { case 0: modrm_ea += bx + si; break; @@ -957,46 +965,46 @@ static int decode_modrm(struct x86_emulate_ctxt *ctxt, modrm_ea += di; break; case 6: - if (ctxt->modrm_mod != 0) + if (c->modrm_mod != 0) modrm_ea += bp; break; case 7: modrm_ea += bx; break; } - if (ctxt->modrm_rm == 2 || ctxt->modrm_rm == 3 || - (ctxt->modrm_rm == 6 && ctxt->modrm_mod != 0)) - ctxt->modrm_seg = VCPU_SREG_SS; + if (c->modrm_rm == 2 || c->modrm_rm == 3 || + (c->modrm_rm == 6 && c->modrm_mod != 0)) + c->modrm_seg = VCPU_SREG_SS; modrm_ea = (u16)modrm_ea; } else { /* 32/64-bit ModR/M decode. */ - if ((ctxt->modrm_rm & 7) == 4) { - sib = insn_fetch(u8, 1, ctxt->_eip); + if ((c->modrm_rm & 7) == 4) { + sib = insn_fetch(u8, 1, c->eip); index_reg |= (sib >> 3) & 7; base_reg |= sib & 7; scale = sib >> 6; - if ((base_reg & 7) == 5 && ctxt->modrm_mod == 0) - modrm_ea += insn_fetch(s32, 4, ctxt->_eip); + if ((base_reg & 7) == 5 && c->modrm_mod == 0) + modrm_ea += insn_fetch(s32, 4, c->eip); else - modrm_ea += ctxt->regs[base_reg]; + modrm_ea += c->regs[base_reg]; if (index_reg != 4) - modrm_ea += ctxt->regs[index_reg] << scale; - } else if ((ctxt->modrm_rm & 7) == 5 && ctxt->modrm_mod == 0) { + modrm_ea += c->regs[index_reg] << scale; + } else if ((c->modrm_rm & 7) == 5 && c->modrm_mod == 0) { if (ctxt->mode == X86EMUL_MODE_PROT64) - ctxt->rip_relative = 1; + c->rip_relative = 1; } else - modrm_ea += ctxt->regs[ctxt->modrm_rm]; - switch (ctxt->modrm_mod) { + modrm_ea += c->regs[c->modrm_rm]; + switch (c->modrm_mod) { case 0: - if (ctxt->modrm_rm == 5) - modrm_ea += insn_fetch(s32, 4, ctxt->_eip); + if (c->modrm_rm == 5) + modrm_ea += insn_fetch(s32, 4, c->eip); break; case 1: - modrm_ea += insn_fetch(s8, 1, ctxt->_eip); + modrm_ea += insn_fetch(s8, 1, c->eip); break; case 2: - modrm_ea += insn_fetch(s32, 4, ctxt->_eip); + modrm_ea += insn_fetch(s32, 4, c->eip); break; } } @@ -1006,50 +1014,53 @@ static int decode_modrm(struct x86_emulate_ctxt *ctxt, } static int decode_abs(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, struct operand *op) { + struct decode_cache *c = &ctxt->decode; int rc = X86EMUL_CONTINUE; op->type = OP_MEM; - switch (ctxt->ad_bytes) { + switch (c->ad_bytes) { case 2: - op->addr.mem.ea = insn_fetch(u16, 2, ctxt->_eip); + op->addr.mem.ea = insn_fetch(u16, 2, c->eip); break; case 4: - op->addr.mem.ea = insn_fetch(u32, 4, ctxt->_eip); + op->addr.mem.ea = insn_fetch(u32, 4, c->eip); break; case 8: - op->addr.mem.ea = insn_fetch(u64, 8, ctxt->_eip); + op->addr.mem.ea = insn_fetch(u64, 8, c->eip); break; } done: return rc; } -static void fetch_bit_operand(struct x86_emulate_ctxt *ctxt) +static void fetch_bit_operand(struct decode_cache *c) { long sv = 0, mask; - if (ctxt->dst.type == OP_MEM && ctxt->src.type == OP_REG) { - mask = ~(ctxt->dst.bytes * 8 - 1); + if (c->dst.type == OP_MEM && c->src.type == OP_REG) { + mask = ~(c->dst.bytes * 8 - 1); - if (ctxt->src.bytes == 2) - sv = (s16)ctxt->src.val & (s16)mask; - else if (ctxt->src.bytes == 4) - sv = (s32)ctxt->src.val & (s32)mask; + if (c->src.bytes == 2) + sv = (s16)c->src.val & (s16)mask; + else if (c->src.bytes == 4) + sv = (s32)c->src.val & (s32)mask; - ctxt->dst.addr.mem.ea += (sv >> 3); + c->dst.addr.mem.ea += (sv >> 3); } /* only subword offset */ - ctxt->src.val &= (ctxt->dst.bytes << 3) - 1; + c->src.val &= (c->dst.bytes << 3) - 1; } static int read_emulated(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, unsigned long addr, void *dest, unsigned size) { int rc; - struct read_cache *mc = &ctxt->mem_read; + struct read_cache *mc = &ctxt->decode.mem_read; while (size) { int n = min(size, 8u); @@ -1057,8 +1068,8 @@ static int read_emulated(struct x86_emulate_ctxt *ctxt, if (mc->pos < mc->end) goto read_cached; - rc = ctxt->ops->read_emulated(ctxt, addr, mc->data + mc->end, n, - &ctxt->exception); + rc = ops->read_emulated(ctxt, addr, mc->data + mc->end, n, + &ctxt->exception); if (rc != X86EMUL_CONTINUE) return rc; mc->end += n; @@ -1083,7 +1094,7 @@ static int segmented_read(struct x86_emulate_ctxt *ctxt, rc = linearize(ctxt, addr, size, false, &linear); if (rc != X86EMUL_CONTINUE) return rc; - return read_emulated(ctxt, linear, data, size); + return read_emulated(ctxt, ctxt->ops, linear, data, size); } static int segmented_write(struct x86_emulate_ctxt *ctxt, @@ -1117,24 +1128,26 @@ static int segmented_cmpxchg(struct x86_emulate_ctxt *ctxt, } static int pio_in_emulated(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, unsigned int size, unsigned short port, void *dest) { - struct read_cache *rc = &ctxt->io_read; + struct read_cache *rc = &ctxt->decode.io_read; if (rc->pos == rc->end) { /* refill pio read ahead */ + struct decode_cache *c = &ctxt->decode; unsigned int in_page, n; - unsigned int count = ctxt->rep_prefix ? - address_mask(ctxt, ctxt->regs[VCPU_REGS_RCX]) : 1; + unsigned int count = c->rep_prefix ? + address_mask(c, c->regs[VCPU_REGS_RCX]) : 1; in_page = (ctxt->eflags & EFLG_DF) ? - offset_in_page(ctxt->regs[VCPU_REGS_RDI]) : - PAGE_SIZE - offset_in_page(ctxt->regs[VCPU_REGS_RDI]); + offset_in_page(c->regs[VCPU_REGS_RDI]) : + PAGE_SIZE - offset_in_page(c->regs[VCPU_REGS_RDI]); n = min(min(in_page, (unsigned int)sizeof(rc->data)) / size, count); if (n == 0) n = 1; rc->pos = rc->end = 0; - if (!ctxt->ops->pio_in_emulated(ctxt, size, port, rc->data, n)) + if (!ops->pio_in_emulated(ctxt, size, port, rc->data, n)) return 0; rc->end = n * size; } @@ -1145,10 +1158,9 @@ static int pio_in_emulated(struct x86_emulate_ctxt *ctxt, } static void get_descriptor_table_ptr(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, u16 selector, struct desc_ptr *dt) { - struct x86_emulate_ops *ops = ctxt->ops; - if (selector & 1 << 2) { struct desc_struct desc; u16 sel; @@ -1165,42 +1177,48 @@ static void get_descriptor_table_ptr(struct x86_emulate_ctxt *ctxt, /* allowed just for 8 bytes segments */ static int read_segment_descriptor(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, u16 selector, struct desc_struct *desc) { struct desc_ptr dt; u16 index = selector >> 3; + int ret; ulong addr; - get_descriptor_table_ptr(ctxt, selector, &dt); + get_descriptor_table_ptr(ctxt, ops, selector, &dt); if (dt.size < index * 8 + 7) return emulate_gp(ctxt, selector & 0xfffc); - addr = dt.address + index * 8; - return ctxt->ops->read_std(ctxt, addr, desc, sizeof *desc, - &ctxt->exception); + ret = ops->read_std(ctxt, addr, desc, sizeof *desc, &ctxt->exception); + + return ret; } /* allowed just for 8 bytes segments */ static int write_segment_descriptor(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, u16 selector, struct desc_struct *desc) { struct desc_ptr dt; u16 index = selector >> 3; ulong addr; + int ret; - get_descriptor_table_ptr(ctxt, selector, &dt); + get_descriptor_table_ptr(ctxt, ops, selector, &dt); if (dt.size < index * 8 + 7) return emulate_gp(ctxt, selector & 0xfffc); addr = dt.address + index * 8; - return ctxt->ops->write_std(ctxt, addr, desc, sizeof *desc, - &ctxt->exception); + ret = ops->write_std(ctxt, addr, desc, sizeof *desc, &ctxt->exception); + + return ret; } /* Does not support long mode */ static int load_segment_descriptor(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, u16 selector, int seg) { struct desc_struct seg_desc; @@ -1235,7 +1253,7 @@ static int load_segment_descriptor(struct x86_emulate_ctxt *ctxt, if (null_selector) /* for NULL selector skip all following checks */ goto load; - ret = read_segment_descriptor(ctxt, selector, &seg_desc); + ret = read_segment_descriptor(ctxt, ops, selector, &seg_desc); if (ret != X86EMUL_CONTINUE) return ret; @@ -1253,7 +1271,7 @@ static int load_segment_descriptor(struct x86_emulate_ctxt *ctxt, rpl = selector & 3; dpl = seg_desc.dpl; - cpl = ctxt->ops->cpl(ctxt); + cpl = ops->cpl(ctxt); switch (seg) { case VCPU_SREG_SS: @@ -1304,12 +1322,12 @@ static int load_segment_descriptor(struct x86_emulate_ctxt *ctxt, if (seg_desc.s) { /* mark segment as accessed */ seg_desc.type |= 1; - ret = write_segment_descriptor(ctxt, selector, &seg_desc); + ret = write_segment_descriptor(ctxt, ops, selector, &seg_desc); if (ret != X86EMUL_CONTINUE) return ret; } load: - ctxt->ops->set_segment(ctxt, selector, &seg_desc, 0, seg); + ops->set_segment(ctxt, selector, &seg_desc, 0, seg); return X86EMUL_CONTINUE; exception: emulate_exception(ctxt, err_vec, err_code, true); @@ -1338,28 +1356,29 @@ static void write_register_operand(struct operand *op) static int writeback(struct x86_emulate_ctxt *ctxt) { int rc; + struct decode_cache *c = &ctxt->decode; - switch (ctxt->dst.type) { + switch (c->dst.type) { case OP_REG: - write_register_operand(&ctxt->dst); + write_register_operand(&c->dst); break; case OP_MEM: - if (ctxt->lock_prefix) + if (c->lock_prefix) rc = segmented_cmpxchg(ctxt, - ctxt->dst.addr.mem, - &ctxt->dst.orig_val, - &ctxt->dst.val, - ctxt->dst.bytes); + c->dst.addr.mem, + &c->dst.orig_val, + &c->dst.val, + c->dst.bytes); else rc = segmented_write(ctxt, - ctxt->dst.addr.mem, - &ctxt->dst.val, - ctxt->dst.bytes); + c->dst.addr.mem, + &c->dst.val, + c->dst.bytes); if (rc != X86EMUL_CONTINUE) return rc; break; case OP_XMM: - write_sse_reg(ctxt, &ctxt->dst.vec_val, ctxt->dst.addr.xmm); + write_sse_reg(ctxt, &c->dst.vec_val, c->dst.addr.xmm); break; case OP_NONE: /* no writeback */ @@ -1372,45 +1391,50 @@ static int writeback(struct x86_emulate_ctxt *ctxt) static int em_push(struct x86_emulate_ctxt *ctxt) { + struct decode_cache *c = &ctxt->decode; struct segmented_address addr; - register_address_increment(ctxt, &ctxt->regs[VCPU_REGS_RSP], -ctxt->op_bytes); - addr.ea = register_address(ctxt, ctxt->regs[VCPU_REGS_RSP]); + register_address_increment(c, &c->regs[VCPU_REGS_RSP], -c->op_bytes); + addr.ea = register_address(c, c->regs[VCPU_REGS_RSP]); addr.seg = VCPU_SREG_SS; /* Disable writeback. */ - ctxt->dst.type = OP_NONE; - return segmented_write(ctxt, addr, &ctxt->src.val, ctxt->op_bytes); + c->dst.type = OP_NONE; + return segmented_write(ctxt, addr, &c->src.val, c->op_bytes); } static int emulate_pop(struct x86_emulate_ctxt *ctxt, void *dest, int len) { + struct decode_cache *c = &ctxt->decode; int rc; struct segmented_address addr; - addr.ea = register_address(ctxt, ctxt->regs[VCPU_REGS_RSP]); + addr.ea = register_address(c, c->regs[VCPU_REGS_RSP]); addr.seg = VCPU_SREG_SS; rc = segmented_read(ctxt, addr, dest, len); if (rc != X86EMUL_CONTINUE) return rc; - register_address_increment(ctxt, &ctxt->regs[VCPU_REGS_RSP], len); + register_address_increment(c, &c->regs[VCPU_REGS_RSP], len); return rc; } static int em_pop(struct x86_emulate_ctxt *ctxt) { - return emulate_pop(ctxt, &ctxt->dst.val, ctxt->op_bytes); + struct decode_cache *c = &ctxt->decode; + + return emulate_pop(ctxt, &c->dst.val, c->op_bytes); } static int emulate_popf(struct x86_emulate_ctxt *ctxt, - void *dest, int len) + struct x86_emulate_ops *ops, + void *dest, int len) { int rc; unsigned long val, change_mask; int iopl = (ctxt->eflags & X86_EFLAGS_IOPL) >> IOPL_SHIFT; - int cpl = ctxt->ops->cpl(ctxt); + int cpl = ops->cpl(ctxt); rc = emulate_pop(ctxt, &val, len); if (rc != X86EMUL_CONTINUE) @@ -1446,41 +1470,49 @@ static int emulate_popf(struct x86_emulate_ctxt *ctxt, static int em_popf(struct x86_emulate_ctxt *ctxt) { - ctxt->dst.type = OP_REG; - ctxt->dst.addr.reg = &ctxt->eflags; - ctxt->dst.bytes = ctxt->op_bytes; - return emulate_popf(ctxt, &ctxt->dst.val, ctxt->op_bytes); + struct decode_cache *c = &ctxt->decode; + + c->dst.type = OP_REG; + c->dst.addr.reg = &ctxt->eflags; + c->dst.bytes = c->op_bytes; + return emulate_popf(ctxt, ctxt->ops, &c->dst.val, c->op_bytes); } -static int emulate_push_sreg(struct x86_emulate_ctxt *ctxt, int seg) +static int emulate_push_sreg(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, int seg) { - ctxt->src.val = get_segment_selector(ctxt, seg); + struct decode_cache *c = &ctxt->decode; + + c->src.val = get_segment_selector(ctxt, seg); return em_push(ctxt); } -static int emulate_pop_sreg(struct x86_emulate_ctxt *ctxt, int seg) +static int emulate_pop_sreg(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, int seg) { + struct decode_cache *c = &ctxt->decode; unsigned long selector; int rc; - rc = emulate_pop(ctxt, &selector, ctxt->op_bytes); + rc = emulate_pop(ctxt, &selector, c->op_bytes); if (rc != X86EMUL_CONTINUE) return rc; - rc = load_segment_descriptor(ctxt, (u16)selector, seg); + rc = load_segment_descriptor(ctxt, ops, (u16)selector, seg); return rc; } static int em_pusha(struct x86_emulate_ctxt *ctxt) { - unsigned long old_esp = ctxt->regs[VCPU_REGS_RSP]; + struct decode_cache *c = &ctxt->decode; + unsigned long old_esp = c->regs[VCPU_REGS_RSP]; int rc = X86EMUL_CONTINUE; int reg = VCPU_REGS_RAX; while (reg <= VCPU_REGS_RDI) { (reg == VCPU_REGS_RSP) ? - (ctxt->src.val = old_esp) : (ctxt->src.val = ctxt->regs[reg]); + (c->src.val = old_esp) : (c->src.val = c->regs[reg]); rc = em_push(ctxt); if (rc != X86EMUL_CONTINUE) @@ -1494,23 +1526,26 @@ static int em_pusha(struct x86_emulate_ctxt *ctxt) static int em_pushf(struct x86_emulate_ctxt *ctxt) { - ctxt->src.val = (unsigned long)ctxt->eflags; + struct decode_cache *c = &ctxt->decode; + + c->src.val = (unsigned long)ctxt->eflags; return em_push(ctxt); } static int em_popa(struct x86_emulate_ctxt *ctxt) { + struct decode_cache *c = &ctxt->decode; int rc = X86EMUL_CONTINUE; int reg = VCPU_REGS_RDI; while (reg >= VCPU_REGS_RAX) { if (reg == VCPU_REGS_RSP) { - register_address_increment(ctxt, &ctxt->regs[VCPU_REGS_RSP], - ctxt->op_bytes); + register_address_increment(c, &c->regs[VCPU_REGS_RSP], + c->op_bytes); --reg; } - rc = emulate_pop(ctxt, &ctxt->regs[reg], ctxt->op_bytes); + rc = emulate_pop(ctxt, &c->regs[reg], c->op_bytes); if (rc != X86EMUL_CONTINUE) break; --reg; @@ -1518,9 +1553,10 @@ static int em_popa(struct x86_emulate_ctxt *ctxt) return rc; } -int emulate_int_real(struct x86_emulate_ctxt *ctxt, int irq) +int emulate_int_real(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, int irq) { - struct x86_emulate_ops *ops = ctxt->ops; + struct decode_cache *c = &ctxt->decode; int rc; struct desc_ptr dt; gva_t cs_addr; @@ -1528,19 +1564,19 @@ int emulate_int_real(struct x86_emulate_ctxt *ctxt, int irq) u16 cs, eip; /* TODO: Add limit checks */ - ctxt->src.val = ctxt->eflags; + c->src.val = ctxt->eflags; rc = em_push(ctxt); if (rc != X86EMUL_CONTINUE) return rc; ctxt->eflags &= ~(EFLG_IF | EFLG_TF | EFLG_AC); - ctxt->src.val = get_segment_selector(ctxt, VCPU_SREG_CS); + c->src.val = get_segment_selector(ctxt, VCPU_SREG_CS); rc = em_push(ctxt); if (rc != X86EMUL_CONTINUE) return rc; - ctxt->src.val = ctxt->_eip; + c->src.val = c->eip; rc = em_push(ctxt); if (rc != X86EMUL_CONTINUE) return rc; @@ -1558,20 +1594,21 @@ int emulate_int_real(struct x86_emulate_ctxt *ctxt, int irq) if (rc != X86EMUL_CONTINUE) return rc; - rc = load_segment_descriptor(ctxt, cs, VCPU_SREG_CS); + rc = load_segment_descriptor(ctxt, ops, cs, VCPU_SREG_CS); if (rc != X86EMUL_CONTINUE) return rc; - ctxt->_eip = eip; + c->eip = eip; return rc; } -static int emulate_int(struct x86_emulate_ctxt *ctxt, int irq) +static int emulate_int(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, int irq) { switch(ctxt->mode) { case X86EMUL_MODE_REAL: - return emulate_int_real(ctxt, irq); + return emulate_int_real(ctxt, ops, irq); case X86EMUL_MODE_VM86: case X86EMUL_MODE_PROT16: case X86EMUL_MODE_PROT32: @@ -1582,8 +1619,10 @@ static int emulate_int(struct x86_emulate_ctxt *ctxt, int irq) } } -static int emulate_iret_real(struct x86_emulate_ctxt *ctxt) +static int emulate_iret_real(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops) { + struct decode_cache *c = &ctxt->decode; int rc = X86EMUL_CONTINUE; unsigned long temp_eip = 0; unsigned long temp_eflags = 0; @@ -1595,7 +1634,7 @@ static int emulate_iret_real(struct x86_emulate_ctxt *ctxt) /* TODO: Add stack limit check */ - rc = emulate_pop(ctxt, &temp_eip, ctxt->op_bytes); + rc = emulate_pop(ctxt, &temp_eip, c->op_bytes); if (rc != X86EMUL_CONTINUE) return rc; @@ -1603,27 +1642,27 @@ static int emulate_iret_real(struct x86_emulate_ctxt *ctxt) if (temp_eip & ~0xffff) return emulate_gp(ctxt, 0); - rc = emulate_pop(ctxt, &cs, ctxt->op_bytes); + rc = emulate_pop(ctxt, &cs, c->op_bytes); if (rc != X86EMUL_CONTINUE) return rc; - rc = emulate_pop(ctxt, &temp_eflags, ctxt->op_bytes); + rc = emulate_pop(ctxt, &temp_eflags, c->op_bytes); if (rc != X86EMUL_CONTINUE) return rc; - rc = load_segment_descriptor(ctxt, (u16)cs, VCPU_SREG_CS); + rc = load_segment_descriptor(ctxt, ops, (u16)cs, VCPU_SREG_CS); if (rc != X86EMUL_CONTINUE) return rc; - ctxt->_eip = temp_eip; + c->eip = temp_eip; - if (ctxt->op_bytes == 4) + if (c->op_bytes == 4) ctxt->eflags = ((temp_eflags & mask) | (ctxt->eflags & vm86_mask)); - else if (ctxt->op_bytes == 2) { + else if (c->op_bytes == 2) { ctxt->eflags &= ~0xffff; ctxt->eflags |= temp_eflags; } @@ -1634,11 +1673,12 @@ static int emulate_iret_real(struct x86_emulate_ctxt *ctxt) return rc; } -static int em_iret(struct x86_emulate_ctxt *ctxt) +static inline int emulate_iret(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops* ops) { switch(ctxt->mode) { case X86EMUL_MODE_REAL: - return emulate_iret_real(ctxt); + return emulate_iret_real(ctxt, ops); case X86EMUL_MODE_VM86: case X86EMUL_MODE_PROT16: case X86EMUL_MODE_PROT32: @@ -1651,49 +1691,53 @@ static int em_iret(struct x86_emulate_ctxt *ctxt) static int em_jmp_far(struct x86_emulate_ctxt *ctxt) { + struct decode_cache *c = &ctxt->decode; int rc; unsigned short sel; - memcpy(&sel, ctxt->src.valptr + ctxt->op_bytes, 2); + memcpy(&sel, c->src.valptr + c->op_bytes, 2); - rc = load_segment_descriptor(ctxt, sel, VCPU_SREG_CS); + rc = load_segment_descriptor(ctxt, ctxt->ops, sel, VCPU_SREG_CS); if (rc != X86EMUL_CONTINUE) return rc; - ctxt->_eip = 0; - memcpy(&ctxt->_eip, ctxt->src.valptr, ctxt->op_bytes); + c->eip = 0; + memcpy(&c->eip, c->src.valptr, c->op_bytes); return X86EMUL_CONTINUE; } static int em_grp1a(struct x86_emulate_ctxt *ctxt) { - return emulate_pop(ctxt, &ctxt->dst.val, ctxt->dst.bytes); + struct decode_cache *c = &ctxt->decode; + + return emulate_pop(ctxt, &c->dst.val, c->dst.bytes); } static int em_grp2(struct x86_emulate_ctxt *ctxt) { - switch (ctxt->modrm_reg) { + struct decode_cache *c = &ctxt->decode; + switch (c->modrm_reg) { case 0: /* rol */ - emulate_2op_SrcB("rol", ctxt->src, ctxt->dst, ctxt->eflags); + emulate_2op_SrcB("rol", c->src, c->dst, ctxt->eflags); break; case 1: /* ror */ - emulate_2op_SrcB("ror", ctxt->src, ctxt->dst, ctxt->eflags); + emulate_2op_SrcB("ror", c->src, c->dst, ctxt->eflags); break; case 2: /* rcl */ - emulate_2op_SrcB("rcl", ctxt->src, ctxt->dst, ctxt->eflags); + emulate_2op_SrcB("rcl", c->src, c->dst, ctxt->eflags); break; case 3: /* rcr */ - emulate_2op_SrcB("rcr", ctxt->src, ctxt->dst, ctxt->eflags); + emulate_2op_SrcB("rcr", c->src, c->dst, ctxt->eflags); break; case 4: /* sal/shl */ case 6: /* sal/shl */ - emulate_2op_SrcB("sal", ctxt->src, ctxt->dst, ctxt->eflags); + emulate_2op_SrcB("sal", c->src, c->dst, ctxt->eflags); break; case 5: /* shr */ - emulate_2op_SrcB("shr", ctxt->src, ctxt->dst, ctxt->eflags); + emulate_2op_SrcB("shr", c->src, c->dst, ctxt->eflags); break; case 7: /* sar */ - emulate_2op_SrcB("sar", ctxt->src, ctxt->dst, ctxt->eflags); + emulate_2op_SrcB("sar", c->src, c->dst, ctxt->eflags); break; } return X86EMUL_CONTINUE; @@ -1701,32 +1745,33 @@ static int em_grp2(struct x86_emulate_ctxt *ctxt) static int em_grp3(struct x86_emulate_ctxt *ctxt) { - unsigned long *rax = &ctxt->regs[VCPU_REGS_RAX]; - unsigned long *rdx = &ctxt->regs[VCPU_REGS_RDX]; + struct decode_cache *c = &ctxt->decode; + unsigned long *rax = &c->regs[VCPU_REGS_RAX]; + unsigned long *rdx = &c->regs[VCPU_REGS_RDX]; u8 de = 0; - switch (ctxt->modrm_reg) { + switch (c->modrm_reg) { case 0 ... 1: /* test */ - emulate_2op_SrcV("test", ctxt->src, ctxt->dst, ctxt->eflags); + emulate_2op_SrcV("test", c->src, c->dst, ctxt->eflags); break; case 2: /* not */ - ctxt->dst.val = ~ctxt->dst.val; + c->dst.val = ~c->dst.val; break; case 3: /* neg */ - emulate_1op("neg", ctxt->dst, ctxt->eflags); + emulate_1op("neg", c->dst, ctxt->eflags); break; case 4: /* mul */ - emulate_1op_rax_rdx("mul", ctxt->src, *rax, *rdx, ctxt->eflags); + emulate_1op_rax_rdx("mul", c->src, *rax, *rdx, ctxt->eflags); break; case 5: /* imul */ - emulate_1op_rax_rdx("imul", ctxt->src, *rax, *rdx, ctxt->eflags); + emulate_1op_rax_rdx("imul", c->src, *rax, *rdx, ctxt->eflags); break; case 6: /* div */ - emulate_1op_rax_rdx_ex("div", ctxt->src, *rax, *rdx, + emulate_1op_rax_rdx_ex("div", c->src, *rax, *rdx, ctxt->eflags, de); break; case 7: /* idiv */ - emulate_1op_rax_rdx_ex("idiv", ctxt->src, *rax, *rdx, + emulate_1op_rax_rdx_ex("idiv", c->src, *rax, *rdx, ctxt->eflags, de); break; default: @@ -1739,25 +1784,26 @@ static int em_grp3(struct x86_emulate_ctxt *ctxt) static int em_grp45(struct x86_emulate_ctxt *ctxt) { + struct decode_cache *c = &ctxt->decode; int rc = X86EMUL_CONTINUE; - switch (ctxt->modrm_reg) { + switch (c->modrm_reg) { case 0: /* inc */ - emulate_1op("inc", ctxt->dst, ctxt->eflags); + emulate_1op("inc", c->dst, ctxt->eflags); break; case 1: /* dec */ - emulate_1op("dec", ctxt->dst, ctxt->eflags); + emulate_1op("dec", c->dst, ctxt->eflags); break; case 2: /* call near abs */ { long int old_eip; - old_eip = ctxt->_eip; - ctxt->_eip = ctxt->src.val; - ctxt->src.val = old_eip; + old_eip = c->eip; + c->eip = c->src.val; + c->src.val = old_eip; rc = em_push(ctxt); break; } case 4: /* jmp abs */ - ctxt->_eip = ctxt->src.val; + c->eip = c->src.val; break; case 5: /* jmp far */ rc = em_jmp_far(ctxt); @@ -1771,70 +1817,68 @@ static int em_grp45(struct x86_emulate_ctxt *ctxt) static int em_grp9(struct x86_emulate_ctxt *ctxt) { - u64 old = ctxt->dst.orig_val64; + struct decode_cache *c = &ctxt->decode; + u64 old = c->dst.orig_val64; - if (((u32) (old >> 0) != (u32) ctxt->regs[VCPU_REGS_RAX]) || - ((u32) (old >> 32) != (u32) ctxt->regs[VCPU_REGS_RDX])) { - ctxt->regs[VCPU_REGS_RAX] = (u32) (old >> 0); - ctxt->regs[VCPU_REGS_RDX] = (u32) (old >> 32); + if (((u32) (old >> 0) != (u32) c->regs[VCPU_REGS_RAX]) || + ((u32) (old >> 32) != (u32) c->regs[VCPU_REGS_RDX])) { + c->regs[VCPU_REGS_RAX] = (u32) (old >> 0); + c->regs[VCPU_REGS_RDX] = (u32) (old >> 32); ctxt->eflags &= ~EFLG_ZF; } else { - ctxt->dst.val64 = ((u64)ctxt->regs[VCPU_REGS_RCX] << 32) | - (u32) ctxt->regs[VCPU_REGS_RBX]; + c->dst.val64 = ((u64)c->regs[VCPU_REGS_RCX] << 32) | + (u32) c->regs[VCPU_REGS_RBX]; ctxt->eflags |= EFLG_ZF; } return X86EMUL_CONTINUE; } -static int em_ret(struct x86_emulate_ctxt *ctxt) -{ - ctxt->dst.type = OP_REG; - ctxt->dst.addr.reg = &ctxt->_eip; - ctxt->dst.bytes = ctxt->op_bytes; - return em_pop(ctxt); -} - -static int em_ret_far(struct x86_emulate_ctxt *ctxt) +static int emulate_ret_far(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops) { + struct decode_cache *c = &ctxt->decode; int rc; unsigned long cs; - rc = emulate_pop(ctxt, &ctxt->_eip, ctxt->op_bytes); + rc = emulate_pop(ctxt, &c->eip, c->op_bytes); if (rc != X86EMUL_CONTINUE) return rc; - if (ctxt->op_bytes == 4) - ctxt->_eip = (u32)ctxt->_eip; - rc = emulate_pop(ctxt, &cs, ctxt->op_bytes); + if (c->op_bytes == 4) + c->eip = (u32)c->eip; + rc = emulate_pop(ctxt, &cs, c->op_bytes); if (rc != X86EMUL_CONTINUE) return rc; - rc = load_segment_descriptor(ctxt, (u16)cs, VCPU_SREG_CS); + rc = load_segment_descriptor(ctxt, ops, (u16)cs, VCPU_SREG_CS); return rc; } -static int emulate_load_segment(struct x86_emulate_ctxt *ctxt, int seg) +static int emulate_load_segment(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, int seg) { + struct decode_cache *c = &ctxt->decode; unsigned short sel; int rc; - memcpy(&sel, ctxt->src.valptr + ctxt->op_bytes, 2); + memcpy(&sel, c->src.valptr + c->op_bytes, 2); - rc = load_segment_descriptor(ctxt, sel, seg); + rc = load_segment_descriptor(ctxt, ops, sel, seg); if (rc != X86EMUL_CONTINUE) return rc; - ctxt->dst.val = ctxt->src.val; + c->dst.val = c->src.val; return rc; } -static void +static inline void setup_syscalls_segments(struct x86_emulate_ctxt *ctxt, - struct desc_struct *cs, struct desc_struct *ss) + struct x86_emulate_ops *ops, struct desc_struct *cs, + struct desc_struct *ss) { u16 selector; memset(cs, 0, sizeof(struct desc_struct)); - ctxt->ops->get_segment(ctxt, &selector, cs, NULL, VCPU_SREG_CS); + ops->get_segment(ctxt, &selector, cs, NULL, VCPU_SREG_CS); memset(ss, 0, sizeof(struct desc_struct)); cs->l = 0; /* will be adjusted later */ @@ -1857,9 +1901,10 @@ setup_syscalls_segments(struct x86_emulate_ctxt *ctxt, ss->p = 1; } -static int em_syscall(struct x86_emulate_ctxt *ctxt) +static int +emulate_syscall(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) { - struct x86_emulate_ops *ops = ctxt->ops; + struct decode_cache *c = &ctxt->decode; struct desc_struct cs, ss; u64 msr_data; u16 cs_sel, ss_sel; @@ -1871,7 +1916,7 @@ static int em_syscall(struct x86_emulate_ctxt *ctxt) return emulate_ud(ctxt); ops->get_msr(ctxt, MSR_EFER, &efer); - setup_syscalls_segments(ctxt, &cs, &ss); + setup_syscalls_segments(ctxt, ops, &cs, &ss); ops->get_msr(ctxt, MSR_STAR, &msr_data); msr_data >>= 32; @@ -1885,15 +1930,15 @@ static int em_syscall(struct x86_emulate_ctxt *ctxt) ops->set_segment(ctxt, cs_sel, &cs, 0, VCPU_SREG_CS); ops->set_segment(ctxt, ss_sel, &ss, 0, VCPU_SREG_SS); - ctxt->regs[VCPU_REGS_RCX] = ctxt->_eip; + c->regs[VCPU_REGS_RCX] = c->eip; if (efer & EFER_LMA) { #ifdef CONFIG_X86_64 - ctxt->regs[VCPU_REGS_R11] = ctxt->eflags & ~EFLG_RF; + c->regs[VCPU_REGS_R11] = ctxt->eflags & ~EFLG_RF; ops->get_msr(ctxt, ctxt->mode == X86EMUL_MODE_PROT64 ? MSR_LSTAR : MSR_CSTAR, &msr_data); - ctxt->_eip = msr_data; + c->eip = msr_data; ops->get_msr(ctxt, MSR_SYSCALL_MASK, &msr_data); ctxt->eflags &= ~(msr_data | EFLG_RF); @@ -1901,7 +1946,7 @@ static int em_syscall(struct x86_emulate_ctxt *ctxt) } else { /* legacy mode */ ops->get_msr(ctxt, MSR_STAR, &msr_data); - ctxt->_eip = (u32)msr_data; + c->eip = (u32)msr_data; ctxt->eflags &= ~(EFLG_VM | EFLG_IF | EFLG_RF); } @@ -1909,15 +1954,16 @@ static int em_syscall(struct x86_emulate_ctxt *ctxt) return X86EMUL_CONTINUE; } -static int em_sysenter(struct x86_emulate_ctxt *ctxt) +static int +emulate_sysenter(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) { - struct x86_emulate_ops *ops = ctxt->ops; + struct decode_cache *c = &ctxt->decode; struct desc_struct cs, ss; u64 msr_data; u16 cs_sel, ss_sel; u64 efer = 0; - ops->get_msr(ctxt, MSR_EFER, &efer); + ctxt->ops->get_msr(ctxt, MSR_EFER, &efer); /* inject #GP if in real mode */ if (ctxt->mode == X86EMUL_MODE_REAL) return emulate_gp(ctxt, 0); @@ -1928,7 +1974,7 @@ static int em_sysenter(struct x86_emulate_ctxt *ctxt) if (ctxt->mode == X86EMUL_MODE_PROT64) return emulate_ud(ctxt); - setup_syscalls_segments(ctxt, &cs, &ss); + setup_syscalls_segments(ctxt, ops, &cs, &ss); ops->get_msr(ctxt, MSR_IA32_SYSENTER_CS, &msr_data); switch (ctxt->mode) { @@ -1956,30 +2002,31 @@ static int em_sysenter(struct x86_emulate_ctxt *ctxt) ops->set_segment(ctxt, ss_sel, &ss, 0, VCPU_SREG_SS); ops->get_msr(ctxt, MSR_IA32_SYSENTER_EIP, &msr_data); - ctxt->_eip = msr_data; + c->eip = msr_data; ops->get_msr(ctxt, MSR_IA32_SYSENTER_ESP, &msr_data); - ctxt->regs[VCPU_REGS_RSP] = msr_data; + c->regs[VCPU_REGS_RSP] = msr_data; return X86EMUL_CONTINUE; } -static int em_sysexit(struct x86_emulate_ctxt *ctxt) +static int +emulate_sysexit(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) { - struct x86_emulate_ops *ops = ctxt->ops; + struct decode_cache *c = &ctxt->decode; struct desc_struct cs, ss; u64 msr_data; int usermode; - u16 cs_sel = 0, ss_sel = 0; + u16 cs_sel, ss_sel; /* inject #GP if in real mode or Virtual 8086 mode */ if (ctxt->mode == X86EMUL_MODE_REAL || ctxt->mode == X86EMUL_MODE_VM86) return emulate_gp(ctxt, 0); - setup_syscalls_segments(ctxt, &cs, &ss); + setup_syscalls_segments(ctxt, ops, &cs, &ss); - if ((ctxt->rex_prefix & 0x8) != 0x0) + if ((c->rex_prefix & 0x8) != 0x0) usermode = X86EMUL_MODE_PROT64; else usermode = X86EMUL_MODE_PROT32; @@ -2009,13 +2056,14 @@ static int em_sysexit(struct x86_emulate_ctxt *ctxt) ops->set_segment(ctxt, cs_sel, &cs, 0, VCPU_SREG_CS); ops->set_segment(ctxt, ss_sel, &ss, 0, VCPU_SREG_SS); - ctxt->_eip = ctxt->regs[VCPU_REGS_RDX]; - ctxt->regs[VCPU_REGS_RSP] = ctxt->regs[VCPU_REGS_RCX]; + c->eip = c->regs[VCPU_REGS_RDX]; + c->regs[VCPU_REGS_RSP] = c->regs[VCPU_REGS_RCX]; return X86EMUL_CONTINUE; } -static bool emulator_bad_iopl(struct x86_emulate_ctxt *ctxt) +static bool emulator_bad_iopl(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops) { int iopl; if (ctxt->mode == X86EMUL_MODE_REAL) @@ -2023,13 +2071,13 @@ static bool emulator_bad_iopl(struct x86_emulate_ctxt *ctxt) if (ctxt->mode == X86EMUL_MODE_VM86) return true; iopl = (ctxt->eflags & X86_EFLAGS_IOPL) >> IOPL_SHIFT; - return ctxt->ops->cpl(ctxt) > iopl; + return ops->cpl(ctxt) > iopl; } static bool emulator_io_port_access_allowed(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, u16 port, u16 len) { - struct x86_emulate_ops *ops = ctxt->ops; struct desc_struct tr_seg; u32 base3; int r; @@ -2060,13 +2108,14 @@ static bool emulator_io_port_access_allowed(struct x86_emulate_ctxt *ctxt, } static bool emulator_io_permited(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, u16 port, u16 len) { if (ctxt->perm_ok) return true; - if (emulator_bad_iopl(ctxt)) - if (!emulator_io_port_access_allowed(ctxt, port, len)) + if (emulator_bad_iopl(ctxt, ops)) + if (!emulator_io_port_access_allowed(ctxt, ops, port, len)) return false; ctxt->perm_ok = true; @@ -2075,18 +2124,21 @@ static bool emulator_io_permited(struct x86_emulate_ctxt *ctxt, } static void save_state_to_tss16(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, struct tss_segment_16 *tss) { - tss->ip = ctxt->_eip; + struct decode_cache *c = &ctxt->decode; + + tss->ip = c->eip; tss->flag = ctxt->eflags; - tss->ax = ctxt->regs[VCPU_REGS_RAX]; - tss->cx = ctxt->regs[VCPU_REGS_RCX]; - tss->dx = ctxt->regs[VCPU_REGS_RDX]; - tss->bx = ctxt->regs[VCPU_REGS_RBX]; - tss->sp = ctxt->regs[VCPU_REGS_RSP]; - tss->bp = ctxt->regs[VCPU_REGS_RBP]; - tss->si = ctxt->regs[VCPU_REGS_RSI]; - tss->di = ctxt->regs[VCPU_REGS_RDI]; + tss->ax = c->regs[VCPU_REGS_RAX]; + tss->cx = c->regs[VCPU_REGS_RCX]; + tss->dx = c->regs[VCPU_REGS_RDX]; + tss->bx = c->regs[VCPU_REGS_RBX]; + tss->sp = c->regs[VCPU_REGS_RSP]; + tss->bp = c->regs[VCPU_REGS_RBP]; + tss->si = c->regs[VCPU_REGS_RSI]; + tss->di = c->regs[VCPU_REGS_RDI]; tss->es = get_segment_selector(ctxt, VCPU_SREG_ES); tss->cs = get_segment_selector(ctxt, VCPU_SREG_CS); @@ -2096,20 +2148,22 @@ static void save_state_to_tss16(struct x86_emulate_ctxt *ctxt, } static int load_state_from_tss16(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, struct tss_segment_16 *tss) { + struct decode_cache *c = &ctxt->decode; int ret; - ctxt->_eip = tss->ip; + c->eip = tss->ip; ctxt->eflags = tss->flag | 2; - ctxt->regs[VCPU_REGS_RAX] = tss->ax; - ctxt->regs[VCPU_REGS_RCX] = tss->cx; - ctxt->regs[VCPU_REGS_RDX] = tss->dx; - ctxt->regs[VCPU_REGS_RBX] = tss->bx; - ctxt->regs[VCPU_REGS_RSP] = tss->sp; - ctxt->regs[VCPU_REGS_RBP] = tss->bp; - ctxt->regs[VCPU_REGS_RSI] = tss->si; - ctxt->regs[VCPU_REGS_RDI] = tss->di; + c->regs[VCPU_REGS_RAX] = tss->ax; + c->regs[VCPU_REGS_RCX] = tss->cx; + c->regs[VCPU_REGS_RDX] = tss->dx; + c->regs[VCPU_REGS_RBX] = tss->bx; + c->regs[VCPU_REGS_RSP] = tss->sp; + c->regs[VCPU_REGS_RBP] = tss->bp; + c->regs[VCPU_REGS_RSI] = tss->si; + c->regs[VCPU_REGS_RDI] = tss->di; /* * SDM says that segment selectors are loaded before segment @@ -2125,19 +2179,19 @@ static int load_state_from_tss16(struct x86_emulate_ctxt *ctxt, * Now load segment descriptors. If fault happenes at this stage * it is handled in a context of new task */ - ret = load_segment_descriptor(ctxt, tss->ldt, VCPU_SREG_LDTR); + ret = load_segment_descriptor(ctxt, ops, tss->ldt, VCPU_SREG_LDTR); if (ret != X86EMUL_CONTINUE) return ret; - ret = load_segment_descriptor(ctxt, tss->es, VCPU_SREG_ES); + ret = load_segment_descriptor(ctxt, ops, tss->es, VCPU_SREG_ES); if (ret != X86EMUL_CONTINUE) return ret; - ret = load_segment_descriptor(ctxt, tss->cs, VCPU_SREG_CS); + ret = load_segment_descriptor(ctxt, ops, tss->cs, VCPU_SREG_CS); if (ret != X86EMUL_CONTINUE) return ret; - ret = load_segment_descriptor(ctxt, tss->ss, VCPU_SREG_SS); + ret = load_segment_descriptor(ctxt, ops, tss->ss, VCPU_SREG_SS); if (ret != X86EMUL_CONTINUE) return ret; - ret = load_segment_descriptor(ctxt, tss->ds, VCPU_SREG_DS); + ret = load_segment_descriptor(ctxt, ops, tss->ds, VCPU_SREG_DS); if (ret != X86EMUL_CONTINUE) return ret; @@ -2145,10 +2199,10 @@ static int load_state_from_tss16(struct x86_emulate_ctxt *ctxt, } static int task_switch_16(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, u16 tss_selector, u16 old_tss_sel, ulong old_tss_base, struct desc_struct *new_desc) { - struct x86_emulate_ops *ops = ctxt->ops; struct tss_segment_16 tss_seg; int ret; u32 new_tss_base = get_desc_base(new_desc); @@ -2159,7 +2213,7 @@ static int task_switch_16(struct x86_emulate_ctxt *ctxt, /* FIXME: need to provide precise fault address */ return ret; - save_state_to_tss16(ctxt, &tss_seg); + save_state_to_tss16(ctxt, ops, &tss_seg); ret = ops->write_std(ctxt, old_tss_base, &tss_seg, sizeof tss_seg, &ctxt->exception); @@ -2185,23 +2239,26 @@ static int task_switch_16(struct x86_emulate_ctxt *ctxt, return ret; } - return load_state_from_tss16(ctxt, &tss_seg); + return load_state_from_tss16(ctxt, ops, &tss_seg); } static void save_state_to_tss32(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, struct tss_segment_32 *tss) { - tss->cr3 = ctxt->ops->get_cr(ctxt, 3); - tss->eip = ctxt->_eip; + struct decode_cache *c = &ctxt->decode; + + tss->cr3 = ops->get_cr(ctxt, 3); + tss->eip = c->eip; tss->eflags = ctxt->eflags; - tss->eax = ctxt->regs[VCPU_REGS_RAX]; - tss->ecx = ctxt->regs[VCPU_REGS_RCX]; - tss->edx = ctxt->regs[VCPU_REGS_RDX]; - tss->ebx = ctxt->regs[VCPU_REGS_RBX]; - tss->esp = ctxt->regs[VCPU_REGS_RSP]; - tss->ebp = ctxt->regs[VCPU_REGS_RBP]; - tss->esi = ctxt->regs[VCPU_REGS_RSI]; - tss->edi = ctxt->regs[VCPU_REGS_RDI]; + tss->eax = c->regs[VCPU_REGS_RAX]; + tss->ecx = c->regs[VCPU_REGS_RCX]; + tss->edx = c->regs[VCPU_REGS_RDX]; + tss->ebx = c->regs[VCPU_REGS_RBX]; + tss->esp = c->regs[VCPU_REGS_RSP]; + tss->ebp = c->regs[VCPU_REGS_RBP]; + tss->esi = c->regs[VCPU_REGS_RSI]; + tss->edi = c->regs[VCPU_REGS_RDI]; tss->es = get_segment_selector(ctxt, VCPU_SREG_ES); tss->cs = get_segment_selector(ctxt, VCPU_SREG_CS); @@ -2213,22 +2270,24 @@ static void save_state_to_tss32(struct x86_emulate_ctxt *ctxt, } static int load_state_from_tss32(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, struct tss_segment_32 *tss) { + struct decode_cache *c = &ctxt->decode; int ret; - if (ctxt->ops->set_cr(ctxt, 3, tss->cr3)) + if (ops->set_cr(ctxt, 3, tss->cr3)) return emulate_gp(ctxt, 0); - ctxt->_eip = tss->eip; + c->eip = tss->eip; ctxt->eflags = tss->eflags | 2; - ctxt->regs[VCPU_REGS_RAX] = tss->eax; - ctxt->regs[VCPU_REGS_RCX] = tss->ecx; - ctxt->regs[VCPU_REGS_RDX] = tss->edx; - ctxt->regs[VCPU_REGS_RBX] = tss->ebx; - ctxt->regs[VCPU_REGS_RSP] = tss->esp; - ctxt->regs[VCPU_REGS_RBP] = tss->ebp; - ctxt->regs[VCPU_REGS_RSI] = tss->esi; - ctxt->regs[VCPU_REGS_RDI] = tss->edi; + c->regs[VCPU_REGS_RAX] = tss->eax; + c->regs[VCPU_REGS_RCX] = tss->ecx; + c->regs[VCPU_REGS_RDX] = tss->edx; + c->regs[VCPU_REGS_RBX] = tss->ebx; + c->regs[VCPU_REGS_RSP] = tss->esp; + c->regs[VCPU_REGS_RBP] = tss->ebp; + c->regs[VCPU_REGS_RSI] = tss->esi; + c->regs[VCPU_REGS_RDI] = tss->edi; /* * SDM says that segment selectors are loaded before segment @@ -2246,25 +2305,25 @@ static int load_state_from_tss32(struct x86_emulate_ctxt *ctxt, * Now load segment descriptors. If fault happenes at this stage * it is handled in a context of new task */ - ret = load_segment_descriptor(ctxt, tss->ldt_selector, VCPU_SREG_LDTR); + ret = load_segment_descriptor(ctxt, ops, tss->ldt_selector, VCPU_SREG_LDTR); if (ret != X86EMUL_CONTINUE) return ret; - ret = load_segment_descriptor(ctxt, tss->es, VCPU_SREG_ES); + ret = load_segment_descriptor(ctxt, ops, tss->es, VCPU_SREG_ES); if (ret != X86EMUL_CONTINUE) return ret; - ret = load_segment_descriptor(ctxt, tss->cs, VCPU_SREG_CS); + ret = load_segment_descriptor(ctxt, ops, tss->cs, VCPU_SREG_CS); if (ret != X86EMUL_CONTINUE) return ret; - ret = load_segment_descriptor(ctxt, tss->ss, VCPU_SREG_SS); + ret = load_segment_descriptor(ctxt, ops, tss->ss, VCPU_SREG_SS); if (ret != X86EMUL_CONTINUE) return ret; - ret = load_segment_descriptor(ctxt, tss->ds, VCPU_SREG_DS); + ret = load_segment_descriptor(ctxt, ops, tss->ds, VCPU_SREG_DS); if (ret != X86EMUL_CONTINUE) return ret; - ret = load_segment_descriptor(ctxt, tss->fs, VCPU_SREG_FS); + ret = load_segment_descriptor(ctxt, ops, tss->fs, VCPU_SREG_FS); if (ret != X86EMUL_CONTINUE) return ret; - ret = load_segment_descriptor(ctxt, tss->gs, VCPU_SREG_GS); + ret = load_segment_descriptor(ctxt, ops, tss->gs, VCPU_SREG_GS); if (ret != X86EMUL_CONTINUE) return ret; @@ -2272,10 +2331,10 @@ static int load_state_from_tss32(struct x86_emulate_ctxt *ctxt, } static int task_switch_32(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, u16 tss_selector, u16 old_tss_sel, ulong old_tss_base, struct desc_struct *new_desc) { - struct x86_emulate_ops *ops = ctxt->ops; struct tss_segment_32 tss_seg; int ret; u32 new_tss_base = get_desc_base(new_desc); @@ -2286,7 +2345,7 @@ static int task_switch_32(struct x86_emulate_ctxt *ctxt, /* FIXME: need to provide precise fault address */ return ret; - save_state_to_tss32(ctxt, &tss_seg); + save_state_to_tss32(ctxt, ops, &tss_seg); ret = ops->write_std(ctxt, old_tss_base, &tss_seg, sizeof tss_seg, &ctxt->exception); @@ -2312,14 +2371,14 @@ static int task_switch_32(struct x86_emulate_ctxt *ctxt, return ret; } - return load_state_from_tss32(ctxt, &tss_seg); + return load_state_from_tss32(ctxt, ops, &tss_seg); } static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, u16 tss_selector, int reason, bool has_error_code, u32 error_code) { - struct x86_emulate_ops *ops = ctxt->ops; struct desc_struct curr_tss_desc, next_tss_desc; int ret; u16 old_tss_sel = get_segment_selector(ctxt, VCPU_SREG_TR); @@ -2329,10 +2388,10 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt, /* FIXME: old_tss_base == ~0 ? */ - ret = read_segment_descriptor(ctxt, tss_selector, &next_tss_desc); + ret = read_segment_descriptor(ctxt, ops, tss_selector, &next_tss_desc); if (ret != X86EMUL_CONTINUE) return ret; - ret = read_segment_descriptor(ctxt, old_tss_sel, &curr_tss_desc); + ret = read_segment_descriptor(ctxt, ops, old_tss_sel, &curr_tss_desc); if (ret != X86EMUL_CONTINUE) return ret; @@ -2354,7 +2413,8 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt, if (reason == TASK_SWITCH_IRET || reason == TASK_SWITCH_JMP) { curr_tss_desc.type &= ~(1 << 1); /* clear busy flag */ - write_segment_descriptor(ctxt, old_tss_sel, &curr_tss_desc); + write_segment_descriptor(ctxt, ops, old_tss_sel, + &curr_tss_desc); } if (reason == TASK_SWITCH_IRET) @@ -2366,10 +2426,10 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt, old_tss_sel = 0xffff; if (next_tss_desc.type & 8) - ret = task_switch_32(ctxt, tss_selector, old_tss_sel, + ret = task_switch_32(ctxt, ops, tss_selector, old_tss_sel, old_tss_base, &next_tss_desc); else - ret = task_switch_16(ctxt, tss_selector, old_tss_sel, + ret = task_switch_16(ctxt, ops, tss_selector, old_tss_sel, old_tss_base, &next_tss_desc); if (ret != X86EMUL_CONTINUE) return ret; @@ -2379,16 +2439,19 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt, if (reason != TASK_SWITCH_IRET) { next_tss_desc.type |= (1 << 1); /* set busy flag */ - write_segment_descriptor(ctxt, tss_selector, &next_tss_desc); + write_segment_descriptor(ctxt, ops, tss_selector, + &next_tss_desc); } ops->set_cr(ctxt, 0, ops->get_cr(ctxt, 0) | X86_CR0_TS); ops->set_segment(ctxt, tss_selector, &next_tss_desc, 0, VCPU_SREG_TR); if (has_error_code) { - ctxt->op_bytes = ctxt->ad_bytes = (next_tss_desc.type & 8) ? 4 : 2; - ctxt->lock_prefix = 0; - ctxt->src.val = (unsigned long) error_code; + struct decode_cache *c = &ctxt->decode; + + c->op_bytes = c->ad_bytes = (next_tss_desc.type & 8) ? 4 : 2; + c->lock_prefix = 0; + c->src.val = (unsigned long) error_code; ret = em_push(ctxt); } @@ -2399,16 +2462,18 @@ int emulator_task_switch(struct x86_emulate_ctxt *ctxt, u16 tss_selector, int reason, bool has_error_code, u32 error_code) { + struct x86_emulate_ops *ops = ctxt->ops; + struct decode_cache *c = &ctxt->decode; int rc; - ctxt->_eip = ctxt->eip; - ctxt->dst.type = OP_NONE; + c->eip = ctxt->eip; + c->dst.type = OP_NONE; - rc = emulator_do_task_switch(ctxt, tss_selector, reason, + rc = emulator_do_task_switch(ctxt, ops, tss_selector, reason, has_error_code, error_code); if (rc == X86EMUL_CONTINUE) - ctxt->eip = ctxt->_eip; + ctxt->eip = c->eip; return (rc == X86EMUL_UNHANDLEABLE) ? EMULATION_FAILED : EMULATION_OK; } @@ -2416,20 +2481,22 @@ int emulator_task_switch(struct x86_emulate_ctxt *ctxt, static void string_addr_inc(struct x86_emulate_ctxt *ctxt, unsigned seg, int reg, struct operand *op) { + struct decode_cache *c = &ctxt->decode; int df = (ctxt->eflags & EFLG_DF) ? -1 : 1; - register_address_increment(ctxt, &ctxt->regs[reg], df * op->bytes); - op->addr.mem.ea = register_address(ctxt, ctxt->regs[reg]); + register_address_increment(c, &c->regs[reg], df * op->bytes); + op->addr.mem.ea = register_address(c, c->regs[reg]); op->addr.mem.seg = seg; } static int em_das(struct x86_emulate_ctxt *ctxt) { + struct decode_cache *c = &ctxt->decode; u8 al, old_al; bool af, cf, old_cf; cf = ctxt->eflags & X86_EFLAGS_CF; - al = ctxt->dst.val; + al = c->dst.val; old_al = al; old_cf = cf; @@ -2447,12 +2514,12 @@ static int em_das(struct x86_emulate_ctxt *ctxt) cf = true; } - ctxt->dst.val = al; + c->dst.val = al; /* Set PF, ZF, SF */ - ctxt->src.type = OP_IMM; - ctxt->src.val = 0; - ctxt->src.bytes = 1; - emulate_2op_SrcV("or", ctxt->src, ctxt->dst, ctxt->eflags); + c->src.type = OP_IMM; + c->src.val = 0; + c->src.bytes = 1; + emulate_2op_SrcV("or", c->src, c->dst, ctxt->eflags); ctxt->eflags &= ~(X86_EFLAGS_AF | X86_EFLAGS_CF); if (cf) ctxt->eflags |= X86_EFLAGS_CF; @@ -2463,189 +2530,175 @@ static int em_das(struct x86_emulate_ctxt *ctxt) static int em_call_far(struct x86_emulate_ctxt *ctxt) { + struct decode_cache *c = &ctxt->decode; u16 sel, old_cs; ulong old_eip; int rc; old_cs = get_segment_selector(ctxt, VCPU_SREG_CS); - old_eip = ctxt->_eip; + old_eip = c->eip; - memcpy(&sel, ctxt->src.valptr + ctxt->op_bytes, 2); - if (load_segment_descriptor(ctxt, sel, VCPU_SREG_CS)) + memcpy(&sel, c->src.valptr + c->op_bytes, 2); + if (load_segment_descriptor(ctxt, ctxt->ops, sel, VCPU_SREG_CS)) return X86EMUL_CONTINUE; - ctxt->_eip = 0; - memcpy(&ctxt->_eip, ctxt->src.valptr, ctxt->op_bytes); + c->eip = 0; + memcpy(&c->eip, c->src.valptr, c->op_bytes); - ctxt->src.val = old_cs; + c->src.val = old_cs; rc = em_push(ctxt); if (rc != X86EMUL_CONTINUE) return rc; - ctxt->src.val = old_eip; + c->src.val = old_eip; return em_push(ctxt); } static int em_ret_near_imm(struct x86_emulate_ctxt *ctxt) { + struct decode_cache *c = &ctxt->decode; int rc; - ctxt->dst.type = OP_REG; - ctxt->dst.addr.reg = &ctxt->_eip; - ctxt->dst.bytes = ctxt->op_bytes; - rc = emulate_pop(ctxt, &ctxt->dst.val, ctxt->op_bytes); + c->dst.type = OP_REG; + c->dst.addr.reg = &c->eip; + c->dst.bytes = c->op_bytes; + rc = emulate_pop(ctxt, &c->dst.val, c->op_bytes); if (rc != X86EMUL_CONTINUE) return rc; - register_address_increment(ctxt, &ctxt->regs[VCPU_REGS_RSP], ctxt->src.val); + register_address_increment(c, &c->regs[VCPU_REGS_RSP], c->src.val); return X86EMUL_CONTINUE; } static int em_add(struct x86_emulate_ctxt *ctxt) { - emulate_2op_SrcV("add", ctxt->src, ctxt->dst, ctxt->eflags); + struct decode_cache *c = &ctxt->decode; + + emulate_2op_SrcV("add", c->src, c->dst, ctxt->eflags); return X86EMUL_CONTINUE; } static int em_or(struct x86_emulate_ctxt *ctxt) { - emulate_2op_SrcV("or", ctxt->src, ctxt->dst, ctxt->eflags); + struct decode_cache *c = &ctxt->decode; + + emulate_2op_SrcV("or", c->src, c->dst, ctxt->eflags); return X86EMUL_CONTINUE; } static int em_adc(struct x86_emulate_ctxt *ctxt) { - emulate_2op_SrcV("adc", ctxt->src, ctxt->dst, ctxt->eflags); + struct decode_cache *c = &ctxt->decode; + + emulate_2op_SrcV("adc", c->src, c->dst, ctxt->eflags); return X86EMUL_CONTINUE; } static int em_sbb(struct x86_emulate_ctxt *ctxt) { - emulate_2op_SrcV("sbb", ctxt->src, ctxt->dst, ctxt->eflags); + struct decode_cache *c = &ctxt->decode; + + emulate_2op_SrcV("sbb", c->src, c->dst, ctxt->eflags); return X86EMUL_CONTINUE; } static int em_and(struct x86_emulate_ctxt *ctxt) { - emulate_2op_SrcV("and", ctxt->src, ctxt->dst, ctxt->eflags); + struct decode_cache *c = &ctxt->decode; + + emulate_2op_SrcV("and", c->src, c->dst, ctxt->eflags); return X86EMUL_CONTINUE; } static int em_sub(struct x86_emulate_ctxt *ctxt) { - emulate_2op_SrcV("sub", ctxt->src, ctxt->dst, ctxt->eflags); - return X86EMUL_CONTINUE; -} + struct decode_cache *c = &ctxt->decode; -static int em_xor(struct x86_emulate_ctxt *ctxt) -{ - emulate_2op_SrcV("xor", ctxt->src, ctxt->dst, ctxt->eflags); + emulate_2op_SrcV("sub", c->src, c->dst, ctxt->eflags); return X86EMUL_CONTINUE; } -static int em_cmp(struct x86_emulate_ctxt *ctxt) +static int em_xor(struct x86_emulate_ctxt *ctxt) { - emulate_2op_SrcV("cmp", ctxt->src, ctxt->dst, ctxt->eflags); - /* Disable writeback. */ - ctxt->dst.type = OP_NONE; - return X86EMUL_CONTINUE; -} + struct decode_cache *c = &ctxt->decode; -static int em_test(struct x86_emulate_ctxt *ctxt) -{ - emulate_2op_SrcV("test", ctxt->src, ctxt->dst, ctxt->eflags); + emulate_2op_SrcV("xor", c->src, c->dst, ctxt->eflags); return X86EMUL_CONTINUE; } -static int em_xchg(struct x86_emulate_ctxt *ctxt) +static int em_cmp(struct x86_emulate_ctxt *ctxt) { - /* Write back the register source. */ - ctxt->src.val = ctxt->dst.val; - write_register_operand(&ctxt->src); + struct decode_cache *c = &ctxt->decode; - /* Write back the memory destination with implicit LOCK prefix. */ - ctxt->dst.val = ctxt->src.orig_val; - ctxt->lock_prefix = 1; + emulate_2op_SrcV("cmp", c->src, c->dst, ctxt->eflags); + /* Disable writeback. */ + c->dst.type = OP_NONE; return X86EMUL_CONTINUE; } static int em_imul(struct x86_emulate_ctxt *ctxt) { - emulate_2op_SrcV_nobyte("imul", ctxt->src, ctxt->dst, ctxt->eflags); + struct decode_cache *c = &ctxt->decode; + + emulate_2op_SrcV_nobyte("imul", c->src, c->dst, ctxt->eflags); return X86EMUL_CONTINUE; } static int em_imul_3op(struct x86_emulate_ctxt *ctxt) { - ctxt->dst.val = ctxt->src2.val; + struct decode_cache *c = &ctxt->decode; + + c->dst.val = c->src2.val; return em_imul(ctxt); } static int em_cwd(struct x86_emulate_ctxt *ctxt) { - ctxt->dst.type = OP_REG; - ctxt->dst.bytes = ctxt->src.bytes; - ctxt->dst.addr.reg = &ctxt->regs[VCPU_REGS_RDX]; - ctxt->dst.val = ~((ctxt->src.val >> (ctxt->src.bytes * 8 - 1)) - 1); + struct decode_cache *c = &ctxt->decode; + + c->dst.type = OP_REG; + c->dst.bytes = c->src.bytes; + c->dst.addr.reg = &c->regs[VCPU_REGS_RDX]; + c->dst.val = ~((c->src.val >> (c->src.bytes * 8 - 1)) - 1); return X86EMUL_CONTINUE; } static int em_rdtsc(struct x86_emulate_ctxt *ctxt) { + struct decode_cache *c = &ctxt->decode; u64 tsc = 0; ctxt->ops->get_msr(ctxt, MSR_IA32_TSC, &tsc); - ctxt->regs[VCPU_REGS_RAX] = (u32)tsc; - ctxt->regs[VCPU_REGS_RDX] = tsc >> 32; + c->regs[VCPU_REGS_RAX] = (u32)tsc; + c->regs[VCPU_REGS_RDX] = tsc >> 32; return X86EMUL_CONTINUE; } static int em_mov(struct x86_emulate_ctxt *ctxt) { - ctxt->dst.val = ctxt->src.val; + struct decode_cache *c = &ctxt->decode; + c->dst.val = c->src.val; return X86EMUL_CONTINUE; } -static int em_mov_rm_sreg(struct x86_emulate_ctxt *ctxt) -{ - if (ctxt->modrm_reg > VCPU_SREG_GS) - return emulate_ud(ctxt); - - ctxt->dst.val = get_segment_selector(ctxt, ctxt->modrm_reg); - return X86EMUL_CONTINUE; -} - -static int em_mov_sreg_rm(struct x86_emulate_ctxt *ctxt) -{ - u16 sel = ctxt->src.val; - - if (ctxt->modrm_reg == VCPU_SREG_CS || ctxt->modrm_reg > VCPU_SREG_GS) - return emulate_ud(ctxt); - - if (ctxt->modrm_reg == VCPU_SREG_SS) - ctxt->interruptibility = KVM_X86_SHADOW_INT_MOV_SS; - - /* Disable writeback. */ - ctxt->dst.type = OP_NONE; - return load_segment_descriptor(ctxt, sel, ctxt->modrm_reg); -} - static int em_movdqu(struct x86_emulate_ctxt *ctxt) { - memcpy(&ctxt->dst.vec_val, &ctxt->src.vec_val, ctxt->op_bytes); + struct decode_cache *c = &ctxt->decode; + memcpy(&c->dst.vec_val, &c->src.vec_val, c->op_bytes); return X86EMUL_CONTINUE; } static int em_invlpg(struct x86_emulate_ctxt *ctxt) { + struct decode_cache *c = &ctxt->decode; int rc; ulong linear; - rc = linearize(ctxt, ctxt->src.addr.mem, 1, false, &linear); + rc = linearize(ctxt, c->src.addr.mem, 1, false, &linear); if (rc == X86EMUL_CONTINUE) ctxt->ops->invlpg(ctxt, linear); /* Disable writeback. */ - ctxt->dst.type = OP_NONE; + c->dst.type = OP_NONE; return X86EMUL_CONTINUE; } @@ -2661,9 +2714,10 @@ static int em_clts(struct x86_emulate_ctxt *ctxt) static int em_vmcall(struct x86_emulate_ctxt *ctxt) { + struct decode_cache *c = &ctxt->decode; int rc; - if (ctxt->modrm_mod != 3 || ctxt->modrm_rm != 1) + if (c->modrm_mod != 3 || c->modrm_rm != 1) return X86EMUL_UNHANDLEABLE; rc = ctxt->ops->fix_hypercall(ctxt); @@ -2671,104 +2725,73 @@ static int em_vmcall(struct x86_emulate_ctxt *ctxt) return rc; /* Let the processor re-execute the fixed hypercall */ - ctxt->_eip = ctxt->eip; + c->eip = ctxt->eip; /* Disable writeback. */ - ctxt->dst.type = OP_NONE; + c->dst.type = OP_NONE; return X86EMUL_CONTINUE; } static int em_lgdt(struct x86_emulate_ctxt *ctxt) { + struct decode_cache *c = &ctxt->decode; struct desc_ptr desc_ptr; int rc; - rc = read_descriptor(ctxt, ctxt->src.addr.mem, + rc = read_descriptor(ctxt, c->src.addr.mem, &desc_ptr.size, &desc_ptr.address, - ctxt->op_bytes); + c->op_bytes); if (rc != X86EMUL_CONTINUE) return rc; ctxt->ops->set_gdt(ctxt, &desc_ptr); /* Disable writeback. */ - ctxt->dst.type = OP_NONE; + c->dst.type = OP_NONE; return X86EMUL_CONTINUE; } static int em_vmmcall(struct x86_emulate_ctxt *ctxt) { + struct decode_cache *c = &ctxt->decode; int rc; rc = ctxt->ops->fix_hypercall(ctxt); /* Disable writeback. */ - ctxt->dst.type = OP_NONE; + c->dst.type = OP_NONE; return rc; } static int em_lidt(struct x86_emulate_ctxt *ctxt) { + struct decode_cache *c = &ctxt->decode; struct desc_ptr desc_ptr; int rc; - rc = read_descriptor(ctxt, ctxt->src.addr.mem, + rc = read_descriptor(ctxt, c->src.addr.mem, &desc_ptr.size, &desc_ptr.address, - ctxt->op_bytes); + c->op_bytes); if (rc != X86EMUL_CONTINUE) return rc; ctxt->ops->set_idt(ctxt, &desc_ptr); /* Disable writeback. */ - ctxt->dst.type = OP_NONE; + c->dst.type = OP_NONE; return X86EMUL_CONTINUE; } static int em_smsw(struct x86_emulate_ctxt *ctxt) { - ctxt->dst.bytes = 2; - ctxt->dst.val = ctxt->ops->get_cr(ctxt, 0); + struct decode_cache *c = &ctxt->decode; + + c->dst.bytes = 2; + c->dst.val = ctxt->ops->get_cr(ctxt, 0); return X86EMUL_CONTINUE; } static int em_lmsw(struct x86_emulate_ctxt *ctxt) { + struct decode_cache *c = &ctxt->decode; ctxt->ops->set_cr(ctxt, 0, (ctxt->ops->get_cr(ctxt, 0) & ~0x0eul) - | (ctxt->src.val & 0x0f)); - ctxt->dst.type = OP_NONE; - return X86EMUL_CONTINUE; -} - -static int em_loop(struct x86_emulate_ctxt *ctxt) -{ - register_address_increment(ctxt, &ctxt->regs[VCPU_REGS_RCX], -1); - if ((address_mask(ctxt, ctxt->regs[VCPU_REGS_RCX]) != 0) && - (ctxt->b == 0xe2 || test_cc(ctxt->b ^ 0x5, ctxt->eflags))) - jmp_rel(ctxt, ctxt->src.val); - - return X86EMUL_CONTINUE; -} - -static int em_jcxz(struct x86_emulate_ctxt *ctxt) -{ - if (address_mask(ctxt, ctxt->regs[VCPU_REGS_RCX]) == 0) - jmp_rel(ctxt, ctxt->src.val); - - return X86EMUL_CONTINUE; -} - -static int em_cli(struct x86_emulate_ctxt *ctxt) -{ - if (emulator_bad_iopl(ctxt)) - return emulate_gp(ctxt, 0); - - ctxt->eflags &= ~X86_EFLAGS_IF; - return X86EMUL_CONTINUE; -} - -static int em_sti(struct x86_emulate_ctxt *ctxt) -{ - if (emulator_bad_iopl(ctxt)) - return emulate_gp(ctxt, 0); - - ctxt->interruptibility = KVM_X86_SHADOW_INT_STI; - ctxt->eflags |= X86_EFLAGS_IF; + | (c->src.val & 0x0f)); + c->dst.type = OP_NONE; return X86EMUL_CONTINUE; } @@ -2786,7 +2809,9 @@ static bool valid_cr(int nr) static int check_cr_read(struct x86_emulate_ctxt *ctxt) { - if (!valid_cr(ctxt->modrm_reg)) + struct decode_cache *c = &ctxt->decode; + + if (!valid_cr(c->modrm_reg)) return emulate_ud(ctxt); return X86EMUL_CONTINUE; @@ -2794,8 +2819,9 @@ static int check_cr_read(struct x86_emulate_ctxt *ctxt) static int check_cr_write(struct x86_emulate_ctxt *ctxt) { - u64 new_val = ctxt->src.val64; - int cr = ctxt->modrm_reg; + struct decode_cache *c = &ctxt->decode; + u64 new_val = c->src.val64; + int cr = c->modrm_reg; u64 efer = 0; static u64 cr_reserved_bits[] = { @@ -2872,7 +2898,8 @@ static int check_dr7_gd(struct x86_emulate_ctxt *ctxt) static int check_dr_read(struct x86_emulate_ctxt *ctxt) { - int dr = ctxt->modrm_reg; + struct decode_cache *c = &ctxt->decode; + int dr = c->modrm_reg; u64 cr4; if (dr > 7) @@ -2890,8 +2917,9 @@ static int check_dr_read(struct x86_emulate_ctxt *ctxt) static int check_dr_write(struct x86_emulate_ctxt *ctxt) { - u64 new_val = ctxt->src.val64; - int dr = ctxt->modrm_reg; + struct decode_cache *c = &ctxt->decode; + u64 new_val = c->src.val64; + int dr = c->modrm_reg; if ((dr == 6 || dr == 7) && (new_val & 0xffffffff00000000ULL)) return emulate_gp(ctxt, 0); @@ -2913,7 +2941,7 @@ static int check_svme(struct x86_emulate_ctxt *ctxt) static int check_svme_pa(struct x86_emulate_ctxt *ctxt) { - u64 rax = ctxt->regs[VCPU_REGS_RAX]; + u64 rax = ctxt->decode.regs[VCPU_REGS_RAX]; /* Valid physical address? */ if (rax & 0xffff000000000000ULL) @@ -2935,7 +2963,7 @@ static int check_rdtsc(struct x86_emulate_ctxt *ctxt) static int check_rdpmc(struct x86_emulate_ctxt *ctxt) { u64 cr4 = ctxt->ops->get_cr(ctxt, 4); - u64 rcx = ctxt->regs[VCPU_REGS_RCX]; + u64 rcx = ctxt->decode.regs[VCPU_REGS_RCX]; if ((!(cr4 & X86_CR4_PCE) && ctxt->ops->cpl(ctxt)) || (rcx > 3)) @@ -2946,8 +2974,10 @@ static int check_rdpmc(struct x86_emulate_ctxt *ctxt) static int check_perm_in(struct x86_emulate_ctxt *ctxt) { - ctxt->dst.bytes = min(ctxt->dst.bytes, 4u); - if (!emulator_io_permited(ctxt, ctxt->src.val, ctxt->dst.bytes)) + struct decode_cache *c = &ctxt->decode; + + c->dst.bytes = min(c->dst.bytes, 4u); + if (!emulator_io_permited(ctxt, ctxt->ops, c->src.val, c->dst.bytes)) return emulate_gp(ctxt, 0); return X86EMUL_CONTINUE; @@ -2955,8 +2985,10 @@ static int check_perm_in(struct x86_emulate_ctxt *ctxt) static int check_perm_out(struct x86_emulate_ctxt *ctxt) { - ctxt->src.bytes = min(ctxt->src.bytes, 4u); - if (!emulator_io_permited(ctxt, ctxt->dst.val, ctxt->src.bytes)) + struct decode_cache *c = &ctxt->decode; + + c->src.bytes = min(c->src.bytes, 4u); + if (!emulator_io_permited(ctxt, ctxt->ops, c->dst.val, c->src.bytes)) return emulate_gp(ctxt, 0); return X86EMUL_CONTINUE; @@ -3133,15 +3165,12 @@ static struct opcode opcode_table[256] = { G(DstMem | SrcImm | ModRM | Group, group1), G(ByteOp | DstMem | SrcImm | ModRM | No64 | Group, group1), G(DstMem | SrcImmByte | ModRM | Group, group1), - I2bv(DstMem | SrcReg | ModRM, em_test), - I2bv(DstMem | SrcReg | ModRM | Lock, em_xchg), + D2bv(DstMem | SrcReg | ModRM), D2bv(DstMem | SrcReg | ModRM | Lock), /* 0x88 - 0x8F */ I2bv(DstMem | SrcReg | ModRM | Mov, em_mov), I2bv(DstReg | SrcMem | ModRM | Mov, em_mov), - I(DstMem | SrcNone | ModRM | Mov, em_mov_rm_sreg), - D(ModRM | SrcMem | NoAccess | DstReg), - I(ImplicitOps | SrcMem16 | ModRM, em_mov_sreg_rm), - G(0, group1A), + D(DstMem | SrcNone | ModRM | Mov), D(ModRM | SrcMem | NoAccess | DstReg), + D(ImplicitOps | SrcMem16 | ModRM), G(0, group1A), /* 0x90 - 0x97 */ DI(SrcAcc | DstReg, pause), X7(D(SrcAcc | DstReg)), /* 0x98 - 0x9F */ @@ -3155,7 +3184,7 @@ static struct opcode opcode_table[256] = { I2bv(SrcSI | DstDI | Mov | String, em_mov), I2bv(SrcSI | DstDI | String, em_cmp), /* 0xA8 - 0xAF */ - I2bv(DstAcc | SrcImm, em_test), + D2bv(DstAcc | SrcImm), I2bv(SrcAcc | DstDI | Mov | String, em_mov), I2bv(SrcSI | DstAcc | Mov | String, em_mov), I2bv(SrcAcc | DstDI | String, em_cmp), @@ -3166,26 +3195,25 @@ static struct opcode opcode_table[256] = { /* 0xC0 - 0xC7 */ D2bv(DstMem | SrcImmByte | ModRM), I(ImplicitOps | Stack | SrcImmU16, em_ret_near_imm), - I(ImplicitOps | Stack, em_ret), + D(ImplicitOps | Stack), D(DstReg | SrcMemFAddr | ModRM | No64), D(DstReg | SrcMemFAddr | ModRM | No64), G(ByteOp, group11), G(0, group11), /* 0xC8 - 0xCF */ - N, N, N, I(ImplicitOps | Stack, em_ret_far), + N, N, N, D(ImplicitOps | Stack), D(ImplicitOps), DI(SrcImmByte, intn), - D(ImplicitOps | No64), II(ImplicitOps, em_iret, iret), + D(ImplicitOps | No64), DI(ImplicitOps, iret), /* 0xD0 - 0xD7 */ D2bv(DstMem | SrcOne | ModRM), D2bv(DstMem | ModRM), N, N, N, N, /* 0xD8 - 0xDF */ N, N, N, N, N, N, N, N, /* 0xE0 - 0xE7 */ - X3(I(SrcImmByte, em_loop)), - I(SrcImmByte, em_jcxz), + X4(D(SrcImmByte)), D2bvIP(SrcImmUByte | DstAcc, in, check_perm_in), D2bvIP(SrcAcc | DstImmUByte, out, check_perm_out), /* 0xE8 - 0xEF */ D(SrcImm | Stack), D(SrcImm | ImplicitOps), - I(SrcImmFAddr | No64, em_jmp_far), D(SrcImmByte | ImplicitOps), + D(SrcImmFAddr | No64), D(SrcImmByte | ImplicitOps), D2bvIP(SrcDX | DstAcc, in, check_perm_in), D2bvIP(SrcAcc | DstDX, out, check_perm_out), /* 0xF0 - 0xF7 */ @@ -3193,16 +3221,14 @@ static struct opcode opcode_table[256] = { DI(ImplicitOps | Priv, hlt), D(ImplicitOps), G(ByteOp, group3), G(0, group3), /* 0xF8 - 0xFF */ - D(ImplicitOps), D(ImplicitOps), - I(ImplicitOps, em_cli), I(ImplicitOps, em_sti), + D(ImplicitOps), D(ImplicitOps), D(ImplicitOps), D(ImplicitOps), D(ImplicitOps), D(ImplicitOps), G(0, group4), G(0, group5), }; static struct opcode twobyte_table[256] = { /* 0x00 - 0x0F */ G(0, group6), GD(0, &group7), N, N, - N, I(ImplicitOps | VendorSpecific, em_syscall), - II(ImplicitOps | Priv, em_clts, clts), N, + N, D(ImplicitOps | VendorSpecific), DI(ImplicitOps | Priv, clts), N, DI(ImplicitOps | Priv, invd), DI(ImplicitOps | Priv, wbinvd), N, N, N, D(ImplicitOps | ModRM), N, N, /* 0x10 - 0x1F */ @@ -3219,8 +3245,7 @@ static struct opcode twobyte_table[256] = { IIP(ImplicitOps, em_rdtsc, rdtsc, check_rdtsc), DI(ImplicitOps | Priv, rdmsr), DIP(ImplicitOps | Priv, rdpmc, check_rdpmc), - I(ImplicitOps | VendorSpecific, em_sysenter), - I(ImplicitOps | Priv | VendorSpecific, em_sysexit), + D(ImplicitOps | VendorSpecific), D(ImplicitOps | Priv | VendorSpecific), N, N, N, N, N, N, N, N, N, N, /* 0x40 - 0x4F */ @@ -3288,11 +3313,11 @@ static struct opcode twobyte_table[256] = { #undef I2bv #undef I6ALU -static unsigned imm_size(struct x86_emulate_ctxt *ctxt) +static unsigned imm_size(struct decode_cache *c) { unsigned size; - size = (ctxt->d & ByteOp) ? 1 : ctxt->op_bytes; + size = (c->d & ByteOp) ? 1 : c->op_bytes; if (size == 8) size = 4; return size; @@ -3301,21 +3326,23 @@ static unsigned imm_size(struct x86_emulate_ctxt *ctxt) static int decode_imm(struct x86_emulate_ctxt *ctxt, struct operand *op, unsigned size, bool sign_extension) { + struct decode_cache *c = &ctxt->decode; + struct x86_emulate_ops *ops = ctxt->ops; int rc = X86EMUL_CONTINUE; op->type = OP_IMM; op->bytes = size; - op->addr.mem.ea = ctxt->_eip; + op->addr.mem.ea = c->eip; /* NB. Immediates are sign-extended as necessary. */ switch (op->bytes) { case 1: - op->val = insn_fetch(s8, 1, ctxt->_eip); + op->val = insn_fetch(s8, 1, c->eip); break; case 2: - op->val = insn_fetch(s16, 2, ctxt->_eip); + op->val = insn_fetch(s16, 2, c->eip); break; case 4: - op->val = insn_fetch(s32, 4, ctxt->_eip); + op->val = insn_fetch(s32, 4, c->eip); break; } if (!sign_extension) { @@ -3335,8 +3362,11 @@ static int decode_imm(struct x86_emulate_ctxt *ctxt, struct operand *op, return rc; } -int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len) +int +x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len) { + struct x86_emulate_ops *ops = ctxt->ops; + struct decode_cache *c = &ctxt->decode; int rc = X86EMUL_CONTINUE; int mode = ctxt->mode; int def_op_bytes, def_ad_bytes, goffset, simd_prefix; @@ -3344,11 +3374,11 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len) struct opcode opcode; struct operand memop = { .type = OP_NONE }, *memopp = NULL; - ctxt->_eip = ctxt->eip; - ctxt->fetch.start = ctxt->_eip; - ctxt->fetch.end = ctxt->fetch.start + insn_len; + c->eip = ctxt->eip; + c->fetch.start = c->eip; + c->fetch.end = c->fetch.start + insn_len; if (insn_len > 0) - memcpy(ctxt->fetch.data, insn, insn_len); + memcpy(c->fetch.data, insn, insn_len); switch (mode) { case X86EMUL_MODE_REAL: @@ -3369,46 +3399,46 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len) return -1; } - ctxt->op_bytes = def_op_bytes; - ctxt->ad_bytes = def_ad_bytes; + c->op_bytes = def_op_bytes; + c->ad_bytes = def_ad_bytes; /* Legacy prefixes. */ for (;;) { - switch (ctxt->b = insn_fetch(u8, 1, ctxt->_eip)) { + switch (c->b = insn_fetch(u8, 1, c->eip)) { case 0x66: /* operand-size override */ op_prefix = true; /* switch between 2/4 bytes */ - ctxt->op_bytes = def_op_bytes ^ 6; + c->op_bytes = def_op_bytes ^ 6; break; case 0x67: /* address-size override */ if (mode == X86EMUL_MODE_PROT64) /* switch between 4/8 bytes */ - ctxt->ad_bytes = def_ad_bytes ^ 12; + c->ad_bytes = def_ad_bytes ^ 12; else /* switch between 2/4 bytes */ - ctxt->ad_bytes = def_ad_bytes ^ 6; + c->ad_bytes = def_ad_bytes ^ 6; break; case 0x26: /* ES override */ case 0x2e: /* CS override */ case 0x36: /* SS override */ case 0x3e: /* DS override */ - set_seg_override(ctxt, (ctxt->b >> 3) & 3); + set_seg_override(c, (c->b >> 3) & 3); break; case 0x64: /* FS override */ case 0x65: /* GS override */ - set_seg_override(ctxt, ctxt->b & 7); + set_seg_override(c, c->b & 7); break; case 0x40 ... 0x4f: /* REX */ if (mode != X86EMUL_MODE_PROT64) goto done_prefixes; - ctxt->rex_prefix = ctxt->b; + c->rex_prefix = c->b; continue; case 0xf0: /* LOCK */ - ctxt->lock_prefix = 1; + c->lock_prefix = 1; break; case 0xf2: /* REPNE/REPNZ */ case 0xf3: /* REP/REPE/REPZ */ - ctxt->rep_prefix = ctxt->b; + c->rep_prefix = c->b; break; default: goto done_prefixes; @@ -3416,50 +3446,50 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len) /* Any legacy prefix after a REX prefix nullifies its effect. */ - ctxt->rex_prefix = 0; + c->rex_prefix = 0; } done_prefixes: /* REX prefix. */ - if (ctxt->rex_prefix & 8) - ctxt->op_bytes = 8; /* REX.W */ + if (c->rex_prefix & 8) + c->op_bytes = 8; /* REX.W */ /* Opcode byte(s). */ - opcode = opcode_table[ctxt->b]; + opcode = opcode_table[c->b]; /* Two-byte opcode? */ - if (ctxt->b == 0x0f) { - ctxt->twobyte = 1; - ctxt->b = insn_fetch(u8, 1, ctxt->_eip); - opcode = twobyte_table[ctxt->b]; + if (c->b == 0x0f) { + c->twobyte = 1; + c->b = insn_fetch(u8, 1, c->eip); + opcode = twobyte_table[c->b]; } - ctxt->d = opcode.flags; + c->d = opcode.flags; - while (ctxt->d & GroupMask) { - switch (ctxt->d & GroupMask) { + while (c->d & GroupMask) { + switch (c->d & GroupMask) { case Group: - ctxt->modrm = insn_fetch(u8, 1, ctxt->_eip); - --ctxt->_eip; - goffset = (ctxt->modrm >> 3) & 7; + c->modrm = insn_fetch(u8, 1, c->eip); + --c->eip; + goffset = (c->modrm >> 3) & 7; opcode = opcode.u.group[goffset]; break; case GroupDual: - ctxt->modrm = insn_fetch(u8, 1, ctxt->_eip); - --ctxt->_eip; - goffset = (ctxt->modrm >> 3) & 7; - if ((ctxt->modrm >> 6) == 3) + c->modrm = insn_fetch(u8, 1, c->eip); + --c->eip; + goffset = (c->modrm >> 3) & 7; + if ((c->modrm >> 6) == 3) opcode = opcode.u.gdual->mod3[goffset]; else opcode = opcode.u.gdual->mod012[goffset]; break; case RMExt: - goffset = ctxt->modrm & 7; + goffset = c->modrm & 7; opcode = opcode.u.group[goffset]; break; case Prefix: - if (ctxt->rep_prefix && op_prefix) + if (c->rep_prefix && op_prefix) return X86EMUL_UNHANDLEABLE; - simd_prefix = op_prefix ? 0x66 : ctxt->rep_prefix; + simd_prefix = op_prefix ? 0x66 : c->rep_prefix; switch (simd_prefix) { case 0x00: opcode = opcode.u.gprefix->pfx_no; break; case 0x66: opcode = opcode.u.gprefix->pfx_66; break; @@ -3471,61 +3501,61 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len) return X86EMUL_UNHANDLEABLE; } - ctxt->d &= ~GroupMask; - ctxt->d |= opcode.flags; + c->d &= ~GroupMask; + c->d |= opcode.flags; } - ctxt->execute = opcode.u.execute; - ctxt->check_perm = opcode.check_perm; - ctxt->intercept = opcode.intercept; + c->execute = opcode.u.execute; + c->check_perm = opcode.check_perm; + c->intercept = opcode.intercept; /* Unrecognised? */ - if (ctxt->d == 0 || (ctxt->d & Undefined)) + if (c->d == 0 || (c->d & Undefined)) return -1; - if (!(ctxt->d & VendorSpecific) && ctxt->only_vendor_specific_insn) + if (!(c->d & VendorSpecific) && ctxt->only_vendor_specific_insn) return -1; - if (mode == X86EMUL_MODE_PROT64 && (ctxt->d & Stack)) - ctxt->op_bytes = 8; + if (mode == X86EMUL_MODE_PROT64 && (c->d & Stack)) + c->op_bytes = 8; - if (ctxt->d & Op3264) { + if (c->d & Op3264) { if (mode == X86EMUL_MODE_PROT64) - ctxt->op_bytes = 8; + c->op_bytes = 8; else - ctxt->op_bytes = 4; + c->op_bytes = 4; } - if (ctxt->d & Sse) - ctxt->op_bytes = 16; + if (c->d & Sse) + c->op_bytes = 16; /* ModRM and SIB bytes. */ - if (ctxt->d & ModRM) { - rc = decode_modrm(ctxt, &memop); - if (!ctxt->has_seg_override) - set_seg_override(ctxt, ctxt->modrm_seg); - } else if (ctxt->d & MemAbs) - rc = decode_abs(ctxt, &memop); + if (c->d & ModRM) { + rc = decode_modrm(ctxt, ops, &memop); + if (!c->has_seg_override) + set_seg_override(c, c->modrm_seg); + } else if (c->d & MemAbs) + rc = decode_abs(ctxt, ops, &memop); if (rc != X86EMUL_CONTINUE) goto done; - if (!ctxt->has_seg_override) - set_seg_override(ctxt, VCPU_SREG_DS); + if (!c->has_seg_override) + set_seg_override(c, VCPU_SREG_DS); - memop.addr.mem.seg = seg_override(ctxt); + memop.addr.mem.seg = seg_override(ctxt, c); - if (memop.type == OP_MEM && ctxt->ad_bytes != 8) + if (memop.type == OP_MEM && c->ad_bytes != 8) memop.addr.mem.ea = (u32)memop.addr.mem.ea; /* * Decode and fetch the source operand: register, memory * or immediate. */ - switch (ctxt->d & SrcMask) { + switch (c->d & SrcMask) { case SrcNone: break; case SrcReg: - decode_register_operand(ctxt, &ctxt->src, 0); + decode_register_operand(ctxt, &c->src, c, 0); break; case SrcMem16: memop.bytes = 2; @@ -3534,60 +3564,60 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len) memop.bytes = 4; goto srcmem_common; case SrcMem: - memop.bytes = (ctxt->d & ByteOp) ? 1 : - ctxt->op_bytes; + memop.bytes = (c->d & ByteOp) ? 1 : + c->op_bytes; srcmem_common: - ctxt->src = memop; - memopp = &ctxt->src; + c->src = memop; + memopp = &c->src; break; case SrcImmU16: - rc = decode_imm(ctxt, &ctxt->src, 2, false); + rc = decode_imm(ctxt, &c->src, 2, false); break; case SrcImm: - rc = decode_imm(ctxt, &ctxt->src, imm_size(ctxt), true); + rc = decode_imm(ctxt, &c->src, imm_size(c), true); break; case SrcImmU: - rc = decode_imm(ctxt, &ctxt->src, imm_size(ctxt), false); + rc = decode_imm(ctxt, &c->src, imm_size(c), false); break; case SrcImmByte: - rc = decode_imm(ctxt, &ctxt->src, 1, true); + rc = decode_imm(ctxt, &c->src, 1, true); break; case SrcImmUByte: - rc = decode_imm(ctxt, &ctxt->src, 1, false); + rc = decode_imm(ctxt, &c->src, 1, false); break; case SrcAcc: - ctxt->src.type = OP_REG; - ctxt->src.bytes = (ctxt->d & ByteOp) ? 1 : ctxt->op_bytes; - ctxt->src.addr.reg = &ctxt->regs[VCPU_REGS_RAX]; - fetch_register_operand(&ctxt->src); + c->src.type = OP_REG; + c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; + c->src.addr.reg = &c->regs[VCPU_REGS_RAX]; + fetch_register_operand(&c->src); break; case SrcOne: - ctxt->src.bytes = 1; - ctxt->src.val = 1; + c->src.bytes = 1; + c->src.val = 1; break; case SrcSI: - ctxt->src.type = OP_MEM; - ctxt->src.bytes = (ctxt->d & ByteOp) ? 1 : ctxt->op_bytes; - ctxt->src.addr.mem.ea = - register_address(ctxt, ctxt->regs[VCPU_REGS_RSI]); - ctxt->src.addr.mem.seg = seg_override(ctxt); - ctxt->src.val = 0; + c->src.type = OP_MEM; + c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; + c->src.addr.mem.ea = + register_address(c, c->regs[VCPU_REGS_RSI]); + c->src.addr.mem.seg = seg_override(ctxt, c); + c->src.val = 0; break; case SrcImmFAddr: - ctxt->src.type = OP_IMM; - ctxt->src.addr.mem.ea = ctxt->_eip; - ctxt->src.bytes = ctxt->op_bytes + 2; - insn_fetch_arr(ctxt->src.valptr, ctxt->src.bytes, ctxt->_eip); + c->src.type = OP_IMM; + c->src.addr.mem.ea = c->eip; + c->src.bytes = c->op_bytes + 2; + insn_fetch_arr(c->src.valptr, c->src.bytes, c->eip); break; case SrcMemFAddr: - memop.bytes = ctxt->op_bytes + 2; + memop.bytes = c->op_bytes + 2; goto srcmem_common; break; case SrcDX: - ctxt->src.type = OP_REG; - ctxt->src.bytes = 2; - ctxt->src.addr.reg = &ctxt->regs[VCPU_REGS_RDX]; - fetch_register_operand(&ctxt->src); + c->src.type = OP_REG; + c->src.bytes = 2; + c->src.addr.reg = &c->regs[VCPU_REGS_RDX]; + fetch_register_operand(&c->src); break; } @@ -3598,22 +3628,22 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len) * Decode and fetch the second source operand: register, memory * or immediate. */ - switch (ctxt->d & Src2Mask) { + switch (c->d & Src2Mask) { case Src2None: break; case Src2CL: - ctxt->src2.bytes = 1; - ctxt->src2.val = ctxt->regs[VCPU_REGS_RCX] & 0x8; + c->src2.bytes = 1; + c->src2.val = c->regs[VCPU_REGS_RCX] & 0x8; break; case Src2ImmByte: - rc = decode_imm(ctxt, &ctxt->src2, 1, true); + rc = decode_imm(ctxt, &c->src2, 1, true); break; case Src2One: - ctxt->src2.bytes = 1; - ctxt->src2.val = 1; + c->src2.bytes = 1; + c->src2.val = 1; break; case Src2Imm: - rc = decode_imm(ctxt, &ctxt->src2, imm_size(ctxt), true); + rc = decode_imm(ctxt, &c->src2, imm_size(c), true); break; } @@ -3621,66 +3651,68 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len) goto done; /* Decode and fetch the destination operand: register or memory. */ - switch (ctxt->d & DstMask) { + switch (c->d & DstMask) { case DstReg: - decode_register_operand(ctxt, &ctxt->dst, - ctxt->twobyte && (ctxt->b == 0xb6 || ctxt->b == 0xb7)); + decode_register_operand(ctxt, &c->dst, c, + c->twobyte && (c->b == 0xb6 || c->b == 0xb7)); break; case DstImmUByte: - ctxt->dst.type = OP_IMM; - ctxt->dst.addr.mem.ea = ctxt->_eip; - ctxt->dst.bytes = 1; - ctxt->dst.val = insn_fetch(u8, 1, ctxt->_eip); + c->dst.type = OP_IMM; + c->dst.addr.mem.ea = c->eip; + c->dst.bytes = 1; + c->dst.val = insn_fetch(u8, 1, c->eip); break; case DstMem: case DstMem64: - ctxt->dst = memop; - memopp = &ctxt->dst; - if ((ctxt->d & DstMask) == DstMem64) - ctxt->dst.bytes = 8; + c->dst = memop; + memopp = &c->dst; + if ((c->d & DstMask) == DstMem64) + c->dst.bytes = 8; else - ctxt->dst.bytes = (ctxt->d & ByteOp) ? 1 : ctxt->op_bytes; - if (ctxt->d & BitOp) - fetch_bit_operand(ctxt); - ctxt->dst.orig_val = ctxt->dst.val; + c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; + if (c->d & BitOp) + fetch_bit_operand(c); + c->dst.orig_val = c->dst.val; break; case DstAcc: - ctxt->dst.type = OP_REG; - ctxt->dst.bytes = (ctxt->d & ByteOp) ? 1 : ctxt->op_bytes; - ctxt->dst.addr.reg = &ctxt->regs[VCPU_REGS_RAX]; - fetch_register_operand(&ctxt->dst); - ctxt->dst.orig_val = ctxt->dst.val; + c->dst.type = OP_REG; + c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; + c->dst.addr.reg = &c->regs[VCPU_REGS_RAX]; + fetch_register_operand(&c->dst); + c->dst.orig_val = c->dst.val; break; case DstDI: - ctxt->dst.type = OP_MEM; - ctxt->dst.bytes = (ctxt->d & ByteOp) ? 1 : ctxt->op_bytes; - ctxt->dst.addr.mem.ea = - register_address(ctxt, ctxt->regs[VCPU_REGS_RDI]); - ctxt->dst.addr.mem.seg = VCPU_SREG_ES; - ctxt->dst.val = 0; + c->dst.type = OP_MEM; + c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; + c->dst.addr.mem.ea = + register_address(c, c->regs[VCPU_REGS_RDI]); + c->dst.addr.mem.seg = VCPU_SREG_ES; + c->dst.val = 0; break; case DstDX: - ctxt->dst.type = OP_REG; - ctxt->dst.bytes = 2; - ctxt->dst.addr.reg = &ctxt->regs[VCPU_REGS_RDX]; - fetch_register_operand(&ctxt->dst); + c->dst.type = OP_REG; + c->dst.bytes = 2; + c->dst.addr.reg = &c->regs[VCPU_REGS_RDX]; + fetch_register_operand(&c->dst); break; case ImplicitOps: /* Special instructions do their own operand decoding. */ default: - ctxt->dst.type = OP_NONE; /* Disable writeback. */ + c->dst.type = OP_NONE; /* Disable writeback. */ break; } done: - if (memopp && memopp->type == OP_MEM && ctxt->rip_relative) - memopp->addr.mem.ea += ctxt->_eip; + if (memopp && memopp->type == OP_MEM && c->rip_relative) + memopp->addr.mem.ea += c->eip; return (rc == X86EMUL_UNHANDLEABLE) ? EMULATION_FAILED : EMULATION_OK; } static bool string_insn_completed(struct x86_emulate_ctxt *ctxt) { + struct decode_cache *c = &ctxt->decode; + /* The second termination condition only applies for REPE * and REPNE. Test if the repeat string operation prefix is * REPE/REPZ or REPNE/REPNZ and if it's the case it tests the @@ -3688,232 +3720,304 @@ static bool string_insn_completed(struct x86_emulate_ctxt *ctxt) * - if REPE/REPZ and ZF = 0 then done * - if REPNE/REPNZ and ZF = 1 then done */ - if (((ctxt->b == 0xa6) || (ctxt->b == 0xa7) || - (ctxt->b == 0xae) || (ctxt->b == 0xaf)) - && (((ctxt->rep_prefix == REPE_PREFIX) && + if (((c->b == 0xa6) || (c->b == 0xa7) || + (c->b == 0xae) || (c->b == 0xaf)) + && (((c->rep_prefix == REPE_PREFIX) && ((ctxt->eflags & EFLG_ZF) == 0)) - || ((ctxt->rep_prefix == REPNE_PREFIX) && + || ((c->rep_prefix == REPNE_PREFIX) && ((ctxt->eflags & EFLG_ZF) == EFLG_ZF)))) return true; return false; } -int x86_emulate_insn(struct x86_emulate_ctxt *ctxt) +int +x86_emulate_insn(struct x86_emulate_ctxt *ctxt) { struct x86_emulate_ops *ops = ctxt->ops; u64 msr_data; + struct decode_cache *c = &ctxt->decode; int rc = X86EMUL_CONTINUE; - int saved_dst_type = ctxt->dst.type; + int saved_dst_type = c->dst.type; + int irq; /* Used for int 3, int, and into */ - ctxt->mem_read.pos = 0; + ctxt->decode.mem_read.pos = 0; - if (ctxt->mode == X86EMUL_MODE_PROT64 && (ctxt->d & No64)) { + if (ctxt->mode == X86EMUL_MODE_PROT64 && (c->d & No64)) { rc = emulate_ud(ctxt); goto done; } /* LOCK prefix is allowed only with some instructions */ - if (ctxt->lock_prefix && (!(ctxt->d & Lock) || ctxt->dst.type != OP_MEM)) { + if (c->lock_prefix && (!(c->d & Lock) || c->dst.type != OP_MEM)) { rc = emulate_ud(ctxt); goto done; } - if ((ctxt->d & SrcMask) == SrcMemFAddr && ctxt->src.type != OP_MEM) { + if ((c->d & SrcMask) == SrcMemFAddr && c->src.type != OP_MEM) { rc = emulate_ud(ctxt); goto done; } - if ((ctxt->d & Sse) + if ((c->d & Sse) && ((ops->get_cr(ctxt, 0) & X86_CR0_EM) || !(ops->get_cr(ctxt, 4) & X86_CR4_OSFXSR))) { rc = emulate_ud(ctxt); goto done; } - if ((ctxt->d & Sse) && (ops->get_cr(ctxt, 0) & X86_CR0_TS)) { + if ((c->d & Sse) && (ops->get_cr(ctxt, 0) & X86_CR0_TS)) { rc = emulate_nm(ctxt); goto done; } - if (unlikely(ctxt->guest_mode) && ctxt->intercept) { - rc = emulator_check_intercept(ctxt, ctxt->intercept, + if (unlikely(ctxt->guest_mode) && c->intercept) { + rc = emulator_check_intercept(ctxt, c->intercept, X86_ICPT_PRE_EXCEPT); if (rc != X86EMUL_CONTINUE) goto done; } /* Privileged instruction can be executed only in CPL=0 */ - if ((ctxt->d & Priv) && ops->cpl(ctxt)) { + if ((c->d & Priv) && ops->cpl(ctxt)) { rc = emulate_gp(ctxt, 0); goto done; } /* Instruction can only be executed in protected mode */ - if ((ctxt->d & Prot) && !(ctxt->mode & X86EMUL_MODE_PROT)) { + if ((c->d & Prot) && !(ctxt->mode & X86EMUL_MODE_PROT)) { rc = emulate_ud(ctxt); goto done; } /* Do instruction specific permission checks */ - if (ctxt->check_perm) { - rc = ctxt->check_perm(ctxt); + if (c->check_perm) { + rc = c->check_perm(ctxt); if (rc != X86EMUL_CONTINUE) goto done; } - if (unlikely(ctxt->guest_mode) && ctxt->intercept) { - rc = emulator_check_intercept(ctxt, ctxt->intercept, + if (unlikely(ctxt->guest_mode) && c->intercept) { + rc = emulator_check_intercept(ctxt, c->intercept, X86_ICPT_POST_EXCEPT); if (rc != X86EMUL_CONTINUE) goto done; } - if (ctxt->rep_prefix && (ctxt->d & String)) { + if (c->rep_prefix && (c->d & String)) { /* All REP prefixes have the same first termination condition */ - if (address_mask(ctxt, ctxt->regs[VCPU_REGS_RCX]) == 0) { - ctxt->eip = ctxt->_eip; + if (address_mask(c, c->regs[VCPU_REGS_RCX]) == 0) { + ctxt->eip = c->eip; goto done; } } - if ((ctxt->src.type == OP_MEM) && !(ctxt->d & NoAccess)) { - rc = segmented_read(ctxt, ctxt->src.addr.mem, - ctxt->src.valptr, ctxt->src.bytes); + if ((c->src.type == OP_MEM) && !(c->d & NoAccess)) { + rc = segmented_read(ctxt, c->src.addr.mem, + c->src.valptr, c->src.bytes); if (rc != X86EMUL_CONTINUE) goto done; - ctxt->src.orig_val64 = ctxt->src.val64; + c->src.orig_val64 = c->src.val64; } - if (ctxt->src2.type == OP_MEM) { - rc = segmented_read(ctxt, ctxt->src2.addr.mem, - &ctxt->src2.val, ctxt->src2.bytes); + if (c->src2.type == OP_MEM) { + rc = segmented_read(ctxt, c->src2.addr.mem, + &c->src2.val, c->src2.bytes); if (rc != X86EMUL_CONTINUE) goto done; } - if ((ctxt->d & DstMask) == ImplicitOps) + if ((c->d & DstMask) == ImplicitOps) goto special_insn; - if ((ctxt->dst.type == OP_MEM) && !(ctxt->d & Mov)) { + if ((c->dst.type == OP_MEM) && !(c->d & Mov)) { /* optimisation - avoid slow emulated read if Mov */ - rc = segmented_read(ctxt, ctxt->dst.addr.mem, - &ctxt->dst.val, ctxt->dst.bytes); + rc = segmented_read(ctxt, c->dst.addr.mem, + &c->dst.val, c->dst.bytes); if (rc != X86EMUL_CONTINUE) goto done; } - ctxt->dst.orig_val = ctxt->dst.val; + c->dst.orig_val = c->dst.val; special_insn: - if (unlikely(ctxt->guest_mode) && ctxt->intercept) { - rc = emulator_check_intercept(ctxt, ctxt->intercept, + if (unlikely(ctxt->guest_mode) && c->intercept) { + rc = emulator_check_intercept(ctxt, c->intercept, X86_ICPT_POST_MEMACCESS); if (rc != X86EMUL_CONTINUE) goto done; } - if (ctxt->execute) { - rc = ctxt->execute(ctxt); + if (c->execute) { + rc = c->execute(ctxt); if (rc != X86EMUL_CONTINUE) goto done; goto writeback; } - if (ctxt->twobyte) + if (c->twobyte) goto twobyte_insn; - switch (ctxt->b) { + switch (c->b) { case 0x06: /* push es */ - rc = emulate_push_sreg(ctxt, VCPU_SREG_ES); + rc = emulate_push_sreg(ctxt, ops, VCPU_SREG_ES); break; case 0x07: /* pop es */ - rc = emulate_pop_sreg(ctxt, VCPU_SREG_ES); + rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_ES); break; case 0x0e: /* push cs */ - rc = emulate_push_sreg(ctxt, VCPU_SREG_CS); + rc = emulate_push_sreg(ctxt, ops, VCPU_SREG_CS); break; case 0x16: /* push ss */ - rc = emulate_push_sreg(ctxt, VCPU_SREG_SS); + rc = emulate_push_sreg(ctxt, ops, VCPU_SREG_SS); break; case 0x17: /* pop ss */ - rc = emulate_pop_sreg(ctxt, VCPU_SREG_SS); + rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_SS); break; case 0x1e: /* push ds */ - rc = emulate_push_sreg(ctxt, VCPU_SREG_DS); + rc = emulate_push_sreg(ctxt, ops, VCPU_SREG_DS); break; case 0x1f: /* pop ds */ - rc = emulate_pop_sreg(ctxt, VCPU_SREG_DS); + rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_DS); break; case 0x40 ... 0x47: /* inc r16/r32 */ - emulate_1op("inc", ctxt->dst, ctxt->eflags); + emulate_1op("inc", c->dst, ctxt->eflags); break; case 0x48 ... 0x4f: /* dec r16/r32 */ - emulate_1op("dec", ctxt->dst, ctxt->eflags); + emulate_1op("dec", c->dst, ctxt->eflags); break; case 0x63: /* movsxd */ if (ctxt->mode != X86EMUL_MODE_PROT64) goto cannot_emulate; - ctxt->dst.val = (s32) ctxt->src.val; + c->dst.val = (s32) c->src.val; break; case 0x6c: /* insb */ case 0x6d: /* insw/insd */ - ctxt->src.val = ctxt->regs[VCPU_REGS_RDX]; + c->src.val = c->regs[VCPU_REGS_RDX]; goto do_io_in; case 0x6e: /* outsb */ case 0x6f: /* outsw/outsd */ - ctxt->dst.val = ctxt->regs[VCPU_REGS_RDX]; + c->dst.val = c->regs[VCPU_REGS_RDX]; goto do_io_out; break; case 0x70 ... 0x7f: /* jcc (short) */ - if (test_cc(ctxt->b, ctxt->eflags)) - jmp_rel(ctxt, ctxt->src.val); + if (test_cc(c->b, ctxt->eflags)) + jmp_rel(c, c->src.val); + break; + case 0x84 ... 0x85: + test: + emulate_2op_SrcV("test", c->src, c->dst, ctxt->eflags); + break; + case 0x86 ... 0x87: /* xchg */ + xchg: + /* Write back the register source. */ + c->src.val = c->dst.val; + write_register_operand(&c->src); + /* + * Write back the memory destination with implicit LOCK + * prefix. + */ + c->dst.val = c->src.orig_val; + c->lock_prefix = 1; + break; + case 0x8c: /* mov r/m, sreg */ + if (c->modrm_reg > VCPU_SREG_GS) { + rc = emulate_ud(ctxt); + goto done; + } + c->dst.val = get_segment_selector(ctxt, c->modrm_reg); break; case 0x8d: /* lea r16/r32, m */ - ctxt->dst.val = ctxt->src.addr.mem.ea; + c->dst.val = c->src.addr.mem.ea; break; + case 0x8e: { /* mov seg, r/m16 */ + uint16_t sel; + + sel = c->src.val; + + if (c->modrm_reg == VCPU_SREG_CS || + c->modrm_reg > VCPU_SREG_GS) { + rc = emulate_ud(ctxt); + goto done; + } + + if (c->modrm_reg == VCPU_SREG_SS) + ctxt->interruptibility = KVM_X86_SHADOW_INT_MOV_SS; + + rc = load_segment_descriptor(ctxt, ops, sel, c->modrm_reg); + + c->dst.type = OP_NONE; /* Disable writeback. */ + break; + } case 0x8f: /* pop (sole member of Grp1a) */ rc = em_grp1a(ctxt); break; case 0x90 ... 0x97: /* nop / xchg reg, rax */ - if (ctxt->dst.addr.reg == &ctxt->regs[VCPU_REGS_RAX]) + if (c->dst.addr.reg == &c->regs[VCPU_REGS_RAX]) break; - rc = em_xchg(ctxt); - break; + goto xchg; case 0x98: /* cbw/cwde/cdqe */ - switch (ctxt->op_bytes) { - case 2: ctxt->dst.val = (s8)ctxt->dst.val; break; - case 4: ctxt->dst.val = (s16)ctxt->dst.val; break; - case 8: ctxt->dst.val = (s32)ctxt->dst.val; break; + switch (c->op_bytes) { + case 2: c->dst.val = (s8)c->dst.val; break; + case 4: c->dst.val = (s16)c->dst.val; break; + case 8: c->dst.val = (s32)c->dst.val; break; } break; + case 0xa8 ... 0xa9: /* test ax, imm */ + goto test; case 0xc0 ... 0xc1: rc = em_grp2(ctxt); break; + case 0xc3: /* ret */ + c->dst.type = OP_REG; + c->dst.addr.reg = &c->eip; + c->dst.bytes = c->op_bytes; + rc = em_pop(ctxt); + break; case 0xc4: /* les */ - rc = emulate_load_segment(ctxt, VCPU_SREG_ES); + rc = emulate_load_segment(ctxt, ops, VCPU_SREG_ES); break; case 0xc5: /* lds */ - rc = emulate_load_segment(ctxt, VCPU_SREG_DS); + rc = emulate_load_segment(ctxt, ops, VCPU_SREG_DS); break; - case 0xcc: /* int3 */ - rc = emulate_int(ctxt, 3); + case 0xcb: /* ret far */ + rc = emulate_ret_far(ctxt, ops); break; + case 0xcc: /* int3 */ + irq = 3; + goto do_interrupt; case 0xcd: /* int n */ - rc = emulate_int(ctxt, ctxt->src.val); + irq = c->src.val; + do_interrupt: + rc = emulate_int(ctxt, ops, irq); break; case 0xce: /* into */ - if (ctxt->eflags & EFLG_OF) - rc = emulate_int(ctxt, 4); + if (ctxt->eflags & EFLG_OF) { + irq = 4; + goto do_interrupt; + } + break; + case 0xcf: /* iret */ + rc = emulate_iret(ctxt, ops); break; case 0xd0 ... 0xd1: /* Grp2 */ rc = em_grp2(ctxt); break; case 0xd2 ... 0xd3: /* Grp2 */ - ctxt->src.val = ctxt->regs[VCPU_REGS_RCX]; + c->src.val = c->regs[VCPU_REGS_RCX]; rc = em_grp2(ctxt); break; + case 0xe0 ... 0xe2: /* loop/loopz/loopnz */ + register_address_increment(c, &c->regs[VCPU_REGS_RCX], -1); + if (address_mask(c, c->regs[VCPU_REGS_RCX]) != 0 && + (c->b == 0xe2 || test_cc(c->b ^ 0x5, ctxt->eflags))) + jmp_rel(c, c->src.val); + break; + case 0xe3: /* jcxz/jecxz/jrcxz */ + if (address_mask(c, c->regs[VCPU_REGS_RCX]) == 0) + jmp_rel(c, c->src.val); + break; case 0xe4: /* inb */ case 0xe5: /* in */ goto do_io_in; @@ -3921,30 +4025,35 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt) case 0xe7: /* out */ goto do_io_out; case 0xe8: /* call (near) */ { - long int rel = ctxt->src.val; - ctxt->src.val = (unsigned long) ctxt->_eip; - jmp_rel(ctxt, rel); + long int rel = c->src.val; + c->src.val = (unsigned long) c->eip; + jmp_rel(c, rel); rc = em_push(ctxt); break; } case 0xe9: /* jmp rel */ - case 0xeb: /* jmp rel short */ - jmp_rel(ctxt, ctxt->src.val); - ctxt->dst.type = OP_NONE; /* Disable writeback. */ + goto jmp; + case 0xea: /* jmp far */ + rc = em_jmp_far(ctxt); + break; + case 0xeb: + jmp: /* jmp rel short */ + jmp_rel(c, c->src.val); + c->dst.type = OP_NONE; /* Disable writeback. */ break; case 0xec: /* in al,dx */ case 0xed: /* in (e/r)ax,dx */ do_io_in: - if (!pio_in_emulated(ctxt, ctxt->dst.bytes, ctxt->src.val, - &ctxt->dst.val)) + if (!pio_in_emulated(ctxt, ops, c->dst.bytes, c->src.val, + &c->dst.val)) goto done; /* IO is needed */ break; case 0xee: /* out dx,al */ case 0xef: /* out dx,(e/r)ax */ do_io_out: - ops->pio_out_emulated(ctxt, ctxt->src.bytes, ctxt->dst.val, - &ctxt->src.val, 1); - ctxt->dst.type = OP_NONE; /* Disable writeback. */ + ops->pio_out_emulated(ctxt, c->src.bytes, c->dst.val, + &c->src.val, 1); + c->dst.type = OP_NONE; /* Disable writeback. */ break; case 0xf4: /* hlt */ ctxt->ops->halt(ctxt); @@ -3962,6 +4071,22 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt) case 0xf9: /* stc */ ctxt->eflags |= EFLG_CF; break; + case 0xfa: /* cli */ + if (emulator_bad_iopl(ctxt, ops)) { + rc = emulate_gp(ctxt, 0); + goto done; + } else + ctxt->eflags &= ~X86_EFLAGS_IF; + break; + case 0xfb: /* sti */ + if (emulator_bad_iopl(ctxt, ops)) { + rc = emulate_gp(ctxt, 0); + goto done; + } else { + ctxt->interruptibility = KVM_X86_SHADOW_INT_STI; + ctxt->eflags |= X86_EFLAGS_IF; + } + break; case 0xfc: /* cld */ ctxt->eflags &= ~EFLG_DF; break; @@ -3990,40 +4115,40 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt) * restore dst type in case the decoding will be reused * (happens for string instruction ) */ - ctxt->dst.type = saved_dst_type; + c->dst.type = saved_dst_type; - if ((ctxt->d & SrcMask) == SrcSI) - string_addr_inc(ctxt, seg_override(ctxt), - VCPU_REGS_RSI, &ctxt->src); + if ((c->d & SrcMask) == SrcSI) + string_addr_inc(ctxt, seg_override(ctxt, c), + VCPU_REGS_RSI, &c->src); - if ((ctxt->d & DstMask) == DstDI) + if ((c->d & DstMask) == DstDI) string_addr_inc(ctxt, VCPU_SREG_ES, VCPU_REGS_RDI, - &ctxt->dst); + &c->dst); - if (ctxt->rep_prefix && (ctxt->d & String)) { - struct read_cache *r = &ctxt->io_read; - register_address_increment(ctxt, &ctxt->regs[VCPU_REGS_RCX], -1); + if (c->rep_prefix && (c->d & String)) { + struct read_cache *r = &ctxt->decode.io_read; + register_address_increment(c, &c->regs[VCPU_REGS_RCX], -1); if (!string_insn_completed(ctxt)) { /* * Re-enter guest when pio read ahead buffer is empty * or, if it is not used, after each 1024 iteration. */ - if ((r->end != 0 || ctxt->regs[VCPU_REGS_RCX] & 0x3ff) && + if ((r->end != 0 || c->regs[VCPU_REGS_RCX] & 0x3ff) && (r->end == 0 || r->end != r->pos)) { /* * Reset read cache. Usually happens before * decode, but since instruction is restarted * we have to do it here. */ - ctxt->mem_read.end = 0; + ctxt->decode.mem_read.end = 0; return EMULATION_RESTART; } goto done; /* skip rip writeback */ } } - ctxt->eip = ctxt->_eip; + ctxt->eip = c->eip; done: if (rc == X86EMUL_PROPAGATE_FAULT) @@ -4034,7 +4159,13 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt) return (rc == X86EMUL_UNHANDLEABLE) ? EMULATION_FAILED : EMULATION_OK; twobyte_insn: - switch (ctxt->b) { + switch (c->b) { + case 0x05: /* syscall */ + rc = emulate_syscall(ctxt, ops); + break; + case 0x06: + rc = em_clts(ctxt); + break; case 0x09: /* wbinvd */ (ctxt->ops->wbinvd)(ctxt); break; @@ -4043,21 +4174,21 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt) case 0x18: /* Grp16 (prefetch/nop) */ break; case 0x20: /* mov cr, reg */ - ctxt->dst.val = ops->get_cr(ctxt, ctxt->modrm_reg); + c->dst.val = ops->get_cr(ctxt, c->modrm_reg); break; case 0x21: /* mov from dr to reg */ - ops->get_dr(ctxt, ctxt->modrm_reg, &ctxt->dst.val); + ops->get_dr(ctxt, c->modrm_reg, &c->dst.val); break; case 0x22: /* mov reg, cr */ - if (ops->set_cr(ctxt, ctxt->modrm_reg, ctxt->src.val)) { + if (ops->set_cr(ctxt, c->modrm_reg, c->src.val)) { emulate_gp(ctxt, 0); rc = X86EMUL_PROPAGATE_FAULT; goto done; } - ctxt->dst.type = OP_NONE; + c->dst.type = OP_NONE; break; case 0x23: /* mov from reg to dr */ - if (ops->set_dr(ctxt, ctxt->modrm_reg, ctxt->src.val & + if (ops->set_dr(ctxt, c->modrm_reg, c->src.val & ((ctxt->mode == X86EMUL_MODE_PROT64) ? ~0ULL : ~0U)) < 0) { /* #UD condition is already handled by the code above */ @@ -4066,13 +4197,13 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt) goto done; } - ctxt->dst.type = OP_NONE; /* no writeback */ + c->dst.type = OP_NONE; /* no writeback */ break; case 0x30: /* wrmsr */ - msr_data = (u32)ctxt->regs[VCPU_REGS_RAX] - | ((u64)ctxt->regs[VCPU_REGS_RDX] << 32); - if (ops->set_msr(ctxt, ctxt->regs[VCPU_REGS_RCX], msr_data)) { + msr_data = (u32)c->regs[VCPU_REGS_RAX] + | ((u64)c->regs[VCPU_REGS_RDX] << 32); + if (ops->set_msr(ctxt, c->regs[VCPU_REGS_RCX], msr_data)) { emulate_gp(ctxt, 0); rc = X86EMUL_PROPAGATE_FAULT; goto done; @@ -4081,58 +4212,64 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt) break; case 0x32: /* rdmsr */ - if (ops->get_msr(ctxt, ctxt->regs[VCPU_REGS_RCX], &msr_data)) { + if (ops->get_msr(ctxt, c->regs[VCPU_REGS_RCX], &msr_data)) { emulate_gp(ctxt, 0); rc = X86EMUL_PROPAGATE_FAULT; goto done; } else { - ctxt->regs[VCPU_REGS_RAX] = (u32)msr_data; - ctxt->regs[VCPU_REGS_RDX] = msr_data >> 32; + c->regs[VCPU_REGS_RAX] = (u32)msr_data; + c->regs[VCPU_REGS_RDX] = msr_data >> 32; } rc = X86EMUL_CONTINUE; break; + case 0x34: /* sysenter */ + rc = emulate_sysenter(ctxt, ops); + break; + case 0x35: /* sysexit */ + rc = emulate_sysexit(ctxt, ops); + break; case 0x40 ... 0x4f: /* cmov */ - ctxt->dst.val = ctxt->dst.orig_val = ctxt->src.val; - if (!test_cc(ctxt->b, ctxt->eflags)) - ctxt->dst.type = OP_NONE; /* no writeback */ + c->dst.val = c->dst.orig_val = c->src.val; + if (!test_cc(c->b, ctxt->eflags)) + c->dst.type = OP_NONE; /* no writeback */ break; case 0x80 ... 0x8f: /* jnz rel, etc*/ - if (test_cc(ctxt->b, ctxt->eflags)) - jmp_rel(ctxt, ctxt->src.val); + if (test_cc(c->b, ctxt->eflags)) + jmp_rel(c, c->src.val); break; case 0x90 ... 0x9f: /* setcc r/m8 */ - ctxt->dst.val = test_cc(ctxt->b, ctxt->eflags); + c->dst.val = test_cc(c->b, ctxt->eflags); break; case 0xa0: /* push fs */ - rc = emulate_push_sreg(ctxt, VCPU_SREG_FS); + rc = emulate_push_sreg(ctxt, ops, VCPU_SREG_FS); break; case 0xa1: /* pop fs */ - rc = emulate_pop_sreg(ctxt, VCPU_SREG_FS); + rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_FS); break; case 0xa3: bt: /* bt */ - ctxt->dst.type = OP_NONE; + c->dst.type = OP_NONE; /* only subword offset */ - ctxt->src.val &= (ctxt->dst.bytes << 3) - 1; - emulate_2op_SrcV_nobyte("bt", ctxt->src, ctxt->dst, ctxt->eflags); + c->src.val &= (c->dst.bytes << 3) - 1; + emulate_2op_SrcV_nobyte("bt", c->src, c->dst, ctxt->eflags); break; case 0xa4: /* shld imm8, r, r/m */ case 0xa5: /* shld cl, r, r/m */ - emulate_2op_cl("shld", ctxt->src2, ctxt->src, ctxt->dst, ctxt->eflags); + emulate_2op_cl("shld", c->src2, c->src, c->dst, ctxt->eflags); break; case 0xa8: /* push gs */ - rc = emulate_push_sreg(ctxt, VCPU_SREG_GS); + rc = emulate_push_sreg(ctxt, ops, VCPU_SREG_GS); break; case 0xa9: /* pop gs */ - rc = emulate_pop_sreg(ctxt, VCPU_SREG_GS); + rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_GS); break; case 0xab: bts: /* bts */ - emulate_2op_SrcV_nobyte("bts", ctxt->src, ctxt->dst, ctxt->eflags); + emulate_2op_SrcV_nobyte("bts", c->src, c->dst, ctxt->eflags); break; case 0xac: /* shrd imm8, r, r/m */ case 0xad: /* shrd cl, r, r/m */ - emulate_2op_cl("shrd", ctxt->src2, ctxt->src, ctxt->dst, ctxt->eflags); + emulate_2op_cl("shrd", c->src2, c->src, c->dst, ctxt->eflags); break; case 0xae: /* clflush */ break; @@ -4141,38 +4278,38 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt) * Save real source value, then compare EAX against * destination. */ - ctxt->src.orig_val = ctxt->src.val; - ctxt->src.val = ctxt->regs[VCPU_REGS_RAX]; - emulate_2op_SrcV("cmp", ctxt->src, ctxt->dst, ctxt->eflags); + c->src.orig_val = c->src.val; + c->src.val = c->regs[VCPU_REGS_RAX]; + emulate_2op_SrcV("cmp", c->src, c->dst, ctxt->eflags); if (ctxt->eflags & EFLG_ZF) { /* Success: write back to memory. */ - ctxt->dst.val = ctxt->src.orig_val; + c->dst.val = c->src.orig_val; } else { /* Failure: write the value we saw to EAX. */ - ctxt->dst.type = OP_REG; - ctxt->dst.addr.reg = (unsigned long *)&ctxt->regs[VCPU_REGS_RAX]; + c->dst.type = OP_REG; + c->dst.addr.reg = (unsigned long *)&c->regs[VCPU_REGS_RAX]; } break; case 0xb2: /* lss */ - rc = emulate_load_segment(ctxt, VCPU_SREG_SS); + rc = emulate_load_segment(ctxt, ops, VCPU_SREG_SS); break; case 0xb3: btr: /* btr */ - emulate_2op_SrcV_nobyte("btr", ctxt->src, ctxt->dst, ctxt->eflags); + emulate_2op_SrcV_nobyte("btr", c->src, c->dst, ctxt->eflags); break; case 0xb4: /* lfs */ - rc = emulate_load_segment(ctxt, VCPU_SREG_FS); + rc = emulate_load_segment(ctxt, ops, VCPU_SREG_FS); break; case 0xb5: /* lgs */ - rc = emulate_load_segment(ctxt, VCPU_SREG_GS); + rc = emulate_load_segment(ctxt, ops, VCPU_SREG_GS); break; case 0xb6 ... 0xb7: /* movzx */ - ctxt->dst.bytes = ctxt->op_bytes; - ctxt->dst.val = (ctxt->d & ByteOp) ? (u8) ctxt->src.val - : (u16) ctxt->src.val; + c->dst.bytes = c->op_bytes; + c->dst.val = (c->d & ByteOp) ? (u8) c->src.val + : (u16) c->src.val; break; case 0xba: /* Grp8 */ - switch (ctxt->modrm_reg & 3) { + switch (c->modrm_reg & 3) { case 0: goto bt; case 1: @@ -4185,47 +4322,47 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt) break; case 0xbb: btc: /* btc */ - emulate_2op_SrcV_nobyte("btc", ctxt->src, ctxt->dst, ctxt->eflags); + emulate_2op_SrcV_nobyte("btc", c->src, c->dst, ctxt->eflags); break; case 0xbc: { /* bsf */ u8 zf; __asm__ ("bsf %2, %0; setz %1" - : "=r"(ctxt->dst.val), "=q"(zf) - : "r"(ctxt->src.val)); + : "=r"(c->dst.val), "=q"(zf) + : "r"(c->src.val)); ctxt->eflags &= ~X86_EFLAGS_ZF; if (zf) { ctxt->eflags |= X86_EFLAGS_ZF; - ctxt->dst.type = OP_NONE; /* Disable writeback. */ + c->dst.type = OP_NONE; /* Disable writeback. */ } break; } case 0xbd: { /* bsr */ u8 zf; __asm__ ("bsr %2, %0; setz %1" - : "=r"(ctxt->dst.val), "=q"(zf) - : "r"(ctxt->src.val)); + : "=r"(c->dst.val), "=q"(zf) + : "r"(c->src.val)); ctxt->eflags &= ~X86_EFLAGS_ZF; if (zf) { ctxt->eflags |= X86_EFLAGS_ZF; - ctxt->dst.type = OP_NONE; /* Disable writeback. */ + c->dst.type = OP_NONE; /* Disable writeback. */ } break; } case 0xbe ... 0xbf: /* movsx */ - ctxt->dst.bytes = ctxt->op_bytes; - ctxt->dst.val = (ctxt->d & ByteOp) ? (s8) ctxt->src.val : - (s16) ctxt->src.val; + c->dst.bytes = c->op_bytes; + c->dst.val = (c->d & ByteOp) ? (s8) c->src.val : + (s16) c->src.val; break; case 0xc0 ... 0xc1: /* xadd */ - emulate_2op_SrcV("add", ctxt->src, ctxt->dst, ctxt->eflags); + emulate_2op_SrcV("add", c->src, c->dst, ctxt->eflags); /* Write back the register source. */ - ctxt->src.val = ctxt->dst.orig_val; - write_register_operand(&ctxt->src); + c->src.val = c->dst.orig_val; + write_register_operand(&c->src); break; case 0xc3: /* movnti */ - ctxt->dst.bytes = ctxt->op_bytes; - ctxt->dst.val = (ctxt->op_bytes == 4) ? (u32) ctxt->src.val : - (u64) ctxt->src.val; + c->dst.bytes = c->op_bytes; + c->dst.val = (c->op_bytes == 4) ? (u32) c->src.val : + (u64) c->src.val; break; case 0xc7: /* Grp9 (cmpxchg8b) */ rc = em_grp9(ctxt); diff --git a/trunk/arch/x86/kvm/mmu.c b/trunk/arch/x86/kvm/mmu.c index 9335e1bf72ad..aee38623b768 100644 --- a/trunk/arch/x86/kvm/mmu.c +++ b/trunk/arch/x86/kvm/mmu.c @@ -148,7 +148,7 @@ module_param(oos_shadow, bool, 0644); #define PT64_PERM_MASK (PT_PRESENT_MASK | PT_WRITABLE_MASK | PT_USER_MASK \ | PT64_NX_MASK) -#define PTE_LIST_EXT 4 +#define RMAP_EXT 4 #define ACC_EXEC_MASK 1 #define ACC_WRITE_MASK PT_WRITABLE_MASK @@ -164,16 +164,16 @@ module_param(oos_shadow, bool, 0644); #define SHADOW_PT_INDEX(addr, level) PT64_INDEX(addr, level) -struct pte_list_desc { - u64 *sptes[PTE_LIST_EXT]; - struct pte_list_desc *more; +struct kvm_rmap_desc { + u64 *sptes[RMAP_EXT]; + struct kvm_rmap_desc *more; }; struct kvm_shadow_walk_iterator { u64 addr; hpa_t shadow_addr; - u64 *sptep; int level; + u64 *sptep; unsigned index; }; @@ -182,68 +182,32 @@ struct kvm_shadow_walk_iterator { shadow_walk_okay(&(_walker)); \ shadow_walk_next(&(_walker))) -#define for_each_shadow_entry_lockless(_vcpu, _addr, _walker, spte) \ - for (shadow_walk_init(&(_walker), _vcpu, _addr); \ - shadow_walk_okay(&(_walker)) && \ - ({ spte = mmu_spte_get_lockless(_walker.sptep); 1; }); \ - __shadow_walk_next(&(_walker), spte)) +typedef void (*mmu_parent_walk_fn) (struct kvm_mmu_page *sp, u64 *spte); -static struct kmem_cache *pte_list_desc_cache; +static struct kmem_cache *pte_chain_cache; +static struct kmem_cache *rmap_desc_cache; static struct kmem_cache *mmu_page_header_cache; static struct percpu_counter kvm_total_used_mmu_pages; +static u64 __read_mostly shadow_trap_nonpresent_pte; +static u64 __read_mostly shadow_notrap_nonpresent_pte; static u64 __read_mostly shadow_nx_mask; static u64 __read_mostly shadow_x_mask; /* mutual exclusive with nx_mask */ static u64 __read_mostly shadow_user_mask; static u64 __read_mostly shadow_accessed_mask; static u64 __read_mostly shadow_dirty_mask; -static u64 __read_mostly shadow_mmio_mask; - -static void mmu_spte_set(u64 *sptep, u64 spte); - -void kvm_mmu_set_mmio_spte_mask(u64 mmio_mask) -{ - shadow_mmio_mask = mmio_mask; -} -EXPORT_SYMBOL_GPL(kvm_mmu_set_mmio_spte_mask); - -static void mark_mmio_spte(u64 *sptep, u64 gfn, unsigned access) -{ - access &= ACC_WRITE_MASK | ACC_USER_MASK; - - trace_mark_mmio_spte(sptep, gfn, access); - mmu_spte_set(sptep, shadow_mmio_mask | access | gfn << PAGE_SHIFT); -} - -static bool is_mmio_spte(u64 spte) -{ - return (spte & shadow_mmio_mask) == shadow_mmio_mask; -} - -static gfn_t get_mmio_spte_gfn(u64 spte) -{ - return (spte & ~shadow_mmio_mask) >> PAGE_SHIFT; -} - -static unsigned get_mmio_spte_access(u64 spte) -{ - return (spte & ~shadow_mmio_mask) & ~PAGE_MASK; -} -static bool set_mmio_spte(u64 *sptep, gfn_t gfn, pfn_t pfn, unsigned access) +static inline u64 rsvd_bits(int s, int e) { - if (unlikely(is_noslot_pfn(pfn))) { - mark_mmio_spte(sptep, gfn, access); - return true; - } - - return false; + return ((1ULL << (e - s + 1)) - 1) << s; } -static inline u64 rsvd_bits(int s, int e) +void kvm_mmu_set_nonpresent_ptes(u64 trap_pte, u64 notrap_pte) { - return ((1ULL << (e - s + 1)) - 1) << s; + shadow_trap_nonpresent_pte = trap_pte; + shadow_notrap_nonpresent_pte = notrap_pte; } +EXPORT_SYMBOL_GPL(kvm_mmu_set_nonpresent_ptes); void kvm_mmu_set_mask_ptes(u64 user_mask, u64 accessed_mask, u64 dirty_mask, u64 nx_mask, u64 x_mask) @@ -256,6 +220,11 @@ void kvm_mmu_set_mask_ptes(u64 user_mask, u64 accessed_mask, } EXPORT_SYMBOL_GPL(kvm_mmu_set_mask_ptes); +static bool is_write_protection(struct kvm_vcpu *vcpu) +{ + return kvm_read_cr0_bits(vcpu, X86_CR0_WP); +} + static int is_cpuid_PSE36(void) { return 1; @@ -268,7 +237,8 @@ static int is_nx(struct kvm_vcpu *vcpu) static int is_shadow_present_pte(u64 pte) { - return pte & PT_PRESENT_MASK && !is_mmio_spte(pte); + return pte != shadow_trap_nonpresent_pte + && pte != shadow_notrap_nonpresent_pte; } static int is_large_pte(u64 pte) @@ -276,6 +246,11 @@ static int is_large_pte(u64 pte) return pte & PT_PAGE_SIZE_MASK; } +static int is_writable_pte(unsigned long pte) +{ + return pte & PT_WRITABLE_MASK; +} + static int is_dirty_gpte(unsigned long pte) { return pte & PT_DIRTY_MASK; @@ -307,153 +282,25 @@ static gfn_t pse36_gfn_delta(u32 gpte) return (gpte & PT32_DIR_PSE36_MASK) << shift; } -#ifdef CONFIG_X86_64 static void __set_spte(u64 *sptep, u64 spte) { - *sptep = spte; + set_64bit(sptep, spte); } -static void __update_clear_spte_fast(u64 *sptep, u64 spte) +static u64 __xchg_spte(u64 *sptep, u64 new_spte) { - *sptep = spte; -} - -static u64 __update_clear_spte_slow(u64 *sptep, u64 spte) -{ - return xchg(sptep, spte); -} - -static u64 __get_spte_lockless(u64 *sptep) -{ - return ACCESS_ONCE(*sptep); -} - -static bool __check_direct_spte_mmio_pf(u64 spte) -{ - /* It is valid if the spte is zapped. */ - return spte == 0ull; -} +#ifdef CONFIG_X86_64 + return xchg(sptep, new_spte); #else -union split_spte { - struct { - u32 spte_low; - u32 spte_high; - }; - u64 spte; -}; - -static void count_spte_clear(u64 *sptep, u64 spte) -{ - struct kvm_mmu_page *sp = page_header(__pa(sptep)); - - if (is_shadow_present_pte(spte)) - return; - - /* Ensure the spte is completely set before we increase the count */ - smp_wmb(); - sp->clear_spte_count++; -} - -static void __set_spte(u64 *sptep, u64 spte) -{ - union split_spte *ssptep, sspte; - - ssptep = (union split_spte *)sptep; - sspte = (union split_spte)spte; - - ssptep->spte_high = sspte.spte_high; - - /* - * If we map the spte from nonpresent to present, We should store - * the high bits firstly, then set present bit, so cpu can not - * fetch this spte while we are setting the spte. - */ - smp_wmb(); - - ssptep->spte_low = sspte.spte_low; -} - -static void __update_clear_spte_fast(u64 *sptep, u64 spte) -{ - union split_spte *ssptep, sspte; - - ssptep = (union split_spte *)sptep; - sspte = (union split_spte)spte; - - ssptep->spte_low = sspte.spte_low; + u64 old_spte; - /* - * If we map the spte from present to nonpresent, we should clear - * present bit firstly to avoid vcpu fetch the old high bits. - */ - smp_wmb(); - - ssptep->spte_high = sspte.spte_high; - count_spte_clear(sptep, spte); -} - -static u64 __update_clear_spte_slow(u64 *sptep, u64 spte) -{ - union split_spte *ssptep, sspte, orig; - - ssptep = (union split_spte *)sptep; - sspte = (union split_spte)spte; - - /* xchg acts as a barrier before the setting of the high bits */ - orig.spte_low = xchg(&ssptep->spte_low, sspte.spte_low); - orig.spte_high = ssptep->spte_high = sspte.spte_high; - count_spte_clear(sptep, spte); - - return orig.spte; -} - -/* - * The idea using the light way get the spte on x86_32 guest is from - * gup_get_pte(arch/x86/mm/gup.c). - * The difference is we can not catch the spte tlb flush if we leave - * guest mode, so we emulate it by increase clear_spte_count when spte - * is cleared. - */ -static u64 __get_spte_lockless(u64 *sptep) -{ - struct kvm_mmu_page *sp = page_header(__pa(sptep)); - union split_spte spte, *orig = (union split_spte *)sptep; - int count; - -retry: - count = sp->clear_spte_count; - smp_rmb(); - - spte.spte_low = orig->spte_low; - smp_rmb(); - - spte.spte_high = orig->spte_high; - smp_rmb(); - - if (unlikely(spte.spte_low != orig->spte_low || - count != sp->clear_spte_count)) - goto retry; - - return spte.spte; -} - -static bool __check_direct_spte_mmio_pf(u64 spte) -{ - union split_spte sspte = (union split_spte)spte; - u32 high_mmio_mask = shadow_mmio_mask >> 32; - - /* It is valid if the spte is zapped. */ - if (spte == 0ull) - return true; - - /* It is valid if the spte is being zapped. */ - if (sspte.spte_low == 0ull && - (sspte.spte_high & high_mmio_mask) == high_mmio_mask) - return true; + do { + old_spte = *sptep; + } while (cmpxchg64(sptep, old_spte, new_spte) != old_spte); - return false; -} + return old_spte; #endif +} static bool spte_has_volatile_bits(u64 spte) { @@ -475,30 +322,12 @@ static bool spte_is_bit_cleared(u64 old_spte, u64 new_spte, u64 bit_mask) return (old_spte & bit_mask) && !(new_spte & bit_mask); } -/* Rules for using mmu_spte_set: - * Set the sptep from nonpresent to present. - * Note: the sptep being assigned *must* be either not present - * or in a state where the hardware will not attempt to update - * the spte. - */ -static void mmu_spte_set(u64 *sptep, u64 new_spte) -{ - WARN_ON(is_shadow_present_pte(*sptep)); - __set_spte(sptep, new_spte); -} - -/* Rules for using mmu_spte_update: - * Update the state bits, it means the mapped pfn is not changged. - */ -static void mmu_spte_update(u64 *sptep, u64 new_spte) +static void update_spte(u64 *sptep, u64 new_spte) { u64 mask, old_spte = *sptep; WARN_ON(!is_rmap_spte(new_spte)); - if (!is_shadow_present_pte(old_spte)) - return mmu_spte_set(sptep, new_spte); - new_spte |= old_spte & shadow_dirty_mask; mask = shadow_accessed_mask; @@ -506,9 +335,9 @@ static void mmu_spte_update(u64 *sptep, u64 new_spte) mask |= shadow_dirty_mask; if (!spte_has_volatile_bits(old_spte) || (new_spte & mask) == mask) - __update_clear_spte_fast(sptep, new_spte); + __set_spte(sptep, new_spte); else - old_spte = __update_clear_spte_slow(sptep, new_spte); + old_spte = __xchg_spte(sptep, new_spte); if (!shadow_accessed_mask) return; @@ -519,64 +348,6 @@ static void mmu_spte_update(u64 *sptep, u64 new_spte) kvm_set_pfn_dirty(spte_to_pfn(old_spte)); } -/* - * Rules for using mmu_spte_clear_track_bits: - * It sets the sptep from present to nonpresent, and track the - * state bits, it is used to clear the last level sptep. - */ -static int mmu_spte_clear_track_bits(u64 *sptep) -{ - pfn_t pfn; - u64 old_spte = *sptep; - - if (!spte_has_volatile_bits(old_spte)) - __update_clear_spte_fast(sptep, 0ull); - else - old_spte = __update_clear_spte_slow(sptep, 0ull); - - if (!is_rmap_spte(old_spte)) - return 0; - - pfn = spte_to_pfn(old_spte); - if (!shadow_accessed_mask || old_spte & shadow_accessed_mask) - kvm_set_pfn_accessed(pfn); - if (!shadow_dirty_mask || (old_spte & shadow_dirty_mask)) - kvm_set_pfn_dirty(pfn); - return 1; -} - -/* - * Rules for using mmu_spte_clear_no_track: - * Directly clear spte without caring the state bits of sptep, - * it is used to set the upper level spte. - */ -static void mmu_spte_clear_no_track(u64 *sptep) -{ - __update_clear_spte_fast(sptep, 0ull); -} - -static u64 mmu_spte_get_lockless(u64 *sptep) -{ - return __get_spte_lockless(sptep); -} - -static void walk_shadow_page_lockless_begin(struct kvm_vcpu *vcpu) -{ - rcu_read_lock(); - atomic_inc(&vcpu->kvm->arch.reader_counter); - - /* Increase the counter before walking shadow page table */ - smp_mb__after_atomic_inc(); -} - -static void walk_shadow_page_lockless_end(struct kvm_vcpu *vcpu) -{ - /* Decrease the counter after walking shadow page table finished */ - smp_mb__before_atomic_dec(); - atomic_dec(&vcpu->kvm->arch.reader_counter); - rcu_read_unlock(); -} - static int mmu_topup_memory_cache(struct kvm_mmu_memory_cache *cache, struct kmem_cache *base_cache, int min) { @@ -626,8 +397,12 @@ static int mmu_topup_memory_caches(struct kvm_vcpu *vcpu) { int r; - r = mmu_topup_memory_cache(&vcpu->arch.mmu_pte_list_desc_cache, - pte_list_desc_cache, 8 + PTE_PREFETCH_NUM); + r = mmu_topup_memory_cache(&vcpu->arch.mmu_pte_chain_cache, + pte_chain_cache, 4); + if (r) + goto out; + r = mmu_topup_memory_cache(&vcpu->arch.mmu_rmap_desc_cache, + rmap_desc_cache, 4 + PTE_PREFETCH_NUM); if (r) goto out; r = mmu_topup_memory_cache_page(&vcpu->arch.mmu_page_cache, 8); @@ -641,8 +416,8 @@ static int mmu_topup_memory_caches(struct kvm_vcpu *vcpu) static void mmu_free_memory_caches(struct kvm_vcpu *vcpu) { - mmu_free_memory_cache(&vcpu->arch.mmu_pte_list_desc_cache, - pte_list_desc_cache); + mmu_free_memory_cache(&vcpu->arch.mmu_pte_chain_cache, pte_chain_cache); + mmu_free_memory_cache(&vcpu->arch.mmu_rmap_desc_cache, rmap_desc_cache); mmu_free_memory_cache_page(&vcpu->arch.mmu_page_cache); mmu_free_memory_cache(&vcpu->arch.mmu_page_header_cache, mmu_page_header_cache); @@ -658,15 +433,26 @@ static void *mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc, return p; } -static struct pte_list_desc *mmu_alloc_pte_list_desc(struct kvm_vcpu *vcpu) +static struct kvm_pte_chain *mmu_alloc_pte_chain(struct kvm_vcpu *vcpu) +{ + return mmu_memory_cache_alloc(&vcpu->arch.mmu_pte_chain_cache, + sizeof(struct kvm_pte_chain)); +} + +static void mmu_free_pte_chain(struct kvm_pte_chain *pc) { - return mmu_memory_cache_alloc(&vcpu->arch.mmu_pte_list_desc_cache, - sizeof(struct pte_list_desc)); + kmem_cache_free(pte_chain_cache, pc); } -static void mmu_free_pte_list_desc(struct pte_list_desc *pte_list_desc) +static struct kvm_rmap_desc *mmu_alloc_rmap_desc(struct kvm_vcpu *vcpu) { - kmem_cache_free(pte_list_desc_cache, pte_list_desc); + return mmu_memory_cache_alloc(&vcpu->arch.mmu_rmap_desc_cache, + sizeof(struct kvm_rmap_desc)); +} + +static void mmu_free_rmap_desc(struct kvm_rmap_desc *rd) +{ + kmem_cache_free(rmap_desc_cache, rd); } static gfn_t kvm_mmu_page_get_gfn(struct kvm_mmu_page *sp, int index) @@ -712,7 +498,6 @@ static void account_shadowed(struct kvm *kvm, gfn_t gfn) linfo = lpage_info_slot(gfn, slot, i); linfo->write_count += 1; } - kvm->arch.indirect_shadow_pages++; } static void unaccount_shadowed(struct kvm *kvm, gfn_t gfn) @@ -728,7 +513,6 @@ static void unaccount_shadowed(struct kvm *kvm, gfn_t gfn) linfo->write_count -= 1; WARN_ON(linfo->write_count < 0); } - kvm->arch.indirect_shadow_pages--; } static int has_wrprotected_page(struct kvm *kvm, @@ -804,42 +588,67 @@ static int mapping_level(struct kvm_vcpu *vcpu, gfn_t large_gfn) } /* - * Pte mapping structures: + * Take gfn and return the reverse mapping to it. + */ + +static unsigned long *gfn_to_rmap(struct kvm *kvm, gfn_t gfn, int level) +{ + struct kvm_memory_slot *slot; + struct kvm_lpage_info *linfo; + + slot = gfn_to_memslot(kvm, gfn); + if (likely(level == PT_PAGE_TABLE_LEVEL)) + return &slot->rmap[gfn - slot->base_gfn]; + + linfo = lpage_info_slot(gfn, slot, level); + + return &linfo->rmap_pde; +} + +/* + * Reverse mapping data structures: * - * If pte_list bit zero is zero, then pte_list point to the spte. + * If rmapp bit zero is zero, then rmapp point to the shadw page table entry + * that points to page_address(page). * - * If pte_list bit zero is one, (then pte_list & ~1) points to a struct - * pte_list_desc containing more mappings. + * If rmapp bit zero is one, (then rmap & ~1) points to a struct kvm_rmap_desc + * containing more mappings. * - * Returns the number of pte entries before the spte was added or zero if + * Returns the number of rmap entries before the spte was added or zero if * the spte was not added. * */ -static int pte_list_add(struct kvm_vcpu *vcpu, u64 *spte, - unsigned long *pte_list) +static int rmap_add(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn) { - struct pte_list_desc *desc; + struct kvm_mmu_page *sp; + struct kvm_rmap_desc *desc; + unsigned long *rmapp; int i, count = 0; - if (!*pte_list) { - rmap_printk("pte_list_add: %p %llx 0->1\n", spte, *spte); - *pte_list = (unsigned long)spte; - } else if (!(*pte_list & 1)) { - rmap_printk("pte_list_add: %p %llx 1->many\n", spte, *spte); - desc = mmu_alloc_pte_list_desc(vcpu); - desc->sptes[0] = (u64 *)*pte_list; + if (!is_rmap_spte(*spte)) + return count; + sp = page_header(__pa(spte)); + kvm_mmu_page_set_gfn(sp, spte - sp->spt, gfn); + rmapp = gfn_to_rmap(vcpu->kvm, gfn, sp->role.level); + if (!*rmapp) { + rmap_printk("rmap_add: %p %llx 0->1\n", spte, *spte); + *rmapp = (unsigned long)spte; + } else if (!(*rmapp & 1)) { + rmap_printk("rmap_add: %p %llx 1->many\n", spte, *spte); + desc = mmu_alloc_rmap_desc(vcpu); + desc->sptes[0] = (u64 *)*rmapp; desc->sptes[1] = spte; - *pte_list = (unsigned long)desc | 1; + *rmapp = (unsigned long)desc | 1; ++count; } else { - rmap_printk("pte_list_add: %p %llx many->many\n", spte, *spte); - desc = (struct pte_list_desc *)(*pte_list & ~1ul); - while (desc->sptes[PTE_LIST_EXT-1] && desc->more) { + rmap_printk("rmap_add: %p %llx many->many\n", spte, *spte); + desc = (struct kvm_rmap_desc *)(*rmapp & ~1ul); + while (desc->sptes[RMAP_EXT-1] && desc->more) { desc = desc->more; - count += PTE_LIST_EXT; + count += RMAP_EXT; } - if (desc->sptes[PTE_LIST_EXT-1]) { - desc->more = mmu_alloc_pte_list_desc(vcpu); + if (desc->sptes[RMAP_EXT-1]) { + desc->more = mmu_alloc_rmap_desc(vcpu); desc = desc->more; } for (i = 0; desc->sptes[i]; ++i) @@ -849,78 +658,59 @@ static int pte_list_add(struct kvm_vcpu *vcpu, u64 *spte, return count; } -static u64 *pte_list_next(unsigned long *pte_list, u64 *spte) -{ - struct pte_list_desc *desc; - u64 *prev_spte; - int i; - - if (!*pte_list) - return NULL; - else if (!(*pte_list & 1)) { - if (!spte) - return (u64 *)*pte_list; - return NULL; - } - desc = (struct pte_list_desc *)(*pte_list & ~1ul); - prev_spte = NULL; - while (desc) { - for (i = 0; i < PTE_LIST_EXT && desc->sptes[i]; ++i) { - if (prev_spte == spte) - return desc->sptes[i]; - prev_spte = desc->sptes[i]; - } - desc = desc->more; - } - return NULL; -} - -static void -pte_list_desc_remove_entry(unsigned long *pte_list, struct pte_list_desc *desc, - int i, struct pte_list_desc *prev_desc) +static void rmap_desc_remove_entry(unsigned long *rmapp, + struct kvm_rmap_desc *desc, + int i, + struct kvm_rmap_desc *prev_desc) { int j; - for (j = PTE_LIST_EXT - 1; !desc->sptes[j] && j > i; --j) + for (j = RMAP_EXT - 1; !desc->sptes[j] && j > i; --j) ; desc->sptes[i] = desc->sptes[j]; desc->sptes[j] = NULL; if (j != 0) return; if (!prev_desc && !desc->more) - *pte_list = (unsigned long)desc->sptes[0]; + *rmapp = (unsigned long)desc->sptes[0]; else if (prev_desc) prev_desc->more = desc->more; else - *pte_list = (unsigned long)desc->more | 1; - mmu_free_pte_list_desc(desc); + *rmapp = (unsigned long)desc->more | 1; + mmu_free_rmap_desc(desc); } -static void pte_list_remove(u64 *spte, unsigned long *pte_list) +static void rmap_remove(struct kvm *kvm, u64 *spte) { - struct pte_list_desc *desc; - struct pte_list_desc *prev_desc; + struct kvm_rmap_desc *desc; + struct kvm_rmap_desc *prev_desc; + struct kvm_mmu_page *sp; + gfn_t gfn; + unsigned long *rmapp; int i; - if (!*pte_list) { - printk(KERN_ERR "pte_list_remove: %p 0->BUG\n", spte); + sp = page_header(__pa(spte)); + gfn = kvm_mmu_page_get_gfn(sp, spte - sp->spt); + rmapp = gfn_to_rmap(kvm, gfn, sp->role.level); + if (!*rmapp) { + printk(KERN_ERR "rmap_remove: %p 0->BUG\n", spte); BUG(); - } else if (!(*pte_list & 1)) { - rmap_printk("pte_list_remove: %p 1->0\n", spte); - if ((u64 *)*pte_list != spte) { - printk(KERN_ERR "pte_list_remove: %p 1->BUG\n", spte); + } else if (!(*rmapp & 1)) { + rmap_printk("rmap_remove: %p 1->0\n", spte); + if ((u64 *)*rmapp != spte) { + printk(KERN_ERR "rmap_remove: %p 1->BUG\n", spte); BUG(); } - *pte_list = 0; + *rmapp = 0; } else { - rmap_printk("pte_list_remove: %p many->many\n", spte); - desc = (struct pte_list_desc *)(*pte_list & ~1ul); + rmap_printk("rmap_remove: %p many->many\n", spte); + desc = (struct kvm_rmap_desc *)(*rmapp & ~1ul); prev_desc = NULL; while (desc) { - for (i = 0; i < PTE_LIST_EXT && desc->sptes[i]; ++i) + for (i = 0; i < RMAP_EXT && desc->sptes[i]; ++i) if (desc->sptes[i] == spte) { - pte_list_desc_remove_entry(pte_list, + rmap_desc_remove_entry(rmapp, desc, i, prev_desc); return; @@ -928,80 +718,62 @@ static void pte_list_remove(u64 *spte, unsigned long *pte_list) prev_desc = desc; desc = desc->more; } - pr_err("pte_list_remove: %p many->many\n", spte); + pr_err("rmap_remove: %p many->many\n", spte); BUG(); } } -typedef void (*pte_list_walk_fn) (u64 *spte); -static void pte_list_walk(unsigned long *pte_list, pte_list_walk_fn fn) +static int set_spte_track_bits(u64 *sptep, u64 new_spte) { - struct pte_list_desc *desc; - int i; - - if (!*pte_list) - return; - - if (!(*pte_list & 1)) - return fn((u64 *)*pte_list); - - desc = (struct pte_list_desc *)(*pte_list & ~1ul); - while (desc) { - for (i = 0; i < PTE_LIST_EXT && desc->sptes[i]; ++i) - fn(desc->sptes[i]); - desc = desc->more; - } -} - -/* - * Take gfn and return the reverse mapping to it. - */ -static unsigned long *gfn_to_rmap(struct kvm *kvm, gfn_t gfn, int level) -{ - struct kvm_memory_slot *slot; - struct kvm_lpage_info *linfo; + pfn_t pfn; + u64 old_spte = *sptep; - slot = gfn_to_memslot(kvm, gfn); - if (likely(level == PT_PAGE_TABLE_LEVEL)) - return &slot->rmap[gfn - slot->base_gfn]; + if (!spte_has_volatile_bits(old_spte)) + __set_spte(sptep, new_spte); + else + old_spte = __xchg_spte(sptep, new_spte); - linfo = lpage_info_slot(gfn, slot, level); + if (!is_rmap_spte(old_spte)) + return 0; - return &linfo->rmap_pde; + pfn = spte_to_pfn(old_spte); + if (!shadow_accessed_mask || old_spte & shadow_accessed_mask) + kvm_set_pfn_accessed(pfn); + if (!shadow_dirty_mask || (old_spte & shadow_dirty_mask)) + kvm_set_pfn_dirty(pfn); + return 1; } -static int rmap_add(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn) +static void drop_spte(struct kvm *kvm, u64 *sptep, u64 new_spte) { - struct kvm_mmu_page *sp; - unsigned long *rmapp; - - sp = page_header(__pa(spte)); - kvm_mmu_page_set_gfn(sp, spte - sp->spt, gfn); - rmapp = gfn_to_rmap(vcpu->kvm, gfn, sp->role.level); - return pte_list_add(vcpu, spte, rmapp); + if (set_spte_track_bits(sptep, new_spte)) + rmap_remove(kvm, sptep); } static u64 *rmap_next(struct kvm *kvm, unsigned long *rmapp, u64 *spte) { - return pte_list_next(rmapp, spte); -} - -static void rmap_remove(struct kvm *kvm, u64 *spte) -{ - struct kvm_mmu_page *sp; - gfn_t gfn; - unsigned long *rmapp; - - sp = page_header(__pa(spte)); - gfn = kvm_mmu_page_get_gfn(sp, spte - sp->spt); - rmapp = gfn_to_rmap(kvm, gfn, sp->role.level); - pte_list_remove(spte, rmapp); -} + struct kvm_rmap_desc *desc; + u64 *prev_spte; + int i; -static void drop_spte(struct kvm *kvm, u64 *sptep) -{ - if (mmu_spte_clear_track_bits(sptep)) - rmap_remove(kvm, sptep); + if (!*rmapp) + return NULL; + else if (!(*rmapp & 1)) { + if (!spte) + return (u64 *)*rmapp; + return NULL; + } + desc = (struct kvm_rmap_desc *)(*rmapp & ~1ul); + prev_spte = NULL; + while (desc) { + for (i = 0; i < RMAP_EXT && desc->sptes[i]; ++i) { + if (prev_spte == spte) + return desc->sptes[i]; + prev_spte = desc->sptes[i]; + } + desc = desc->more; + } + return NULL; } static int rmap_write_protect(struct kvm *kvm, u64 gfn) @@ -1018,7 +790,7 @@ static int rmap_write_protect(struct kvm *kvm, u64 gfn) BUG_ON(!(*spte & PT_PRESENT_MASK)); rmap_printk("rmap_write_protect: spte %p %llx\n", spte, *spte); if (is_writable_pte(*spte)) { - mmu_spte_update(spte, *spte & ~PT_WRITABLE_MASK); + update_spte(spte, *spte & ~PT_WRITABLE_MASK); write_protected = 1; } spte = rmap_next(kvm, rmapp, spte); @@ -1035,7 +807,8 @@ static int rmap_write_protect(struct kvm *kvm, u64 gfn) BUG_ON((*spte & (PT_PAGE_SIZE_MASK|PT_PRESENT_MASK)) != (PT_PAGE_SIZE_MASK|PT_PRESENT_MASK)); pgprintk("rmap_write_protect(large): spte %p %llx %lld\n", spte, *spte, gfn); if (is_writable_pte(*spte)) { - drop_spte(kvm, spte); + drop_spte(kvm, spte, + shadow_trap_nonpresent_pte); --kvm->stat.lpages; spte = NULL; write_protected = 1; @@ -1056,7 +829,7 @@ static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp, while ((spte = rmap_next(kvm, rmapp, NULL))) { BUG_ON(!(*spte & PT_PRESENT_MASK)); rmap_printk("kvm_rmap_unmap_hva: spte %p %llx\n", spte, *spte); - drop_spte(kvm, spte); + drop_spte(kvm, spte, shadow_trap_nonpresent_pte); need_tlb_flush = 1; } return need_tlb_flush; @@ -1078,7 +851,7 @@ static int kvm_set_pte_rmapp(struct kvm *kvm, unsigned long *rmapp, rmap_printk("kvm_set_pte_rmapp: spte %p %llx\n", spte, *spte); need_flush = 1; if (pte_write(*ptep)) { - drop_spte(kvm, spte); + drop_spte(kvm, spte, shadow_trap_nonpresent_pte); spte = rmap_next(kvm, rmapp, NULL); } else { new_spte = *spte &~ (PT64_BASE_ADDR_MASK); @@ -1087,8 +860,7 @@ static int kvm_set_pte_rmapp(struct kvm *kvm, unsigned long *rmapp, new_spte &= ~PT_WRITABLE_MASK; new_spte &= ~SPTE_HOST_WRITEABLE; new_spte &= ~shadow_accessed_mask; - mmu_spte_clear_track_bits(spte); - mmu_spte_set(spte, new_spte); + set_spte_track_bits(spte, new_spte); spte = rmap_next(kvm, rmapp, spte); } } @@ -1260,29 +1032,16 @@ static inline void kvm_mod_used_mmu_pages(struct kvm *kvm, int nr) percpu_counter_add(&kvm_total_used_mmu_pages, nr); } -/* - * Remove the sp from shadow page cache, after call it, - * we can not find this sp from the cache, and the shadow - * page table is still valid. - * It should be under the protection of mmu lock. - */ -static void kvm_mmu_isolate_page(struct kvm_mmu_page *sp) +static void kvm_mmu_free_page(struct kvm *kvm, struct kvm_mmu_page *sp) { ASSERT(is_empty_shadow_page(sp->spt)); hlist_del(&sp->hash_link); - if (!sp->role.direct) - free_page((unsigned long)sp->gfns); -} - -/* - * Free the shadow page table and the sp, we can do it - * out of the protection of mmu lock. - */ -static void kvm_mmu_free_page(struct kvm_mmu_page *sp) -{ list_del(&sp->link); free_page((unsigned long)sp->spt); + if (!sp->role.direct) + free_page((unsigned long)sp->gfns); kmem_cache_free(mmu_page_header_cache, sp); + kvm_mod_used_mmu_pages(kvm, -1); } static unsigned kvm_page_table_hashfn(gfn_t gfn) @@ -1290,59 +1049,134 @@ static unsigned kvm_page_table_hashfn(gfn_t gfn) return gfn & ((1 << KVM_MMU_HASH_SHIFT) - 1); } +static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu, + u64 *parent_pte, int direct) +{ + struct kvm_mmu_page *sp; + + sp = mmu_memory_cache_alloc(&vcpu->arch.mmu_page_header_cache, sizeof *sp); + sp->spt = mmu_memory_cache_alloc(&vcpu->arch.mmu_page_cache, PAGE_SIZE); + if (!direct) + sp->gfns = mmu_memory_cache_alloc(&vcpu->arch.mmu_page_cache, + PAGE_SIZE); + set_page_private(virt_to_page(sp->spt), (unsigned long)sp); + list_add(&sp->link, &vcpu->kvm->arch.active_mmu_pages); + bitmap_zero(sp->slot_bitmap, KVM_MEMORY_SLOTS + KVM_PRIVATE_MEM_SLOTS); + sp->multimapped = 0; + sp->parent_pte = parent_pte; + kvm_mod_used_mmu_pages(vcpu->kvm, +1); + return sp; +} + static void mmu_page_add_parent_pte(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, u64 *parent_pte) { + struct kvm_pte_chain *pte_chain; + struct hlist_node *node; + int i; + if (!parent_pte) return; + if (!sp->multimapped) { + u64 *old = sp->parent_pte; - pte_list_add(vcpu, parent_pte, &sp->parent_ptes); + if (!old) { + sp->parent_pte = parent_pte; + return; + } + sp->multimapped = 1; + pte_chain = mmu_alloc_pte_chain(vcpu); + INIT_HLIST_HEAD(&sp->parent_ptes); + hlist_add_head(&pte_chain->link, &sp->parent_ptes); + pte_chain->parent_ptes[0] = old; + } + hlist_for_each_entry(pte_chain, node, &sp->parent_ptes, link) { + if (pte_chain->parent_ptes[NR_PTE_CHAIN_ENTRIES-1]) + continue; + for (i = 0; i < NR_PTE_CHAIN_ENTRIES; ++i) + if (!pte_chain->parent_ptes[i]) { + pte_chain->parent_ptes[i] = parent_pte; + return; + } + } + pte_chain = mmu_alloc_pte_chain(vcpu); + BUG_ON(!pte_chain); + hlist_add_head(&pte_chain->link, &sp->parent_ptes); + pte_chain->parent_ptes[0] = parent_pte; } static void mmu_page_remove_parent_pte(struct kvm_mmu_page *sp, u64 *parent_pte) { - pte_list_remove(parent_pte, &sp->parent_ptes); -} + struct kvm_pte_chain *pte_chain; + struct hlist_node *node; + int i; -static void drop_parent_pte(struct kvm_mmu_page *sp, - u64 *parent_pte) -{ - mmu_page_remove_parent_pte(sp, parent_pte); - mmu_spte_clear_no_track(parent_pte); + if (!sp->multimapped) { + BUG_ON(sp->parent_pte != parent_pte); + sp->parent_pte = NULL; + return; + } + hlist_for_each_entry(pte_chain, node, &sp->parent_ptes, link) + for (i = 0; i < NR_PTE_CHAIN_ENTRIES; ++i) { + if (!pte_chain->parent_ptes[i]) + break; + if (pte_chain->parent_ptes[i] != parent_pte) + continue; + while (i + 1 < NR_PTE_CHAIN_ENTRIES + && pte_chain->parent_ptes[i + 1]) { + pte_chain->parent_ptes[i] + = pte_chain->parent_ptes[i + 1]; + ++i; + } + pte_chain->parent_ptes[i] = NULL; + if (i == 0) { + hlist_del(&pte_chain->link); + mmu_free_pte_chain(pte_chain); + if (hlist_empty(&sp->parent_ptes)) { + sp->multimapped = 0; + sp->parent_pte = NULL; + } + } + return; + } + BUG(); } -static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu, - u64 *parent_pte, int direct) +static void mmu_parent_walk(struct kvm_mmu_page *sp, mmu_parent_walk_fn fn) { - struct kvm_mmu_page *sp; - sp = mmu_memory_cache_alloc(&vcpu->arch.mmu_page_header_cache, - sizeof *sp); - sp->spt = mmu_memory_cache_alloc(&vcpu->arch.mmu_page_cache, PAGE_SIZE); - if (!direct) - sp->gfns = mmu_memory_cache_alloc(&vcpu->arch.mmu_page_cache, - PAGE_SIZE); - set_page_private(virt_to_page(sp->spt), (unsigned long)sp); - list_add(&sp->link, &vcpu->kvm->arch.active_mmu_pages); - bitmap_zero(sp->slot_bitmap, KVM_MEMORY_SLOTS + KVM_PRIVATE_MEM_SLOTS); - sp->parent_ptes = 0; - mmu_page_add_parent_pte(vcpu, sp, parent_pte); - kvm_mod_used_mmu_pages(vcpu->kvm, +1); - return sp; + struct kvm_pte_chain *pte_chain; + struct hlist_node *node; + struct kvm_mmu_page *parent_sp; + int i; + + if (!sp->multimapped && sp->parent_pte) { + parent_sp = page_header(__pa(sp->parent_pte)); + fn(parent_sp, sp->parent_pte); + return; + } + + hlist_for_each_entry(pte_chain, node, &sp->parent_ptes, link) + for (i = 0; i < NR_PTE_CHAIN_ENTRIES; ++i) { + u64 *spte = pte_chain->parent_ptes[i]; + + if (!spte) + break; + parent_sp = page_header(__pa(spte)); + fn(parent_sp, spte); + } } -static void mark_unsync(u64 *spte); +static void mark_unsync(struct kvm_mmu_page *sp, u64 *spte); static void kvm_mmu_mark_parents_unsync(struct kvm_mmu_page *sp) { - pte_list_walk(&sp->parent_ptes, mark_unsync); + mmu_parent_walk(sp, mark_unsync); } -static void mark_unsync(u64 *spte) +static void mark_unsync(struct kvm_mmu_page *sp, u64 *spte) { - struct kvm_mmu_page *sp; unsigned int index; - sp = page_header(__pa(spte)); index = spte - sp->spt; if (__test_and_set_bit(index, sp->unsync_child_bitmap)) return; @@ -1351,6 +1185,15 @@ static void mark_unsync(u64 *spte) kvm_mmu_mark_parents_unsync(sp); } +static void nonpaging_prefetch_page(struct kvm_vcpu *vcpu, + struct kvm_mmu_page *sp) +{ + int i; + + for (i = 0; i < PT64_ENT_PER_PAGE; ++i) + sp->spt[i] = shadow_trap_nonpresent_pte; +} + static int nonpaging_sync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp) { @@ -1632,14 +1475,6 @@ static void mmu_sync_children(struct kvm_vcpu *vcpu, } } -static void init_shadow_page_table(struct kvm_mmu_page *sp) -{ - int i; - - for (i = 0; i < PT64_ENT_PER_PAGE; ++i) - sp->spt[i] = 0ull; -} - static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, gfn_t gfn, gva_t gaddr, @@ -1702,7 +1537,10 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, account_shadowed(vcpu->kvm, gfn); } - init_shadow_page_table(sp); + if (shadow_trap_nonpresent_pte != shadow_notrap_nonpresent_pte) + vcpu->arch.mmu.prefetch_page(vcpu, sp); + else + nonpaging_prefetch_page(vcpu, sp); trace_kvm_mmu_get_page(sp, true); return sp; } @@ -1734,26 +1572,19 @@ static bool shadow_walk_okay(struct kvm_shadow_walk_iterator *iterator) if (iterator->level < PT_PAGE_TABLE_LEVEL) return false; + if (iterator->level == PT_PAGE_TABLE_LEVEL) + if (is_large_pte(*iterator->sptep)) + return false; + iterator->index = SHADOW_PT_INDEX(iterator->addr, iterator->level); iterator->sptep = ((u64 *)__va(iterator->shadow_addr)) + iterator->index; return true; } -static void __shadow_walk_next(struct kvm_shadow_walk_iterator *iterator, - u64 spte) -{ - if (is_last_spte(spte, iterator->level)) { - iterator->level = 0; - return; - } - - iterator->shadow_addr = spte & PT64_BASE_ADDR_MASK; - --iterator->level; -} - static void shadow_walk_next(struct kvm_shadow_walk_iterator *iterator) { - return __shadow_walk_next(iterator, *iterator->sptep); + iterator->shadow_addr = *iterator->sptep & PT64_BASE_ADDR_MASK; + --iterator->level; } static void link_shadow_page(u64 *sptep, struct kvm_mmu_page *sp) @@ -1763,13 +1594,13 @@ static void link_shadow_page(u64 *sptep, struct kvm_mmu_page *sp) spte = __pa(sp->spt) | PT_PRESENT_MASK | PT_ACCESSED_MASK | PT_WRITABLE_MASK | PT_USER_MASK; - mmu_spte_set(sptep, spte); + __set_spte(sptep, spte); } static void drop_large_spte(struct kvm_vcpu *vcpu, u64 *sptep) { if (is_large_pte(*sptep)) { - drop_spte(vcpu->kvm, sptep); + drop_spte(vcpu->kvm, sptep, shadow_trap_nonpresent_pte); kvm_flush_remote_tlbs(vcpu->kvm); } } @@ -1791,39 +1622,38 @@ static void validate_direct_spte(struct kvm_vcpu *vcpu, u64 *sptep, if (child->role.access == direct_access) return; - drop_parent_pte(child, sptep); + mmu_page_remove_parent_pte(child, sptep); + __set_spte(sptep, shadow_trap_nonpresent_pte); kvm_flush_remote_tlbs(vcpu->kvm); } } -static void mmu_page_zap_pte(struct kvm *kvm, struct kvm_mmu_page *sp, - u64 *spte) -{ - u64 pte; - struct kvm_mmu_page *child; - - pte = *spte; - if (is_shadow_present_pte(pte)) { - if (is_last_spte(pte, sp->role.level)) - drop_spte(kvm, spte); - else { - child = page_header(pte & PT64_BASE_ADDR_MASK); - drop_parent_pte(child, spte); - } - } else if (is_mmio_spte(pte)) - mmu_spte_clear_no_track(spte); - - if (is_large_pte(pte)) - --kvm->stat.lpages; -} - static void kvm_mmu_page_unlink_children(struct kvm *kvm, struct kvm_mmu_page *sp) { unsigned i; - - for (i = 0; i < PT64_ENT_PER_PAGE; ++i) - mmu_page_zap_pte(kvm, sp, sp->spt + i); + u64 *pt; + u64 ent; + + pt = sp->spt; + + for (i = 0; i < PT64_ENT_PER_PAGE; ++i) { + ent = pt[i]; + + if (is_shadow_present_pte(ent)) { + if (!is_last_spte(ent, sp->role.level)) { + ent &= PT64_BASE_ADDR_MASK; + mmu_page_remove_parent_pte(page_header(ent), + &pt[i]); + } else { + if (is_large_pte(ent)) + --kvm->stat.lpages; + drop_spte(kvm, &pt[i], + shadow_trap_nonpresent_pte); + } + } + pt[i] = shadow_trap_nonpresent_pte; + } } static void kvm_mmu_put_page(struct kvm_mmu_page *sp, u64 *parent_pte) @@ -1844,8 +1674,20 @@ static void kvm_mmu_unlink_parents(struct kvm *kvm, struct kvm_mmu_page *sp) { u64 *parent_pte; - while ((parent_pte = pte_list_next(&sp->parent_ptes, NULL))) - drop_parent_pte(sp, parent_pte); + while (sp->multimapped || sp->parent_pte) { + if (!sp->multimapped) + parent_pte = sp->parent_pte; + else { + struct kvm_pte_chain *chain; + + chain = container_of(sp->parent_ptes.first, + struct kvm_pte_chain, link); + parent_pte = chain->parent_ptes[0]; + } + BUG_ON(!parent_pte); + kvm_mmu_put_page(sp, parent_pte); + __set_spte(parent_pte, shadow_trap_nonpresent_pte); + } } static int mmu_zap_unsync_children(struct kvm *kvm, @@ -1892,7 +1734,6 @@ static int kvm_mmu_prepare_zap_page(struct kvm *kvm, struct kvm_mmu_page *sp, /* Count self */ ret++; list_move(&sp->link, invalid_list); - kvm_mod_used_mmu_pages(kvm, -1); } else { list_move(&sp->link, &kvm->arch.active_mmu_pages); kvm_reload_remote_mmus(kvm); @@ -1903,30 +1744,6 @@ static int kvm_mmu_prepare_zap_page(struct kvm *kvm, struct kvm_mmu_page *sp, return ret; } -static void kvm_mmu_isolate_pages(struct list_head *invalid_list) -{ - struct kvm_mmu_page *sp; - - list_for_each_entry(sp, invalid_list, link) - kvm_mmu_isolate_page(sp); -} - -static void free_pages_rcu(struct rcu_head *head) -{ - struct kvm_mmu_page *next, *sp; - - sp = container_of(head, struct kvm_mmu_page, rcu); - while (sp) { - if (!list_empty(&sp->link)) - next = list_first_entry(&sp->link, - struct kvm_mmu_page, link); - else - next = NULL; - kvm_mmu_free_page(sp); - sp = next; - } -} - static void kvm_mmu_commit_zap_page(struct kvm *kvm, struct list_head *invalid_list) { @@ -1937,21 +1754,10 @@ static void kvm_mmu_commit_zap_page(struct kvm *kvm, kvm_flush_remote_tlbs(kvm); - if (atomic_read(&kvm->arch.reader_counter)) { - kvm_mmu_isolate_pages(invalid_list); - sp = list_first_entry(invalid_list, struct kvm_mmu_page, link); - list_del_init(invalid_list); - - trace_kvm_mmu_delay_free_pages(sp); - call_rcu(&sp->rcu, free_pages_rcu); - return; - } - do { sp = list_first_entry(invalid_list, struct kvm_mmu_page, link); WARN_ON(!sp->role.invalid || sp->root_count); - kvm_mmu_isolate_page(sp); - kvm_mmu_free_page(sp); + kvm_mmu_free_page(kvm, sp); } while (!list_empty(invalid_list)); } @@ -1977,8 +1783,8 @@ void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned int goal_nr_mmu_pages) page = container_of(kvm->arch.active_mmu_pages.prev, struct kvm_mmu_page, link); kvm_mmu_prepare_zap_page(kvm, page, &invalid_list); + kvm_mmu_commit_zap_page(kvm, &invalid_list); } - kvm_mmu_commit_zap_page(kvm, &invalid_list); goal_nr_mmu_pages = kvm->arch.n_used_mmu_pages; } @@ -2027,6 +1833,20 @@ static void page_header_update_slot(struct kvm *kvm, void *pte, gfn_t gfn) __set_bit(slot, sp->slot_bitmap); } +static void mmu_convert_notrap(struct kvm_mmu_page *sp) +{ + int i; + u64 *pt = sp->spt; + + if (shadow_trap_nonpresent_pte == shadow_notrap_nonpresent_pte) + return; + + for (i = 0; i < PT64_ENT_PER_PAGE; ++i) { + if (pt[i] == shadow_notrap_nonpresent_pte) + __set_spte(&pt[i], shadow_trap_nonpresent_pte); + } +} + /* * The function is based on mtrr_type_lookup() in * arch/x86/kernel/cpu/mtrr/generic.c @@ -2139,6 +1959,7 @@ static void __kvm_unsync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp) sp->unsync = 1; kvm_mmu_mark_parents_unsync(sp); + mmu_convert_notrap(sp); } static void kvm_unsync_pages(struct kvm_vcpu *vcpu, gfn_t gfn) @@ -2181,16 +2002,13 @@ static int mmu_need_write_protect(struct kvm_vcpu *vcpu, gfn_t gfn, static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep, unsigned pte_access, int user_fault, - int write_fault, int level, + int write_fault, int dirty, int level, gfn_t gfn, pfn_t pfn, bool speculative, bool can_unsync, bool host_writable) { u64 spte, entry = *sptep; int ret = 0; - if (set_mmio_spte(sptep, gfn, pfn, pte_access)) - return 0; - /* * We don't set the accessed bit, since we sometimes want to see * whether the guest actually used the pte (in order to detect @@ -2199,7 +2017,8 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep, spte = PT_PRESENT_MASK; if (!speculative) spte |= shadow_accessed_mask; - + if (!dirty) + pte_access &= ~ACC_WRITE_MASK; if (pte_access & ACC_EXEC_MASK) spte |= shadow_x_mask; else @@ -2226,24 +2045,15 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep, if (level > PT_PAGE_TABLE_LEVEL && has_wrprotected_page(vcpu->kvm, gfn, level)) { ret = 1; - drop_spte(vcpu->kvm, sptep); + drop_spte(vcpu->kvm, sptep, shadow_trap_nonpresent_pte); goto done; } spte |= PT_WRITABLE_MASK; if (!vcpu->arch.mmu.direct_map - && !(pte_access & ACC_WRITE_MASK)) { + && !(pte_access & ACC_WRITE_MASK)) spte &= ~PT_USER_MASK; - /* - * If we converted a user page to a kernel page, - * so that the kernel can write to it when cr0.wp=0, - * then we should prevent the kernel from executing it - * if SMEP is enabled. - */ - if (kvm_read_cr4_bits(vcpu, X86_CR4_SMEP)) - spte |= PT64_NX_MASK; - } /* * Optimization: for pte sync, if spte was writable the hash @@ -2268,7 +2078,7 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep, mark_page_dirty(vcpu->kvm, gfn); set_pte: - mmu_spte_update(sptep, spte); + update_spte(sptep, spte); /* * If we overwrite a writable spte with a read-only one we * should flush remote TLBs. Otherwise rmap_write_protect @@ -2283,8 +2093,8 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep, static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep, unsigned pt_access, unsigned pte_access, - int user_fault, int write_fault, - int *emulate, int level, gfn_t gfn, + int user_fault, int write_fault, int dirty, + int *ptwrite, int level, gfn_t gfn, pfn_t pfn, bool speculative, bool host_writable) { @@ -2307,28 +2117,26 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep, u64 pte = *sptep; child = page_header(pte & PT64_BASE_ADDR_MASK); - drop_parent_pte(child, sptep); + mmu_page_remove_parent_pte(child, sptep); + __set_spte(sptep, shadow_trap_nonpresent_pte); kvm_flush_remote_tlbs(vcpu->kvm); } else if (pfn != spte_to_pfn(*sptep)) { pgprintk("hfn old %llx new %llx\n", spte_to_pfn(*sptep), pfn); - drop_spte(vcpu->kvm, sptep); + drop_spte(vcpu->kvm, sptep, shadow_trap_nonpresent_pte); kvm_flush_remote_tlbs(vcpu->kvm); } else was_rmapped = 1; } if (set_spte(vcpu, sptep, pte_access, user_fault, write_fault, - level, gfn, pfn, speculative, true, + dirty, level, gfn, pfn, speculative, true, host_writable)) { if (write_fault) - *emulate = 1; + *ptwrite = 1; kvm_mmu_flush_tlb(vcpu); } - if (unlikely(is_mmio_spte(*sptep) && emulate)) - *emulate = 1; - pgprintk("%s: setting spte %llx\n", __func__, *sptep); pgprintk("instantiating %s PTE (%s) at %llx (%llx) addr %p\n", is_large_pte(*sptep)? "2MB" : "4kB", @@ -2337,13 +2145,11 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep, if (!was_rmapped && is_large_pte(*sptep)) ++vcpu->kvm->stat.lpages; - if (is_shadow_present_pte(*sptep)) { - page_header_update_slot(vcpu->kvm, sptep, gfn); - if (!was_rmapped) { - rmap_count = rmap_add(vcpu, sptep, gfn); - if (rmap_count > RMAP_RECYCLE_THRESHOLD) - rmap_recycle(vcpu, sptep, gfn); - } + page_header_update_slot(vcpu->kvm, sptep, gfn); + if (!was_rmapped) { + rmap_count = rmap_add(vcpu, sptep, gfn); + if (rmap_count > RMAP_RECYCLE_THRESHOLD) + rmap_recycle(vcpu, sptep, gfn); } kvm_release_pfn_clean(pfn); if (speculative) { @@ -2364,8 +2170,8 @@ static pfn_t pte_prefetch_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn, slot = gfn_to_memslot_dirty_bitmap(vcpu, gfn, no_dirty_log); if (!slot) { - get_page(fault_page); - return page_to_pfn(fault_page); + get_page(bad_page); + return page_to_pfn(bad_page); } hva = gfn_to_hva_memslot(slot, gfn); @@ -2392,7 +2198,7 @@ static int direct_pte_prefetch_many(struct kvm_vcpu *vcpu, for (i = 0; i < ret; i++, gfn++, start++) mmu_set_spte(vcpu, start, ACC_ALL, - access, 0, 0, NULL, + access, 0, 0, 1, NULL, sp->role.level, gfn, page_to_pfn(pages[i]), true, true); @@ -2411,7 +2217,7 @@ static void __direct_pte_prefetch(struct kvm_vcpu *vcpu, spte = sp->spt + i; for (i = 0; i < PTE_PREFETCH_NUM; i++, spte++) { - if (is_shadow_present_pte(*spte) || spte == sptep) { + if (*spte != shadow_trap_nonpresent_pte || spte == sptep) { if (!start) continue; if (direct_pte_prefetch_many(vcpu, sp, start, spte) < 0) @@ -2448,7 +2254,7 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write, { struct kvm_shadow_walk_iterator iterator; struct kvm_mmu_page *sp; - int emulate = 0; + int pt_write = 0; gfn_t pseudo_gfn; for_each_shadow_entry(vcpu, (u64)gfn << PAGE_SHIFT, iterator) { @@ -2456,14 +2262,14 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write, unsigned pte_access = ACC_ALL; mmu_set_spte(vcpu, iterator.sptep, ACC_ALL, pte_access, - 0, write, &emulate, + 0, write, 1, &pt_write, level, gfn, pfn, prefault, map_writable); direct_pte_prefetch(vcpu, iterator.sptep); ++vcpu->stat.pf_fixed; break; } - if (!is_shadow_present_pte(*iterator.sptep)) { + if (*iterator.sptep == shadow_trap_nonpresent_pte) { u64 base_addr = iterator.addr; base_addr &= PT64_LVL_ADDR_MASK(iterator.level); @@ -2477,14 +2283,14 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write, return -ENOMEM; } - mmu_spte_set(iterator.sptep, - __pa(sp->spt) - | PT_PRESENT_MASK | PT_WRITABLE_MASK - | shadow_user_mask | shadow_x_mask - | shadow_accessed_mask); + __set_spte(iterator.sptep, + __pa(sp->spt) + | PT_PRESENT_MASK | PT_WRITABLE_MASK + | shadow_user_mask | shadow_x_mask + | shadow_accessed_mask); } } - return emulate; + return pt_write; } static void kvm_send_hwpoison_signal(unsigned long address, struct task_struct *tsk) @@ -2500,15 +2306,16 @@ static void kvm_send_hwpoison_signal(unsigned long address, struct task_struct * send_sig_info(SIGBUS, &info, tsk); } -static int kvm_handle_bad_page(struct kvm_vcpu *vcpu, gfn_t gfn, pfn_t pfn) +static int kvm_handle_bad_page(struct kvm *kvm, gfn_t gfn, pfn_t pfn) { kvm_release_pfn_clean(pfn); if (is_hwpoison_pfn(pfn)) { - kvm_send_hwpoison_signal(gfn_to_hva(vcpu->kvm, gfn), current); + kvm_send_hwpoison_signal(gfn_to_hva(kvm, gfn), current); return 0; - } + } else if (is_fault_pfn(pfn)) + return -EFAULT; - return -EFAULT; + return 1; } static void transparent_hugepage_adjust(struct kvm_vcpu *vcpu, @@ -2553,30 +2360,6 @@ static void transparent_hugepage_adjust(struct kvm_vcpu *vcpu, } } -static bool mmu_invalid_pfn(pfn_t pfn) -{ - return unlikely(is_invalid_pfn(pfn)); -} - -static bool handle_abnormal_pfn(struct kvm_vcpu *vcpu, gva_t gva, gfn_t gfn, - pfn_t pfn, unsigned access, int *ret_val) -{ - bool ret = true; - - /* The pfn is invalid, report the error! */ - if (unlikely(is_invalid_pfn(pfn))) { - *ret_val = kvm_handle_bad_page(vcpu, gfn, pfn); - goto exit; - } - - if (unlikely(is_noslot_pfn(pfn))) - vcpu_cache_mmio_info(vcpu, gva, gfn, access); - - ret = false; -exit: - return ret; -} - static bool try_async_pf(struct kvm_vcpu *vcpu, bool prefault, gfn_t gfn, gva_t gva, pfn_t *pfn, bool write, bool *writable); @@ -2611,8 +2394,9 @@ static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, int write, gfn_t gfn, if (try_async_pf(vcpu, prefault, gfn, v, &pfn, write, &map_writable)) return 0; - if (handle_abnormal_pfn(vcpu, v, gfn, pfn, ACC_ALL, &r)) - return r; + /* mmio */ + if (is_error_pfn(pfn)) + return kvm_handle_bad_page(vcpu->kvm, gfn, pfn); spin_lock(&vcpu->kvm->mmu_lock); if (mmu_notifier_retry(vcpu, mmu_seq)) @@ -2839,7 +2623,6 @@ static void mmu_sync_roots(struct kvm_vcpu *vcpu) if (!VALID_PAGE(vcpu->arch.mmu.root_hpa)) return; - vcpu_clear_mmio_info(vcpu, ~0ul); trace_kvm_mmu_audit(vcpu, AUDIT_PRE_SYNC); if (vcpu->arch.mmu.root_level == PT64_ROOT_LEVEL) { hpa_t root = vcpu->arch.mmu.root_hpa; @@ -2884,94 +2667,6 @@ static gpa_t nonpaging_gva_to_gpa_nested(struct kvm_vcpu *vcpu, gva_t vaddr, return vcpu->arch.nested_mmu.translate_gpa(vcpu, vaddr, access); } -static bool quickly_check_mmio_pf(struct kvm_vcpu *vcpu, u64 addr, bool direct) -{ - if (direct) - return vcpu_match_mmio_gpa(vcpu, addr); - - return vcpu_match_mmio_gva(vcpu, addr); -} - - -/* - * On direct hosts, the last spte is only allows two states - * for mmio page fault: - * - It is the mmio spte - * - It is zapped or it is being zapped. - * - * This function completely checks the spte when the last spte - * is not the mmio spte. - */ -static bool check_direct_spte_mmio_pf(u64 spte) -{ - return __check_direct_spte_mmio_pf(spte); -} - -static u64 walk_shadow_page_get_mmio_spte(struct kvm_vcpu *vcpu, u64 addr) -{ - struct kvm_shadow_walk_iterator iterator; - u64 spte = 0ull; - - walk_shadow_page_lockless_begin(vcpu); - for_each_shadow_entry_lockless(vcpu, addr, iterator, spte) - if (!is_shadow_present_pte(spte)) - break; - walk_shadow_page_lockless_end(vcpu); - - return spte; -} - -/* - * If it is a real mmio page fault, return 1 and emulat the instruction - * directly, return 0 to let CPU fault again on the address, -1 is - * returned if bug is detected. - */ -int handle_mmio_page_fault_common(struct kvm_vcpu *vcpu, u64 addr, bool direct) -{ - u64 spte; - - if (quickly_check_mmio_pf(vcpu, addr, direct)) - return 1; - - spte = walk_shadow_page_get_mmio_spte(vcpu, addr); - - if (is_mmio_spte(spte)) { - gfn_t gfn = get_mmio_spte_gfn(spte); - unsigned access = get_mmio_spte_access(spte); - - if (direct) - addr = 0; - - trace_handle_mmio_page_fault(addr, gfn, access); - vcpu_cache_mmio_info(vcpu, addr, gfn, access); - return 1; - } - - /* - * It's ok if the gva is remapped by other cpus on shadow guest, - * it's a BUG if the gfn is not a mmio page. - */ - if (direct && !check_direct_spte_mmio_pf(spte)) - return -1; - - /* - * If the page table is zapped by other cpus, let CPU fault again on - * the address. - */ - return 0; -} -EXPORT_SYMBOL_GPL(handle_mmio_page_fault_common); - -static int handle_mmio_page_fault(struct kvm_vcpu *vcpu, u64 addr, - u32 error_code, bool direct) -{ - int ret; - - ret = handle_mmio_page_fault_common(vcpu, addr, direct); - WARN_ON(ret < 0); - return ret; -} - static int nonpaging_page_fault(struct kvm_vcpu *vcpu, gva_t gva, u32 error_code, bool prefault) { @@ -2979,10 +2674,6 @@ static int nonpaging_page_fault(struct kvm_vcpu *vcpu, gva_t gva, int r; pgprintk("%s: gva %lx error %x\n", __func__, gva, error_code); - - if (unlikely(error_code & PFERR_RSVD_MASK)) - return handle_mmio_page_fault(vcpu, gva, error_code, true); - r = mmu_topup_memory_caches(vcpu); if (r) return r; @@ -3059,9 +2750,6 @@ static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa, u32 error_code, ASSERT(vcpu); ASSERT(VALID_PAGE(vcpu->arch.mmu.root_hpa)); - if (unlikely(error_code & PFERR_RSVD_MASK)) - return handle_mmio_page_fault(vcpu, gpa, error_code, true); - r = mmu_topup_memory_caches(vcpu); if (r) return r; @@ -3079,9 +2767,9 @@ static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa, u32 error_code, if (try_async_pf(vcpu, prefault, gfn, gpa, &pfn, write, &map_writable)) return 0; - if (handle_abnormal_pfn(vcpu, 0, gfn, pfn, ACC_ALL, &r)) - return r; - + /* mmio */ + if (is_error_pfn(pfn)) + return kvm_handle_bad_page(vcpu->kvm, gfn, pfn); spin_lock(&vcpu->kvm->mmu_lock); if (mmu_notifier_retry(vcpu, mmu_seq)) goto out_unlock; @@ -3112,6 +2800,7 @@ static int nonpaging_init_context(struct kvm_vcpu *vcpu, context->page_fault = nonpaging_page_fault; context->gva_to_gpa = nonpaging_gva_to_gpa; context->free = nonpaging_free; + context->prefetch_page = nonpaging_prefetch_page; context->sync_page = nonpaging_sync_page; context->invlpg = nonpaging_invlpg; context->update_pte = nonpaging_update_pte; @@ -3159,23 +2848,6 @@ static bool is_rsvd_bits_set(struct kvm_mmu *mmu, u64 gpte, int level) return (gpte & mmu->rsvd_bits_mask[bit7][level-1]) != 0; } -static bool sync_mmio_spte(u64 *sptep, gfn_t gfn, unsigned access, - int *nr_present) -{ - if (unlikely(is_mmio_spte(*sptep))) { - if (gfn != get_mmio_spte_gfn(*sptep)) { - mmu_spte_clear_no_track(sptep); - return true; - } - - (*nr_present)++; - mark_mmio_spte(sptep, gfn, access); - return true; - } - - return false; -} - #define PTTYPE 64 #include "paging_tmpl.h" #undef PTTYPE @@ -3258,6 +2930,7 @@ static int paging64_init_context_common(struct kvm_vcpu *vcpu, context->new_cr3 = paging_new_cr3; context->page_fault = paging64_page_fault; context->gva_to_gpa = paging64_gva_to_gpa; + context->prefetch_page = paging64_prefetch_page; context->sync_page = paging64_sync_page; context->invlpg = paging64_invlpg; context->update_pte = paging64_update_pte; @@ -3286,6 +2959,7 @@ static int paging32_init_context(struct kvm_vcpu *vcpu, context->page_fault = paging32_page_fault; context->gva_to_gpa = paging32_gva_to_gpa; context->free = paging_free; + context->prefetch_page = paging32_prefetch_page; context->sync_page = paging32_sync_page; context->invlpg = paging32_invlpg; context->update_pte = paging32_update_pte; @@ -3310,6 +2984,7 @@ static int init_kvm_tdp_mmu(struct kvm_vcpu *vcpu) context->new_cr3 = nonpaging_new_cr3; context->page_fault = tdp_page_fault; context->free = nonpaging_free; + context->prefetch_page = nonpaging_prefetch_page; context->sync_page = nonpaging_sync_page; context->invlpg = nonpaging_invlpg; context->update_pte = nonpaging_update_pte; @@ -3348,7 +3023,6 @@ static int init_kvm_tdp_mmu(struct kvm_vcpu *vcpu) int kvm_init_shadow_mmu(struct kvm_vcpu *vcpu, struct kvm_mmu *context) { int r; - bool smep = kvm_read_cr4_bits(vcpu, X86_CR4_SMEP); ASSERT(vcpu); ASSERT(!VALID_PAGE(vcpu->arch.mmu.root_hpa)); @@ -3363,8 +3037,6 @@ int kvm_init_shadow_mmu(struct kvm_vcpu *vcpu, struct kvm_mmu *context) vcpu->arch.mmu.base_role.cr4_pae = !!is_pae(vcpu); vcpu->arch.mmu.base_role.cr0_wp = is_write_protection(vcpu); - vcpu->arch.mmu.base_role.smep_andnot_wp - = smep && !is_write_protection(vcpu); return r; } @@ -3469,6 +3141,27 @@ void kvm_mmu_unload(struct kvm_vcpu *vcpu) } EXPORT_SYMBOL_GPL(kvm_mmu_unload); +static void mmu_pte_write_zap_pte(struct kvm_vcpu *vcpu, + struct kvm_mmu_page *sp, + u64 *spte) +{ + u64 pte; + struct kvm_mmu_page *child; + + pte = *spte; + if (is_shadow_present_pte(pte)) { + if (is_last_spte(pte, sp->role.level)) + drop_spte(vcpu->kvm, spte, shadow_trap_nonpresent_pte); + else { + child = page_header(pte & PT64_BASE_ADDR_MASK); + mmu_page_remove_parent_pte(child, spte); + } + } + __set_spte(spte, shadow_trap_nonpresent_pte); + if (is_large_pte(pte)) + --vcpu->kvm->stat.lpages; +} + static void mmu_pte_write_new_pte(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, u64 *spte, const void *new) @@ -3540,13 +3233,6 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, int level, npte, invlpg_counter, r, flooded = 0; bool remote_flush, local_flush, zap_page; - /* - * If we don't have indirect shadow pages, it means no page is - * write-protected, so we can exit simply. - */ - if (!ACCESS_ONCE(vcpu->kvm->arch.indirect_shadow_pages)) - return; - zap_page = remote_flush = local_flush = false; offset = offset_in_page(gpa); @@ -3650,7 +3336,7 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, spte = &sp->spt[page_offset / sizeof(*spte)]; while (npte--) { entry = *spte; - mmu_page_zap_pte(vcpu->kvm, sp, spte); + mmu_pte_write_zap_pte(vcpu, sp, spte); if (gentry && !((sp->role.word ^ vcpu->arch.mmu.base_role.word) & mask.word)) @@ -3694,9 +3380,9 @@ void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu) sp = container_of(vcpu->kvm->arch.active_mmu_pages.prev, struct kvm_mmu_page, link); kvm_mmu_prepare_zap_page(vcpu->kvm, sp, &invalid_list); + kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list); ++vcpu->kvm->stat.mmu_recycled; } - kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list); } int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t cr2, u32 error_code, @@ -3820,15 +3506,15 @@ void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot) continue; if (is_large_pte(pt[i])) { - drop_spte(kvm, &pt[i]); + drop_spte(kvm, &pt[i], + shadow_trap_nonpresent_pte); --kvm->stat.lpages; continue; } /* avoid RMW */ if (is_writable_pte(pt[i])) - mmu_spte_update(&pt[i], - pt[i] & ~PT_WRITABLE_MASK); + update_spte(&pt[i], pt[i] & ~PT_WRITABLE_MASK); } } kvm_flush_remote_tlbs(kvm); @@ -3904,18 +3590,25 @@ static struct shrinker mmu_shrinker = { static void mmu_destroy_caches(void) { - if (pte_list_desc_cache) - kmem_cache_destroy(pte_list_desc_cache); + if (pte_chain_cache) + kmem_cache_destroy(pte_chain_cache); + if (rmap_desc_cache) + kmem_cache_destroy(rmap_desc_cache); if (mmu_page_header_cache) kmem_cache_destroy(mmu_page_header_cache); } int kvm_mmu_module_init(void) { - pte_list_desc_cache = kmem_cache_create("pte_list_desc", - sizeof(struct pte_list_desc), + pte_chain_cache = kmem_cache_create("kvm_pte_chain", + sizeof(struct kvm_pte_chain), + 0, 0, NULL); + if (!pte_chain_cache) + goto nomem; + rmap_desc_cache = kmem_cache_create("kvm_rmap_desc", + sizeof(struct kvm_rmap_desc), 0, 0, NULL); - if (!pte_list_desc_cache) + if (!rmap_desc_cache) goto nomem; mmu_page_header_cache = kmem_cache_create("kvm_mmu_page_header", @@ -4082,17 +3775,16 @@ int kvm_pv_mmu_op(struct kvm_vcpu *vcpu, unsigned long bytes, int kvm_mmu_get_spte_hierarchy(struct kvm_vcpu *vcpu, u64 addr, u64 sptes[4]) { struct kvm_shadow_walk_iterator iterator; - u64 spte; int nr_sptes = 0; - walk_shadow_page_lockless_begin(vcpu); - for_each_shadow_entry_lockless(vcpu, addr, iterator, spte) { - sptes[iterator.level-1] = spte; + spin_lock(&vcpu->kvm->mmu_lock); + for_each_shadow_entry(vcpu, addr, iterator) { + sptes[iterator.level-1] = *iterator.sptep; nr_sptes++; - if (!is_shadow_present_pte(spte)) + if (!is_shadow_present_pte(*iterator.sptep)) break; } - walk_shadow_page_lockless_end(vcpu); + spin_unlock(&vcpu->kvm->mmu_lock); return nr_sptes; } diff --git a/trunk/arch/x86/kvm/mmu.h b/trunk/arch/x86/kvm/mmu.h index e374db9af021..7086ca85d3e7 100644 --- a/trunk/arch/x86/kvm/mmu.h +++ b/trunk/arch/x86/kvm/mmu.h @@ -49,8 +49,6 @@ #define PFERR_FETCH_MASK (1U << 4) int kvm_mmu_get_spte_hierarchy(struct kvm_vcpu *vcpu, u64 addr, u64 sptes[4]); -void kvm_mmu_set_mmio_spte_mask(u64 mmio_mask); -int handle_mmio_page_fault_common(struct kvm_vcpu *vcpu, u64 addr, bool direct); int kvm_init_shadow_mmu(struct kvm_vcpu *vcpu, struct kvm_mmu *context); static inline unsigned int kvm_mmu_available_pages(struct kvm *kvm) @@ -78,27 +76,4 @@ static inline int is_present_gpte(unsigned long pte) return pte & PT_PRESENT_MASK; } -static inline int is_writable_pte(unsigned long pte) -{ - return pte & PT_WRITABLE_MASK; -} - -static inline bool is_write_protection(struct kvm_vcpu *vcpu) -{ - return kvm_read_cr0_bits(vcpu, X86_CR0_WP); -} - -static inline bool check_write_user_access(struct kvm_vcpu *vcpu, - bool write_fault, bool user_fault, - unsigned long pte) -{ - if (unlikely(write_fault && !is_writable_pte(pte) - && (user_fault || is_write_protection(vcpu)))) - return false; - - if (unlikely(user_fault && !(pte & PT_USER_MASK))) - return false; - - return true; -} #endif diff --git a/trunk/arch/x86/kvm/mmu_audit.c b/trunk/arch/x86/kvm/mmu_audit.c index 2460a265be23..5f6223b8bcf7 100644 --- a/trunk/arch/x86/kvm/mmu_audit.c +++ b/trunk/arch/x86/kvm/mmu_audit.c @@ -99,6 +99,18 @@ static void audit_mappings(struct kvm_vcpu *vcpu, u64 *sptep, int level) "level = %d\n", sp, level); return; } + + if (*sptep == shadow_notrap_nonpresent_pte) { + audit_printk(vcpu->kvm, "notrap spte in unsync " + "sp: %p\n", sp); + return; + } + } + + if (sp->role.direct && *sptep == shadow_notrap_nonpresent_pte) { + audit_printk(vcpu->kvm, "notrap spte in direct sp: %p\n", + sp); + return; } if (!is_shadow_present_pte(*sptep) || !is_last_spte(*sptep, level)) diff --git a/trunk/arch/x86/kvm/mmutrace.h b/trunk/arch/x86/kvm/mmutrace.h index eed67f34146d..b60b4fdb3eda 100644 --- a/trunk/arch/x86/kvm/mmutrace.h +++ b/trunk/arch/x86/kvm/mmutrace.h @@ -196,54 +196,6 @@ DEFINE_EVENT(kvm_mmu_page_class, kvm_mmu_prepare_zap_page, TP_ARGS(sp) ); -DEFINE_EVENT(kvm_mmu_page_class, kvm_mmu_delay_free_pages, - TP_PROTO(struct kvm_mmu_page *sp), - - TP_ARGS(sp) -); - -TRACE_EVENT( - mark_mmio_spte, - TP_PROTO(u64 *sptep, gfn_t gfn, unsigned access), - TP_ARGS(sptep, gfn, access), - - TP_STRUCT__entry( - __field(void *, sptep) - __field(gfn_t, gfn) - __field(unsigned, access) - ), - - TP_fast_assign( - __entry->sptep = sptep; - __entry->gfn = gfn; - __entry->access = access; - ), - - TP_printk("sptep:%p gfn %llx access %x", __entry->sptep, __entry->gfn, - __entry->access) -); - -TRACE_EVENT( - handle_mmio_page_fault, - TP_PROTO(u64 addr, gfn_t gfn, unsigned access), - TP_ARGS(addr, gfn, access), - - TP_STRUCT__entry( - __field(u64, addr) - __field(gfn_t, gfn) - __field(unsigned, access) - ), - - TP_fast_assign( - __entry->addr = addr; - __entry->gfn = gfn; - __entry->access = access; - ), - - TP_printk("addr:%llx gfn %llx access %x", __entry->addr, __entry->gfn, - __entry->access) -); - TRACE_EVENT( kvm_mmu_audit, TP_PROTO(struct kvm_vcpu *vcpu, int audit_point), diff --git a/trunk/arch/x86/kvm/paging_tmpl.h b/trunk/arch/x86/kvm/paging_tmpl.h index 507e2b844cfa..9d03ad4dd5ec 100644 --- a/trunk/arch/x86/kvm/paging_tmpl.h +++ b/trunk/arch/x86/kvm/paging_tmpl.h @@ -101,15 +101,11 @@ static int FNAME(cmpxchg_gpte)(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, return (ret != orig_pte); } -static unsigned FNAME(gpte_access)(struct kvm_vcpu *vcpu, pt_element_t gpte, - bool last) +static unsigned FNAME(gpte_access)(struct kvm_vcpu *vcpu, pt_element_t gpte) { unsigned access; access = (gpte & (PT_WRITABLE_MASK | PT_USER_MASK)) | ACC_EXEC_MASK; - if (last && !is_dirty_gpte(gpte)) - access &= ~ACC_WRITE_MASK; - #if PTTYPE == 64 if (vcpu->arch.mmu.nx) access &= ~(gpte >> PT64_NX_SHIFT); @@ -117,24 +113,6 @@ static unsigned FNAME(gpte_access)(struct kvm_vcpu *vcpu, pt_element_t gpte, return access; } -static bool FNAME(is_last_gpte)(struct guest_walker *walker, - struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, - pt_element_t gpte) -{ - if (walker->level == PT_PAGE_TABLE_LEVEL) - return true; - - if ((walker->level == PT_DIRECTORY_LEVEL) && is_large_pte(gpte) && - (PTTYPE == 64 || is_pse(vcpu))) - return true; - - if ((walker->level == PT_PDPE_LEVEL) && is_large_pte(gpte) && - (mmu->root_level == PT64_ROOT_LEVEL)) - return true; - - return false; -} - /* * Fetch a guest pte for a guest virtual address */ @@ -147,17 +125,18 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, gfn_t table_gfn; unsigned index, pt_access, uninitialized_var(pte_access); gpa_t pte_gpa; - bool eperm; - int offset; - const int write_fault = access & PFERR_WRITE_MASK; - const int user_fault = access & PFERR_USER_MASK; - const int fetch_fault = access & PFERR_FETCH_MASK; - u16 errcode = 0; + bool eperm, present, rsvd_fault; + int offset, write_fault, user_fault, fetch_fault; + + write_fault = access & PFERR_WRITE_MASK; + user_fault = access & PFERR_USER_MASK; + fetch_fault = access & PFERR_FETCH_MASK; trace_kvm_mmu_pagetable_walk(addr, write_fault, user_fault, fetch_fault); -retry_walk: - eperm = false; +walk: + present = true; + eperm = rsvd_fault = false; walker->level = mmu->root_level; pte = mmu->get_cr3(vcpu); @@ -165,8 +144,10 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, if (walker->level == PT32E_ROOT_LEVEL) { pte = kvm_pdptr_read_mmu(vcpu, mmu, (addr >> 30) & 3); trace_kvm_mmu_paging_element(pte, walker->level); - if (!is_present_gpte(pte)) + if (!is_present_gpte(pte)) { + present = false; goto error; + } --walker->level; } #endif @@ -189,31 +170,42 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, real_gfn = mmu->translate_gpa(vcpu, gfn_to_gpa(table_gfn), PFERR_USER_MASK|PFERR_WRITE_MASK); - if (unlikely(real_gfn == UNMAPPED_GVA)) - goto error; + if (unlikely(real_gfn == UNMAPPED_GVA)) { + present = false; + break; + } real_gfn = gpa_to_gfn(real_gfn); host_addr = gfn_to_hva(vcpu->kvm, real_gfn); - if (unlikely(kvm_is_error_hva(host_addr))) - goto error; + if (unlikely(kvm_is_error_hva(host_addr))) { + present = false; + break; + } ptep_user = (pt_element_t __user *)((void *)host_addr + offset); - if (unlikely(__copy_from_user(&pte, ptep_user, sizeof(pte)))) - goto error; + if (unlikely(__copy_from_user(&pte, ptep_user, sizeof(pte)))) { + present = false; + break; + } trace_kvm_mmu_paging_element(pte, walker->level); - if (unlikely(!is_present_gpte(pte))) - goto error; + if (unlikely(!is_present_gpte(pte))) { + present = false; + break; + } if (unlikely(is_rsvd_bits_set(&vcpu->arch.mmu, pte, walker->level))) { - errcode |= PFERR_RSVD_MASK | PFERR_PRESENT_MASK; - goto error; + rsvd_fault = true; + break; } - if (!check_write_user_access(vcpu, write_fault, user_fault, - pte)) + if (unlikely(write_fault && !is_writable_pte(pte) + && (user_fault || is_write_protection(vcpu)))) + eperm = true; + + if (unlikely(user_fault && !(pte & PT_USER_MASK))) eperm = true; #if PTTYPE == 64 @@ -221,35 +213,39 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, eperm = true; #endif - if (!eperm && unlikely(!(pte & PT_ACCESSED_MASK))) { + if (!eperm && !rsvd_fault + && unlikely(!(pte & PT_ACCESSED_MASK))) { int ret; trace_kvm_mmu_set_accessed_bit(table_gfn, index, sizeof(pte)); ret = FNAME(cmpxchg_gpte)(vcpu, mmu, ptep_user, index, pte, pte|PT_ACCESSED_MASK); - if (unlikely(ret < 0)) - goto error; - else if (ret) - goto retry_walk; + if (unlikely(ret < 0)) { + present = false; + break; + } else if (ret) + goto walk; mark_page_dirty(vcpu->kvm, table_gfn); pte |= PT_ACCESSED_MASK; } + pte_access = pt_access & FNAME(gpte_access)(vcpu, pte); + walker->ptes[walker->level - 1] = pte; - if (FNAME(is_last_gpte)(walker, vcpu, mmu, pte)) { + if ((walker->level == PT_PAGE_TABLE_LEVEL) || + ((walker->level == PT_DIRECTORY_LEVEL) && + is_large_pte(pte) && + (PTTYPE == 64 || is_pse(vcpu))) || + ((walker->level == PT_PDPE_LEVEL) && + is_large_pte(pte) && + mmu->root_level == PT64_ROOT_LEVEL)) { int lvl = walker->level; gpa_t real_gpa; gfn_t gfn; u32 ac; - /* check if the kernel is fetching from user page */ - if (unlikely(pte_access & PT_USER_MASK) && - kvm_read_cr4_bits(vcpu, X86_CR4_SMEP)) - if (fetch_fault && !user_fault) - eperm = true; - gfn = gpte_to_gfn_lvl(pte, lvl); gfn += (addr & PT_LVL_OFFSET_MASK(lvl)) >> PAGE_SHIFT; @@ -270,14 +266,12 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, break; } - pt_access &= FNAME(gpte_access)(vcpu, pte, false); + pt_access = pte_access; --walker->level; } - if (unlikely(eperm)) { - errcode |= PFERR_PRESENT_MASK; + if (unlikely(!present || eperm || rsvd_fault)) goto error; - } if (write_fault && unlikely(!is_dirty_gpte(pte))) { int ret; @@ -285,17 +279,17 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, trace_kvm_mmu_set_dirty_bit(table_gfn, index, sizeof(pte)); ret = FNAME(cmpxchg_gpte)(vcpu, mmu, ptep_user, index, pte, pte|PT_DIRTY_MASK); - if (unlikely(ret < 0)) + if (unlikely(ret < 0)) { + present = false; goto error; - else if (ret) - goto retry_walk; + } else if (ret) + goto walk; mark_page_dirty(vcpu->kvm, table_gfn); pte |= PT_DIRTY_MASK; walker->ptes[walker->level - 1] = pte; } - pte_access = pt_access & FNAME(gpte_access)(vcpu, pte, true); walker->pt_access = pt_access; walker->pte_access = pte_access; pgprintk("%s: pte %llx pte_access %x pt_access %x\n", @@ -303,14 +297,19 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, return 1; error: - errcode |= write_fault | user_fault; - if (fetch_fault && (mmu->nx || - kvm_read_cr4_bits(vcpu, X86_CR4_SMEP))) - errcode |= PFERR_FETCH_MASK; - walker->fault.vector = PF_VECTOR; walker->fault.error_code_valid = true; - walker->fault.error_code = errcode; + walker->fault.error_code = 0; + if (present) + walker->fault.error_code |= PFERR_PRESENT_MASK; + + walker->fault.error_code |= write_fault | user_fault; + + if (fetch_fault && mmu->nx) + walker->fault.error_code |= PFERR_FETCH_MASK; + if (rsvd_fault) + walker->fault.error_code |= PFERR_RSVD_MASK; + walker->fault.address = addr; walker->fault.nested_page_fault = mmu != vcpu->arch.walk_mmu; @@ -337,11 +336,16 @@ static bool FNAME(prefetch_invalid_gpte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, u64 *spte, pt_element_t gpte) { + u64 nonpresent = shadow_trap_nonpresent_pte; + if (is_rsvd_bits_set(&vcpu->arch.mmu, gpte, PT_PAGE_TABLE_LEVEL)) goto no_present; - if (!is_present_gpte(gpte)) + if (!is_present_gpte(gpte)) { + if (!sp->unsync) + nonpresent = shadow_notrap_nonpresent_pte; goto no_present; + } if (!(gpte & PT_ACCESSED_MASK)) goto no_present; @@ -349,7 +353,7 @@ static bool FNAME(prefetch_invalid_gpte)(struct kvm_vcpu *vcpu, return false; no_present: - drop_spte(vcpu->kvm, spte); + drop_spte(vcpu->kvm, spte, nonpresent); return true; } @@ -365,9 +369,9 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, return; pgprintk("%s: gpte %llx spte %p\n", __func__, (u64)gpte, spte); - pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte, true); + pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte); pfn = gfn_to_pfn_atomic(vcpu->kvm, gpte_to_gfn(gpte)); - if (mmu_invalid_pfn(pfn)) { + if (is_error_pfn(pfn)) { kvm_release_pfn_clean(pfn); return; } @@ -377,7 +381,7 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, * vcpu->arch.update_pte.pfn was fetched from get_user_pages(write = 1). */ mmu_set_spte(vcpu, spte, sp->role.access, pte_access, 0, 0, - NULL, PT_PAGE_TABLE_LEVEL, + is_dirty_gpte(gpte), NULL, PT_PAGE_TABLE_LEVEL, gpte_to_gfn(gpte), pfn, true, true); } @@ -428,11 +432,12 @@ static void FNAME(pte_prefetch)(struct kvm_vcpu *vcpu, struct guest_walker *gw, unsigned pte_access; gfn_t gfn; pfn_t pfn; + bool dirty; if (spte == sptep) continue; - if (is_shadow_present_pte(*spte)) + if (*spte != shadow_trap_nonpresent_pte) continue; gpte = gptep[i]; @@ -440,18 +445,18 @@ static void FNAME(pte_prefetch)(struct kvm_vcpu *vcpu, struct guest_walker *gw, if (FNAME(prefetch_invalid_gpte)(vcpu, sp, spte, gpte)) continue; - pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte, - true); + pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte); gfn = gpte_to_gfn(gpte); + dirty = is_dirty_gpte(gpte); pfn = pte_prefetch_gfn_to_pfn(vcpu, gfn, - pte_access & ACC_WRITE_MASK); - if (mmu_invalid_pfn(pfn)) { + (pte_access & ACC_WRITE_MASK) && dirty); + if (is_error_pfn(pfn)) { kvm_release_pfn_clean(pfn); break; } mmu_set_spte(vcpu, spte, sp->role.access, pte_access, 0, 0, - NULL, PT_PAGE_TABLE_LEVEL, gfn, + dirty, NULL, PT_PAGE_TABLE_LEVEL, gfn, pfn, true, true); } } @@ -462,11 +467,12 @@ static void FNAME(pte_prefetch)(struct kvm_vcpu *vcpu, struct guest_walker *gw, static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, struct guest_walker *gw, int user_fault, int write_fault, int hlevel, - int *emulate, pfn_t pfn, bool map_writable, + int *ptwrite, pfn_t pfn, bool map_writable, bool prefault) { unsigned access = gw->pt_access; struct kvm_mmu_page *sp = NULL; + bool dirty = is_dirty_gpte(gw->ptes[gw->level - 1]); int top_level; unsigned direct_access; struct kvm_shadow_walk_iterator it; @@ -474,7 +480,9 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, if (!is_present_gpte(gw->ptes[gw->level - 1])) return NULL; - direct_access = gw->pte_access; + direct_access = gw->pt_access & gw->pte_access; + if (!dirty) + direct_access &= ~ACC_WRITE_MASK; top_level = vcpu->arch.mmu.root_level; if (top_level == PT32E_ROOT_LEVEL) @@ -532,8 +540,8 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, link_shadow_page(it.sptep, sp); } - mmu_set_spte(vcpu, it.sptep, access, gw->pte_access, - user_fault, write_fault, emulate, it.level, + mmu_set_spte(vcpu, it.sptep, access, gw->pte_access & access, + user_fault, write_fault, dirty, ptwrite, it.level, gw->gfn, pfn, prefault, map_writable); FNAME(pte_prefetch)(vcpu, gw, it.sptep); @@ -567,7 +575,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, u32 error_code, int user_fault = error_code & PFERR_USER_MASK; struct guest_walker walker; u64 *sptep; - int emulate = 0; + int write_pt = 0; int r; pfn_t pfn; int level = PT_PAGE_TABLE_LEVEL; @@ -577,10 +585,6 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, u32 error_code, pgprintk("%s: addr %lx err %x\n", __func__, addr, error_code); - if (unlikely(error_code & PFERR_RSVD_MASK)) - return handle_mmio_page_fault(vcpu, addr, error_code, - mmu_is_nested(vcpu)); - r = mmu_topup_memory_caches(vcpu); if (r) return r; @@ -619,9 +623,9 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, u32 error_code, &map_writable)) return 0; - if (handle_abnormal_pfn(vcpu, mmu_is_nested(vcpu) ? 0 : addr, - walker.gfn, pfn, walker.pte_access, &r)) - return r; + /* mmio */ + if (is_error_pfn(pfn)) + return kvm_handle_bad_page(vcpu->kvm, walker.gfn, pfn); spin_lock(&vcpu->kvm->mmu_lock); if (mmu_notifier_retry(vcpu, mmu_seq)) @@ -632,19 +636,19 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, u32 error_code, if (!force_pt_level) transparent_hugepage_adjust(vcpu, &walker.gfn, &pfn, &level); sptep = FNAME(fetch)(vcpu, addr, &walker, user_fault, write_fault, - level, &emulate, pfn, map_writable, prefault); + level, &write_pt, pfn, map_writable, prefault); (void)sptep; - pgprintk("%s: shadow pte %p %llx emulate %d\n", __func__, - sptep, *sptep, emulate); + pgprintk("%s: shadow pte %p %llx ptwrite %d\n", __func__, + sptep, *sptep, write_pt); - if (!emulate) + if (!write_pt) vcpu->arch.last_pt_write_count = 0; /* reset fork detector */ ++vcpu->stat.pf_fixed; trace_kvm_mmu_audit(vcpu, AUDIT_POST_PAGE_FAULT); spin_unlock(&vcpu->kvm->mmu_lock); - return emulate; + return write_pt; out_unlock: spin_unlock(&vcpu->kvm->mmu_lock); @@ -661,8 +665,6 @@ static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva) u64 *sptep; int need_flush = 0; - vcpu_clear_mmio_info(vcpu, gva); - spin_lock(&vcpu->kvm->mmu_lock); for_each_shadow_entry(vcpu, gva, iterator) { @@ -686,11 +688,11 @@ static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva) if (is_shadow_present_pte(*sptep)) { if (is_large_pte(*sptep)) --vcpu->kvm->stat.lpages; - drop_spte(vcpu->kvm, sptep); + drop_spte(vcpu->kvm, sptep, + shadow_trap_nonpresent_pte); need_flush = 1; - } else if (is_mmio_spte(*sptep)) - mmu_spte_clear_no_track(sptep); - + } else + __set_spte(sptep, shadow_trap_nonpresent_pte); break; } @@ -750,6 +752,36 @@ static gpa_t FNAME(gva_to_gpa_nested)(struct kvm_vcpu *vcpu, gva_t vaddr, return gpa; } +static void FNAME(prefetch_page)(struct kvm_vcpu *vcpu, + struct kvm_mmu_page *sp) +{ + int i, j, offset, r; + pt_element_t pt[256 / sizeof(pt_element_t)]; + gpa_t pte_gpa; + + if (sp->role.direct + || (PTTYPE == 32 && sp->role.level > PT_PAGE_TABLE_LEVEL)) { + nonpaging_prefetch_page(vcpu, sp); + return; + } + + pte_gpa = gfn_to_gpa(sp->gfn); + if (PTTYPE == 32) { + offset = sp->role.quadrant << PT64_LEVEL_BITS; + pte_gpa += offset * sizeof(pt_element_t); + } + + for (i = 0; i < PT64_ENT_PER_PAGE; i += ARRAY_SIZE(pt)) { + r = kvm_read_guest_atomic(vcpu->kvm, pte_gpa, pt, sizeof pt); + pte_gpa += ARRAY_SIZE(pt) * sizeof(pt_element_t); + for (j = 0; j < ARRAY_SIZE(pt); ++j) + if (r || is_present_gpte(pt[j])) + sp->spt[i+j] = shadow_trap_nonpresent_pte; + else + sp->spt[i+j] = shadow_notrap_nonpresent_pte; + } +} + /* * Using the cached information from sp->gfns is safe because: * - The spte has a reference to the struct page, so the pfn for a given gfn @@ -785,7 +817,7 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp) gpa_t pte_gpa; gfn_t gfn; - if (!sp->spt[i]) + if (!is_shadow_present_pte(sp->spt[i])) continue; pte_gpa = first_pte_gpa + i * sizeof(pt_element_t); @@ -794,30 +826,26 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp) sizeof(pt_element_t))) return -EINVAL; + gfn = gpte_to_gfn(gpte); + if (FNAME(prefetch_invalid_gpte)(vcpu, sp, &sp->spt[i], gpte)) { vcpu->kvm->tlbs_dirty++; continue; } - gfn = gpte_to_gfn(gpte); - pte_access = sp->role.access; - pte_access &= FNAME(gpte_access)(vcpu, gpte, true); - - if (sync_mmio_spte(&sp->spt[i], gfn, pte_access, &nr_present)) - continue; - if (gfn != sp->gfns[i]) { - drop_spte(vcpu->kvm, &sp->spt[i]); + drop_spte(vcpu->kvm, &sp->spt[i], + shadow_trap_nonpresent_pte); vcpu->kvm->tlbs_dirty++; continue; } nr_present++; - + pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte); host_writable = sp->spt[i] & SPTE_HOST_WRITEABLE; set_spte(vcpu, &sp->spt[i], pte_access, 0, 0, - PT_PAGE_TABLE_LEVEL, gfn, + is_dirty_gpte(gpte), PT_PAGE_TABLE_LEVEL, gfn, spte_to_pfn(sp->spt[i]), true, false, host_writable); } diff --git a/trunk/arch/x86/kvm/svm.c b/trunk/arch/x86/kvm/svm.c index 475d1c948501..506e4fe23adc 100644 --- a/trunk/arch/x86/kvm/svm.c +++ b/trunk/arch/x86/kvm/svm.c @@ -1496,14 +1496,11 @@ static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) update_cr0_intercept(svm); } -static int svm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) +static void svm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) { unsigned long host_cr4_mce = read_cr4() & X86_CR4_MCE; unsigned long old_cr4 = to_svm(vcpu)->vmcb->save.cr4; - if (cr4 & X86_CR4_VMXE) - return 1; - if (npt_enabled && ((old_cr4 ^ cr4) & X86_CR4_PGE)) svm_flush_tlb(vcpu); @@ -1513,7 +1510,6 @@ static int svm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) cr4 |= host_cr4_mce; to_svm(vcpu)->vmcb->save.cr4 = cr4; mark_dirty(to_svm(vcpu)->vmcb, VMCB_CR); - return 0; } static void svm_set_segment(struct kvm_vcpu *vcpu, diff --git a/trunk/arch/x86/kvm/trace.h b/trunk/arch/x86/kvm/trace.h index 3ff898c104f7..db932760ea82 100644 --- a/trunk/arch/x86/kvm/trace.h +++ b/trunk/arch/x86/kvm/trace.h @@ -675,12 +675,12 @@ TRACE_EVENT(kvm_emulate_insn, ), TP_fast_assign( - __entry->rip = vcpu->arch.emulate_ctxt.fetch.start; + __entry->rip = vcpu->arch.emulate_ctxt.decode.fetch.start; __entry->csbase = kvm_x86_ops->get_segment_base(vcpu, VCPU_SREG_CS); - __entry->len = vcpu->arch.emulate_ctxt._eip - - vcpu->arch.emulate_ctxt.fetch.start; + __entry->len = vcpu->arch.emulate_ctxt.decode.eip + - vcpu->arch.emulate_ctxt.decode.fetch.start; memcpy(__entry->insn, - vcpu->arch.emulate_ctxt.fetch.data, + vcpu->arch.emulate_ctxt.decode.fetch.data, 15); __entry->flags = kei_decode_mode(vcpu->arch.emulate_ctxt.mode); __entry->failed = failed; @@ -698,29 +698,6 @@ TRACE_EVENT(kvm_emulate_insn, #define trace_kvm_emulate_insn_start(vcpu) trace_kvm_emulate_insn(vcpu, 0) #define trace_kvm_emulate_insn_failed(vcpu) trace_kvm_emulate_insn(vcpu, 1) -TRACE_EVENT( - vcpu_match_mmio, - TP_PROTO(gva_t gva, gpa_t gpa, bool write, bool gpa_match), - TP_ARGS(gva, gpa, write, gpa_match), - - TP_STRUCT__entry( - __field(gva_t, gva) - __field(gpa_t, gpa) - __field(bool, write) - __field(bool, gpa_match) - ), - - TP_fast_assign( - __entry->gva = gva; - __entry->gpa = gpa; - __entry->write = write; - __entry->gpa_match = gpa_match - ), - - TP_printk("gva %#lx gpa %#llx %s %s", __entry->gva, __entry->gpa, - __entry->write ? "Write" : "Read", - __entry->gpa_match ? "GPA" : "GVA") -); #endif /* _TRACE_KVM_H */ #undef TRACE_INCLUDE_PATH diff --git a/trunk/arch/x86/kvm/vmx.c b/trunk/arch/x86/kvm/vmx.c index e65a158dee64..d48ec60ea421 100644 --- a/trunk/arch/x86/kvm/vmx.c +++ b/trunk/arch/x86/kvm/vmx.c @@ -43,12 +43,13 @@ #include "trace.h" #define __ex(x) __kvm_handle_fault_on_reboot(x) -#define __ex_clear(x, reg) \ - ____kvm_handle_fault_on_reboot(x, "xor " reg " , " reg) MODULE_AUTHOR("Qumranet"); MODULE_LICENSE("GPL"); +static int __read_mostly bypass_guest_pf = 1; +module_param(bypass_guest_pf, bool, S_IRUGO); + static int __read_mostly enable_vpid = 1; module_param_named(vpid, enable_vpid, bool, 0444); @@ -71,14 +72,6 @@ module_param(vmm_exclusive, bool, S_IRUGO); static int __read_mostly yield_on_hlt = 1; module_param(yield_on_hlt, bool, S_IRUGO); -/* - * If nested=1, nested virtualization is supported, i.e., guests may use - * VMX and be a hypervisor for its own guests. If nested=0, guests may not - * use VMX instructions. - */ -static int __read_mostly nested = 0; -module_param(nested, bool, S_IRUGO); - #define KVM_GUEST_CR0_MASK_UNRESTRICTED_GUEST \ (X86_CR0_WP | X86_CR0_NE | X86_CR0_NW | X86_CR0_CD) #define KVM_GUEST_CR0_MASK \ @@ -116,7 +109,6 @@ static int ple_window = KVM_VMX_DEFAULT_PLE_WINDOW; module_param(ple_window, int, S_IRUGO); #define NR_AUTOLOAD_MSRS 1 -#define VMCS02_POOL_SIZE 1 struct vmcs { u32 revision_id; @@ -124,237 +116,17 @@ struct vmcs { char data[0]; }; -/* - * Track a VMCS that may be loaded on a certain CPU. If it is (cpu!=-1), also - * remember whether it was VMLAUNCHed, and maintain a linked list of all VMCSs - * loaded on this CPU (so we can clear them if the CPU goes down). - */ -struct loaded_vmcs { - struct vmcs *vmcs; - int cpu; - int launched; - struct list_head loaded_vmcss_on_cpu_link; -}; - struct shared_msr_entry { unsigned index; u64 data; u64 mask; }; -/* - * struct vmcs12 describes the state that our guest hypervisor (L1) keeps for a - * single nested guest (L2), hence the name vmcs12. Any VMX implementation has - * a VMCS structure, and vmcs12 is our emulated VMX's VMCS. This structure is - * stored in guest memory specified by VMPTRLD, but is opaque to the guest, - * which must access it using VMREAD/VMWRITE/VMCLEAR instructions. - * More than one of these structures may exist, if L1 runs multiple L2 guests. - * nested_vmx_run() will use the data here to build a vmcs02: a VMCS for the - * underlying hardware which will be used to run L2. - * This structure is packed to ensure that its layout is identical across - * machines (necessary for live migration). - * If there are changes in this struct, VMCS12_REVISION must be changed. - */ -typedef u64 natural_width; -struct __packed vmcs12 { - /* According to the Intel spec, a VMCS region must start with the - * following two fields. Then follow implementation-specific data. - */ - u32 revision_id; - u32 abort; - - u32 launch_state; /* set to 0 by VMCLEAR, to 1 by VMLAUNCH */ - u32 padding[7]; /* room for future expansion */ - - u64 io_bitmap_a; - u64 io_bitmap_b; - u64 msr_bitmap; - u64 vm_exit_msr_store_addr; - u64 vm_exit_msr_load_addr; - u64 vm_entry_msr_load_addr; - u64 tsc_offset; - u64 virtual_apic_page_addr; - u64 apic_access_addr; - u64 ept_pointer; - u64 guest_physical_address; - u64 vmcs_link_pointer; - u64 guest_ia32_debugctl; - u64 guest_ia32_pat; - u64 guest_ia32_efer; - u64 guest_ia32_perf_global_ctrl; - u64 guest_pdptr0; - u64 guest_pdptr1; - u64 guest_pdptr2; - u64 guest_pdptr3; - u64 host_ia32_pat; - u64 host_ia32_efer; - u64 host_ia32_perf_global_ctrl; - u64 padding64[8]; /* room for future expansion */ - /* - * To allow migration of L1 (complete with its L2 guests) between - * machines of different natural widths (32 or 64 bit), we cannot have - * unsigned long fields with no explict size. We use u64 (aliased - * natural_width) instead. Luckily, x86 is little-endian. - */ - natural_width cr0_guest_host_mask; - natural_width cr4_guest_host_mask; - natural_width cr0_read_shadow; - natural_width cr4_read_shadow; - natural_width cr3_target_value0; - natural_width cr3_target_value1; - natural_width cr3_target_value2; - natural_width cr3_target_value3; - natural_width exit_qualification; - natural_width guest_linear_address; - natural_width guest_cr0; - natural_width guest_cr3; - natural_width guest_cr4; - natural_width guest_es_base; - natural_width guest_cs_base; - natural_width guest_ss_base; - natural_width guest_ds_base; - natural_width guest_fs_base; - natural_width guest_gs_base; - natural_width guest_ldtr_base; - natural_width guest_tr_base; - natural_width guest_gdtr_base; - natural_width guest_idtr_base; - natural_width guest_dr7; - natural_width guest_rsp; - natural_width guest_rip; - natural_width guest_rflags; - natural_width guest_pending_dbg_exceptions; - natural_width guest_sysenter_esp; - natural_width guest_sysenter_eip; - natural_width host_cr0; - natural_width host_cr3; - natural_width host_cr4; - natural_width host_fs_base; - natural_width host_gs_base; - natural_width host_tr_base; - natural_width host_gdtr_base; - natural_width host_idtr_base; - natural_width host_ia32_sysenter_esp; - natural_width host_ia32_sysenter_eip; - natural_width host_rsp; - natural_width host_rip; - natural_width paddingl[8]; /* room for future expansion */ - u32 pin_based_vm_exec_control; - u32 cpu_based_vm_exec_control; - u32 exception_bitmap; - u32 page_fault_error_code_mask; - u32 page_fault_error_code_match; - u32 cr3_target_count; - u32 vm_exit_controls; - u32 vm_exit_msr_store_count; - u32 vm_exit_msr_load_count; - u32 vm_entry_controls; - u32 vm_entry_msr_load_count; - u32 vm_entry_intr_info_field; - u32 vm_entry_exception_error_code; - u32 vm_entry_instruction_len; - u32 tpr_threshold; - u32 secondary_vm_exec_control; - u32 vm_instruction_error; - u32 vm_exit_reason; - u32 vm_exit_intr_info; - u32 vm_exit_intr_error_code; - u32 idt_vectoring_info_field; - u32 idt_vectoring_error_code; - u32 vm_exit_instruction_len; - u32 vmx_instruction_info; - u32 guest_es_limit; - u32 guest_cs_limit; - u32 guest_ss_limit; - u32 guest_ds_limit; - u32 guest_fs_limit; - u32 guest_gs_limit; - u32 guest_ldtr_limit; - u32 guest_tr_limit; - u32 guest_gdtr_limit; - u32 guest_idtr_limit; - u32 guest_es_ar_bytes; - u32 guest_cs_ar_bytes; - u32 guest_ss_ar_bytes; - u32 guest_ds_ar_bytes; - u32 guest_fs_ar_bytes; - u32 guest_gs_ar_bytes; - u32 guest_ldtr_ar_bytes; - u32 guest_tr_ar_bytes; - u32 guest_interruptibility_info; - u32 guest_activity_state; - u32 guest_sysenter_cs; - u32 host_ia32_sysenter_cs; - u32 padding32[8]; /* room for future expansion */ - u16 virtual_processor_id; - u16 guest_es_selector; - u16 guest_cs_selector; - u16 guest_ss_selector; - u16 guest_ds_selector; - u16 guest_fs_selector; - u16 guest_gs_selector; - u16 guest_ldtr_selector; - u16 guest_tr_selector; - u16 host_es_selector; - u16 host_cs_selector; - u16 host_ss_selector; - u16 host_ds_selector; - u16 host_fs_selector; - u16 host_gs_selector; - u16 host_tr_selector; -}; - -/* - * VMCS12_REVISION is an arbitrary id that should be changed if the content or - * layout of struct vmcs12 is changed. MSR_IA32_VMX_BASIC returns this id, and - * VMPTRLD verifies that the VMCS region that L1 is loading contains this id. - */ -#define VMCS12_REVISION 0x11e57ed0 - -/* - * VMCS12_SIZE is the number of bytes L1 should allocate for the VMXON region - * and any VMCS region. Although only sizeof(struct vmcs12) are used by the - * current implementation, 4K are reserved to avoid future complications. - */ -#define VMCS12_SIZE 0x1000 - -/* Used to remember the last vmcs02 used for some recently used vmcs12s */ -struct vmcs02_list { - struct list_head list; - gpa_t vmptr; - struct loaded_vmcs vmcs02; -}; - -/* - * The nested_vmx structure is part of vcpu_vmx, and holds information we need - * for correct emulation of VMX (i.e., nested VMX) on this vcpu. - */ -struct nested_vmx { - /* Has the level1 guest done vmxon? */ - bool vmxon; - - /* The guest-physical address of the current VMCS L1 keeps for L2 */ - gpa_t current_vmptr; - /* The host-usable pointer to the above */ - struct page *current_vmcs12_page; - struct vmcs12 *current_vmcs12; - - /* vmcs02_list cache of VMCSs recently used to run L2 guests */ - struct list_head vmcs02_pool; - int vmcs02_num; - u64 vmcs01_tsc_offset; - /* L2 must run next, and mustn't decide to exit to L1. */ - bool nested_run_pending; - /* - * Guest pages referred to in vmcs02 with host-physical pointers, so - * we must keep them pinned while L2 runs. - */ - struct page *apic_access_page; -}; - struct vcpu_vmx { struct kvm_vcpu vcpu; + struct list_head local_vcpus_link; unsigned long host_rsp; + int launched; u8 fail; u8 cpl; bool nmi_known_unmasked; @@ -368,14 +140,7 @@ struct vcpu_vmx { u64 msr_host_kernel_gs_base; u64 msr_guest_kernel_gs_base; #endif - /* - * loaded_vmcs points to the VMCS currently used in this vcpu. For a - * non-nested (L1) guest, it always points to vmcs01. For a nested - * guest (L2), it points to a different VMCS. - */ - struct loaded_vmcs vmcs01; - struct loaded_vmcs *loaded_vmcs; - bool __launched; /* temporary, used in vmx_vcpu_run */ + struct vmcs *vmcs; struct msr_autoload { unsigned nr; struct vmx_msr_entry guest[NR_AUTOLOAD_MSRS]; @@ -411,9 +176,6 @@ struct vcpu_vmx { u32 exit_reason; bool rdtscp_enabled; - - /* Support for a guest hypervisor (nested VMX) */ - struct nested_vmx nested; }; enum segment_cache_field { @@ -430,174 +192,6 @@ static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu) return container_of(vcpu, struct vcpu_vmx, vcpu); } -#define VMCS12_OFFSET(x) offsetof(struct vmcs12, x) -#define FIELD(number, name) [number] = VMCS12_OFFSET(name) -#define FIELD64(number, name) [number] = VMCS12_OFFSET(name), \ - [number##_HIGH] = VMCS12_OFFSET(name)+4 - -static unsigned short vmcs_field_to_offset_table[] = { - FIELD(VIRTUAL_PROCESSOR_ID, virtual_processor_id), - FIELD(GUEST_ES_SELECTOR, guest_es_selector), - FIELD(GUEST_CS_SELECTOR, guest_cs_selector), - FIELD(GUEST_SS_SELECTOR, guest_ss_selector), - FIELD(GUEST_DS_SELECTOR, guest_ds_selector), - FIELD(GUEST_FS_SELECTOR, guest_fs_selector), - FIELD(GUEST_GS_SELECTOR, guest_gs_selector), - FIELD(GUEST_LDTR_SELECTOR, guest_ldtr_selector), - FIELD(GUEST_TR_SELECTOR, guest_tr_selector), - FIELD(HOST_ES_SELECTOR, host_es_selector), - FIELD(HOST_CS_SELECTOR, host_cs_selector), - FIELD(HOST_SS_SELECTOR, host_ss_selector), - FIELD(HOST_DS_SELECTOR, host_ds_selector), - FIELD(HOST_FS_SELECTOR, host_fs_selector), - FIELD(HOST_GS_SELECTOR, host_gs_selector), - FIELD(HOST_TR_SELECTOR, host_tr_selector), - FIELD64(IO_BITMAP_A, io_bitmap_a), - FIELD64(IO_BITMAP_B, io_bitmap_b), - FIELD64(MSR_BITMAP, msr_bitmap), - FIELD64(VM_EXIT_MSR_STORE_ADDR, vm_exit_msr_store_addr), - FIELD64(VM_EXIT_MSR_LOAD_ADDR, vm_exit_msr_load_addr), - FIELD64(VM_ENTRY_MSR_LOAD_ADDR, vm_entry_msr_load_addr), - FIELD64(TSC_OFFSET, tsc_offset), - FIELD64(VIRTUAL_APIC_PAGE_ADDR, virtual_apic_page_addr), - FIELD64(APIC_ACCESS_ADDR, apic_access_addr), - FIELD64(EPT_POINTER, ept_pointer), - FIELD64(GUEST_PHYSICAL_ADDRESS, guest_physical_address), - FIELD64(VMCS_LINK_POINTER, vmcs_link_pointer), - FIELD64(GUEST_IA32_DEBUGCTL, guest_ia32_debugctl), - FIELD64(GUEST_IA32_PAT, guest_ia32_pat), - FIELD64(GUEST_IA32_EFER, guest_ia32_efer), - FIELD64(GUEST_IA32_PERF_GLOBAL_CTRL, guest_ia32_perf_global_ctrl), - FIELD64(GUEST_PDPTR0, guest_pdptr0), - FIELD64(GUEST_PDPTR1, guest_pdptr1), - FIELD64(GUEST_PDPTR2, guest_pdptr2), - FIELD64(GUEST_PDPTR3, guest_pdptr3), - FIELD64(HOST_IA32_PAT, host_ia32_pat), - FIELD64(HOST_IA32_EFER, host_ia32_efer), - FIELD64(HOST_IA32_PERF_GLOBAL_CTRL, host_ia32_perf_global_ctrl), - FIELD(PIN_BASED_VM_EXEC_CONTROL, pin_based_vm_exec_control), - FIELD(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control), - FIELD(EXCEPTION_BITMAP, exception_bitmap), - FIELD(PAGE_FAULT_ERROR_CODE_MASK, page_fault_error_code_mask), - FIELD(PAGE_FAULT_ERROR_CODE_MATCH, page_fault_error_code_match), - FIELD(CR3_TARGET_COUNT, cr3_target_count), - FIELD(VM_EXIT_CONTROLS, vm_exit_controls), - FIELD(VM_EXIT_MSR_STORE_COUNT, vm_exit_msr_store_count), - FIELD(VM_EXIT_MSR_LOAD_COUNT, vm_exit_msr_load_count), - FIELD(VM_ENTRY_CONTROLS, vm_entry_controls), - FIELD(VM_ENTRY_MSR_LOAD_COUNT, vm_entry_msr_load_count), - FIELD(VM_ENTRY_INTR_INFO_FIELD, vm_entry_intr_info_field), - FIELD(VM_ENTRY_EXCEPTION_ERROR_CODE, vm_entry_exception_error_code), - FIELD(VM_ENTRY_INSTRUCTION_LEN, vm_entry_instruction_len), - FIELD(TPR_THRESHOLD, tpr_threshold), - FIELD(SECONDARY_VM_EXEC_CONTROL, secondary_vm_exec_control), - FIELD(VM_INSTRUCTION_ERROR, vm_instruction_error), - FIELD(VM_EXIT_REASON, vm_exit_reason), - FIELD(VM_EXIT_INTR_INFO, vm_exit_intr_info), - FIELD(VM_EXIT_INTR_ERROR_CODE, vm_exit_intr_error_code), - FIELD(IDT_VECTORING_INFO_FIELD, idt_vectoring_info_field), - FIELD(IDT_VECTORING_ERROR_CODE, idt_vectoring_error_code), - FIELD(VM_EXIT_INSTRUCTION_LEN, vm_exit_instruction_len), - FIELD(VMX_INSTRUCTION_INFO, vmx_instruction_info), - FIELD(GUEST_ES_LIMIT, guest_es_limit), - FIELD(GUEST_CS_LIMIT, guest_cs_limit), - FIELD(GUEST_SS_LIMIT, guest_ss_limit), - FIELD(GUEST_DS_LIMIT, guest_ds_limit), - FIELD(GUEST_FS_LIMIT, guest_fs_limit), - FIELD(GUEST_GS_LIMIT, guest_gs_limit), - FIELD(GUEST_LDTR_LIMIT, guest_ldtr_limit), - FIELD(GUEST_TR_LIMIT, guest_tr_limit), - FIELD(GUEST_GDTR_LIMIT, guest_gdtr_limit), - FIELD(GUEST_IDTR_LIMIT, guest_idtr_limit), - FIELD(GUEST_ES_AR_BYTES, guest_es_ar_bytes), - FIELD(GUEST_CS_AR_BYTES, guest_cs_ar_bytes), - FIELD(GUEST_SS_AR_BYTES, guest_ss_ar_bytes), - FIELD(GUEST_DS_AR_BYTES, guest_ds_ar_bytes), - FIELD(GUEST_FS_AR_BYTES, guest_fs_ar_bytes), - FIELD(GUEST_GS_AR_BYTES, guest_gs_ar_bytes), - FIELD(GUEST_LDTR_AR_BYTES, guest_ldtr_ar_bytes), - FIELD(GUEST_TR_AR_BYTES, guest_tr_ar_bytes), - FIELD(GUEST_INTERRUPTIBILITY_INFO, guest_interruptibility_info), - FIELD(GUEST_ACTIVITY_STATE, guest_activity_state), - FIELD(GUEST_SYSENTER_CS, guest_sysenter_cs), - FIELD(HOST_IA32_SYSENTER_CS, host_ia32_sysenter_cs), - FIELD(CR0_GUEST_HOST_MASK, cr0_guest_host_mask), - FIELD(CR4_GUEST_HOST_MASK, cr4_guest_host_mask), - FIELD(CR0_READ_SHADOW, cr0_read_shadow), - FIELD(CR4_READ_SHADOW, cr4_read_shadow), - FIELD(CR3_TARGET_VALUE0, cr3_target_value0), - FIELD(CR3_TARGET_VALUE1, cr3_target_value1), - FIELD(CR3_TARGET_VALUE2, cr3_target_value2), - FIELD(CR3_TARGET_VALUE3, cr3_target_value3), - FIELD(EXIT_QUALIFICATION, exit_qualification), - FIELD(GUEST_LINEAR_ADDRESS, guest_linear_address), - FIELD(GUEST_CR0, guest_cr0), - FIELD(GUEST_CR3, guest_cr3), - FIELD(GUEST_CR4, guest_cr4), - FIELD(GUEST_ES_BASE, guest_es_base), - FIELD(GUEST_CS_BASE, guest_cs_base), - FIELD(GUEST_SS_BASE, guest_ss_base), - FIELD(GUEST_DS_BASE, guest_ds_base), - FIELD(GUEST_FS_BASE, guest_fs_base), - FIELD(GUEST_GS_BASE, guest_gs_base), - FIELD(GUEST_LDTR_BASE, guest_ldtr_base), - FIELD(GUEST_TR_BASE, guest_tr_base), - FIELD(GUEST_GDTR_BASE, guest_gdtr_base), - FIELD(GUEST_IDTR_BASE, guest_idtr_base), - FIELD(GUEST_DR7, guest_dr7), - FIELD(GUEST_RSP, guest_rsp), - FIELD(GUEST_RIP, guest_rip), - FIELD(GUEST_RFLAGS, guest_rflags), - FIELD(GUEST_PENDING_DBG_EXCEPTIONS, guest_pending_dbg_exceptions), - FIELD(GUEST_SYSENTER_ESP, guest_sysenter_esp), - FIELD(GUEST_SYSENTER_EIP, guest_sysenter_eip), - FIELD(HOST_CR0, host_cr0), - FIELD(HOST_CR3, host_cr3), - FIELD(HOST_CR4, host_cr4), - FIELD(HOST_FS_BASE, host_fs_base), - FIELD(HOST_GS_BASE, host_gs_base), - FIELD(HOST_TR_BASE, host_tr_base), - FIELD(HOST_GDTR_BASE, host_gdtr_base), - FIELD(HOST_IDTR_BASE, host_idtr_base), - FIELD(HOST_IA32_SYSENTER_ESP, host_ia32_sysenter_esp), - FIELD(HOST_IA32_SYSENTER_EIP, host_ia32_sysenter_eip), - FIELD(HOST_RSP, host_rsp), - FIELD(HOST_RIP, host_rip), -}; -static const int max_vmcs_field = ARRAY_SIZE(vmcs_field_to_offset_table); - -static inline short vmcs_field_to_offset(unsigned long field) -{ - if (field >= max_vmcs_field || vmcs_field_to_offset_table[field] == 0) - return -1; - return vmcs_field_to_offset_table[field]; -} - -static inline struct vmcs12 *get_vmcs12(struct kvm_vcpu *vcpu) -{ - return to_vmx(vcpu)->nested.current_vmcs12; -} - -static struct page *nested_get_page(struct kvm_vcpu *vcpu, gpa_t addr) -{ - struct page *page = gfn_to_page(vcpu->kvm, addr >> PAGE_SHIFT); - if (is_error_page(page)) { - kvm_release_page_clean(page); - return NULL; - } - return page; -} - -static void nested_release_page(struct page *page) -{ - kvm_release_page_dirty(page); -} - -static void nested_release_page_clean(struct page *page) -{ - kvm_release_page_clean(page); -} - static u64 construct_eptp(unsigned long root_hpa); static void kvm_cpu_vmxon(u64 addr); static void kvm_cpu_vmxoff(void); @@ -606,11 +200,7 @@ static int vmx_set_tss_addr(struct kvm *kvm, unsigned int addr); static DEFINE_PER_CPU(struct vmcs *, vmxarea); static DEFINE_PER_CPU(struct vmcs *, current_vmcs); -/* - * We maintain a per-CPU linked-list of VMCS loaded on that CPU. This is needed - * when a CPU is brought down, and we need to VMCLEAR all VMCSs loaded on it. - */ -static DEFINE_PER_CPU(struct list_head, loaded_vmcss_on_cpu); +static DEFINE_PER_CPU(struct list_head, vcpus_on_cpu); static DEFINE_PER_CPU(struct desc_ptr, host_gdt); static unsigned long *vmx_io_bitmap_a; @@ -852,35 +442,6 @@ static inline bool report_flexpriority(void) return flexpriority_enabled; } -static inline bool nested_cpu_has(struct vmcs12 *vmcs12, u32 bit) -{ - return vmcs12->cpu_based_vm_exec_control & bit; -} - -static inline bool nested_cpu_has2(struct vmcs12 *vmcs12, u32 bit) -{ - return (vmcs12->cpu_based_vm_exec_control & - CPU_BASED_ACTIVATE_SECONDARY_CONTROLS) && - (vmcs12->secondary_vm_exec_control & bit); -} - -static inline bool nested_cpu_has_virtual_nmis(struct vmcs12 *vmcs12, - struct kvm_vcpu *vcpu) -{ - return vmcs12->pin_based_vm_exec_control & PIN_BASED_VIRTUAL_NMIS; -} - -static inline bool is_exception(u32 intr_info) -{ - return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VALID_MASK)) - == (INTR_TYPE_HARD_EXCEPTION | INTR_INFO_VALID_MASK); -} - -static void nested_vmx_vmexit(struct kvm_vcpu *vcpu); -static void nested_vmx_entry_failure(struct kvm_vcpu *vcpu, - struct vmcs12 *vmcs12, - u32 reason, unsigned long qualification); - static int __find_msr_index(struct vcpu_vmx *vmx, u32 msr) { int i; @@ -940,13 +501,6 @@ static void vmcs_clear(struct vmcs *vmcs) vmcs, phys_addr); } -static inline void loaded_vmcs_init(struct loaded_vmcs *loaded_vmcs) -{ - vmcs_clear(loaded_vmcs->vmcs); - loaded_vmcs->cpu = -1; - loaded_vmcs->launched = 0; -} - static void vmcs_load(struct vmcs *vmcs) { u64 phys_addr = __pa(vmcs); @@ -956,28 +510,29 @@ static void vmcs_load(struct vmcs *vmcs) : "=qm"(error) : "a"(&phys_addr), "m"(phys_addr) : "cc", "memory"); if (error) - printk(KERN_ERR "kvm: vmptrld %p/%llx failed\n", + printk(KERN_ERR "kvm: vmptrld %p/%llx fail\n", vmcs, phys_addr); } -static void __loaded_vmcs_clear(void *arg) +static void __vcpu_clear(void *arg) { - struct loaded_vmcs *loaded_vmcs = arg; + struct vcpu_vmx *vmx = arg; int cpu = raw_smp_processor_id(); - if (loaded_vmcs->cpu != cpu) - return; /* vcpu migration can race with cpu offline */ - if (per_cpu(current_vmcs, cpu) == loaded_vmcs->vmcs) + if (vmx->vcpu.cpu == cpu) + vmcs_clear(vmx->vmcs); + if (per_cpu(current_vmcs, cpu) == vmx->vmcs) per_cpu(current_vmcs, cpu) = NULL; - list_del(&loaded_vmcs->loaded_vmcss_on_cpu_link); - loaded_vmcs_init(loaded_vmcs); + list_del(&vmx->local_vcpus_link); + vmx->vcpu.cpu = -1; + vmx->launched = 0; } -static void loaded_vmcs_clear(struct loaded_vmcs *loaded_vmcs) +static void vcpu_clear(struct vcpu_vmx *vmx) { - if (loaded_vmcs->cpu != -1) - smp_call_function_single( - loaded_vmcs->cpu, __loaded_vmcs_clear, loaded_vmcs, 1); + if (vmx->vcpu.cpu == -1) + return; + smp_call_function_single(vmx->vcpu.cpu, __vcpu_clear, vmx, 1); } static inline void vpid_sync_vcpu_single(struct vcpu_vmx *vmx) @@ -1030,26 +585,26 @@ static inline void ept_sync_individual_addr(u64 eptp, gpa_t gpa) } } -static __always_inline unsigned long vmcs_readl(unsigned long field) +static unsigned long vmcs_readl(unsigned long field) { - unsigned long value; + unsigned long value = 0; - asm volatile (__ex_clear(ASM_VMX_VMREAD_RDX_RAX, "%0") - : "=a"(value) : "d"(field) : "cc"); + asm volatile (__ex(ASM_VMX_VMREAD_RDX_RAX) + : "+a"(value) : "d"(field) : "cc"); return value; } -static __always_inline u16 vmcs_read16(unsigned long field) +static u16 vmcs_read16(unsigned long field) { return vmcs_readl(field); } -static __always_inline u32 vmcs_read32(unsigned long field) +static u32 vmcs_read32(unsigned long field) { return vmcs_readl(field); } -static __always_inline u64 vmcs_read64(unsigned long field) +static u64 vmcs_read64(unsigned long field) { #ifdef CONFIG_X86_64 return vmcs_readl(field); @@ -1176,15 +731,6 @@ static void update_exception_bitmap(struct kvm_vcpu *vcpu) eb &= ~(1u << PF_VECTOR); /* bypass_guest_pf = 0 */ if (vcpu->fpu_active) eb &= ~(1u << NM_VECTOR); - - /* When we are running a nested L2 guest and L1 specified for it a - * certain exception bitmap, we must trap the same exceptions and pass - * them to L1. When running L2, we will only handle the exceptions - * specified above if L1 did not want them. - */ - if (is_guest_mode(vcpu)) - eb |= get_vmcs12(vcpu)->exception_bitmap; - vmcs_write32(EXCEPTION_BITMAP, eb); } @@ -1425,22 +971,22 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu) if (!vmm_exclusive) kvm_cpu_vmxon(phys_addr); - else if (vmx->loaded_vmcs->cpu != cpu) - loaded_vmcs_clear(vmx->loaded_vmcs); + else if (vcpu->cpu != cpu) + vcpu_clear(vmx); - if (per_cpu(current_vmcs, cpu) != vmx->loaded_vmcs->vmcs) { - per_cpu(current_vmcs, cpu) = vmx->loaded_vmcs->vmcs; - vmcs_load(vmx->loaded_vmcs->vmcs); + if (per_cpu(current_vmcs, cpu) != vmx->vmcs) { + per_cpu(current_vmcs, cpu) = vmx->vmcs; + vmcs_load(vmx->vmcs); } - if (vmx->loaded_vmcs->cpu != cpu) { + if (vcpu->cpu != cpu) { struct desc_ptr *gdt = &__get_cpu_var(host_gdt); unsigned long sysenter_esp; kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu); local_irq_disable(); - list_add(&vmx->loaded_vmcs->loaded_vmcss_on_cpu_link, - &per_cpu(loaded_vmcss_on_cpu, cpu)); + list_add(&vmx->local_vcpus_link, + &per_cpu(vcpus_on_cpu, cpu)); local_irq_enable(); /* @@ -1452,7 +998,6 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu) rdmsrl(MSR_IA32_SYSENTER_ESP, sysenter_esp); vmcs_writel(HOST_IA32_SYSENTER_ESP, sysenter_esp); /* 22.2.3 */ - vmx->loaded_vmcs->cpu = cpu; } } @@ -1460,8 +1005,7 @@ static void vmx_vcpu_put(struct kvm_vcpu *vcpu) { __vmx_load_host_state(to_vmx(vcpu)); if (!vmm_exclusive) { - __loaded_vmcs_clear(to_vmx(vcpu)->loaded_vmcs); - vcpu->cpu = -1; + __vcpu_clear(to_vmx(vcpu)); kvm_cpu_vmxoff(); } } @@ -1479,55 +1023,19 @@ static void vmx_fpu_activate(struct kvm_vcpu *vcpu) vmcs_writel(GUEST_CR0, cr0); update_exception_bitmap(vcpu); vcpu->arch.cr0_guest_owned_bits = X86_CR0_TS; - if (is_guest_mode(vcpu)) - vcpu->arch.cr0_guest_owned_bits &= - ~get_vmcs12(vcpu)->cr0_guest_host_mask; vmcs_writel(CR0_GUEST_HOST_MASK, ~vcpu->arch.cr0_guest_owned_bits); } static void vmx_decache_cr0_guest_bits(struct kvm_vcpu *vcpu); -/* - * Return the cr0 value that a nested guest would read. This is a combination - * of the real cr0 used to run the guest (guest_cr0), and the bits shadowed by - * its hypervisor (cr0_read_shadow). - */ -static inline unsigned long nested_read_cr0(struct vmcs12 *fields) -{ - return (fields->guest_cr0 & ~fields->cr0_guest_host_mask) | - (fields->cr0_read_shadow & fields->cr0_guest_host_mask); -} -static inline unsigned long nested_read_cr4(struct vmcs12 *fields) -{ - return (fields->guest_cr4 & ~fields->cr4_guest_host_mask) | - (fields->cr4_read_shadow & fields->cr4_guest_host_mask); -} - static void vmx_fpu_deactivate(struct kvm_vcpu *vcpu) { - /* Note that there is no vcpu->fpu_active = 0 here. The caller must - * set this *before* calling this function. - */ vmx_decache_cr0_guest_bits(vcpu); vmcs_set_bits(GUEST_CR0, X86_CR0_TS | X86_CR0_MP); update_exception_bitmap(vcpu); vcpu->arch.cr0_guest_owned_bits = 0; vmcs_writel(CR0_GUEST_HOST_MASK, ~vcpu->arch.cr0_guest_owned_bits); - if (is_guest_mode(vcpu)) { - /* - * L1's specified read shadow might not contain the TS bit, - * so now that we turned on shadowing of this bit, we need to - * set this bit of the shadow. Like in nested_vmx_run we need - * nested_read_cr0(vmcs12), but vmcs12->guest_cr0 is not yet - * up-to-date here because we just decached cr0.TS (and we'll - * only update vmcs12->guest_cr0 on nested exit). - */ - struct vmcs12 *vmcs12 = get_vmcs12(vcpu); - vmcs12->guest_cr0 = (vmcs12->guest_cr0 & ~X86_CR0_TS) | - (vcpu->arch.cr0 & X86_CR0_TS); - vmcs_writel(CR0_READ_SHADOW, nested_read_cr0(vmcs12)); - } else - vmcs_writel(CR0_READ_SHADOW, vcpu->arch.cr0); + vmcs_writel(CR0_READ_SHADOW, vcpu->arch.cr0); } static unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu) @@ -1611,25 +1119,6 @@ static void vmx_clear_hlt(struct kvm_vcpu *vcpu) vmcs_write32(GUEST_ACTIVITY_STATE, GUEST_ACTIVITY_ACTIVE); } -/* - * KVM wants to inject page-faults which it got to the guest. This function - * checks whether in a nested guest, we need to inject them to L1 or L2. - * This function assumes it is called with the exit reason in vmcs02 being - * a #PF exception (this is the only case in which KVM injects a #PF when L2 - * is running). - */ -static int nested_pf_handled(struct kvm_vcpu *vcpu) -{ - struct vmcs12 *vmcs12 = get_vmcs12(vcpu); - - /* TODO: also check PFEC_MATCH/MASK, not just EB.PF. */ - if (!(vmcs12->exception_bitmap & PF_VECTOR)) - return 0; - - nested_vmx_vmexit(vcpu); - return 1; -} - static void vmx_queue_exception(struct kvm_vcpu *vcpu, unsigned nr, bool has_error_code, u32 error_code, bool reinject) @@ -1637,10 +1126,6 @@ static void vmx_queue_exception(struct kvm_vcpu *vcpu, unsigned nr, struct vcpu_vmx *vmx = to_vmx(vcpu); u32 intr_info = nr | INTR_INFO_VALID_MASK; - if (nr == PF_VECTOR && is_guest_mode(vcpu) && - nested_pf_handled(vcpu)) - return; - if (has_error_code) { vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, error_code); intr_info |= INTR_INFO_DELIVER_CODE_MASK; @@ -1763,24 +1248,12 @@ static void vmx_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz) static void vmx_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset) { vmcs_write64(TSC_OFFSET, offset); - if (is_guest_mode(vcpu)) - /* - * We're here if L1 chose not to trap the TSC MSR. Since - * prepare_vmcs12() does not copy tsc_offset, we need to also - * set the vmcs12 field here. - */ - get_vmcs12(vcpu)->tsc_offset = offset - - to_vmx(vcpu)->nested.vmcs01_tsc_offset; } static void vmx_adjust_tsc_offset(struct kvm_vcpu *vcpu, s64 adjustment) { u64 offset = vmcs_read64(TSC_OFFSET); vmcs_write64(TSC_OFFSET, offset + adjustment); - if (is_guest_mode(vcpu)) { - /* Even when running L2, the adjustment needs to apply to L1 */ - to_vmx(vcpu)->nested.vmcs01_tsc_offset += adjustment; - } } static u64 vmx_compute_tsc_offset(struct kvm_vcpu *vcpu, u64 target_tsc) @@ -1788,236 +1261,6 @@ static u64 vmx_compute_tsc_offset(struct kvm_vcpu *vcpu, u64 target_tsc) return target_tsc - native_read_tsc(); } -static bool guest_cpuid_has_vmx(struct kvm_vcpu *vcpu) -{ - struct kvm_cpuid_entry2 *best = kvm_find_cpuid_entry(vcpu, 1, 0); - return best && (best->ecx & (1 << (X86_FEATURE_VMX & 31))); -} - -/* - * nested_vmx_allowed() checks whether a guest should be allowed to use VMX - * instructions and MSRs (i.e., nested VMX). Nested VMX is disabled for - * all guests if the "nested" module option is off, and can also be disabled - * for a single guest by disabling its VMX cpuid bit. - */ -static inline bool nested_vmx_allowed(struct kvm_vcpu *vcpu) -{ - return nested && guest_cpuid_has_vmx(vcpu); -} - -/* - * nested_vmx_setup_ctls_msrs() sets up variables containing the values to be - * returned for the various VMX controls MSRs when nested VMX is enabled. - * The same values should also be used to verify that vmcs12 control fields are - * valid during nested entry from L1 to L2. - * Each of these control msrs has a low and high 32-bit half: A low bit is on - * if the corresponding bit in the (32-bit) control field *must* be on, and a - * bit in the high half is on if the corresponding bit in the control field - * may be on. See also vmx_control_verify(). - * TODO: allow these variables to be modified (downgraded) by module options - * or other means. - */ -static u32 nested_vmx_procbased_ctls_low, nested_vmx_procbased_ctls_high; -static u32 nested_vmx_secondary_ctls_low, nested_vmx_secondary_ctls_high; -static u32 nested_vmx_pinbased_ctls_low, nested_vmx_pinbased_ctls_high; -static u32 nested_vmx_exit_ctls_low, nested_vmx_exit_ctls_high; -static u32 nested_vmx_entry_ctls_low, nested_vmx_entry_ctls_high; -static __init void nested_vmx_setup_ctls_msrs(void) -{ - /* - * Note that as a general rule, the high half of the MSRs (bits in - * the control fields which may be 1) should be initialized by the - * intersection of the underlying hardware's MSR (i.e., features which - * can be supported) and the list of features we want to expose - - * because they are known to be properly supported in our code. - * Also, usually, the low half of the MSRs (bits which must be 1) can - * be set to 0, meaning that L1 may turn off any of these bits. The - * reason is that if one of these bits is necessary, it will appear - * in vmcs01 and prepare_vmcs02, when it bitwise-or's the control - * fields of vmcs01 and vmcs02, will turn these bits off - and - * nested_vmx_exit_handled() will not pass related exits to L1. - * These rules have exceptions below. - */ - - /* pin-based controls */ - /* - * According to the Intel spec, if bit 55 of VMX_BASIC is off (as it is - * in our case), bits 1, 2 and 4 (i.e., 0x16) must be 1 in this MSR. - */ - nested_vmx_pinbased_ctls_low = 0x16 ; - nested_vmx_pinbased_ctls_high = 0x16 | - PIN_BASED_EXT_INTR_MASK | PIN_BASED_NMI_EXITING | - PIN_BASED_VIRTUAL_NMIS; - - /* exit controls */ - nested_vmx_exit_ctls_low = 0; - /* Note that guest use of VM_EXIT_ACK_INTR_ON_EXIT is not supported. */ -#ifdef CONFIG_X86_64 - nested_vmx_exit_ctls_high = VM_EXIT_HOST_ADDR_SPACE_SIZE; -#else - nested_vmx_exit_ctls_high = 0; -#endif - - /* entry controls */ - rdmsr(MSR_IA32_VMX_ENTRY_CTLS, - nested_vmx_entry_ctls_low, nested_vmx_entry_ctls_high); - nested_vmx_entry_ctls_low = 0; - nested_vmx_entry_ctls_high &= - VM_ENTRY_LOAD_IA32_PAT | VM_ENTRY_IA32E_MODE; - - /* cpu-based controls */ - rdmsr(MSR_IA32_VMX_PROCBASED_CTLS, - nested_vmx_procbased_ctls_low, nested_vmx_procbased_ctls_high); - nested_vmx_procbased_ctls_low = 0; - nested_vmx_procbased_ctls_high &= - CPU_BASED_VIRTUAL_INTR_PENDING | CPU_BASED_USE_TSC_OFFSETING | - CPU_BASED_HLT_EXITING | CPU_BASED_INVLPG_EXITING | - CPU_BASED_MWAIT_EXITING | CPU_BASED_CR3_LOAD_EXITING | - CPU_BASED_CR3_STORE_EXITING | -#ifdef CONFIG_X86_64 - CPU_BASED_CR8_LOAD_EXITING | CPU_BASED_CR8_STORE_EXITING | -#endif - CPU_BASED_MOV_DR_EXITING | CPU_BASED_UNCOND_IO_EXITING | - CPU_BASED_USE_IO_BITMAPS | CPU_BASED_MONITOR_EXITING | - CPU_BASED_ACTIVATE_SECONDARY_CONTROLS; - /* - * We can allow some features even when not supported by the - * hardware. For example, L1 can specify an MSR bitmap - and we - * can use it to avoid exits to L1 - even when L0 runs L2 - * without MSR bitmaps. - */ - nested_vmx_procbased_ctls_high |= CPU_BASED_USE_MSR_BITMAPS; - - /* secondary cpu-based controls */ - rdmsr(MSR_IA32_VMX_PROCBASED_CTLS2, - nested_vmx_secondary_ctls_low, nested_vmx_secondary_ctls_high); - nested_vmx_secondary_ctls_low = 0; - nested_vmx_secondary_ctls_high &= - SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES; -} - -static inline bool vmx_control_verify(u32 control, u32 low, u32 high) -{ - /* - * Bits 0 in high must be 0, and bits 1 in low must be 1. - */ - return ((control & high) | low) == control; -} - -static inline u64 vmx_control_msr(u32 low, u32 high) -{ - return low | ((u64)high << 32); -} - -/* - * If we allow our guest to use VMX instructions (i.e., nested VMX), we should - * also let it use VMX-specific MSRs. - * vmx_get_vmx_msr() and vmx_set_vmx_msr() return 1 when we handled a - * VMX-specific MSR, or 0 when we haven't (and the caller should handle it - * like all other MSRs). - */ -static int vmx_get_vmx_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata) -{ - if (!nested_vmx_allowed(vcpu) && msr_index >= MSR_IA32_VMX_BASIC && - msr_index <= MSR_IA32_VMX_TRUE_ENTRY_CTLS) { - /* - * According to the spec, processors which do not support VMX - * should throw a #GP(0) when VMX capability MSRs are read. - */ - kvm_queue_exception_e(vcpu, GP_VECTOR, 0); - return 1; - } - - switch (msr_index) { - case MSR_IA32_FEATURE_CONTROL: - *pdata = 0; - break; - case MSR_IA32_VMX_BASIC: - /* - * This MSR reports some information about VMX support. We - * should return information about the VMX we emulate for the - * guest, and the VMCS structure we give it - not about the - * VMX support of the underlying hardware. - */ - *pdata = VMCS12_REVISION | - ((u64)VMCS12_SIZE << VMX_BASIC_VMCS_SIZE_SHIFT) | - (VMX_BASIC_MEM_TYPE_WB << VMX_BASIC_MEM_TYPE_SHIFT); - break; - case MSR_IA32_VMX_TRUE_PINBASED_CTLS: - case MSR_IA32_VMX_PINBASED_CTLS: - *pdata = vmx_control_msr(nested_vmx_pinbased_ctls_low, - nested_vmx_pinbased_ctls_high); - break; - case MSR_IA32_VMX_TRUE_PROCBASED_CTLS: - case MSR_IA32_VMX_PROCBASED_CTLS: - *pdata = vmx_control_msr(nested_vmx_procbased_ctls_low, - nested_vmx_procbased_ctls_high); - break; - case MSR_IA32_VMX_TRUE_EXIT_CTLS: - case MSR_IA32_VMX_EXIT_CTLS: - *pdata = vmx_control_msr(nested_vmx_exit_ctls_low, - nested_vmx_exit_ctls_high); - break; - case MSR_IA32_VMX_TRUE_ENTRY_CTLS: - case MSR_IA32_VMX_ENTRY_CTLS: - *pdata = vmx_control_msr(nested_vmx_entry_ctls_low, - nested_vmx_entry_ctls_high); - break; - case MSR_IA32_VMX_MISC: - *pdata = 0; - break; - /* - * These MSRs specify bits which the guest must keep fixed (on or off) - * while L1 is in VMXON mode (in L1's root mode, or running an L2). - * We picked the standard core2 setting. - */ -#define VMXON_CR0_ALWAYSON (X86_CR0_PE | X86_CR0_PG | X86_CR0_NE) -#define VMXON_CR4_ALWAYSON X86_CR4_VMXE - case MSR_IA32_VMX_CR0_FIXED0: - *pdata = VMXON_CR0_ALWAYSON; - break; - case MSR_IA32_VMX_CR0_FIXED1: - *pdata = -1ULL; - break; - case MSR_IA32_VMX_CR4_FIXED0: - *pdata = VMXON_CR4_ALWAYSON; - break; - case MSR_IA32_VMX_CR4_FIXED1: - *pdata = -1ULL; - break; - case MSR_IA32_VMX_VMCS_ENUM: - *pdata = 0x1f; - break; - case MSR_IA32_VMX_PROCBASED_CTLS2: - *pdata = vmx_control_msr(nested_vmx_secondary_ctls_low, - nested_vmx_secondary_ctls_high); - break; - case MSR_IA32_VMX_EPT_VPID_CAP: - /* Currently, no nested ept or nested vpid */ - *pdata = 0; - break; - default: - return 0; - } - - return 1; -} - -static int vmx_set_vmx_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data) -{ - if (!nested_vmx_allowed(vcpu)) - return 0; - - if (msr_index == MSR_IA32_FEATURE_CONTROL) - /* TODO: the right thing. */ - return 1; - /* - * No need to treat VMX capability MSRs specially: If we don't handle - * them, handle_wrmsr will #GP(0), which is correct (they are readonly) - */ - return 0; -} - /* * Reads an msr value (of 'msr_index') into 'pdata'. * Returns 0 on success, non-0 otherwise. @@ -2066,8 +1309,6 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata) /* Otherwise falls through */ default: vmx_load_host_state(to_vmx(vcpu)); - if (vmx_get_vmx_msr(vcpu, msr_index, pdata)) - return 0; msr = find_msr_entry(to_vmx(vcpu), msr_index); if (msr) { vmx_load_host_state(to_vmx(vcpu)); @@ -2139,8 +1380,6 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data) return 1; /* Otherwise falls through */ default: - if (vmx_set_vmx_msr(vcpu, msr_index, data)) - break; msr = find_msr_entry(vmx, msr_index); if (msr) { vmx_load_host_state(vmx); @@ -2230,7 +1469,7 @@ static int hardware_enable(void *garbage) if (read_cr4() & X86_CR4_VMXE) return -EBUSY; - INIT_LIST_HEAD(&per_cpu(loaded_vmcss_on_cpu, cpu)); + INIT_LIST_HEAD(&per_cpu(vcpus_on_cpu, cpu)); rdmsrl(MSR_IA32_FEATURE_CONTROL, old); test_bits = FEATURE_CONTROL_LOCKED; @@ -2254,14 +1493,14 @@ static int hardware_enable(void *garbage) return 0; } -static void vmclear_local_loaded_vmcss(void) +static void vmclear_local_vcpus(void) { int cpu = raw_smp_processor_id(); - struct loaded_vmcs *v, *n; + struct vcpu_vmx *vmx, *n; - list_for_each_entry_safe(v, n, &per_cpu(loaded_vmcss_on_cpu, cpu), - loaded_vmcss_on_cpu_link) - __loaded_vmcs_clear(v); + list_for_each_entry_safe(vmx, n, &per_cpu(vcpus_on_cpu, cpu), + local_vcpus_link) + __vcpu_clear(vmx); } @@ -2276,7 +1515,7 @@ static void kvm_cpu_vmxoff(void) static void hardware_disable(void *garbage) { if (vmm_exclusive) { - vmclear_local_loaded_vmcss(); + vmclear_local_vcpus(); kvm_cpu_vmxoff(); } write_cr4(read_cr4() & ~X86_CR4_VMXE); @@ -2457,18 +1696,6 @@ static void free_vmcs(struct vmcs *vmcs) free_pages((unsigned long)vmcs, vmcs_config.order); } -/* - * Free a VMCS, but before that VMCLEAR it on the CPU where it was last loaded - */ -static void free_loaded_vmcs(struct loaded_vmcs *loaded_vmcs) -{ - if (!loaded_vmcs->vmcs) - return; - loaded_vmcs_clear(loaded_vmcs); - free_vmcs(loaded_vmcs->vmcs); - loaded_vmcs->vmcs = NULL; -} - static void free_kvm_area(void) { int cpu; @@ -2529,9 +1756,6 @@ static __init int hardware_setup(void) if (!cpu_has_vmx_ple()) ple_gap = 0; - if (nested) - nested_vmx_setup_ctls_msrs(); - return alloc_kvm_area(); } @@ -2817,7 +2041,7 @@ static void ept_save_pdptrs(struct kvm_vcpu *vcpu) (unsigned long *)&vcpu->arch.regs_dirty); } -static int vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4); +static void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4); static void ept_update_paging_mode_cr0(unsigned long *hw_cr0, unsigned long cr0, @@ -2915,23 +2139,11 @@ static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) vmcs_writel(GUEST_CR3, guest_cr3); } -static int vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) +static void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) { unsigned long hw_cr4 = cr4 | (to_vmx(vcpu)->rmode.vm86_active ? KVM_RMODE_VM_CR4_ALWAYS_ON : KVM_PMODE_VM_CR4_ALWAYS_ON); - if (cr4 & X86_CR4_VMXE) { - /* - * To use VMXON (and later other VMX instructions), a guest - * must first be able to turn on cr4.VMXE (see handle_vmon()). - * So basically the check on whether to allow nested VMX - * is here. - */ - if (!nested_vmx_allowed(vcpu)) - return 1; - } else if (to_vmx(vcpu)->nested.vmxon) - return 1; - vcpu->arch.cr4 = cr4; if (enable_ept) { if (!is_paging(vcpu)) { @@ -2944,7 +2156,6 @@ static int vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) vmcs_writel(CR4_READ_SHADOW, cr4); vmcs_writel(GUEST_CR4, hw_cr4); - return 0; } static void vmx_get_segment(struct kvm_vcpu *vcpu, @@ -3510,58 +2721,33 @@ static void vmx_disable_intercept_for_msr(u32 msr, bool longmode_only) } /* - * Set up the vmcs's constant host-state fields, i.e., host-state fields that - * will not change in the lifetime of the guest. - * Note that host-state that does change is set elsewhere. E.g., host-state - * that is set differently for each CPU is set in vmx_vcpu_load(), not here. + * Sets up the vmcs for emulated real mode. */ -static void vmx_set_constant_host_state(void) +static int vmx_vcpu_setup(struct vcpu_vmx *vmx) { - u32 low32, high32; - unsigned long tmpl; + u32 host_sysenter_cs, msr_low, msr_high; + u32 junk; + u64 host_pat; + unsigned long a; struct desc_ptr dt; + int i; + unsigned long kvm_vmx_return; + u32 exec_control; - vmcs_writel(HOST_CR0, read_cr0() | X86_CR0_TS); /* 22.2.3 */ - vmcs_writel(HOST_CR4, read_cr4()); /* 22.2.3, 22.2.5 */ - vmcs_writel(HOST_CR3, read_cr3()); /* 22.2.3 FIXME: shadow tables */ - - vmcs_write16(HOST_CS_SELECTOR, __KERNEL_CS); /* 22.2.4 */ - vmcs_write16(HOST_DS_SELECTOR, __KERNEL_DS); /* 22.2.4 */ - vmcs_write16(HOST_ES_SELECTOR, __KERNEL_DS); /* 22.2.4 */ - vmcs_write16(HOST_SS_SELECTOR, __KERNEL_DS); /* 22.2.4 */ - vmcs_write16(HOST_TR_SELECTOR, GDT_ENTRY_TSS*8); /* 22.2.4 */ - - native_store_idt(&dt); - vmcs_writel(HOST_IDTR_BASE, dt.address); /* 22.2.4 */ - - asm("mov $.Lkvm_vmx_return, %0" : "=r"(tmpl)); - vmcs_writel(HOST_RIP, tmpl); /* 22.2.5 */ + /* I/O */ + vmcs_write64(IO_BITMAP_A, __pa(vmx_io_bitmap_a)); + vmcs_write64(IO_BITMAP_B, __pa(vmx_io_bitmap_b)); - rdmsr(MSR_IA32_SYSENTER_CS, low32, high32); - vmcs_write32(HOST_IA32_SYSENTER_CS, low32); - rdmsrl(MSR_IA32_SYSENTER_EIP, tmpl); - vmcs_writel(HOST_IA32_SYSENTER_EIP, tmpl); /* 22.2.3 */ + if (cpu_has_vmx_msr_bitmap()) + vmcs_write64(MSR_BITMAP, __pa(vmx_msr_bitmap_legacy)); - if (vmcs_config.vmexit_ctrl & VM_EXIT_LOAD_IA32_PAT) { - rdmsr(MSR_IA32_CR_PAT, low32, high32); - vmcs_write64(HOST_IA32_PAT, low32 | ((u64) high32 << 32)); - } -} + vmcs_write64(VMCS_LINK_POINTER, -1ull); /* 22.3.1.5 */ -static void set_cr4_guest_host_mask(struct vcpu_vmx *vmx) -{ - vmx->vcpu.arch.cr4_guest_owned_bits = KVM_CR4_GUEST_OWNED_BITS; - if (enable_ept) - vmx->vcpu.arch.cr4_guest_owned_bits |= X86_CR4_PGE; - if (is_guest_mode(&vmx->vcpu)) - vmx->vcpu.arch.cr4_guest_owned_bits &= - ~get_vmcs12(&vmx->vcpu)->cr4_guest_host_mask; - vmcs_writel(CR4_GUEST_HOST_MASK, ~vmx->vcpu.arch.cr4_guest_owned_bits); -} + /* Control */ + vmcs_write32(PIN_BASED_VM_EXEC_CONTROL, + vmcs_config.pin_based_exec_ctrl); -static u32 vmx_exec_control(struct vcpu_vmx *vmx) -{ - u32 exec_control = vmcs_config.cpu_based_exec_ctrl; + exec_control = vmcs_config.cpu_based_exec_ctrl; if (!vm_need_tpr_shadow(vmx->vcpu.kvm)) { exec_control &= ~CPU_BASED_TPR_SHADOW; #ifdef CONFIG_X86_64 @@ -3573,80 +2759,45 @@ static u32 vmx_exec_control(struct vcpu_vmx *vmx) exec_control |= CPU_BASED_CR3_STORE_EXITING | CPU_BASED_CR3_LOAD_EXITING | CPU_BASED_INVLPG_EXITING; - return exec_control; -} + vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, exec_control); -static u32 vmx_secondary_exec_control(struct vcpu_vmx *vmx) -{ - u32 exec_control = vmcs_config.cpu_based_2nd_exec_ctrl; - if (!vm_need_virtualize_apic_accesses(vmx->vcpu.kvm)) - exec_control &= ~SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES; - if (vmx->vpid == 0) - exec_control &= ~SECONDARY_EXEC_ENABLE_VPID; - if (!enable_ept) { - exec_control &= ~SECONDARY_EXEC_ENABLE_EPT; - enable_unrestricted_guest = 0; + if (cpu_has_secondary_exec_ctrls()) { + exec_control = vmcs_config.cpu_based_2nd_exec_ctrl; + if (!vm_need_virtualize_apic_accesses(vmx->vcpu.kvm)) + exec_control &= + ~SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES; + if (vmx->vpid == 0) + exec_control &= ~SECONDARY_EXEC_ENABLE_VPID; + if (!enable_ept) { + exec_control &= ~SECONDARY_EXEC_ENABLE_EPT; + enable_unrestricted_guest = 0; + } + if (!enable_unrestricted_guest) + exec_control &= ~SECONDARY_EXEC_UNRESTRICTED_GUEST; + if (!ple_gap) + exec_control &= ~SECONDARY_EXEC_PAUSE_LOOP_EXITING; + vmcs_write32(SECONDARY_VM_EXEC_CONTROL, exec_control); } - if (!enable_unrestricted_guest) - exec_control &= ~SECONDARY_EXEC_UNRESTRICTED_GUEST; - if (!ple_gap) - exec_control &= ~SECONDARY_EXEC_PAUSE_LOOP_EXITING; - return exec_control; -} -static void ept_set_mmio_spte_mask(void) -{ - /* - * EPT Misconfigurations can be generated if the value of bits 2:0 - * of an EPT paging-structure entry is 110b (write/execute). - * Also, magic bits (0xffull << 49) is set to quickly identify mmio - * spte. - */ - kvm_mmu_set_mmio_spte_mask(0xffull << 49 | 0x6ull); -} + if (ple_gap) { + vmcs_write32(PLE_GAP, ple_gap); + vmcs_write32(PLE_WINDOW, ple_window); + } -/* - * Sets up the vmcs for emulated real mode. - */ -static int vmx_vcpu_setup(struct vcpu_vmx *vmx) -{ -#ifdef CONFIG_X86_64 - unsigned long a; -#endif - int i; - - /* I/O */ - vmcs_write64(IO_BITMAP_A, __pa(vmx_io_bitmap_a)); - vmcs_write64(IO_BITMAP_B, __pa(vmx_io_bitmap_b)); - - if (cpu_has_vmx_msr_bitmap()) - vmcs_write64(MSR_BITMAP, __pa(vmx_msr_bitmap_legacy)); - - vmcs_write64(VMCS_LINK_POINTER, -1ull); /* 22.3.1.5 */ - - /* Control */ - vmcs_write32(PIN_BASED_VM_EXEC_CONTROL, - vmcs_config.pin_based_exec_ctrl); - - vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, vmx_exec_control(vmx)); - - if (cpu_has_secondary_exec_ctrls()) { - vmcs_write32(SECONDARY_VM_EXEC_CONTROL, - vmx_secondary_exec_control(vmx)); - } - - if (ple_gap) { - vmcs_write32(PLE_GAP, ple_gap); - vmcs_write32(PLE_WINDOW, ple_window); - } - - vmcs_write32(PAGE_FAULT_ERROR_CODE_MASK, 0); - vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, 0); + vmcs_write32(PAGE_FAULT_ERROR_CODE_MASK, !!bypass_guest_pf); + vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, !!bypass_guest_pf); vmcs_write32(CR3_TARGET_COUNT, 0); /* 22.2.1 */ + vmcs_writel(HOST_CR0, read_cr0() | X86_CR0_TS); /* 22.2.3 */ + vmcs_writel(HOST_CR4, read_cr4()); /* 22.2.3, 22.2.5 */ + vmcs_writel(HOST_CR3, read_cr3()); /* 22.2.3 FIXME: shadow tables */ + + vmcs_write16(HOST_CS_SELECTOR, __KERNEL_CS); /* 22.2.4 */ + vmcs_write16(HOST_DS_SELECTOR, __KERNEL_DS); /* 22.2.4 */ + vmcs_write16(HOST_ES_SELECTOR, __KERNEL_DS); /* 22.2.4 */ vmcs_write16(HOST_FS_SELECTOR, 0); /* 22.2.4 */ vmcs_write16(HOST_GS_SELECTOR, 0); /* 22.2.4 */ - vmx_set_constant_host_state(); + vmcs_write16(HOST_SS_SELECTOR, __KERNEL_DS); /* 22.2.4 */ #ifdef CONFIG_X86_64 rdmsrl(MSR_FS_BASE, a); vmcs_writel(HOST_FS_BASE, a); /* 22.2.4 */ @@ -3657,15 +2808,32 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx) vmcs_writel(HOST_GS_BASE, 0); /* 22.2.4 */ #endif + vmcs_write16(HOST_TR_SELECTOR, GDT_ENTRY_TSS*8); /* 22.2.4 */ + + native_store_idt(&dt); + vmcs_writel(HOST_IDTR_BASE, dt.address); /* 22.2.4 */ + + asm("mov $.Lkvm_vmx_return, %0" : "=r"(kvm_vmx_return)); + vmcs_writel(HOST_RIP, kvm_vmx_return); /* 22.2.5 */ vmcs_write32(VM_EXIT_MSR_STORE_COUNT, 0); vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, 0); vmcs_write64(VM_EXIT_MSR_LOAD_ADDR, __pa(vmx->msr_autoload.host)); vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, 0); vmcs_write64(VM_ENTRY_MSR_LOAD_ADDR, __pa(vmx->msr_autoload.guest)); + rdmsr(MSR_IA32_SYSENTER_CS, host_sysenter_cs, junk); + vmcs_write32(HOST_IA32_SYSENTER_CS, host_sysenter_cs); + rdmsrl(MSR_IA32_SYSENTER_ESP, a); + vmcs_writel(HOST_IA32_SYSENTER_ESP, a); /* 22.2.3 */ + rdmsrl(MSR_IA32_SYSENTER_EIP, a); + vmcs_writel(HOST_IA32_SYSENTER_EIP, a); /* 22.2.3 */ + + if (vmcs_config.vmexit_ctrl & VM_EXIT_LOAD_IA32_PAT) { + rdmsr(MSR_IA32_CR_PAT, msr_low, msr_high); + host_pat = msr_low | ((u64) msr_high << 32); + vmcs_write64(HOST_IA32_PAT, host_pat); + } if (vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_IA32_PAT) { - u32 msr_low, msr_high; - u64 host_pat; rdmsr(MSR_IA32_CR_PAT, msr_low, msr_high); host_pat = msr_low | ((u64) msr_high << 32); /* Write the default value follow host pat */ @@ -3695,7 +2863,10 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx) vmcs_write32(VM_ENTRY_CONTROLS, vmcs_config.vmentry_ctrl); vmcs_writel(CR0_GUEST_HOST_MASK, ~0UL); - set_cr4_guest_host_mask(vmx); + vmx->vcpu.arch.cr4_guest_owned_bits = KVM_CR4_GUEST_OWNED_BITS; + if (enable_ept) + vmx->vcpu.arch.cr4_guest_owned_bits |= X86_CR4_PGE; + vmcs_writel(CR4_GUEST_HOST_MASK, ~vmx->vcpu.arch.cr4_guest_owned_bits); kvm_write_tsc(&vmx->vcpu, 0); @@ -3819,25 +2990,9 @@ static int vmx_vcpu_reset(struct kvm_vcpu *vcpu) return ret; } -/* - * In nested virtualization, check if L1 asked to exit on external interrupts. - * For most existing hypervisors, this will always return true. - */ -static bool nested_exit_on_intr(struct kvm_vcpu *vcpu) -{ - return get_vmcs12(vcpu)->pin_based_vm_exec_control & - PIN_BASED_EXT_INTR_MASK; -} - static void enable_irq_window(struct kvm_vcpu *vcpu) { u32 cpu_based_vm_exec_control; - if (is_guest_mode(vcpu) && nested_exit_on_intr(vcpu)) - /* We can get here when nested_run_pending caused - * vmx_interrupt_allowed() to return false. In this case, do - * nothing - the interrupt will be injected later. - */ - return; cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL); cpu_based_vm_exec_control |= CPU_BASED_VIRTUAL_INTR_PENDING; @@ -3894,9 +3049,6 @@ static void vmx_inject_nmi(struct kvm_vcpu *vcpu) { struct vcpu_vmx *vmx = to_vmx(vcpu); - if (is_guest_mode(vcpu)) - return; - if (!cpu_has_virtual_nmis()) { /* * Tracking the NMI-blocked state in software is built upon @@ -3963,17 +3115,6 @@ static void vmx_set_nmi_mask(struct kvm_vcpu *vcpu, bool masked) static int vmx_interrupt_allowed(struct kvm_vcpu *vcpu) { - if (is_guest_mode(vcpu) && nested_exit_on_intr(vcpu)) { - struct vmcs12 *vmcs12; - if (to_vmx(vcpu)->nested.nested_run_pending) - return 0; - nested_vmx_vmexit(vcpu); - vmcs12 = get_vmcs12(vcpu); - vmcs12->vm_exit_reason = EXIT_REASON_EXTERNAL_INTERRUPT; - vmcs12->vm_exit_intr_info = 0; - /* fall through to normal code, but now in L1, not L2 */ - } - return (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) && !(vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & (GUEST_INTR_STATE_STI | GUEST_INTR_STATE_MOV_SS)); @@ -4215,58 +3356,6 @@ vmx_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall) hypercall[2] = 0xc1; } -/* called to set cr0 as approriate for a mov-to-cr0 exit. */ -static int handle_set_cr0(struct kvm_vcpu *vcpu, unsigned long val) -{ - if (to_vmx(vcpu)->nested.vmxon && - ((val & VMXON_CR0_ALWAYSON) != VMXON_CR0_ALWAYSON)) - return 1; - - if (is_guest_mode(vcpu)) { - /* - * We get here when L2 changed cr0 in a way that did not change - * any of L1's shadowed bits (see nested_vmx_exit_handled_cr), - * but did change L0 shadowed bits. This can currently happen - * with the TS bit: L0 may want to leave TS on (for lazy fpu - * loading) while pretending to allow the guest to change it. - */ - if (kvm_set_cr0(vcpu, (val & vcpu->arch.cr0_guest_owned_bits) | - (vcpu->arch.cr0 & ~vcpu->arch.cr0_guest_owned_bits))) - return 1; - vmcs_writel(CR0_READ_SHADOW, val); - return 0; - } else - return kvm_set_cr0(vcpu, val); -} - -static int handle_set_cr4(struct kvm_vcpu *vcpu, unsigned long val) -{ - if (is_guest_mode(vcpu)) { - if (kvm_set_cr4(vcpu, (val & vcpu->arch.cr4_guest_owned_bits) | - (vcpu->arch.cr4 & ~vcpu->arch.cr4_guest_owned_bits))) - return 1; - vmcs_writel(CR4_READ_SHADOW, val); - return 0; - } else - return kvm_set_cr4(vcpu, val); -} - -/* called to set cr0 as approriate for clts instruction exit. */ -static void handle_clts(struct kvm_vcpu *vcpu) -{ - if (is_guest_mode(vcpu)) { - /* - * We get here when L2 did CLTS, and L1 didn't shadow CR0.TS - * but we did (!fpu_active). We need to keep GUEST_CR0.TS on, - * just pretend it's off (also in arch.cr0 for fpu_activate). - */ - vmcs_writel(CR0_READ_SHADOW, - vmcs_readl(CR0_READ_SHADOW) & ~X86_CR0_TS); - vcpu->arch.cr0 &= ~X86_CR0_TS; - } else - vmx_set_cr0(vcpu, kvm_read_cr0_bits(vcpu, ~X86_CR0_TS)); -} - static int handle_cr(struct kvm_vcpu *vcpu) { unsigned long exit_qualification, val; @@ -4283,7 +3372,7 @@ static int handle_cr(struct kvm_vcpu *vcpu) trace_kvm_cr_write(cr, val); switch (cr) { case 0: - err = handle_set_cr0(vcpu, val); + err = kvm_set_cr0(vcpu, val); kvm_complete_insn_gp(vcpu, err); return 1; case 3: @@ -4291,7 +3380,7 @@ static int handle_cr(struct kvm_vcpu *vcpu) kvm_complete_insn_gp(vcpu, err); return 1; case 4: - err = handle_set_cr4(vcpu, val); + err = kvm_set_cr4(vcpu, val); kvm_complete_insn_gp(vcpu, err); return 1; case 8: { @@ -4309,7 +3398,7 @@ static int handle_cr(struct kvm_vcpu *vcpu) }; break; case 2: /* clts */ - handle_clts(vcpu); + vmx_set_cr0(vcpu, kvm_read_cr0_bits(vcpu, ~X86_CR0_TS)); trace_kvm_cr_write(0, kvm_read_cr0(vcpu)); skip_emulated_instruction(vcpu); vmx_fpu_activate(vcpu); @@ -4485,6 +3574,12 @@ static int handle_vmcall(struct kvm_vcpu *vcpu) return 1; } +static int handle_vmx_insn(struct kvm_vcpu *vcpu) +{ + kvm_queue_exception(vcpu, UD_VECTOR); + return 1; +} + static int handle_invd(struct kvm_vcpu *vcpu) { return emulate_instruction(vcpu, 0) == EMULATE_DONE; @@ -4682,19 +3777,11 @@ static void ept_misconfig_inspect_spte(struct kvm_vcpu *vcpu, u64 spte, static int handle_ept_misconfig(struct kvm_vcpu *vcpu) { u64 sptes[4]; - int nr_sptes, i, ret; + int nr_sptes, i; gpa_t gpa; gpa = vmcs_read64(GUEST_PHYSICAL_ADDRESS); - ret = handle_mmio_page_fault_common(vcpu, gpa, true); - if (likely(ret == 1)) - return x86_emulate_instruction(vcpu, gpa, 0, NULL, 0) == - EMULATE_DONE; - if (unlikely(!ret)) - return 1; - - /* It is the real ept misconfig */ printk(KERN_ERR "EPT: Misconfiguration.\n"); printk(KERN_ERR "EPT: GPA: 0x%llx\n", gpa); @@ -4779,1024 +3866,147 @@ static int handle_invalid_op(struct kvm_vcpu *vcpu) } /* - * To run an L2 guest, we need a vmcs02 based on the L1-specified vmcs12. - * We could reuse a single VMCS for all the L2 guests, but we also want the - * option to allocate a separate vmcs02 for each separate loaded vmcs12 - this - * allows keeping them loaded on the processor, and in the future will allow - * optimizations where prepare_vmcs02 doesn't need to set all the fields on - * every entry if they never change. - * So we keep, in vmx->nested.vmcs02_pool, a cache of size VMCS02_POOL_SIZE - * (>=0) with a vmcs02 for each recently loaded vmcs12s, most recent first. - * - * The following functions allocate and free a vmcs02 in this pool. + * The exit handlers return 1 if the exit was handled fully and guest execution + * may resume. Otherwise they set the kvm_run parameter to indicate what needs + * to be done to userspace and return 0. */ +static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu) = { + [EXIT_REASON_EXCEPTION_NMI] = handle_exception, + [EXIT_REASON_EXTERNAL_INTERRUPT] = handle_external_interrupt, + [EXIT_REASON_TRIPLE_FAULT] = handle_triple_fault, + [EXIT_REASON_NMI_WINDOW] = handle_nmi_window, + [EXIT_REASON_IO_INSTRUCTION] = handle_io, + [EXIT_REASON_CR_ACCESS] = handle_cr, + [EXIT_REASON_DR_ACCESS] = handle_dr, + [EXIT_REASON_CPUID] = handle_cpuid, + [EXIT_REASON_MSR_READ] = handle_rdmsr, + [EXIT_REASON_MSR_WRITE] = handle_wrmsr, + [EXIT_REASON_PENDING_INTERRUPT] = handle_interrupt_window, + [EXIT_REASON_HLT] = handle_halt, + [EXIT_REASON_INVD] = handle_invd, + [EXIT_REASON_INVLPG] = handle_invlpg, + [EXIT_REASON_VMCALL] = handle_vmcall, + [EXIT_REASON_VMCLEAR] = handle_vmx_insn, + [EXIT_REASON_VMLAUNCH] = handle_vmx_insn, + [EXIT_REASON_VMPTRLD] = handle_vmx_insn, + [EXIT_REASON_VMPTRST] = handle_vmx_insn, + [EXIT_REASON_VMREAD] = handle_vmx_insn, + [EXIT_REASON_VMRESUME] = handle_vmx_insn, + [EXIT_REASON_VMWRITE] = handle_vmx_insn, + [EXIT_REASON_VMOFF] = handle_vmx_insn, + [EXIT_REASON_VMON] = handle_vmx_insn, + [EXIT_REASON_TPR_BELOW_THRESHOLD] = handle_tpr_below_threshold, + [EXIT_REASON_APIC_ACCESS] = handle_apic_access, + [EXIT_REASON_WBINVD] = handle_wbinvd, + [EXIT_REASON_XSETBV] = handle_xsetbv, + [EXIT_REASON_TASK_SWITCH] = handle_task_switch, + [EXIT_REASON_MCE_DURING_VMENTRY] = handle_machine_check, + [EXIT_REASON_EPT_VIOLATION] = handle_ept_violation, + [EXIT_REASON_EPT_MISCONFIG] = handle_ept_misconfig, + [EXIT_REASON_PAUSE_INSTRUCTION] = handle_pause, + [EXIT_REASON_MWAIT_INSTRUCTION] = handle_invalid_op, + [EXIT_REASON_MONITOR_INSTRUCTION] = handle_invalid_op, +}; -/* Get a VMCS from the pool to use as vmcs02 for the current vmcs12. */ -static struct loaded_vmcs *nested_get_current_vmcs02(struct vcpu_vmx *vmx) -{ - struct vmcs02_list *item; - list_for_each_entry(item, &vmx->nested.vmcs02_pool, list) - if (item->vmptr == vmx->nested.current_vmptr) { - list_move(&item->list, &vmx->nested.vmcs02_pool); - return &item->vmcs02; - } - - if (vmx->nested.vmcs02_num >= max(VMCS02_POOL_SIZE, 1)) { - /* Recycle the least recently used VMCS. */ - item = list_entry(vmx->nested.vmcs02_pool.prev, - struct vmcs02_list, list); - item->vmptr = vmx->nested.current_vmptr; - list_move(&item->list, &vmx->nested.vmcs02_pool); - return &item->vmcs02; - } - - /* Create a new VMCS */ - item = (struct vmcs02_list *) - kmalloc(sizeof(struct vmcs02_list), GFP_KERNEL); - if (!item) - return NULL; - item->vmcs02.vmcs = alloc_vmcs(); - if (!item->vmcs02.vmcs) { - kfree(item); - return NULL; - } - loaded_vmcs_init(&item->vmcs02); - item->vmptr = vmx->nested.current_vmptr; - list_add(&(item->list), &(vmx->nested.vmcs02_pool)); - vmx->nested.vmcs02_num++; - return &item->vmcs02; -} - -/* Free and remove from pool a vmcs02 saved for a vmcs12 (if there is one) */ -static void nested_free_vmcs02(struct vcpu_vmx *vmx, gpa_t vmptr) -{ - struct vmcs02_list *item; - list_for_each_entry(item, &vmx->nested.vmcs02_pool, list) - if (item->vmptr == vmptr) { - free_loaded_vmcs(&item->vmcs02); - list_del(&item->list); - kfree(item); - vmx->nested.vmcs02_num--; - return; - } -} - -/* - * Free all VMCSs saved for this vcpu, except the one pointed by - * vmx->loaded_vmcs. These include the VMCSs in vmcs02_pool (except the one - * currently used, if running L2), and vmcs01 when running L2. - */ -static void nested_free_all_saved_vmcss(struct vcpu_vmx *vmx) -{ - struct vmcs02_list *item, *n; - list_for_each_entry_safe(item, n, &vmx->nested.vmcs02_pool, list) { - if (vmx->loaded_vmcs != &item->vmcs02) - free_loaded_vmcs(&item->vmcs02); - list_del(&item->list); - kfree(item); - } - vmx->nested.vmcs02_num = 0; +static const int kvm_vmx_max_exit_handlers = + ARRAY_SIZE(kvm_vmx_exit_handlers); - if (vmx->loaded_vmcs != &vmx->vmcs01) - free_loaded_vmcs(&vmx->vmcs01); +static void vmx_get_exit_info(struct kvm_vcpu *vcpu, u64 *info1, u64 *info2) +{ + *info1 = vmcs_readl(EXIT_QUALIFICATION); + *info2 = vmcs_read32(VM_EXIT_INTR_INFO); } /* - * Emulate the VMXON instruction. - * Currently, we just remember that VMX is active, and do not save or even - * inspect the argument to VMXON (the so-called "VMXON pointer") because we - * do not currently need to store anything in that guest-allocated memory - * region. Consequently, VMCLEAR and VMPTRLD also do not verify that the their - * argument is different from the VMXON pointer (which the spec says they do). + * The guest has exited. See if we can fix it or if we need userspace + * assistance. */ -static int handle_vmon(struct kvm_vcpu *vcpu) +static int vmx_handle_exit(struct kvm_vcpu *vcpu) { - struct kvm_segment cs; struct vcpu_vmx *vmx = to_vmx(vcpu); + u32 exit_reason = vmx->exit_reason; + u32 vectoring_info = vmx->idt_vectoring_info; - /* The Intel VMX Instruction Reference lists a bunch of bits that - * are prerequisite to running VMXON, most notably cr4.VMXE must be - * set to 1 (see vmx_set_cr4() for when we allow the guest to set this). - * Otherwise, we should fail with #UD. We test these now: - */ - if (!kvm_read_cr4_bits(vcpu, X86_CR4_VMXE) || - !kvm_read_cr0_bits(vcpu, X86_CR0_PE) || - (vmx_get_rflags(vcpu) & X86_EFLAGS_VM)) { - kvm_queue_exception(vcpu, UD_VECTOR); - return 1; - } - - vmx_get_segment(vcpu, &cs, VCPU_SREG_CS); - if (is_long_mode(vcpu) && !cs.l) { - kvm_queue_exception(vcpu, UD_VECTOR); - return 1; - } - - if (vmx_get_cpl(vcpu)) { - kvm_inject_gp(vcpu, 0); - return 1; - } - - INIT_LIST_HEAD(&(vmx->nested.vmcs02_pool)); - vmx->nested.vmcs02_num = 0; - - vmx->nested.vmxon = true; - - skip_emulated_instruction(vcpu); - return 1; -} + trace_kvm_exit(exit_reason, vcpu, KVM_ISA_VMX); -/* - * Intel's VMX Instruction Reference specifies a common set of prerequisites - * for running VMX instructions (except VMXON, whose prerequisites are - * slightly different). It also specifies what exception to inject otherwise. - */ -static int nested_vmx_check_permission(struct kvm_vcpu *vcpu) -{ - struct kvm_segment cs; - struct vcpu_vmx *vmx = to_vmx(vcpu); + /* If guest state is invalid, start emulating */ + if (vmx->emulation_required && emulate_invalid_guest_state) + return handle_invalid_guest_state(vcpu); - if (!vmx->nested.vmxon) { - kvm_queue_exception(vcpu, UD_VECTOR); + if (exit_reason & VMX_EXIT_REASONS_FAILED_VMENTRY) { + vcpu->run->exit_reason = KVM_EXIT_FAIL_ENTRY; + vcpu->run->fail_entry.hardware_entry_failure_reason + = exit_reason; return 0; } - vmx_get_segment(vcpu, &cs, VCPU_SREG_CS); - if ((vmx_get_rflags(vcpu) & X86_EFLAGS_VM) || - (is_long_mode(vcpu) && !cs.l)) { - kvm_queue_exception(vcpu, UD_VECTOR); + if (unlikely(vmx->fail)) { + vcpu->run->exit_reason = KVM_EXIT_FAIL_ENTRY; + vcpu->run->fail_entry.hardware_entry_failure_reason + = vmcs_read32(VM_INSTRUCTION_ERROR); return 0; } - if (vmx_get_cpl(vcpu)) { - kvm_inject_gp(vcpu, 0); - return 0; + if ((vectoring_info & VECTORING_INFO_VALID_MASK) && + (exit_reason != EXIT_REASON_EXCEPTION_NMI && + exit_reason != EXIT_REASON_EPT_VIOLATION && + exit_reason != EXIT_REASON_TASK_SWITCH)) + printk(KERN_WARNING "%s: unexpected, valid vectoring info " + "(0x%x) and exit reason is 0x%x\n", + __func__, vectoring_info, exit_reason); + + if (unlikely(!cpu_has_virtual_nmis() && vmx->soft_vnmi_blocked)) { + if (vmx_interrupt_allowed(vcpu)) { + vmx->soft_vnmi_blocked = 0; + } else if (vmx->vnmi_blocked_time > 1000000000LL && + vcpu->arch.nmi_pending) { + /* + * This CPU don't support us in finding the end of an + * NMI-blocked window if the guest runs with IRQs + * disabled. So we pull the trigger after 1 s of + * futile waiting, but inform the user about this. + */ + printk(KERN_WARNING "%s: Breaking out of NMI-blocked " + "state on VCPU %d after 1 s timeout\n", + __func__, vcpu->vcpu_id); + vmx->soft_vnmi_blocked = 0; + } } - return 1; + if (exit_reason < kvm_vmx_max_exit_handlers + && kvm_vmx_exit_handlers[exit_reason]) + return kvm_vmx_exit_handlers[exit_reason](vcpu); + else { + vcpu->run->exit_reason = KVM_EXIT_UNKNOWN; + vcpu->run->hw.hardware_exit_reason = exit_reason; + } + return 0; } -/* - * Free whatever needs to be freed from vmx->nested when L1 goes down, or - * just stops using VMX. - */ -static void free_nested(struct vcpu_vmx *vmx) +static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr) { - if (!vmx->nested.vmxon) + if (irr == -1 || tpr < irr) { + vmcs_write32(TPR_THRESHOLD, 0); return; - vmx->nested.vmxon = false; - if (vmx->nested.current_vmptr != -1ull) { - kunmap(vmx->nested.current_vmcs12_page); - nested_release_page(vmx->nested.current_vmcs12_page); - vmx->nested.current_vmptr = -1ull; - vmx->nested.current_vmcs12 = NULL; } - /* Unpin physical memory we referred to in current vmcs02 */ - if (vmx->nested.apic_access_page) { - nested_release_page(vmx->nested.apic_access_page); - vmx->nested.apic_access_page = 0; - } - - nested_free_all_saved_vmcss(vmx); -} -/* Emulate the VMXOFF instruction */ -static int handle_vmoff(struct kvm_vcpu *vcpu) -{ - if (!nested_vmx_check_permission(vcpu)) - return 1; - free_nested(to_vmx(vcpu)); - skip_emulated_instruction(vcpu); - return 1; + vmcs_write32(TPR_THRESHOLD, irr); } -/* - * Decode the memory-address operand of a vmx instruction, as recorded on an - * exit caused by such an instruction (run by a guest hypervisor). - * On success, returns 0. When the operand is invalid, returns 1 and throws - * #UD or #GP. - */ -static int get_vmx_mem_address(struct kvm_vcpu *vcpu, - unsigned long exit_qualification, - u32 vmx_instruction_info, gva_t *ret) +static void vmx_complete_atomic_exit(struct vcpu_vmx *vmx) { - /* - * According to Vol. 3B, "Information for VM Exits Due to Instruction - * Execution", on an exit, vmx_instruction_info holds most of the - * addressing components of the operand. Only the displacement part - * is put in exit_qualification (see 3B, "Basic VM-Exit Information"). - * For how an actual address is calculated from all these components, - * refer to Vol. 1, "Operand Addressing". - */ - int scaling = vmx_instruction_info & 3; - int addr_size = (vmx_instruction_info >> 7) & 7; - bool is_reg = vmx_instruction_info & (1u << 10); - int seg_reg = (vmx_instruction_info >> 15) & 7; - int index_reg = (vmx_instruction_info >> 18) & 0xf; - bool index_is_valid = !(vmx_instruction_info & (1u << 22)); - int base_reg = (vmx_instruction_info >> 23) & 0xf; - bool base_is_valid = !(vmx_instruction_info & (1u << 27)); - - if (is_reg) { - kvm_queue_exception(vcpu, UD_VECTOR); - return 1; - } + u32 exit_intr_info; - /* Addr = segment_base + offset */ - /* offset = base + [index * scale] + displacement */ - *ret = vmx_get_segment_base(vcpu, seg_reg); - if (base_is_valid) - *ret += kvm_register_read(vcpu, base_reg); - if (index_is_valid) - *ret += kvm_register_read(vcpu, index_reg)<exit_reason == EXIT_REASON_MCE_DURING_VMENTRY + || vmx->exit_reason == EXIT_REASON_EXCEPTION_NMI)) + return; - if (addr_size == 1) /* 32 bit */ - *ret &= 0xffffffff; + vmx->exit_intr_info = vmcs_read32(VM_EXIT_INTR_INFO); + exit_intr_info = vmx->exit_intr_info; - /* - * TODO: throw #GP (and return 1) in various cases that the VM* - * instructions require it - e.g., offset beyond segment limit, - * unusable or unreadable/unwritable segment, non-canonical 64-bit - * address, and so on. Currently these are not checked. - */ - return 0; -} - -/* - * The following 3 functions, nested_vmx_succeed()/failValid()/failInvalid(), - * set the success or error code of an emulated VMX instruction, as specified - * by Vol 2B, VMX Instruction Reference, "Conventions". - */ -static void nested_vmx_succeed(struct kvm_vcpu *vcpu) -{ - vmx_set_rflags(vcpu, vmx_get_rflags(vcpu) - & ~(X86_EFLAGS_CF | X86_EFLAGS_PF | X86_EFLAGS_AF | - X86_EFLAGS_ZF | X86_EFLAGS_SF | X86_EFLAGS_OF)); -} - -static void nested_vmx_failInvalid(struct kvm_vcpu *vcpu) -{ - vmx_set_rflags(vcpu, (vmx_get_rflags(vcpu) - & ~(X86_EFLAGS_PF | X86_EFLAGS_AF | X86_EFLAGS_ZF | - X86_EFLAGS_SF | X86_EFLAGS_OF)) - | X86_EFLAGS_CF); -} - -static void nested_vmx_failValid(struct kvm_vcpu *vcpu, - u32 vm_instruction_error) -{ - if (to_vmx(vcpu)->nested.current_vmptr == -1ull) { - /* - * failValid writes the error number to the current VMCS, which - * can't be done there isn't a current VMCS. - */ - nested_vmx_failInvalid(vcpu); - return; - } - vmx_set_rflags(vcpu, (vmx_get_rflags(vcpu) - & ~(X86_EFLAGS_CF | X86_EFLAGS_PF | X86_EFLAGS_AF | - X86_EFLAGS_SF | X86_EFLAGS_OF)) - | X86_EFLAGS_ZF); - get_vmcs12(vcpu)->vm_instruction_error = vm_instruction_error; -} - -/* Emulate the VMCLEAR instruction */ -static int handle_vmclear(struct kvm_vcpu *vcpu) -{ - struct vcpu_vmx *vmx = to_vmx(vcpu); - gva_t gva; - gpa_t vmptr; - struct vmcs12 *vmcs12; - struct page *page; - struct x86_exception e; - - if (!nested_vmx_check_permission(vcpu)) - return 1; - - if (get_vmx_mem_address(vcpu, vmcs_readl(EXIT_QUALIFICATION), - vmcs_read32(VMX_INSTRUCTION_INFO), &gva)) - return 1; - - if (kvm_read_guest_virt(&vcpu->arch.emulate_ctxt, gva, &vmptr, - sizeof(vmptr), &e)) { - kvm_inject_page_fault(vcpu, &e); - return 1; - } - - if (!IS_ALIGNED(vmptr, PAGE_SIZE)) { - nested_vmx_failValid(vcpu, VMXERR_VMCLEAR_INVALID_ADDRESS); - skip_emulated_instruction(vcpu); - return 1; - } - - if (vmptr == vmx->nested.current_vmptr) { - kunmap(vmx->nested.current_vmcs12_page); - nested_release_page(vmx->nested.current_vmcs12_page); - vmx->nested.current_vmptr = -1ull; - vmx->nested.current_vmcs12 = NULL; - } - - page = nested_get_page(vcpu, vmptr); - if (page == NULL) { - /* - * For accurate processor emulation, VMCLEAR beyond available - * physical memory should do nothing at all. However, it is - * possible that a nested vmx bug, not a guest hypervisor bug, - * resulted in this case, so let's shut down before doing any - * more damage: - */ - kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu); - return 1; - } - vmcs12 = kmap(page); - vmcs12->launch_state = 0; - kunmap(page); - nested_release_page(page); - - nested_free_vmcs02(vmx, vmptr); - - skip_emulated_instruction(vcpu); - nested_vmx_succeed(vcpu); - return 1; -} - -static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch); - -/* Emulate the VMLAUNCH instruction */ -static int handle_vmlaunch(struct kvm_vcpu *vcpu) -{ - return nested_vmx_run(vcpu, true); -} - -/* Emulate the VMRESUME instruction */ -static int handle_vmresume(struct kvm_vcpu *vcpu) -{ - - return nested_vmx_run(vcpu, false); -} - -enum vmcs_field_type { - VMCS_FIELD_TYPE_U16 = 0, - VMCS_FIELD_TYPE_U64 = 1, - VMCS_FIELD_TYPE_U32 = 2, - VMCS_FIELD_TYPE_NATURAL_WIDTH = 3 -}; - -static inline int vmcs_field_type(unsigned long field) -{ - if (0x1 & field) /* the *_HIGH fields are all 32 bit */ - return VMCS_FIELD_TYPE_U32; - return (field >> 13) & 0x3 ; -} - -static inline int vmcs_field_readonly(unsigned long field) -{ - return (((field >> 10) & 0x3) == 1); -} - -/* - * Read a vmcs12 field. Since these can have varying lengths and we return - * one type, we chose the biggest type (u64) and zero-extend the return value - * to that size. Note that the caller, handle_vmread, might need to use only - * some of the bits we return here (e.g., on 32-bit guests, only 32 bits of - * 64-bit fields are to be returned). - */ -static inline bool vmcs12_read_any(struct kvm_vcpu *vcpu, - unsigned long field, u64 *ret) -{ - short offset = vmcs_field_to_offset(field); - char *p; - - if (offset < 0) - return 0; - - p = ((char *)(get_vmcs12(vcpu))) + offset; - - switch (vmcs_field_type(field)) { - case VMCS_FIELD_TYPE_NATURAL_WIDTH: - *ret = *((natural_width *)p); - return 1; - case VMCS_FIELD_TYPE_U16: - *ret = *((u16 *)p); - return 1; - case VMCS_FIELD_TYPE_U32: - *ret = *((u32 *)p); - return 1; - case VMCS_FIELD_TYPE_U64: - *ret = *((u64 *)p); - return 1; - default: - return 0; /* can never happen. */ - } -} - -/* - * VMX instructions which assume a current vmcs12 (i.e., that VMPTRLD was - * used before) all generate the same failure when it is missing. - */ -static int nested_vmx_check_vmcs12(struct kvm_vcpu *vcpu) -{ - struct vcpu_vmx *vmx = to_vmx(vcpu); - if (vmx->nested.current_vmptr == -1ull) { - nested_vmx_failInvalid(vcpu); - skip_emulated_instruction(vcpu); - return 0; - } - return 1; -} - -static int handle_vmread(struct kvm_vcpu *vcpu) -{ - unsigned long field; - u64 field_value; - unsigned long exit_qualification = vmcs_readl(EXIT_QUALIFICATION); - u32 vmx_instruction_info = vmcs_read32(VMX_INSTRUCTION_INFO); - gva_t gva = 0; - - if (!nested_vmx_check_permission(vcpu) || - !nested_vmx_check_vmcs12(vcpu)) - return 1; - - /* Decode instruction info and find the field to read */ - field = kvm_register_read(vcpu, (((vmx_instruction_info) >> 28) & 0xf)); - /* Read the field, zero-extended to a u64 field_value */ - if (!vmcs12_read_any(vcpu, field, &field_value)) { - nested_vmx_failValid(vcpu, VMXERR_UNSUPPORTED_VMCS_COMPONENT); - skip_emulated_instruction(vcpu); - return 1; - } - /* - * Now copy part of this value to register or memory, as requested. - * Note that the number of bits actually copied is 32 or 64 depending - * on the guest's mode (32 or 64 bit), not on the given field's length. - */ - if (vmx_instruction_info & (1u << 10)) { - kvm_register_write(vcpu, (((vmx_instruction_info) >> 3) & 0xf), - field_value); - } else { - if (get_vmx_mem_address(vcpu, exit_qualification, - vmx_instruction_info, &gva)) - return 1; - /* _system ok, as nested_vmx_check_permission verified cpl=0 */ - kvm_write_guest_virt_system(&vcpu->arch.emulate_ctxt, gva, - &field_value, (is_long_mode(vcpu) ? 8 : 4), NULL); - } - - nested_vmx_succeed(vcpu); - skip_emulated_instruction(vcpu); - return 1; -} - - -static int handle_vmwrite(struct kvm_vcpu *vcpu) -{ - unsigned long field; - gva_t gva; - unsigned long exit_qualification = vmcs_readl(EXIT_QUALIFICATION); - u32 vmx_instruction_info = vmcs_read32(VMX_INSTRUCTION_INFO); - char *p; - short offset; - /* The value to write might be 32 or 64 bits, depending on L1's long - * mode, and eventually we need to write that into a field of several - * possible lengths. The code below first zero-extends the value to 64 - * bit (field_value), and then copies only the approriate number of - * bits into the vmcs12 field. - */ - u64 field_value = 0; - struct x86_exception e; - - if (!nested_vmx_check_permission(vcpu) || - !nested_vmx_check_vmcs12(vcpu)) - return 1; - - if (vmx_instruction_info & (1u << 10)) - field_value = kvm_register_read(vcpu, - (((vmx_instruction_info) >> 3) & 0xf)); - else { - if (get_vmx_mem_address(vcpu, exit_qualification, - vmx_instruction_info, &gva)) - return 1; - if (kvm_read_guest_virt(&vcpu->arch.emulate_ctxt, gva, - &field_value, (is_long_mode(vcpu) ? 8 : 4), &e)) { - kvm_inject_page_fault(vcpu, &e); - return 1; - } - } - - - field = kvm_register_read(vcpu, (((vmx_instruction_info) >> 28) & 0xf)); - if (vmcs_field_readonly(field)) { - nested_vmx_failValid(vcpu, - VMXERR_VMWRITE_READ_ONLY_VMCS_COMPONENT); - skip_emulated_instruction(vcpu); - return 1; - } - - offset = vmcs_field_to_offset(field); - if (offset < 0) { - nested_vmx_failValid(vcpu, VMXERR_UNSUPPORTED_VMCS_COMPONENT); - skip_emulated_instruction(vcpu); - return 1; - } - p = ((char *) get_vmcs12(vcpu)) + offset; - - switch (vmcs_field_type(field)) { - case VMCS_FIELD_TYPE_U16: - *(u16 *)p = field_value; - break; - case VMCS_FIELD_TYPE_U32: - *(u32 *)p = field_value; - break; - case VMCS_FIELD_TYPE_U64: - *(u64 *)p = field_value; - break; - case VMCS_FIELD_TYPE_NATURAL_WIDTH: - *(natural_width *)p = field_value; - break; - default: - nested_vmx_failValid(vcpu, VMXERR_UNSUPPORTED_VMCS_COMPONENT); - skip_emulated_instruction(vcpu); - return 1; - } - - nested_vmx_succeed(vcpu); - skip_emulated_instruction(vcpu); - return 1; -} - -/* Emulate the VMPTRLD instruction */ -static int handle_vmptrld(struct kvm_vcpu *vcpu) -{ - struct vcpu_vmx *vmx = to_vmx(vcpu); - gva_t gva; - gpa_t vmptr; - struct x86_exception e; - - if (!nested_vmx_check_permission(vcpu)) - return 1; - - if (get_vmx_mem_address(vcpu, vmcs_readl(EXIT_QUALIFICATION), - vmcs_read32(VMX_INSTRUCTION_INFO), &gva)) - return 1; - - if (kvm_read_guest_virt(&vcpu->arch.emulate_ctxt, gva, &vmptr, - sizeof(vmptr), &e)) { - kvm_inject_page_fault(vcpu, &e); - return 1; - } - - if (!IS_ALIGNED(vmptr, PAGE_SIZE)) { - nested_vmx_failValid(vcpu, VMXERR_VMPTRLD_INVALID_ADDRESS); - skip_emulated_instruction(vcpu); - return 1; - } - - if (vmx->nested.current_vmptr != vmptr) { - struct vmcs12 *new_vmcs12; - struct page *page; - page = nested_get_page(vcpu, vmptr); - if (page == NULL) { - nested_vmx_failInvalid(vcpu); - skip_emulated_instruction(vcpu); - return 1; - } - new_vmcs12 = kmap(page); - if (new_vmcs12->revision_id != VMCS12_REVISION) { - kunmap(page); - nested_release_page_clean(page); - nested_vmx_failValid(vcpu, - VMXERR_VMPTRLD_INCORRECT_VMCS_REVISION_ID); - skip_emulated_instruction(vcpu); - return 1; - } - if (vmx->nested.current_vmptr != -1ull) { - kunmap(vmx->nested.current_vmcs12_page); - nested_release_page(vmx->nested.current_vmcs12_page); - } - - vmx->nested.current_vmptr = vmptr; - vmx->nested.current_vmcs12 = new_vmcs12; - vmx->nested.current_vmcs12_page = page; - } - - nested_vmx_succeed(vcpu); - skip_emulated_instruction(vcpu); - return 1; -} - -/* Emulate the VMPTRST instruction */ -static int handle_vmptrst(struct kvm_vcpu *vcpu) -{ - unsigned long exit_qualification = vmcs_readl(EXIT_QUALIFICATION); - u32 vmx_instruction_info = vmcs_read32(VMX_INSTRUCTION_INFO); - gva_t vmcs_gva; - struct x86_exception e; - - if (!nested_vmx_check_permission(vcpu)) - return 1; - - if (get_vmx_mem_address(vcpu, exit_qualification, - vmx_instruction_info, &vmcs_gva)) - return 1; - /* ok to use *_system, as nested_vmx_check_permission verified cpl=0 */ - if (kvm_write_guest_virt_system(&vcpu->arch.emulate_ctxt, vmcs_gva, - (void *)&to_vmx(vcpu)->nested.current_vmptr, - sizeof(u64), &e)) { - kvm_inject_page_fault(vcpu, &e); - return 1; - } - nested_vmx_succeed(vcpu); - skip_emulated_instruction(vcpu); - return 1; -} - -/* - * The exit handlers return 1 if the exit was handled fully and guest execution - * may resume. Otherwise they set the kvm_run parameter to indicate what needs - * to be done to userspace and return 0. - */ -static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu) = { - [EXIT_REASON_EXCEPTION_NMI] = handle_exception, - [EXIT_REASON_EXTERNAL_INTERRUPT] = handle_external_interrupt, - [EXIT_REASON_TRIPLE_FAULT] = handle_triple_fault, - [EXIT_REASON_NMI_WINDOW] = handle_nmi_window, - [EXIT_REASON_IO_INSTRUCTION] = handle_io, - [EXIT_REASON_CR_ACCESS] = handle_cr, - [EXIT_REASON_DR_ACCESS] = handle_dr, - [EXIT_REASON_CPUID] = handle_cpuid, - [EXIT_REASON_MSR_READ] = handle_rdmsr, - [EXIT_REASON_MSR_WRITE] = handle_wrmsr, - [EXIT_REASON_PENDING_INTERRUPT] = handle_interrupt_window, - [EXIT_REASON_HLT] = handle_halt, - [EXIT_REASON_INVD] = handle_invd, - [EXIT_REASON_INVLPG] = handle_invlpg, - [EXIT_REASON_VMCALL] = handle_vmcall, - [EXIT_REASON_VMCLEAR] = handle_vmclear, - [EXIT_REASON_VMLAUNCH] = handle_vmlaunch, - [EXIT_REASON_VMPTRLD] = handle_vmptrld, - [EXIT_REASON_VMPTRST] = handle_vmptrst, - [EXIT_REASON_VMREAD] = handle_vmread, - [EXIT_REASON_VMRESUME] = handle_vmresume, - [EXIT_REASON_VMWRITE] = handle_vmwrite, - [EXIT_REASON_VMOFF] = handle_vmoff, - [EXIT_REASON_VMON] = handle_vmon, - [EXIT_REASON_TPR_BELOW_THRESHOLD] = handle_tpr_below_threshold, - [EXIT_REASON_APIC_ACCESS] = handle_apic_access, - [EXIT_REASON_WBINVD] = handle_wbinvd, - [EXIT_REASON_XSETBV] = handle_xsetbv, - [EXIT_REASON_TASK_SWITCH] = handle_task_switch, - [EXIT_REASON_MCE_DURING_VMENTRY] = handle_machine_check, - [EXIT_REASON_EPT_VIOLATION] = handle_ept_violation, - [EXIT_REASON_EPT_MISCONFIG] = handle_ept_misconfig, - [EXIT_REASON_PAUSE_INSTRUCTION] = handle_pause, - [EXIT_REASON_MWAIT_INSTRUCTION] = handle_invalid_op, - [EXIT_REASON_MONITOR_INSTRUCTION] = handle_invalid_op, -}; - -static const int kvm_vmx_max_exit_handlers = - ARRAY_SIZE(kvm_vmx_exit_handlers); - -/* - * Return 1 if we should exit from L2 to L1 to handle an MSR access access, - * rather than handle it ourselves in L0. I.e., check whether L1 expressed - * disinterest in the current event (read or write a specific MSR) by using an - * MSR bitmap. This may be the case even when L0 doesn't use MSR bitmaps. - */ -static bool nested_vmx_exit_handled_msr(struct kvm_vcpu *vcpu, - struct vmcs12 *vmcs12, u32 exit_reason) -{ - u32 msr_index = vcpu->arch.regs[VCPU_REGS_RCX]; - gpa_t bitmap; - - if (!nested_cpu_has(get_vmcs12(vcpu), CPU_BASED_USE_MSR_BITMAPS)) - return 1; - - /* - * The MSR_BITMAP page is divided into four 1024-byte bitmaps, - * for the four combinations of read/write and low/high MSR numbers. - * First we need to figure out which of the four to use: - */ - bitmap = vmcs12->msr_bitmap; - if (exit_reason == EXIT_REASON_MSR_WRITE) - bitmap += 2048; - if (msr_index >= 0xc0000000) { - msr_index -= 0xc0000000; - bitmap += 1024; - } - - /* Then read the msr_index'th bit from this bitmap: */ - if (msr_index < 1024*8) { - unsigned char b; - kvm_read_guest(vcpu->kvm, bitmap + msr_index/8, &b, 1); - return 1 & (b >> (msr_index & 7)); - } else - return 1; /* let L1 handle the wrong parameter */ -} - -/* - * Return 1 if we should exit from L2 to L1 to handle a CR access exit, - * rather than handle it ourselves in L0. I.e., check if L1 wanted to - * intercept (via guest_host_mask etc.) the current event. - */ -static bool nested_vmx_exit_handled_cr(struct kvm_vcpu *vcpu, - struct vmcs12 *vmcs12) -{ - unsigned long exit_qualification = vmcs_readl(EXIT_QUALIFICATION); - int cr = exit_qualification & 15; - int reg = (exit_qualification >> 8) & 15; - unsigned long val = kvm_register_read(vcpu, reg); - - switch ((exit_qualification >> 4) & 3) { - case 0: /* mov to cr */ - switch (cr) { - case 0: - if (vmcs12->cr0_guest_host_mask & - (val ^ vmcs12->cr0_read_shadow)) - return 1; - break; - case 3: - if ((vmcs12->cr3_target_count >= 1 && - vmcs12->cr3_target_value0 == val) || - (vmcs12->cr3_target_count >= 2 && - vmcs12->cr3_target_value1 == val) || - (vmcs12->cr3_target_count >= 3 && - vmcs12->cr3_target_value2 == val) || - (vmcs12->cr3_target_count >= 4 && - vmcs12->cr3_target_value3 == val)) - return 0; - if (nested_cpu_has(vmcs12, CPU_BASED_CR3_LOAD_EXITING)) - return 1; - break; - case 4: - if (vmcs12->cr4_guest_host_mask & - (vmcs12->cr4_read_shadow ^ val)) - return 1; - break; - case 8: - if (nested_cpu_has(vmcs12, CPU_BASED_CR8_LOAD_EXITING)) - return 1; - break; - } - break; - case 2: /* clts */ - if ((vmcs12->cr0_guest_host_mask & X86_CR0_TS) && - (vmcs12->cr0_read_shadow & X86_CR0_TS)) - return 1; - break; - case 1: /* mov from cr */ - switch (cr) { - case 3: - if (vmcs12->cpu_based_vm_exec_control & - CPU_BASED_CR3_STORE_EXITING) - return 1; - break; - case 8: - if (vmcs12->cpu_based_vm_exec_control & - CPU_BASED_CR8_STORE_EXITING) - return 1; - break; - } - break; - case 3: /* lmsw */ - /* - * lmsw can change bits 1..3 of cr0, and only set bit 0 of - * cr0. Other attempted changes are ignored, with no exit. - */ - if (vmcs12->cr0_guest_host_mask & 0xe & - (val ^ vmcs12->cr0_read_shadow)) - return 1; - if ((vmcs12->cr0_guest_host_mask & 0x1) && - !(vmcs12->cr0_read_shadow & 0x1) && - (val & 0x1)) - return 1; - break; - } - return 0; -} - -/* - * Return 1 if we should exit from L2 to L1 to handle an exit, or 0 if we - * should handle it ourselves in L0 (and then continue L2). Only call this - * when in is_guest_mode (L2). - */ -static bool nested_vmx_exit_handled(struct kvm_vcpu *vcpu) -{ - u32 exit_reason = vmcs_read32(VM_EXIT_REASON); - u32 intr_info = vmcs_read32(VM_EXIT_INTR_INFO); - struct vcpu_vmx *vmx = to_vmx(vcpu); - struct vmcs12 *vmcs12 = get_vmcs12(vcpu); - - if (vmx->nested.nested_run_pending) - return 0; - - if (unlikely(vmx->fail)) { - printk(KERN_INFO "%s failed vm entry %x\n", - __func__, vmcs_read32(VM_INSTRUCTION_ERROR)); - return 1; - } - - switch (exit_reason) { - case EXIT_REASON_EXCEPTION_NMI: - if (!is_exception(intr_info)) - return 0; - else if (is_page_fault(intr_info)) - return enable_ept; - return vmcs12->exception_bitmap & - (1u << (intr_info & INTR_INFO_VECTOR_MASK)); - case EXIT_REASON_EXTERNAL_INTERRUPT: - return 0; - case EXIT_REASON_TRIPLE_FAULT: - return 1; - case EXIT_REASON_PENDING_INTERRUPT: - case EXIT_REASON_NMI_WINDOW: - /* - * prepare_vmcs02() set the CPU_BASED_VIRTUAL_INTR_PENDING bit - * (aka Interrupt Window Exiting) only when L1 turned it on, - * so if we got a PENDING_INTERRUPT exit, this must be for L1. - * Same for NMI Window Exiting. - */ - return 1; - case EXIT_REASON_TASK_SWITCH: - return 1; - case EXIT_REASON_CPUID: - return 1; - case EXIT_REASON_HLT: - return nested_cpu_has(vmcs12, CPU_BASED_HLT_EXITING); - case EXIT_REASON_INVD: - return 1; - case EXIT_REASON_INVLPG: - return nested_cpu_has(vmcs12, CPU_BASED_INVLPG_EXITING); - case EXIT_REASON_RDPMC: - return nested_cpu_has(vmcs12, CPU_BASED_RDPMC_EXITING); - case EXIT_REASON_RDTSC: - return nested_cpu_has(vmcs12, CPU_BASED_RDTSC_EXITING); - case EXIT_REASON_VMCALL: case EXIT_REASON_VMCLEAR: - case EXIT_REASON_VMLAUNCH: case EXIT_REASON_VMPTRLD: - case EXIT_REASON_VMPTRST: case EXIT_REASON_VMREAD: - case EXIT_REASON_VMRESUME: case EXIT_REASON_VMWRITE: - case EXIT_REASON_VMOFF: case EXIT_REASON_VMON: - /* - * VMX instructions trap unconditionally. This allows L1 to - * emulate them for its L2 guest, i.e., allows 3-level nesting! - */ - return 1; - case EXIT_REASON_CR_ACCESS: - return nested_vmx_exit_handled_cr(vcpu, vmcs12); - case EXIT_REASON_DR_ACCESS: - return nested_cpu_has(vmcs12, CPU_BASED_MOV_DR_EXITING); - case EXIT_REASON_IO_INSTRUCTION: - /* TODO: support IO bitmaps */ - return 1; - case EXIT_REASON_MSR_READ: - case EXIT_REASON_MSR_WRITE: - return nested_vmx_exit_handled_msr(vcpu, vmcs12, exit_reason); - case EXIT_REASON_INVALID_STATE: - return 1; - case EXIT_REASON_MWAIT_INSTRUCTION: - return nested_cpu_has(vmcs12, CPU_BASED_MWAIT_EXITING); - case EXIT_REASON_MONITOR_INSTRUCTION: - return nested_cpu_has(vmcs12, CPU_BASED_MONITOR_EXITING); - case EXIT_REASON_PAUSE_INSTRUCTION: - return nested_cpu_has(vmcs12, CPU_BASED_PAUSE_EXITING) || - nested_cpu_has2(vmcs12, - SECONDARY_EXEC_PAUSE_LOOP_EXITING); - case EXIT_REASON_MCE_DURING_VMENTRY: - return 0; - case EXIT_REASON_TPR_BELOW_THRESHOLD: - return 1; - case EXIT_REASON_APIC_ACCESS: - return nested_cpu_has2(vmcs12, - SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES); - case EXIT_REASON_EPT_VIOLATION: - case EXIT_REASON_EPT_MISCONFIG: - return 0; - case EXIT_REASON_WBINVD: - return nested_cpu_has2(vmcs12, SECONDARY_EXEC_WBINVD_EXITING); - case EXIT_REASON_XSETBV: - return 1; - default: - return 1; - } -} - -static void vmx_get_exit_info(struct kvm_vcpu *vcpu, u64 *info1, u64 *info2) -{ - *info1 = vmcs_readl(EXIT_QUALIFICATION); - *info2 = vmcs_read32(VM_EXIT_INTR_INFO); -} - -/* - * The guest has exited. See if we can fix it or if we need userspace - * assistance. - */ -static int vmx_handle_exit(struct kvm_vcpu *vcpu) -{ - struct vcpu_vmx *vmx = to_vmx(vcpu); - u32 exit_reason = vmx->exit_reason; - u32 vectoring_info = vmx->idt_vectoring_info; - - trace_kvm_exit(exit_reason, vcpu, KVM_ISA_VMX); - - /* If guest state is invalid, start emulating */ - if (vmx->emulation_required && emulate_invalid_guest_state) - return handle_invalid_guest_state(vcpu); - - /* - * the KVM_REQ_EVENT optimization bit is only on for one entry, and if - * we did not inject a still-pending event to L1 now because of - * nested_run_pending, we need to re-enable this bit. - */ - if (vmx->nested.nested_run_pending) - kvm_make_request(KVM_REQ_EVENT, vcpu); - - if (!is_guest_mode(vcpu) && (exit_reason == EXIT_REASON_VMLAUNCH || - exit_reason == EXIT_REASON_VMRESUME)) - vmx->nested.nested_run_pending = 1; - else - vmx->nested.nested_run_pending = 0; - - if (is_guest_mode(vcpu) && nested_vmx_exit_handled(vcpu)) { - nested_vmx_vmexit(vcpu); - return 1; - } - - if (exit_reason & VMX_EXIT_REASONS_FAILED_VMENTRY) { - vcpu->run->exit_reason = KVM_EXIT_FAIL_ENTRY; - vcpu->run->fail_entry.hardware_entry_failure_reason - = exit_reason; - return 0; - } - - if (unlikely(vmx->fail)) { - vcpu->run->exit_reason = KVM_EXIT_FAIL_ENTRY; - vcpu->run->fail_entry.hardware_entry_failure_reason - = vmcs_read32(VM_INSTRUCTION_ERROR); - return 0; - } - - if ((vectoring_info & VECTORING_INFO_VALID_MASK) && - (exit_reason != EXIT_REASON_EXCEPTION_NMI && - exit_reason != EXIT_REASON_EPT_VIOLATION && - exit_reason != EXIT_REASON_TASK_SWITCH)) - printk(KERN_WARNING "%s: unexpected, valid vectoring info " - "(0x%x) and exit reason is 0x%x\n", - __func__, vectoring_info, exit_reason); - - if (unlikely(!cpu_has_virtual_nmis() && vmx->soft_vnmi_blocked && - !(is_guest_mode(vcpu) && nested_cpu_has_virtual_nmis( - get_vmcs12(vcpu), vcpu)))) { - if (vmx_interrupt_allowed(vcpu)) { - vmx->soft_vnmi_blocked = 0; - } else if (vmx->vnmi_blocked_time > 1000000000LL && - vcpu->arch.nmi_pending) { - /* - * This CPU don't support us in finding the end of an - * NMI-blocked window if the guest runs with IRQs - * disabled. So we pull the trigger after 1 s of - * futile waiting, but inform the user about this. - */ - printk(KERN_WARNING "%s: Breaking out of NMI-blocked " - "state on VCPU %d after 1 s timeout\n", - __func__, vcpu->vcpu_id); - vmx->soft_vnmi_blocked = 0; - } - } - - if (exit_reason < kvm_vmx_max_exit_handlers - && kvm_vmx_exit_handlers[exit_reason]) - return kvm_vmx_exit_handlers[exit_reason](vcpu); - else { - vcpu->run->exit_reason = KVM_EXIT_UNKNOWN; - vcpu->run->hw.hardware_exit_reason = exit_reason; - } - return 0; -} - -static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr) -{ - if (irr == -1 || tpr < irr) { - vmcs_write32(TPR_THRESHOLD, 0); - return; - } - - vmcs_write32(TPR_THRESHOLD, irr); -} - -static void vmx_complete_atomic_exit(struct vcpu_vmx *vmx) -{ - u32 exit_intr_info; - - if (!(vmx->exit_reason == EXIT_REASON_MCE_DURING_VMENTRY - || vmx->exit_reason == EXIT_REASON_EXCEPTION_NMI)) - return; - - vmx->exit_intr_info = vmcs_read32(VM_EXIT_INTR_INFO); - exit_intr_info = vmx->exit_intr_info; - - /* Handle machine checks before interrupts are enabled */ - if (is_machine_check(exit_intr_info)) - kvm_machine_check(); + /* Handle machine checks before interrupts are enabled */ + if (is_machine_check(exit_intr_info)) + kvm_machine_check(); /* We need to handle NMIs before interrupts are enabled */ if ((exit_intr_info & INTR_INFO_INTR_TYPE_MASK) == INTR_TYPE_NMI_INTR && @@ -5908,8 +4118,6 @@ static void __vmx_complete_interrupts(struct vcpu_vmx *vmx, static void vmx_complete_interrupts(struct vcpu_vmx *vmx) { - if (is_guest_mode(&vmx->vcpu)) - return; __vmx_complete_interrupts(vmx, vmx->idt_vectoring_info, VM_EXIT_INSTRUCTION_LEN, IDT_VECTORING_ERROR_CODE); @@ -5917,8 +4125,6 @@ static void vmx_complete_interrupts(struct vcpu_vmx *vmx) static void vmx_cancel_injection(struct kvm_vcpu *vcpu) { - if (is_guest_mode(vcpu)) - return; __vmx_complete_interrupts(to_vmx(vcpu), vmcs_read32(VM_ENTRY_INTR_INFO_FIELD), VM_ENTRY_INSTRUCTION_LEN, @@ -5939,21 +4145,6 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) { struct vcpu_vmx *vmx = to_vmx(vcpu); - if (is_guest_mode(vcpu) && !vmx->nested.nested_run_pending) { - struct vmcs12 *vmcs12 = get_vmcs12(vcpu); - if (vmcs12->idt_vectoring_info_field & - VECTORING_INFO_VALID_MASK) { - vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, - vmcs12->idt_vectoring_info_field); - vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, - vmcs12->vm_exit_instruction_len); - if (vmcs12->idt_vectoring_info_field & - VECTORING_INFO_DELIVER_CODE_MASK) - vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, - vmcs12->idt_vectoring_error_code); - } - } - /* Record the guest's net vcpu time for enforced NMI injections. */ if (unlikely(!cpu_has_virtual_nmis() && vmx->soft_vnmi_blocked)) vmx->entry_time = ktime_get(); @@ -5976,7 +4167,6 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) vmx_set_interrupt_shadow(vcpu, 0); - vmx->__launched = vmx->loaded_vmcs->launched; asm( /* Store host registers */ "push %%"R"dx; push %%"R"bp;" @@ -6047,7 +4237,7 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) "pop %%"R"bp; pop %%"R"dx \n\t" "setbe %c[fail](%0) \n\t" : : "c"(vmx), "d"((unsigned long)HOST_RSP), - [launched]"i"(offsetof(struct vcpu_vmx, __launched)), + [launched]"i"(offsetof(struct vcpu_vmx, launched)), [fail]"i"(offsetof(struct vcpu_vmx, fail)), [host_rsp]"i"(offsetof(struct vcpu_vmx, host_rsp)), [rax]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_RAX])), @@ -6086,19 +4276,8 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) vmx->idt_vectoring_info = vmcs_read32(IDT_VECTORING_INFO_FIELD); - if (is_guest_mode(vcpu)) { - struct vmcs12 *vmcs12 = get_vmcs12(vcpu); - vmcs12->idt_vectoring_info_field = vmx->idt_vectoring_info; - if (vmx->idt_vectoring_info & VECTORING_INFO_VALID_MASK) { - vmcs12->idt_vectoring_error_code = - vmcs_read32(IDT_VECTORING_ERROR_CODE); - vmcs12->vm_exit_instruction_len = - vmcs_read32(VM_EXIT_INSTRUCTION_LEN); - } - } - asm("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS)); - vmx->loaded_vmcs->launched = 1; + vmx->launched = 1; vmx->exit_reason = vmcs_read32(VM_EXIT_REASON); @@ -6110,18 +4289,41 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) #undef R #undef Q +static void vmx_free_vmcs(struct kvm_vcpu *vcpu) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + + if (vmx->vmcs) { + vcpu_clear(vmx); + free_vmcs(vmx->vmcs); + vmx->vmcs = NULL; + } +} + static void vmx_free_vcpu(struct kvm_vcpu *vcpu) { struct vcpu_vmx *vmx = to_vmx(vcpu); free_vpid(vmx); - free_nested(vmx); - free_loaded_vmcs(vmx->loaded_vmcs); + vmx_free_vmcs(vcpu); kfree(vmx->guest_msrs); kvm_vcpu_uninit(vcpu); kmem_cache_free(kvm_vcpu_cache, vmx); } +static inline void vmcs_init(struct vmcs *vmcs) +{ + u64 phys_addr = __pa(per_cpu(vmxarea, raw_smp_processor_id())); + + if (!vmm_exclusive) + kvm_cpu_vmxon(phys_addr); + + vmcs_clear(vmcs); + + if (!vmm_exclusive) + kvm_cpu_vmxoff(); +} + static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id) { int err; @@ -6143,15 +4345,11 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id) goto uninit_vcpu; } - vmx->loaded_vmcs = &vmx->vmcs01; - vmx->loaded_vmcs->vmcs = alloc_vmcs(); - if (!vmx->loaded_vmcs->vmcs) + vmx->vmcs = alloc_vmcs(); + if (!vmx->vmcs) goto free_msrs; - if (!vmm_exclusive) - kvm_cpu_vmxon(__pa(per_cpu(vmxarea, raw_smp_processor_id()))); - loaded_vmcs_init(vmx->loaded_vmcs); - if (!vmm_exclusive) - kvm_cpu_vmxoff(); + + vmcs_init(vmx->vmcs); cpu = get_cpu(); vmx_vcpu_load(&vmx->vcpu, cpu); @@ -6177,13 +4375,10 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id) goto free_vmcs; } - vmx->nested.current_vmptr = -1ull; - vmx->nested.current_vmcs12 = NULL; - return &vmx->vcpu; free_vmcs: - free_vmcs(vmx->loaded_vmcs->vmcs); + free_vmcs(vmx->vmcs); free_msrs: kfree(vmx->guest_msrs); uninit_vcpu: @@ -6317,650 +4512,6 @@ static void vmx_cpuid_update(struct kvm_vcpu *vcpu) static void vmx_set_supported_cpuid(u32 func, struct kvm_cpuid_entry2 *entry) { - if (func == 1 && nested) - entry->ecx |= bit(X86_FEATURE_VMX); -} - -/* - * prepare_vmcs02 is called when the L1 guest hypervisor runs its nested - * L2 guest. L1 has a vmcs for L2 (vmcs12), and this function "merges" it - * with L0's requirements for its guest (a.k.a. vmsc01), so we can run the L2 - * guest in a way that will both be appropriate to L1's requests, and our - * needs. In addition to modifying the active vmcs (which is vmcs02), this - * function also has additional necessary side-effects, like setting various - * vcpu->arch fields. - */ -static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) -{ - struct vcpu_vmx *vmx = to_vmx(vcpu); - u32 exec_control; - - vmcs_write16(GUEST_ES_SELECTOR, vmcs12->guest_es_selector); - vmcs_write16(GUEST_CS_SELECTOR, vmcs12->guest_cs_selector); - vmcs_write16(GUEST_SS_SELECTOR, vmcs12->guest_ss_selector); - vmcs_write16(GUEST_DS_SELECTOR, vmcs12->guest_ds_selector); - vmcs_write16(GUEST_FS_SELECTOR, vmcs12->guest_fs_selector); - vmcs_write16(GUEST_GS_SELECTOR, vmcs12->guest_gs_selector); - vmcs_write16(GUEST_LDTR_SELECTOR, vmcs12->guest_ldtr_selector); - vmcs_write16(GUEST_TR_SELECTOR, vmcs12->guest_tr_selector); - vmcs_write32(GUEST_ES_LIMIT, vmcs12->guest_es_limit); - vmcs_write32(GUEST_CS_LIMIT, vmcs12->guest_cs_limit); - vmcs_write32(GUEST_SS_LIMIT, vmcs12->guest_ss_limit); - vmcs_write32(GUEST_DS_LIMIT, vmcs12->guest_ds_limit); - vmcs_write32(GUEST_FS_LIMIT, vmcs12->guest_fs_limit); - vmcs_write32(GUEST_GS_LIMIT, vmcs12->guest_gs_limit); - vmcs_write32(GUEST_LDTR_LIMIT, vmcs12->guest_ldtr_limit); - vmcs_write32(GUEST_TR_LIMIT, vmcs12->guest_tr_limit); - vmcs_write32(GUEST_GDTR_LIMIT, vmcs12->guest_gdtr_limit); - vmcs_write32(GUEST_IDTR_LIMIT, vmcs12->guest_idtr_limit); - vmcs_write32(GUEST_ES_AR_BYTES, vmcs12->guest_es_ar_bytes); - vmcs_write32(GUEST_CS_AR_BYTES, vmcs12->guest_cs_ar_bytes); - vmcs_write32(GUEST_SS_AR_BYTES, vmcs12->guest_ss_ar_bytes); - vmcs_write32(GUEST_DS_AR_BYTES, vmcs12->guest_ds_ar_bytes); - vmcs_write32(GUEST_FS_AR_BYTES, vmcs12->guest_fs_ar_bytes); - vmcs_write32(GUEST_GS_AR_BYTES, vmcs12->guest_gs_ar_bytes); - vmcs_write32(GUEST_LDTR_AR_BYTES, vmcs12->guest_ldtr_ar_bytes); - vmcs_write32(GUEST_TR_AR_BYTES, vmcs12->guest_tr_ar_bytes); - vmcs_writel(GUEST_ES_BASE, vmcs12->guest_es_base); - vmcs_writel(GUEST_CS_BASE, vmcs12->guest_cs_base); - vmcs_writel(GUEST_SS_BASE, vmcs12->guest_ss_base); - vmcs_writel(GUEST_DS_BASE, vmcs12->guest_ds_base); - vmcs_writel(GUEST_FS_BASE, vmcs12->guest_fs_base); - vmcs_writel(GUEST_GS_BASE, vmcs12->guest_gs_base); - vmcs_writel(GUEST_LDTR_BASE, vmcs12->guest_ldtr_base); - vmcs_writel(GUEST_TR_BASE, vmcs12->guest_tr_base); - vmcs_writel(GUEST_GDTR_BASE, vmcs12->guest_gdtr_base); - vmcs_writel(GUEST_IDTR_BASE, vmcs12->guest_idtr_base); - - vmcs_write64(GUEST_IA32_DEBUGCTL, vmcs12->guest_ia32_debugctl); - vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, - vmcs12->vm_entry_intr_info_field); - vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, - vmcs12->vm_entry_exception_error_code); - vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, - vmcs12->vm_entry_instruction_len); - vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, - vmcs12->guest_interruptibility_info); - vmcs_write32(GUEST_ACTIVITY_STATE, vmcs12->guest_activity_state); - vmcs_write32(GUEST_SYSENTER_CS, vmcs12->guest_sysenter_cs); - vmcs_writel(GUEST_DR7, vmcs12->guest_dr7); - vmcs_writel(GUEST_RFLAGS, vmcs12->guest_rflags); - vmcs_writel(GUEST_PENDING_DBG_EXCEPTIONS, - vmcs12->guest_pending_dbg_exceptions); - vmcs_writel(GUEST_SYSENTER_ESP, vmcs12->guest_sysenter_esp); - vmcs_writel(GUEST_SYSENTER_EIP, vmcs12->guest_sysenter_eip); - - vmcs_write64(VMCS_LINK_POINTER, -1ull); - - vmcs_write32(PIN_BASED_VM_EXEC_CONTROL, - (vmcs_config.pin_based_exec_ctrl | - vmcs12->pin_based_vm_exec_control)); - - /* - * Whether page-faults are trapped is determined by a combination of - * 3 settings: PFEC_MASK, PFEC_MATCH and EXCEPTION_BITMAP.PF. - * If enable_ept, L0 doesn't care about page faults and we should - * set all of these to L1's desires. However, if !enable_ept, L0 does - * care about (at least some) page faults, and because it is not easy - * (if at all possible?) to merge L0 and L1's desires, we simply ask - * to exit on each and every L2 page fault. This is done by setting - * MASK=MATCH=0 and (see below) EB.PF=1. - * Note that below we don't need special code to set EB.PF beyond the - * "or"ing of the EB of vmcs01 and vmcs12, because when enable_ept, - * vmcs01's EB.PF is 0 so the "or" will take vmcs12's value, and when - * !enable_ept, EB.PF is 1, so the "or" will always be 1. - * - * A problem with this approach (when !enable_ept) is that L1 may be - * injected with more page faults than it asked for. This could have - * caused problems, but in practice existing hypervisors don't care. - * To fix this, we will need to emulate the PFEC checking (on the L1 - * page tables), using walk_addr(), when injecting PFs to L1. - */ - vmcs_write32(PAGE_FAULT_ERROR_CODE_MASK, - enable_ept ? vmcs12->page_fault_error_code_mask : 0); - vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, - enable_ept ? vmcs12->page_fault_error_code_match : 0); - - if (cpu_has_secondary_exec_ctrls()) { - u32 exec_control = vmx_secondary_exec_control(vmx); - if (!vmx->rdtscp_enabled) - exec_control &= ~SECONDARY_EXEC_RDTSCP; - /* Take the following fields only from vmcs12 */ - exec_control &= ~SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES; - if (nested_cpu_has(vmcs12, - CPU_BASED_ACTIVATE_SECONDARY_CONTROLS)) - exec_control |= vmcs12->secondary_vm_exec_control; - - if (exec_control & SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES) { - /* - * Translate L1 physical address to host physical - * address for vmcs02. Keep the page pinned, so this - * physical address remains valid. We keep a reference - * to it so we can release it later. - */ - if (vmx->nested.apic_access_page) /* shouldn't happen */ - nested_release_page(vmx->nested.apic_access_page); - vmx->nested.apic_access_page = - nested_get_page(vcpu, vmcs12->apic_access_addr); - /* - * If translation failed, no matter: This feature asks - * to exit when accessing the given address, and if it - * can never be accessed, this feature won't do - * anything anyway. - */ - if (!vmx->nested.apic_access_page) - exec_control &= - ~SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES; - else - vmcs_write64(APIC_ACCESS_ADDR, - page_to_phys(vmx->nested.apic_access_page)); - } - - vmcs_write32(SECONDARY_VM_EXEC_CONTROL, exec_control); - } - - - /* - * Set host-state according to L0's settings (vmcs12 is irrelevant here) - * Some constant fields are set here by vmx_set_constant_host_state(). - * Other fields are different per CPU, and will be set later when - * vmx_vcpu_load() is called, and when vmx_save_host_state() is called. - */ - vmx_set_constant_host_state(); - - /* - * HOST_RSP is normally set correctly in vmx_vcpu_run() just before - * entry, but only if the current (host) sp changed from the value - * we wrote last (vmx->host_rsp). This cache is no longer relevant - * if we switch vmcs, and rather than hold a separate cache per vmcs, - * here we just force the write to happen on entry. - */ - vmx->host_rsp = 0; - - exec_control = vmx_exec_control(vmx); /* L0's desires */ - exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING; - exec_control &= ~CPU_BASED_VIRTUAL_NMI_PENDING; - exec_control &= ~CPU_BASED_TPR_SHADOW; - exec_control |= vmcs12->cpu_based_vm_exec_control; - /* - * Merging of IO and MSR bitmaps not currently supported. - * Rather, exit every time. - */ - exec_control &= ~CPU_BASED_USE_MSR_BITMAPS; - exec_control &= ~CPU_BASED_USE_IO_BITMAPS; - exec_control |= CPU_BASED_UNCOND_IO_EXITING; - - vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, exec_control); - - /* EXCEPTION_BITMAP and CR0_GUEST_HOST_MASK should basically be the - * bitwise-or of what L1 wants to trap for L2, and what we want to - * trap. Note that CR0.TS also needs updating - we do this later. - */ - update_exception_bitmap(vcpu); - vcpu->arch.cr0_guest_owned_bits &= ~vmcs12->cr0_guest_host_mask; - vmcs_writel(CR0_GUEST_HOST_MASK, ~vcpu->arch.cr0_guest_owned_bits); - - /* Note: IA32_MODE, LOAD_IA32_EFER are modified by vmx_set_efer below */ - vmcs_write32(VM_EXIT_CONTROLS, - vmcs12->vm_exit_controls | vmcs_config.vmexit_ctrl); - vmcs_write32(VM_ENTRY_CONTROLS, vmcs12->vm_entry_controls | - (vmcs_config.vmentry_ctrl & ~VM_ENTRY_IA32E_MODE)); - - if (vmcs12->vm_entry_controls & VM_ENTRY_LOAD_IA32_PAT) - vmcs_write64(GUEST_IA32_PAT, vmcs12->guest_ia32_pat); - else if (vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_IA32_PAT) - vmcs_write64(GUEST_IA32_PAT, vmx->vcpu.arch.pat); - - - set_cr4_guest_host_mask(vmx); - - vmcs_write64(TSC_OFFSET, - vmx->nested.vmcs01_tsc_offset + vmcs12->tsc_offset); - - if (enable_vpid) { - /* - * Trivially support vpid by letting L2s share their parent - * L1's vpid. TODO: move to a more elaborate solution, giving - * each L2 its own vpid and exposing the vpid feature to L1. - */ - vmcs_write16(VIRTUAL_PROCESSOR_ID, vmx->vpid); - vmx_flush_tlb(vcpu); - } - - if (vmcs12->vm_entry_controls & VM_ENTRY_LOAD_IA32_EFER) - vcpu->arch.efer = vmcs12->guest_ia32_efer; - if (vmcs12->vm_entry_controls & VM_ENTRY_IA32E_MODE) - vcpu->arch.efer |= (EFER_LMA | EFER_LME); - else - vcpu->arch.efer &= ~(EFER_LMA | EFER_LME); - /* Note: modifies VM_ENTRY/EXIT_CONTROLS and GUEST/HOST_IA32_EFER */ - vmx_set_efer(vcpu, vcpu->arch.efer); - - /* - * This sets GUEST_CR0 to vmcs12->guest_cr0, with possibly a modified - * TS bit (for lazy fpu) and bits which we consider mandatory enabled. - * The CR0_READ_SHADOW is what L2 should have expected to read given - * the specifications by L1; It's not enough to take - * vmcs12->cr0_read_shadow because on our cr0_guest_host_mask we we - * have more bits than L1 expected. - */ - vmx_set_cr0(vcpu, vmcs12->guest_cr0); - vmcs_writel(CR0_READ_SHADOW, nested_read_cr0(vmcs12)); - - vmx_set_cr4(vcpu, vmcs12->guest_cr4); - vmcs_writel(CR4_READ_SHADOW, nested_read_cr4(vmcs12)); - - /* shadow page tables on either EPT or shadow page tables */ - kvm_set_cr3(vcpu, vmcs12->guest_cr3); - kvm_mmu_reset_context(vcpu); - - kvm_register_write(vcpu, VCPU_REGS_RSP, vmcs12->guest_rsp); - kvm_register_write(vcpu, VCPU_REGS_RIP, vmcs12->guest_rip); -} - -/* - * nested_vmx_run() handles a nested entry, i.e., a VMLAUNCH or VMRESUME on L1 - * for running an L2 nested guest. - */ -static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) -{ - struct vmcs12 *vmcs12; - struct vcpu_vmx *vmx = to_vmx(vcpu); - int cpu; - struct loaded_vmcs *vmcs02; - - if (!nested_vmx_check_permission(vcpu) || - !nested_vmx_check_vmcs12(vcpu)) - return 1; - - skip_emulated_instruction(vcpu); - vmcs12 = get_vmcs12(vcpu); - - /* - * The nested entry process starts with enforcing various prerequisites - * on vmcs12 as required by the Intel SDM, and act appropriately when - * they fail: As the SDM explains, some conditions should cause the - * instruction to fail, while others will cause the instruction to seem - * to succeed, but return an EXIT_REASON_INVALID_STATE. - * To speed up the normal (success) code path, we should avoid checking - * for misconfigurations which will anyway be caught by the processor - * when using the merged vmcs02. - */ - if (vmcs12->launch_state == launch) { - nested_vmx_failValid(vcpu, - launch ? VMXERR_VMLAUNCH_NONCLEAR_VMCS - : VMXERR_VMRESUME_NONLAUNCHED_VMCS); - return 1; - } - - if ((vmcs12->cpu_based_vm_exec_control & CPU_BASED_USE_MSR_BITMAPS) && - !IS_ALIGNED(vmcs12->msr_bitmap, PAGE_SIZE)) { - /*TODO: Also verify bits beyond physical address width are 0*/ - nested_vmx_failValid(vcpu, VMXERR_ENTRY_INVALID_CONTROL_FIELD); - return 1; - } - - if (nested_cpu_has2(vmcs12, SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES) && - !IS_ALIGNED(vmcs12->apic_access_addr, PAGE_SIZE)) { - /*TODO: Also verify bits beyond physical address width are 0*/ - nested_vmx_failValid(vcpu, VMXERR_ENTRY_INVALID_CONTROL_FIELD); - return 1; - } - - if (vmcs12->vm_entry_msr_load_count > 0 || - vmcs12->vm_exit_msr_load_count > 0 || - vmcs12->vm_exit_msr_store_count > 0) { - if (printk_ratelimit()) - printk(KERN_WARNING - "%s: VMCS MSR_{LOAD,STORE} unsupported\n", __func__); - nested_vmx_failValid(vcpu, VMXERR_ENTRY_INVALID_CONTROL_FIELD); - return 1; - } - - if (!vmx_control_verify(vmcs12->cpu_based_vm_exec_control, - nested_vmx_procbased_ctls_low, nested_vmx_procbased_ctls_high) || - !vmx_control_verify(vmcs12->secondary_vm_exec_control, - nested_vmx_secondary_ctls_low, nested_vmx_secondary_ctls_high) || - !vmx_control_verify(vmcs12->pin_based_vm_exec_control, - nested_vmx_pinbased_ctls_low, nested_vmx_pinbased_ctls_high) || - !vmx_control_verify(vmcs12->vm_exit_controls, - nested_vmx_exit_ctls_low, nested_vmx_exit_ctls_high) || - !vmx_control_verify(vmcs12->vm_entry_controls, - nested_vmx_entry_ctls_low, nested_vmx_entry_ctls_high)) - { - nested_vmx_failValid(vcpu, VMXERR_ENTRY_INVALID_CONTROL_FIELD); - return 1; - } - - if (((vmcs12->host_cr0 & VMXON_CR0_ALWAYSON) != VMXON_CR0_ALWAYSON) || - ((vmcs12->host_cr4 & VMXON_CR4_ALWAYSON) != VMXON_CR4_ALWAYSON)) { - nested_vmx_failValid(vcpu, - VMXERR_ENTRY_INVALID_HOST_STATE_FIELD); - return 1; - } - - if (((vmcs12->guest_cr0 & VMXON_CR0_ALWAYSON) != VMXON_CR0_ALWAYSON) || - ((vmcs12->guest_cr4 & VMXON_CR4_ALWAYSON) != VMXON_CR4_ALWAYSON)) { - nested_vmx_entry_failure(vcpu, vmcs12, - EXIT_REASON_INVALID_STATE, ENTRY_FAIL_DEFAULT); - return 1; - } - if (vmcs12->vmcs_link_pointer != -1ull) { - nested_vmx_entry_failure(vcpu, vmcs12, - EXIT_REASON_INVALID_STATE, ENTRY_FAIL_VMCS_LINK_PTR); - return 1; - } - - /* - * We're finally done with prerequisite checking, and can start with - * the nested entry. - */ - - vmcs02 = nested_get_current_vmcs02(vmx); - if (!vmcs02) - return -ENOMEM; - - enter_guest_mode(vcpu); - - vmx->nested.vmcs01_tsc_offset = vmcs_read64(TSC_OFFSET); - - cpu = get_cpu(); - vmx->loaded_vmcs = vmcs02; - vmx_vcpu_put(vcpu); - vmx_vcpu_load(vcpu, cpu); - vcpu->cpu = cpu; - put_cpu(); - - vmcs12->launch_state = 1; - - prepare_vmcs02(vcpu, vmcs12); - - /* - * Note no nested_vmx_succeed or nested_vmx_fail here. At this point - * we are no longer running L1, and VMLAUNCH/VMRESUME has not yet - * returned as far as L1 is concerned. It will only return (and set - * the success flag) when L2 exits (see nested_vmx_vmexit()). - */ - return 1; -} - -/* - * On a nested exit from L2 to L1, vmcs12.guest_cr0 might not be up-to-date - * because L2 may have changed some cr0 bits directly (CRO_GUEST_HOST_MASK). - * This function returns the new value we should put in vmcs12.guest_cr0. - * It's not enough to just return the vmcs02 GUEST_CR0. Rather, - * 1. Bits that neither L0 nor L1 trapped, were set directly by L2 and are now - * available in vmcs02 GUEST_CR0. (Note: It's enough to check that L0 - * didn't trap the bit, because if L1 did, so would L0). - * 2. Bits that L1 asked to trap (and therefore L0 also did) could not have - * been modified by L2, and L1 knows it. So just leave the old value of - * the bit from vmcs12.guest_cr0. Note that the bit from vmcs02 GUEST_CR0 - * isn't relevant, because if L0 traps this bit it can set it to anything. - * 3. Bits that L1 didn't trap, but L0 did. L1 believes the guest could have - * changed these bits, and therefore they need to be updated, but L0 - * didn't necessarily allow them to be changed in GUEST_CR0 - and rather - * put them in vmcs02 CR0_READ_SHADOW. So take these bits from there. - */ -static inline unsigned long -vmcs12_guest_cr0(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) -{ - return - /*1*/ (vmcs_readl(GUEST_CR0) & vcpu->arch.cr0_guest_owned_bits) | - /*2*/ (vmcs12->guest_cr0 & vmcs12->cr0_guest_host_mask) | - /*3*/ (vmcs_readl(CR0_READ_SHADOW) & ~(vmcs12->cr0_guest_host_mask | - vcpu->arch.cr0_guest_owned_bits)); -} - -static inline unsigned long -vmcs12_guest_cr4(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) -{ - return - /*1*/ (vmcs_readl(GUEST_CR4) & vcpu->arch.cr4_guest_owned_bits) | - /*2*/ (vmcs12->guest_cr4 & vmcs12->cr4_guest_host_mask) | - /*3*/ (vmcs_readl(CR4_READ_SHADOW) & ~(vmcs12->cr4_guest_host_mask | - vcpu->arch.cr4_guest_owned_bits)); -} - -/* - * prepare_vmcs12 is part of what we need to do when the nested L2 guest exits - * and we want to prepare to run its L1 parent. L1 keeps a vmcs for L2 (vmcs12), - * and this function updates it to reflect the changes to the guest state while - * L2 was running (and perhaps made some exits which were handled directly by L0 - * without going back to L1), and to reflect the exit reason. - * Note that we do not have to copy here all VMCS fields, just those that - * could have changed by the L2 guest or the exit - i.e., the guest-state and - * exit-information fields only. Other fields are modified by L1 with VMWRITE, - * which already writes to vmcs12 directly. - */ -void prepare_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) -{ - /* update guest state fields: */ - vmcs12->guest_cr0 = vmcs12_guest_cr0(vcpu, vmcs12); - vmcs12->guest_cr4 = vmcs12_guest_cr4(vcpu, vmcs12); - - kvm_get_dr(vcpu, 7, (unsigned long *)&vmcs12->guest_dr7); - vmcs12->guest_rsp = kvm_register_read(vcpu, VCPU_REGS_RSP); - vmcs12->guest_rip = kvm_register_read(vcpu, VCPU_REGS_RIP); - vmcs12->guest_rflags = vmcs_readl(GUEST_RFLAGS); - - vmcs12->guest_es_selector = vmcs_read16(GUEST_ES_SELECTOR); - vmcs12->guest_cs_selector = vmcs_read16(GUEST_CS_SELECTOR); - vmcs12->guest_ss_selector = vmcs_read16(GUEST_SS_SELECTOR); - vmcs12->guest_ds_selector = vmcs_read16(GUEST_DS_SELECTOR); - vmcs12->guest_fs_selector = vmcs_read16(GUEST_FS_SELECTOR); - vmcs12->guest_gs_selector = vmcs_read16(GUEST_GS_SELECTOR); - vmcs12->guest_ldtr_selector = vmcs_read16(GUEST_LDTR_SELECTOR); - vmcs12->guest_tr_selector = vmcs_read16(GUEST_TR_SELECTOR); - vmcs12->guest_es_limit = vmcs_read32(GUEST_ES_LIMIT); - vmcs12->guest_cs_limit = vmcs_read32(GUEST_CS_LIMIT); - vmcs12->guest_ss_limit = vmcs_read32(GUEST_SS_LIMIT); - vmcs12->guest_ds_limit = vmcs_read32(GUEST_DS_LIMIT); - vmcs12->guest_fs_limit = vmcs_read32(GUEST_FS_LIMIT); - vmcs12->guest_gs_limit = vmcs_read32(GUEST_GS_LIMIT); - vmcs12->guest_ldtr_limit = vmcs_read32(GUEST_LDTR_LIMIT); - vmcs12->guest_tr_limit = vmcs_read32(GUEST_TR_LIMIT); - vmcs12->guest_gdtr_limit = vmcs_read32(GUEST_GDTR_LIMIT); - vmcs12->guest_idtr_limit = vmcs_read32(GUEST_IDTR_LIMIT); - vmcs12->guest_es_ar_bytes = vmcs_read32(GUEST_ES_AR_BYTES); - vmcs12->guest_cs_ar_bytes = vmcs_read32(GUEST_CS_AR_BYTES); - vmcs12->guest_ss_ar_bytes = vmcs_read32(GUEST_SS_AR_BYTES); - vmcs12->guest_ds_ar_bytes = vmcs_read32(GUEST_DS_AR_BYTES); - vmcs12->guest_fs_ar_bytes = vmcs_read32(GUEST_FS_AR_BYTES); - vmcs12->guest_gs_ar_bytes = vmcs_read32(GUEST_GS_AR_BYTES); - vmcs12->guest_ldtr_ar_bytes = vmcs_read32(GUEST_LDTR_AR_BYTES); - vmcs12->guest_tr_ar_bytes = vmcs_read32(GUEST_TR_AR_BYTES); - vmcs12->guest_es_base = vmcs_readl(GUEST_ES_BASE); - vmcs12->guest_cs_base = vmcs_readl(GUEST_CS_BASE); - vmcs12->guest_ss_base = vmcs_readl(GUEST_SS_BASE); - vmcs12->guest_ds_base = vmcs_readl(GUEST_DS_BASE); - vmcs12->guest_fs_base = vmcs_readl(GUEST_FS_BASE); - vmcs12->guest_gs_base = vmcs_readl(GUEST_GS_BASE); - vmcs12->guest_ldtr_base = vmcs_readl(GUEST_LDTR_BASE); - vmcs12->guest_tr_base = vmcs_readl(GUEST_TR_BASE); - vmcs12->guest_gdtr_base = vmcs_readl(GUEST_GDTR_BASE); - vmcs12->guest_idtr_base = vmcs_readl(GUEST_IDTR_BASE); - - vmcs12->guest_activity_state = vmcs_read32(GUEST_ACTIVITY_STATE); - vmcs12->guest_interruptibility_info = - vmcs_read32(GUEST_INTERRUPTIBILITY_INFO); - vmcs12->guest_pending_dbg_exceptions = - vmcs_readl(GUEST_PENDING_DBG_EXCEPTIONS); - - /* TODO: These cannot have changed unless we have MSR bitmaps and - * the relevant bit asks not to trap the change */ - vmcs12->guest_ia32_debugctl = vmcs_read64(GUEST_IA32_DEBUGCTL); - if (vmcs12->vm_entry_controls & VM_EXIT_SAVE_IA32_PAT) - vmcs12->guest_ia32_pat = vmcs_read64(GUEST_IA32_PAT); - vmcs12->guest_sysenter_cs = vmcs_read32(GUEST_SYSENTER_CS); - vmcs12->guest_sysenter_esp = vmcs_readl(GUEST_SYSENTER_ESP); - vmcs12->guest_sysenter_eip = vmcs_readl(GUEST_SYSENTER_EIP); - - /* update exit information fields: */ - - vmcs12->vm_exit_reason = vmcs_read32(VM_EXIT_REASON); - vmcs12->exit_qualification = vmcs_readl(EXIT_QUALIFICATION); - - vmcs12->vm_exit_intr_info = vmcs_read32(VM_EXIT_INTR_INFO); - vmcs12->vm_exit_intr_error_code = vmcs_read32(VM_EXIT_INTR_ERROR_CODE); - vmcs12->idt_vectoring_info_field = - vmcs_read32(IDT_VECTORING_INFO_FIELD); - vmcs12->idt_vectoring_error_code = - vmcs_read32(IDT_VECTORING_ERROR_CODE); - vmcs12->vm_exit_instruction_len = vmcs_read32(VM_EXIT_INSTRUCTION_LEN); - vmcs12->vmx_instruction_info = vmcs_read32(VMX_INSTRUCTION_INFO); - - /* clear vm-entry fields which are to be cleared on exit */ - if (!(vmcs12->vm_exit_reason & VMX_EXIT_REASONS_FAILED_VMENTRY)) - vmcs12->vm_entry_intr_info_field &= ~INTR_INFO_VALID_MASK; -} - -/* - * A part of what we need to when the nested L2 guest exits and we want to - * run its L1 parent, is to reset L1's guest state to the host state specified - * in vmcs12. - * This function is to be called not only on normal nested exit, but also on - * a nested entry failure, as explained in Intel's spec, 3B.23.7 ("VM-Entry - * Failures During or After Loading Guest State"). - * This function should be called when the active VMCS is L1's (vmcs01). - */ -void load_vmcs12_host_state(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) -{ - if (vmcs12->vm_exit_controls & VM_EXIT_LOAD_IA32_EFER) - vcpu->arch.efer = vmcs12->host_ia32_efer; - if (vmcs12->vm_exit_controls & VM_EXIT_HOST_ADDR_SPACE_SIZE) - vcpu->arch.efer |= (EFER_LMA | EFER_LME); - else - vcpu->arch.efer &= ~(EFER_LMA | EFER_LME); - vmx_set_efer(vcpu, vcpu->arch.efer); - - kvm_register_write(vcpu, VCPU_REGS_RSP, vmcs12->host_rsp); - kvm_register_write(vcpu, VCPU_REGS_RIP, vmcs12->host_rip); - /* - * Note that calling vmx_set_cr0 is important, even if cr0 hasn't - * actually changed, because it depends on the current state of - * fpu_active (which may have changed). - * Note that vmx_set_cr0 refers to efer set above. - */ - kvm_set_cr0(vcpu, vmcs12->host_cr0); - /* - * If we did fpu_activate()/fpu_deactivate() during L2's run, we need - * to apply the same changes to L1's vmcs. We just set cr0 correctly, - * but we also need to update cr0_guest_host_mask and exception_bitmap. - */ - update_exception_bitmap(vcpu); - vcpu->arch.cr0_guest_owned_bits = (vcpu->fpu_active ? X86_CR0_TS : 0); - vmcs_writel(CR0_GUEST_HOST_MASK, ~vcpu->arch.cr0_guest_owned_bits); - - /* - * Note that CR4_GUEST_HOST_MASK is already set in the original vmcs01 - * (KVM doesn't change it)- no reason to call set_cr4_guest_host_mask(); - */ - vcpu->arch.cr4_guest_owned_bits = ~vmcs_readl(CR4_GUEST_HOST_MASK); - kvm_set_cr4(vcpu, vmcs12->host_cr4); - - /* shadow page tables on either EPT or shadow page tables */ - kvm_set_cr3(vcpu, vmcs12->host_cr3); - kvm_mmu_reset_context(vcpu); - - if (enable_vpid) { - /* - * Trivially support vpid by letting L2s share their parent - * L1's vpid. TODO: move to a more elaborate solution, giving - * each L2 its own vpid and exposing the vpid feature to L1. - */ - vmx_flush_tlb(vcpu); - } - - - vmcs_write32(GUEST_SYSENTER_CS, vmcs12->host_ia32_sysenter_cs); - vmcs_writel(GUEST_SYSENTER_ESP, vmcs12->host_ia32_sysenter_esp); - vmcs_writel(GUEST_SYSENTER_EIP, vmcs12->host_ia32_sysenter_eip); - vmcs_writel(GUEST_IDTR_BASE, vmcs12->host_idtr_base); - vmcs_writel(GUEST_GDTR_BASE, vmcs12->host_gdtr_base); - vmcs_writel(GUEST_TR_BASE, vmcs12->host_tr_base); - vmcs_writel(GUEST_GS_BASE, vmcs12->host_gs_base); - vmcs_writel(GUEST_FS_BASE, vmcs12->host_fs_base); - vmcs_write16(GUEST_ES_SELECTOR, vmcs12->host_es_selector); - vmcs_write16(GUEST_CS_SELECTOR, vmcs12->host_cs_selector); - vmcs_write16(GUEST_SS_SELECTOR, vmcs12->host_ss_selector); - vmcs_write16(GUEST_DS_SELECTOR, vmcs12->host_ds_selector); - vmcs_write16(GUEST_FS_SELECTOR, vmcs12->host_fs_selector); - vmcs_write16(GUEST_GS_SELECTOR, vmcs12->host_gs_selector); - vmcs_write16(GUEST_TR_SELECTOR, vmcs12->host_tr_selector); - - if (vmcs12->vm_exit_controls & VM_EXIT_LOAD_IA32_PAT) - vmcs_write64(GUEST_IA32_PAT, vmcs12->host_ia32_pat); - if (vmcs12->vm_exit_controls & VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL) - vmcs_write64(GUEST_IA32_PERF_GLOBAL_CTRL, - vmcs12->host_ia32_perf_global_ctrl); -} - -/* - * Emulate an exit from nested guest (L2) to L1, i.e., prepare to run L1 - * and modify vmcs12 to make it see what it would expect to see there if - * L2 was its real guest. Must only be called when in L2 (is_guest_mode()) - */ -static void nested_vmx_vmexit(struct kvm_vcpu *vcpu) -{ - struct vcpu_vmx *vmx = to_vmx(vcpu); - int cpu; - struct vmcs12 *vmcs12 = get_vmcs12(vcpu); - - leave_guest_mode(vcpu); - prepare_vmcs12(vcpu, vmcs12); - - cpu = get_cpu(); - vmx->loaded_vmcs = &vmx->vmcs01; - vmx_vcpu_put(vcpu); - vmx_vcpu_load(vcpu, cpu); - vcpu->cpu = cpu; - put_cpu(); - - /* if no vmcs02 cache requested, remove the one we used */ - if (VMCS02_POOL_SIZE == 0) - nested_free_vmcs02(vmx, vmx->nested.current_vmptr); - - load_vmcs12_host_state(vcpu, vmcs12); - - /* Update TSC_OFFSET if vmx_adjust_tsc_offset() was used while L2 ran */ - vmcs_write64(TSC_OFFSET, vmx->nested.vmcs01_tsc_offset); - - /* This is needed for same reason as it was needed in prepare_vmcs02 */ - vmx->host_rsp = 0; - - /* Unpin physical memory we referred to in vmcs02 */ - if (vmx->nested.apic_access_page) { - nested_release_page(vmx->nested.apic_access_page); - vmx->nested.apic_access_page = 0; - } - - /* - * Exiting from L2 to L1, we're now back to L1 which thinks it just - * finished a VMLAUNCH or VMRESUME instruction, so we need to set the - * success or failure flag accordingly. - */ - if (unlikely(vmx->fail)) { - vmx->fail = 0; - nested_vmx_failValid(vcpu, vmcs_read32(VM_INSTRUCTION_ERROR)); - } else - nested_vmx_succeed(vcpu); -} - -/* - * L1's failure to enter L2 is a subset of a normal exit, as explained in - * 23.7 "VM-entry failures during or after loading guest state" (this also - * lists the acceptable exit-reason and exit-qualification parameters). - * It should only be called before L2 actually succeeded to run, and when - * vmcs01 is current (it doesn't leave_guest_mode() or switch vmcss). - */ -static void nested_vmx_entry_failure(struct kvm_vcpu *vcpu, - struct vmcs12 *vmcs12, - u32 reason, unsigned long qualification) -{ - load_vmcs12_host_state(vcpu, vmcs12); - vmcs12->vm_exit_reason = reason | VMX_EXIT_REASONS_FAILED_VMENTRY; - vmcs12->exit_qualification = qualification; - nested_vmx_succeed(vcpu); } static int vmx_check_intercept(struct kvm_vcpu *vcpu, @@ -7119,13 +4670,16 @@ static int __init vmx_init(void) vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_EIP, false); if (enable_ept) { + bypass_guest_pf = 0; kvm_mmu_set_mask_ptes(0ull, 0ull, 0ull, 0ull, VMX_EPT_EXECUTABLE_MASK); - ept_set_mmio_spte_mask(); kvm_enable_tdp(); } else kvm_disable_tdp(); + if (bypass_guest_pf) + kvm_mmu_set_nonpresent_ptes(~0xffeull, 0ull); + return 0; out3: diff --git a/trunk/arch/x86/kvm/x86.c b/trunk/arch/x86/kvm/x86.c index 84a28ea45fa4..77c9d8673dc4 100644 --- a/trunk/arch/x86/kvm/x86.c +++ b/trunk/arch/x86/kvm/x86.c @@ -347,7 +347,6 @@ void kvm_inject_page_fault(struct kvm_vcpu *vcpu, struct x86_exception *fault) vcpu->arch.cr2 = fault->address; kvm_queue_exception_e(vcpu, PF_VECTOR, fault->error_code); } -EXPORT_SYMBOL_GPL(kvm_inject_page_fault); void kvm_propagate_fault(struct kvm_vcpu *vcpu, struct x86_exception *fault) { @@ -580,22 +579,6 @@ static bool guest_cpuid_has_xsave(struct kvm_vcpu *vcpu) return best && (best->ecx & bit(X86_FEATURE_XSAVE)); } -static bool guest_cpuid_has_smep(struct kvm_vcpu *vcpu) -{ - struct kvm_cpuid_entry2 *best; - - best = kvm_find_cpuid_entry(vcpu, 7, 0); - return best && (best->ebx & bit(X86_FEATURE_SMEP)); -} - -static bool guest_cpuid_has_fsgsbase(struct kvm_vcpu *vcpu) -{ - struct kvm_cpuid_entry2 *best; - - best = kvm_find_cpuid_entry(vcpu, 7, 0); - return best && (best->ebx & bit(X86_FEATURE_FSGSBASE)); -} - static void update_cpuid(struct kvm_vcpu *vcpu) { struct kvm_cpuid_entry2 *best; @@ -615,20 +598,14 @@ static void update_cpuid(struct kvm_vcpu *vcpu) int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) { unsigned long old_cr4 = kvm_read_cr4(vcpu); - unsigned long pdptr_bits = X86_CR4_PGE | X86_CR4_PSE | - X86_CR4_PAE | X86_CR4_SMEP; + unsigned long pdptr_bits = X86_CR4_PGE | X86_CR4_PSE | X86_CR4_PAE; + if (cr4 & CR4_RESERVED_BITS) return 1; if (!guest_cpuid_has_xsave(vcpu) && (cr4 & X86_CR4_OSXSAVE)) return 1; - if (!guest_cpuid_has_smep(vcpu) && (cr4 & X86_CR4_SMEP)) - return 1; - - if (!guest_cpuid_has_fsgsbase(vcpu) && (cr4 & X86_CR4_RDWRGSFS)) - return 1; - if (is_long_mode(vcpu)) { if (!(cr4 & X86_CR4_PAE)) return 1; @@ -638,9 +615,11 @@ int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) kvm_read_cr3(vcpu))) return 1; - if (kvm_x86_ops->set_cr4(vcpu, cr4)) + if (cr4 & X86_CR4_VMXE) return 1; + kvm_x86_ops->set_cr4(vcpu, cr4); + if ((cr4 ^ old_cr4) & pdptr_bits) kvm_mmu_reset_context(vcpu); @@ -808,12 +787,12 @@ EXPORT_SYMBOL_GPL(kvm_get_dr); * kvm-specific. Those are put in the beginning of the list. */ -#define KVM_SAVE_MSRS_BEGIN 9 +#define KVM_SAVE_MSRS_BEGIN 8 static u32 msrs_to_save[] = { MSR_KVM_SYSTEM_TIME, MSR_KVM_WALL_CLOCK, MSR_KVM_SYSTEM_TIME_NEW, MSR_KVM_WALL_CLOCK_NEW, HV_X64_MSR_GUEST_OS_ID, HV_X64_MSR_HYPERCALL, - HV_X64_MSR_APIC_ASSIST_PAGE, MSR_KVM_ASYNC_PF_EN, MSR_KVM_STEAL_TIME, + HV_X64_MSR_APIC_ASSIST_PAGE, MSR_KVM_ASYNC_PF_EN, MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP, MSR_STAR, #ifdef CONFIG_X86_64 @@ -1409,7 +1388,7 @@ static int set_msr_hyperv_pw(struct kvm_vcpu *vcpu, u32 msr, u64 data) return 1; kvm_x86_ops->patch_hypercall(vcpu, instructions); ((unsigned char *)instructions)[3] = 0xc3; /* ret */ - if (__copy_to_user((void __user *)addr, instructions, 4)) + if (copy_to_user((void __user *)addr, instructions, 4)) return 1; kvm->arch.hv_hypercall = data; break; @@ -1436,7 +1415,7 @@ static int set_msr_hyperv(struct kvm_vcpu *vcpu, u32 msr, u64 data) HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_SHIFT); if (kvm_is_error_hva(addr)) return 1; - if (__clear_user((void __user *)addr, PAGE_SIZE)) + if (clear_user((void __user *)addr, PAGE_SIZE)) return 1; vcpu->arch.hv_vapic = data; break; @@ -1488,35 +1467,6 @@ static void kvmclock_reset(struct kvm_vcpu *vcpu) } } -static void accumulate_steal_time(struct kvm_vcpu *vcpu) -{ - u64 delta; - - if (!(vcpu->arch.st.msr_val & KVM_MSR_ENABLED)) - return; - - delta = current->sched_info.run_delay - vcpu->arch.st.last_steal; - vcpu->arch.st.last_steal = current->sched_info.run_delay; - vcpu->arch.st.accum_steal = delta; -} - -static void record_steal_time(struct kvm_vcpu *vcpu) -{ - if (!(vcpu->arch.st.msr_val & KVM_MSR_ENABLED)) - return; - - if (unlikely(kvm_read_guest_cached(vcpu->kvm, &vcpu->arch.st.stime, - &vcpu->arch.st.steal, sizeof(struct kvm_steal_time)))) - return; - - vcpu->arch.st.steal.steal += vcpu->arch.st.accum_steal; - vcpu->arch.st.steal.version += 2; - vcpu->arch.st.accum_steal = 0; - - kvm_write_guest_cached(vcpu->kvm, &vcpu->arch.st.stime, - &vcpu->arch.st.steal, sizeof(struct kvm_steal_time)); -} - int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data) { switch (msr) { @@ -1599,33 +1549,6 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data) if (kvm_pv_enable_async_pf(vcpu, data)) return 1; break; - case MSR_KVM_STEAL_TIME: - - if (unlikely(!sched_info_on())) - return 1; - - if (data & KVM_STEAL_RESERVED_MASK) - return 1; - - if (kvm_gfn_to_hva_cache_init(vcpu->kvm, &vcpu->arch.st.stime, - data & KVM_STEAL_VALID_BITS)) - return 1; - - vcpu->arch.st.msr_val = data; - - if (!(data & KVM_MSR_ENABLED)) - break; - - vcpu->arch.st.last_steal = current->sched_info.run_delay; - - preempt_disable(); - accumulate_steal_time(vcpu); - preempt_enable(); - - kvm_make_request(KVM_REQ_STEAL_UPDATE, vcpu); - - break; - case MSR_IA32_MCG_CTL: case MSR_IA32_MCG_STATUS: case MSR_IA32_MC0_CTL ... MSR_IA32_MC0_CTL + 4 * KVM_MAX_MCE_BANKS - 1: @@ -1911,9 +1834,6 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) case MSR_KVM_ASYNC_PF_EN: data = vcpu->arch.apf.msr_val; break; - case MSR_KVM_STEAL_TIME: - data = vcpu->arch.st.msr_val; - break; case MSR_IA32_P5_MC_ADDR: case MSR_IA32_P5_MC_TYPE: case MSR_IA32_MCG_CAP: @@ -2225,9 +2145,6 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) kvm_migrate_timers(vcpu); vcpu->cpu = cpu; } - - accumulate_steal_time(vcpu); - kvm_make_request(KVM_REQ_STEAL_UPDATE, vcpu); } void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) @@ -2366,13 +2283,6 @@ static void do_cpuid_1_ent(struct kvm_cpuid_entry2 *entry, u32 function, entry->flags = 0; } -static bool supported_xcr0_bit(unsigned bit) -{ - u64 mask = ((u64)1 << bit); - - return mask & (XSTATE_FP | XSTATE_SSE | XSTATE_YMM) & host_xcr0; -} - #define F(x) bit(X86_FEATURE_##x) static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, @@ -2418,7 +2328,7 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, 0 /* Reserved, DCA */ | F(XMM4_1) | F(XMM4_2) | F(X2APIC) | F(MOVBE) | F(POPCNT) | 0 /* Reserved*/ | F(AES) | F(XSAVE) | 0 /* OSXSAVE */ | F(AVX) | - F(F16C) | F(RDRAND); + F(F16C); /* cpuid 0x80000001.ecx */ const u32 kvm_supported_word6_x86_features = F(LAHF_LM) | F(CMP_LEGACY) | 0 /*SVM*/ | 0 /* ExtApicSpace */ | @@ -2432,10 +2342,6 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, F(ACE2) | F(ACE2_EN) | F(PHE) | F(PHE_EN) | F(PMM) | F(PMM_EN); - /* cpuid 7.0.ebx */ - const u32 kvm_supported_word9_x86_features = - F(SMEP) | F(FSGSBASE) | F(ERMS); - /* all calls to cpuid_count() should be made on the same cpu */ get_cpu(); do_cpuid_1_ent(entry, function, index); @@ -2470,7 +2376,7 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, } break; } - /* function 4 has additional index. */ + /* function 4 and 0xb have additional index. */ case 4: { int i, cache_type; @@ -2487,22 +2393,6 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, } break; } - case 7: { - entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX; - /* Mask ebx against host capbability word 9 */ - if (index == 0) { - entry->ebx &= kvm_supported_word9_x86_features; - cpuid_mask(&entry->ebx, 9); - } else - entry->ebx = 0; - entry->eax = 0; - entry->ecx = 0; - entry->edx = 0; - break; - } - case 9: - break; - /* function 0xb has additional index. */ case 0xb: { int i, level_type; @@ -2520,17 +2410,16 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, break; } case 0xd: { - int idx, i; + int i; entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX; - for (idx = 1, i = 1; *nent < maxnent && idx < 64; ++idx) { - do_cpuid_1_ent(&entry[i], function, idx); - if (entry[i].eax == 0 || !supported_xcr0_bit(idx)) + for (i = 1; *nent < maxnent && i < 64; ++i) { + if (entry[i].eax == 0) continue; + do_cpuid_1_ent(&entry[i], function, i); entry[i].flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX; ++*nent; - ++i; } break; } @@ -2549,10 +2438,6 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, (1 << KVM_FEATURE_CLOCKSOURCE2) | (1 << KVM_FEATURE_ASYNC_PF) | (1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT); - - if (sched_info_on()) - entry->eax |= (1 << KVM_FEATURE_STEAL_TIME); - entry->ebx = 0; entry->ecx = 0; entry->edx = 0; @@ -2566,24 +2451,6 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, entry->ecx &= kvm_supported_word6_x86_features; cpuid_mask(&entry->ecx, 6); break; - case 0x80000008: { - unsigned g_phys_as = (entry->eax >> 16) & 0xff; - unsigned virt_as = max((entry->eax >> 8) & 0xff, 48U); - unsigned phys_as = entry->eax & 0xff; - - if (!g_phys_as) - g_phys_as = phys_as; - entry->eax = g_phys_as | (virt_as << 8); - entry->ebx = entry->edx = 0; - break; - } - case 0x80000019: - entry->ecx = entry->edx = 0; - break; - case 0x8000001a: - break; - case 0x8000001d: - break; /*Add support for Centaur's CPUID instruction*/ case 0xC0000000: /*Just support up to 0xC0000004 now*/ @@ -2593,16 +2460,10 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, entry->edx &= kvm_supported_word5_x86_features; cpuid_mask(&entry->edx, 5); break; - case 3: /* Processor serial number */ - case 5: /* MONITOR/MWAIT */ - case 6: /* Thermal management */ - case 0xA: /* Architectural Performance Monitoring */ - case 0x80000007: /* Advanced power management */ case 0xC0000002: case 0xC0000003: case 0xC0000004: - default: - entry->eax = entry->ebx = entry->ecx = entry->edx = 0; + /*Now nothing to do, reserved for the future*/ break; } @@ -3956,7 +3817,7 @@ static int kvm_fetch_guest_virt(struct x86_emulate_ctxt *ctxt, exception); } -int kvm_read_guest_virt(struct x86_emulate_ctxt *ctxt, +static int kvm_read_guest_virt(struct x86_emulate_ctxt *ctxt, gva_t addr, void *val, unsigned int bytes, struct x86_exception *exception) { @@ -3966,7 +3827,6 @@ int kvm_read_guest_virt(struct x86_emulate_ctxt *ctxt, return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, access, exception); } -EXPORT_SYMBOL_GPL(kvm_read_guest_virt); static int kvm_read_guest_virt_system(struct x86_emulate_ctxt *ctxt, gva_t addr, void *val, unsigned int bytes, @@ -3976,7 +3836,7 @@ static int kvm_read_guest_virt_system(struct x86_emulate_ctxt *ctxt, return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, 0, exception); } -int kvm_write_guest_virt_system(struct x86_emulate_ctxt *ctxt, +static int kvm_write_guest_virt_system(struct x86_emulate_ctxt *ctxt, gva_t addr, void *val, unsigned int bytes, struct x86_exception *exception) @@ -4008,42 +3868,6 @@ int kvm_write_guest_virt_system(struct x86_emulate_ctxt *ctxt, out: return r; } -EXPORT_SYMBOL_GPL(kvm_write_guest_virt_system); - -static int vcpu_mmio_gva_to_gpa(struct kvm_vcpu *vcpu, unsigned long gva, - gpa_t *gpa, struct x86_exception *exception, - bool write) -{ - u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0; - - if (vcpu_match_mmio_gva(vcpu, gva) && - check_write_user_access(vcpu, write, access, - vcpu->arch.access)) { - *gpa = vcpu->arch.mmio_gfn << PAGE_SHIFT | - (gva & (PAGE_SIZE - 1)); - trace_vcpu_match_mmio(gva, *gpa, write, false); - return 1; - } - - if (write) - access |= PFERR_WRITE_MASK; - - *gpa = vcpu->arch.walk_mmu->gva_to_gpa(vcpu, gva, access, exception); - - if (*gpa == UNMAPPED_GVA) - return -1; - - /* For APIC access vmexit */ - if ((*gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE) - return 1; - - if (vcpu_match_mmio_gpa(vcpu, *gpa)) { - trace_vcpu_match_mmio(gva, *gpa, write, true); - return 1; - } - - return 0; -} static int emulator_read_emulated(struct x86_emulate_ctxt *ctxt, unsigned long addr, @@ -4052,8 +3876,8 @@ static int emulator_read_emulated(struct x86_emulate_ctxt *ctxt, struct x86_exception *exception) { struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt); - gpa_t gpa; - int handled, ret; + gpa_t gpa; + int handled; if (vcpu->mmio_read_completed) { memcpy(val, vcpu->mmio_data, bytes); @@ -4063,12 +3887,13 @@ static int emulator_read_emulated(struct x86_emulate_ctxt *ctxt, return X86EMUL_CONTINUE; } - ret = vcpu_mmio_gva_to_gpa(vcpu, addr, &gpa, exception, false); + gpa = kvm_mmu_gva_to_gpa_read(vcpu, addr, exception); - if (ret < 0) + if (gpa == UNMAPPED_GVA) return X86EMUL_PROPAGATE_FAULT; - if (ret) + /* For APIC access vmexit */ + if ((gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE) goto mmio; if (kvm_read_guest_virt(ctxt, addr, val, bytes, exception) @@ -4119,16 +3944,16 @@ static int emulator_write_emulated_onepage(unsigned long addr, struct x86_exception *exception, struct kvm_vcpu *vcpu) { - gpa_t gpa; - int handled, ret; + gpa_t gpa; + int handled; - ret = vcpu_mmio_gva_to_gpa(vcpu, addr, &gpa, exception, true); + gpa = kvm_mmu_gva_to_gpa_write(vcpu, addr, exception); - if (ret < 0) + if (gpa == UNMAPPED_GVA) return X86EMUL_PROPAGATE_FAULT; /* For APIC access vmexit */ - if (ret) + if ((gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE) goto mmio; if (emulator_write_phys(vcpu, gpa, val, bytes)) @@ -4648,24 +4473,9 @@ static void inject_emulated_exception(struct kvm_vcpu *vcpu) kvm_queue_exception(vcpu, ctxt->exception.vector); } -static void init_decode_cache(struct x86_emulate_ctxt *ctxt, - const unsigned long *regs) -{ - memset(&ctxt->twobyte, 0, - (void *)&ctxt->regs - (void *)&ctxt->twobyte); - memcpy(ctxt->regs, regs, sizeof(ctxt->regs)); - - ctxt->fetch.start = 0; - ctxt->fetch.end = 0; - ctxt->io_read.pos = 0; - ctxt->io_read.end = 0; - ctxt->mem_read.pos = 0; - ctxt->mem_read.end = 0; -} - static void init_emulate_ctxt(struct kvm_vcpu *vcpu) { - struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt; + struct decode_cache *c = &vcpu->arch.emulate_ctxt.decode; int cs_db, cs_l; /* @@ -4678,38 +4488,40 @@ static void init_emulate_ctxt(struct kvm_vcpu *vcpu) kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l); - ctxt->eflags = kvm_get_rflags(vcpu); - ctxt->eip = kvm_rip_read(vcpu); - ctxt->mode = (!is_protmode(vcpu)) ? X86EMUL_MODE_REAL : - (ctxt->eflags & X86_EFLAGS_VM) ? X86EMUL_MODE_VM86 : - cs_l ? X86EMUL_MODE_PROT64 : - cs_db ? X86EMUL_MODE_PROT32 : - X86EMUL_MODE_PROT16; - ctxt->guest_mode = is_guest_mode(vcpu); - - init_decode_cache(ctxt, vcpu->arch.regs); + vcpu->arch.emulate_ctxt.eflags = kvm_get_rflags(vcpu); + vcpu->arch.emulate_ctxt.eip = kvm_rip_read(vcpu); + vcpu->arch.emulate_ctxt.mode = + (!is_protmode(vcpu)) ? X86EMUL_MODE_REAL : + (vcpu->arch.emulate_ctxt.eflags & X86_EFLAGS_VM) + ? X86EMUL_MODE_VM86 : cs_l + ? X86EMUL_MODE_PROT64 : cs_db + ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16; + vcpu->arch.emulate_ctxt.guest_mode = is_guest_mode(vcpu); + memset(c, 0, sizeof(struct decode_cache)); + memcpy(c->regs, vcpu->arch.regs, sizeof c->regs); vcpu->arch.emulate_regs_need_sync_from_vcpu = false; } int kvm_inject_realmode_interrupt(struct kvm_vcpu *vcpu, int irq, int inc_eip) { - struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt; + struct decode_cache *c = &vcpu->arch.emulate_ctxt.decode; int ret; init_emulate_ctxt(vcpu); - ctxt->op_bytes = 2; - ctxt->ad_bytes = 2; - ctxt->_eip = ctxt->eip + inc_eip; - ret = emulate_int_real(ctxt, irq); + vcpu->arch.emulate_ctxt.decode.op_bytes = 2; + vcpu->arch.emulate_ctxt.decode.ad_bytes = 2; + vcpu->arch.emulate_ctxt.decode.eip = vcpu->arch.emulate_ctxt.eip + + inc_eip; + ret = emulate_int_real(&vcpu->arch.emulate_ctxt, &emulate_ops, irq); if (ret != X86EMUL_CONTINUE) return EMULATE_FAIL; - ctxt->eip = ctxt->_eip; - memcpy(vcpu->arch.regs, ctxt->regs, sizeof ctxt->regs); - kvm_rip_write(vcpu, ctxt->eip); - kvm_set_rflags(vcpu, ctxt->eflags); + vcpu->arch.emulate_ctxt.eip = c->eip; + memcpy(vcpu->arch.regs, c->regs, sizeof c->regs); + kvm_rip_write(vcpu, vcpu->arch.emulate_ctxt.eip); + kvm_set_rflags(vcpu, vcpu->arch.emulate_ctxt.eflags); if (irq == NMI_VECTOR) vcpu->arch.nmi_pending = false; @@ -4770,21 +4582,21 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, int insn_len) { int r; - struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt; + struct decode_cache *c = &vcpu->arch.emulate_ctxt.decode; bool writeback = true; kvm_clear_exception_queue(vcpu); if (!(emulation_type & EMULTYPE_NO_DECODE)) { init_emulate_ctxt(vcpu); - ctxt->interruptibility = 0; - ctxt->have_exception = false; - ctxt->perm_ok = false; + vcpu->arch.emulate_ctxt.interruptibility = 0; + vcpu->arch.emulate_ctxt.have_exception = false; + vcpu->arch.emulate_ctxt.perm_ok = false; - ctxt->only_vendor_specific_insn + vcpu->arch.emulate_ctxt.only_vendor_specific_insn = emulation_type & EMULTYPE_TRAP_UD; - r = x86_decode_insn(ctxt, insn, insn_len); + r = x86_decode_insn(&vcpu->arch.emulate_ctxt, insn, insn_len); trace_kvm_emulate_insn_start(vcpu); ++vcpu->stat.insn_emulation; @@ -4800,7 +4612,7 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, } if (emulation_type & EMULTYPE_SKIP) { - kvm_rip_write(vcpu, ctxt->_eip); + kvm_rip_write(vcpu, vcpu->arch.emulate_ctxt.decode.eip); return EMULATE_DONE; } @@ -4808,11 +4620,11 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, changes registers values during IO operation */ if (vcpu->arch.emulate_regs_need_sync_from_vcpu) { vcpu->arch.emulate_regs_need_sync_from_vcpu = false; - memcpy(ctxt->regs, vcpu->arch.regs, sizeof ctxt->regs); + memcpy(c->regs, vcpu->arch.regs, sizeof c->regs); } restart: - r = x86_emulate_insn(ctxt); + r = x86_emulate_insn(&vcpu->arch.emulate_ctxt); if (r == EMULATION_INTERCEPTED) return EMULATE_DONE; @@ -4824,7 +4636,7 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, return handle_emulation_failure(vcpu); } - if (ctxt->have_exception) { + if (vcpu->arch.emulate_ctxt.have_exception) { inject_emulated_exception(vcpu); r = EMULATE_DONE; } else if (vcpu->arch.pio.count) { @@ -4843,12 +4655,13 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, r = EMULATE_DONE; if (writeback) { - toggle_interruptibility(vcpu, ctxt->interruptibility); - kvm_set_rflags(vcpu, ctxt->eflags); + toggle_interruptibility(vcpu, + vcpu->arch.emulate_ctxt.interruptibility); + kvm_set_rflags(vcpu, vcpu->arch.emulate_ctxt.eflags); kvm_make_request(KVM_REQ_EVENT, vcpu); - memcpy(vcpu->arch.regs, ctxt->regs, sizeof ctxt->regs); + memcpy(vcpu->arch.regs, c->regs, sizeof c->regs); vcpu->arch.emulate_regs_need_sync_to_vcpu = false; - kvm_rip_write(vcpu, ctxt->eip); + kvm_rip_write(vcpu, vcpu->arch.emulate_ctxt.eip); } else vcpu->arch.emulate_regs_need_sync_to_vcpu = true; @@ -5065,30 +4878,6 @@ void kvm_after_handle_nmi(struct kvm_vcpu *vcpu) } EXPORT_SYMBOL_GPL(kvm_after_handle_nmi); -static void kvm_set_mmio_spte_mask(void) -{ - u64 mask; - int maxphyaddr = boot_cpu_data.x86_phys_bits; - - /* - * Set the reserved bits and the present bit of an paging-structure - * entry to generate page fault with PFER.RSV = 1. - */ - mask = ((1ull << (62 - maxphyaddr + 1)) - 1) << maxphyaddr; - mask |= 1ull; - -#ifdef CONFIG_X86_64 - /* - * If reserved bit is not supported, clear the present bit to disable - * mmio page fault. - */ - if (maxphyaddr == 52) - mask &= ~1ull; -#endif - - kvm_mmu_set_mmio_spte_mask(mask); -} - int kvm_arch_init(void *opaque) { int r; @@ -5115,10 +4904,10 @@ int kvm_arch_init(void *opaque) if (r) goto out; - kvm_set_mmio_spte_mask(); kvm_init_msr_list(); kvm_x86_ops = ops; + kvm_mmu_set_nonpresent_ptes(0ull, 0ull); kvm_mmu_set_mask_ptes(PT_USER_MASK, PT_ACCESSED_MASK, PT_DIRTY_MASK, PT64_NX_MASK, 0); @@ -5293,7 +5082,8 @@ int emulator_fix_hypercall(struct x86_emulate_ctxt *ctxt) kvm_x86_ops->patch_hypercall(vcpu, instruction); - return emulator_write_emulated(ctxt, rip, instruction, 3, NULL); + return emulator_write_emulated(&vcpu->arch.emulate_ctxt, + rip, instruction, 3, NULL); } static int move_to_next_stateful_cpuid_entry(struct kvm_vcpu *vcpu, int i) @@ -5594,9 +5384,6 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) r = 1; goto out; } - if (kvm_check_request(KVM_REQ_STEAL_UPDATE, vcpu)) - record_steal_time(vcpu); - } r = kvm_mmu_reload(vcpu); @@ -5884,8 +5671,8 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) * that usually, but some bad designed PV devices (vmware * backdoor interface) need this to work */ - struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt; - memcpy(vcpu->arch.regs, ctxt->regs, sizeof ctxt->regs); + struct decode_cache *c = &vcpu->arch.emulate_ctxt.decode; + memcpy(vcpu->arch.regs, c->regs, sizeof c->regs); vcpu->arch.emulate_regs_need_sync_to_vcpu = false; } regs->rax = kvm_register_read(vcpu, VCPU_REGS_RAX); @@ -6014,20 +5801,21 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu, int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason, bool has_error_code, u32 error_code) { - struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt; + struct decode_cache *c = &vcpu->arch.emulate_ctxt.decode; int ret; init_emulate_ctxt(vcpu); - ret = emulator_task_switch(ctxt, tss_selector, reason, - has_error_code, error_code); + ret = emulator_task_switch(&vcpu->arch.emulate_ctxt, + tss_selector, reason, has_error_code, + error_code); if (ret) return EMULATE_FAIL; - memcpy(vcpu->arch.regs, ctxt->regs, sizeof ctxt->regs); - kvm_rip_write(vcpu, ctxt->eip); - kvm_set_rflags(vcpu, ctxt->eflags); + memcpy(vcpu->arch.regs, c->regs, sizeof c->regs); + kvm_rip_write(vcpu, vcpu->arch.emulate_ctxt.eip); + kvm_set_rflags(vcpu, vcpu->arch.emulate_ctxt.eflags); kvm_make_request(KVM_REQ_EVENT, vcpu); return EMULATE_DONE; } @@ -6305,7 +6093,12 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) if (r == 0) r = kvm_mmu_setup(vcpu); vcpu_put(vcpu); + if (r < 0) + goto free_vcpu; + return 0; +free_vcpu: + kvm_x86_ops->vcpu_free(vcpu); return r; } @@ -6333,7 +6126,6 @@ int kvm_arch_vcpu_reset(struct kvm_vcpu *vcpu) kvm_make_request(KVM_REQ_EVENT, vcpu); vcpu->arch.apf.msr_val = 0; - vcpu->arch.st.msr_val = 0; kvmclock_reset(vcpu); diff --git a/trunk/arch/x86/kvm/x86.h b/trunk/arch/x86/kvm/x86.h index d36fe237c665..e407ed3df817 100644 --- a/trunk/arch/x86/kvm/x86.h +++ b/trunk/arch/x86/kvm/x86.h @@ -75,54 +75,10 @@ static inline u32 bit(int bitno) return 1 << (bitno & 31); } -static inline void vcpu_cache_mmio_info(struct kvm_vcpu *vcpu, - gva_t gva, gfn_t gfn, unsigned access) -{ - vcpu->arch.mmio_gva = gva & PAGE_MASK; - vcpu->arch.access = access; - vcpu->arch.mmio_gfn = gfn; -} - -/* - * Clear the mmio cache info for the given gva, - * specially, if gva is ~0ul, we clear all mmio cache info. - */ -static inline void vcpu_clear_mmio_info(struct kvm_vcpu *vcpu, gva_t gva) -{ - if (gva != (~0ul) && vcpu->arch.mmio_gva != (gva & PAGE_MASK)) - return; - - vcpu->arch.mmio_gva = 0; -} - -static inline bool vcpu_match_mmio_gva(struct kvm_vcpu *vcpu, unsigned long gva) -{ - if (vcpu->arch.mmio_gva && vcpu->arch.mmio_gva == (gva & PAGE_MASK)) - return true; - - return false; -} - -static inline bool vcpu_match_mmio_gpa(struct kvm_vcpu *vcpu, gpa_t gpa) -{ - if (vcpu->arch.mmio_gfn && vcpu->arch.mmio_gfn == gpa >> PAGE_SHIFT) - return true; - - return false; -} - void kvm_before_handle_nmi(struct kvm_vcpu *vcpu); void kvm_after_handle_nmi(struct kvm_vcpu *vcpu); int kvm_inject_realmode_interrupt(struct kvm_vcpu *vcpu, int irq, int inc_eip); void kvm_write_tsc(struct kvm_vcpu *vcpu, u64 data); -int kvm_read_guest_virt(struct x86_emulate_ctxt *ctxt, - gva_t addr, void *val, unsigned int bytes, - struct x86_exception *exception); - -int kvm_write_guest_virt_system(struct x86_emulate_ctxt *ctxt, - gva_t addr, void *val, unsigned int bytes, - struct x86_exception *exception); - #endif diff --git a/trunk/arch/x86/lib/Makefile b/trunk/arch/x86/lib/Makefile index b00f6785da74..f2479f19ddde 100644 --- a/trunk/arch/x86/lib/Makefile +++ b/trunk/arch/x86/lib/Makefile @@ -18,10 +18,8 @@ obj-$(CONFIG_SMP) += msr-smp.o cache-smp.o lib-y := delay.o lib-y += thunk_$(BITS).o -lib-y += usercopy_$(BITS).o usercopy.o getuser.o putuser.o +lib-y += usercopy_$(BITS).o getuser.o putuser.o lib-y += memcpy_$(BITS).o -lib-$(CONFIG_SMP) += rwlock.o -lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o lib-$(CONFIG_INSTRUCTION_DECODER) += insn.o inat.o obj-y += msr.o msr-reg.o msr-reg-export.o @@ -31,7 +29,7 @@ ifeq ($(CONFIG_X86_32),y) lib-y += atomic64_cx8_32.o lib-y += checksum_32.o lib-y += strstr_32.o - lib-y += string_32.o + lib-y += semaphore_32.o string_32.o lib-y += cmpxchg.o ifneq ($(CONFIG_X86_CMPXCHG64),y) lib-y += cmpxchg8b_emu.o atomic64_386_32.o @@ -42,6 +40,7 @@ else lib-y += csum-partial_64.o csum-copy_64.o csum-wrappers_64.o lib-y += thunk_64.o clear_page_64.o copy_page_64.o lib-y += memmove_64.o memset_64.o - lib-y += copy_user_64.o copy_user_nocache_64.o + lib-y += copy_user_64.o rwlock_64.o copy_user_nocache_64.o + lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem_64.o lib-y += cmpxchg16b_emu.o endif diff --git a/trunk/arch/x86/lib/copy_page_64.S b/trunk/arch/x86/lib/copy_page_64.S index 01c805ba5359..6fec2d1cebe1 100644 --- a/trunk/arch/x86/lib/copy_page_64.S +++ b/trunk/arch/x86/lib/copy_page_64.S @@ -2,7 +2,6 @@ #include #include -#include ALIGN copy_page_c: @@ -111,6 +110,10 @@ ENDPROC(copy_page) 2: .previous .section .altinstructions,"a" - altinstruction_entry copy_page, 1b, X86_FEATURE_REP_GOOD, \ - .Lcopy_page_end-copy_page, 2b-1b + .align 8 + .quad copy_page + .quad 1b + .word X86_FEATURE_REP_GOOD + .byte .Lcopy_page_end - copy_page + .byte 2b - 1b .previous diff --git a/trunk/arch/x86/lib/memmove_64.S b/trunk/arch/x86/lib/memmove_64.S index ee164610ec46..d0ec9c2936d7 100644 --- a/trunk/arch/x86/lib/memmove_64.S +++ b/trunk/arch/x86/lib/memmove_64.S @@ -9,7 +9,6 @@ #include #include #include -#include #undef memmove @@ -215,9 +214,11 @@ ENTRY(memmove) .previous .section .altinstructions,"a" - altinstruction_entry .Lmemmove_begin_forward, \ - .Lmemmove_begin_forward_efs,X86_FEATURE_ERMS, \ - .Lmemmove_end_forward-.Lmemmove_begin_forward, \ - .Lmemmove_end_forward_efs-.Lmemmove_begin_forward_efs + .align 8 + .quad .Lmemmove_begin_forward + .quad .Lmemmove_begin_forward_efs + .word X86_FEATURE_ERMS + .byte .Lmemmove_end_forward-.Lmemmove_begin_forward + .byte .Lmemmove_end_forward_efs-.Lmemmove_begin_forward_efs .previous ENDPROC(memmove) diff --git a/trunk/arch/x86/lib/rwlock.S b/trunk/arch/x86/lib/rwlock.S deleted file mode 100644 index 1cad22139c88..000000000000 --- a/trunk/arch/x86/lib/rwlock.S +++ /dev/null @@ -1,44 +0,0 @@ -/* Slow paths of read/write spinlocks. */ - -#include -#include -#include -#include - -#ifdef CONFIG_X86_32 -# define __lock_ptr eax -#else -# define __lock_ptr rdi -#endif - -ENTRY(__write_lock_failed) - CFI_STARTPROC - FRAME -0: LOCK_PREFIX - WRITE_LOCK_ADD($RW_LOCK_BIAS) (%__lock_ptr) -1: rep; nop - cmpl $WRITE_LOCK_CMP, (%__lock_ptr) - jne 1b - LOCK_PREFIX - WRITE_LOCK_SUB($RW_LOCK_BIAS) (%__lock_ptr) - jnz 0b - ENDFRAME - ret - CFI_ENDPROC -END(__write_lock_failed) - -ENTRY(__read_lock_failed) - CFI_STARTPROC - FRAME -0: LOCK_PREFIX - READ_LOCK_SIZE(inc) (%__lock_ptr) -1: rep; nop - READ_LOCK_SIZE(cmp) $1, (%__lock_ptr) - js 1b - LOCK_PREFIX - READ_LOCK_SIZE(dec) (%__lock_ptr) - js 0b - ENDFRAME - ret - CFI_ENDPROC -END(__read_lock_failed) diff --git a/trunk/arch/x86/lib/rwlock_64.S b/trunk/arch/x86/lib/rwlock_64.S new file mode 100644 index 000000000000..05ea55f71405 --- /dev/null +++ b/trunk/arch/x86/lib/rwlock_64.S @@ -0,0 +1,38 @@ +/* Slow paths of read/write spinlocks. */ + +#include +#include +#include +#include + +/* rdi: pointer to rwlock_t */ +ENTRY(__write_lock_failed) + CFI_STARTPROC + LOCK_PREFIX + addl $RW_LOCK_BIAS,(%rdi) +1: rep + nop + cmpl $RW_LOCK_BIAS,(%rdi) + jne 1b + LOCK_PREFIX + subl $RW_LOCK_BIAS,(%rdi) + jnz __write_lock_failed + ret + CFI_ENDPROC +END(__write_lock_failed) + +/* rdi: pointer to rwlock_t */ +ENTRY(__read_lock_failed) + CFI_STARTPROC + LOCK_PREFIX + incl (%rdi) +1: rep + nop + cmpl $1,(%rdi) + js 1b + LOCK_PREFIX + decl (%rdi) + js __read_lock_failed + ret + CFI_ENDPROC +END(__read_lock_failed) diff --git a/trunk/arch/x86/lib/rwsem.S b/trunk/arch/x86/lib/rwsem_64.S similarity index 55% rename from trunk/arch/x86/lib/rwsem.S rename to trunk/arch/x86/lib/rwsem_64.S index 5dff5f042468..67743977398b 100644 --- a/trunk/arch/x86/lib/rwsem.S +++ b/trunk/arch/x86/lib/rwsem_64.S @@ -1,50 +1,3 @@ -/* - * x86 semaphore implementation. - * - * (C) Copyright 1999 Linus Torvalds - * - * Portions Copyright 1999 Red Hat, 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. - * - * rw semaphores implemented November 1999 by Benjamin LaHaise - */ - -#include -#include -#include - -#define __ASM_HALF_REG(reg) __ASM_SEL(reg, e##reg) -#define __ASM_HALF_SIZE(inst) __ASM_SEL(inst##w, inst##l) - -#ifdef CONFIG_X86_32 - -/* - * The semaphore operations have a special calling sequence that - * allow us to do a simpler in-line version of them. These routines - * need to convert that sequence back into the C sequence when - * there is contention on the semaphore. - * - * %eax contains the semaphore pointer on entry. Save the C-clobbered - * registers (%eax, %edx and %ecx) except %eax whish is either a return - * value or just clobbered.. - */ - -#define save_common_regs \ - pushl_cfi %ecx; CFI_REL_OFFSET ecx, 0 - -#define restore_common_regs \ - popl_cfi %ecx; CFI_RESTORE ecx - - /* Avoid uglifying the argument copying x86-64 needs to do. */ - .macro movq src, dst - .endm - -#else - /* * x86-64 rwsem wrappers * @@ -63,6 +16,12 @@ * but %rdi, %rsi, %rcx, %r8-r11 always need saving. */ +#include +#include +#include +#include +#include + #define save_common_regs \ pushq_cfi %rdi; CFI_REL_OFFSET rdi, 0; \ pushq_cfi %rsi; CFI_REL_OFFSET rsi, 0; \ @@ -81,18 +40,16 @@ popq_cfi %rsi; CFI_RESTORE rsi; \ popq_cfi %rdi; CFI_RESTORE rdi -#endif - /* Fix up special calling conventions */ ENTRY(call_rwsem_down_read_failed) CFI_STARTPROC save_common_regs - __ASM_SIZE(push,_cfi) %__ASM_REG(dx) - CFI_REL_OFFSET __ASM_REG(dx), 0 + pushq_cfi %rdx + CFI_REL_OFFSET rdx, 0 movq %rax,%rdi call rwsem_down_read_failed - __ASM_SIZE(pop,_cfi) %__ASM_REG(dx) - CFI_RESTORE __ASM_REG(dx) + popq_cfi %rdx + CFI_RESTORE rdx restore_common_regs ret CFI_ENDPROC @@ -110,8 +67,7 @@ ENDPROC(call_rwsem_down_write_failed) ENTRY(call_rwsem_wake) CFI_STARTPROC - /* do nothing if still outstanding active readers */ - __ASM_HALF_SIZE(dec) %__ASM_HALF_REG(dx) + decl %edx /* do nothing if still outstanding active readers */ jnz 1f save_common_regs movq %rax,%rdi @@ -121,15 +77,16 @@ ENTRY(call_rwsem_wake) CFI_ENDPROC ENDPROC(call_rwsem_wake) +/* Fix up special calling conventions */ ENTRY(call_rwsem_downgrade_wake) CFI_STARTPROC save_common_regs - __ASM_SIZE(push,_cfi) %__ASM_REG(dx) - CFI_REL_OFFSET __ASM_REG(dx), 0 + pushq_cfi %rdx + CFI_REL_OFFSET rdx, 0 movq %rax,%rdi call rwsem_downgrade_wake - __ASM_SIZE(pop,_cfi) %__ASM_REG(dx) - CFI_RESTORE __ASM_REG(dx) + popq_cfi %rdx + CFI_RESTORE rdx restore_common_regs ret CFI_ENDPROC diff --git a/trunk/arch/x86/lib/semaphore_32.S b/trunk/arch/x86/lib/semaphore_32.S new file mode 100644 index 000000000000..06691daa4108 --- /dev/null +++ b/trunk/arch/x86/lib/semaphore_32.S @@ -0,0 +1,124 @@ +/* + * i386 semaphore implementation. + * + * (C) Copyright 1999 Linus Torvalds + * + * Portions Copyright 1999 Red Hat, 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. + * + * rw semaphores implemented November 1999 by Benjamin LaHaise + */ + +#include +#include +#include +#include +#include + +/* + * The semaphore operations have a special calling sequence that + * allow us to do a simpler in-line version of them. These routines + * need to convert that sequence back into the C sequence when + * there is contention on the semaphore. + * + * %eax contains the semaphore pointer on entry. Save the C-clobbered + * registers (%eax, %edx and %ecx) except %eax whish is either a return + * value or just clobbered.. + */ + .section .sched.text, "ax" + +/* + * rw spinlock fallbacks + */ +#ifdef CONFIG_SMP +ENTRY(__write_lock_failed) + CFI_STARTPROC + FRAME +2: LOCK_PREFIX + addl $ RW_LOCK_BIAS,(%eax) +1: rep; nop + cmpl $ RW_LOCK_BIAS,(%eax) + jne 1b + LOCK_PREFIX + subl $ RW_LOCK_BIAS,(%eax) + jnz 2b + ENDFRAME + ret + CFI_ENDPROC + ENDPROC(__write_lock_failed) + +ENTRY(__read_lock_failed) + CFI_STARTPROC + FRAME +2: LOCK_PREFIX + incl (%eax) +1: rep; nop + cmpl $1,(%eax) + js 1b + LOCK_PREFIX + decl (%eax) + js 2b + ENDFRAME + ret + CFI_ENDPROC + ENDPROC(__read_lock_failed) + +#endif + +#ifdef CONFIG_RWSEM_XCHGADD_ALGORITHM + +/* Fix up special calling conventions */ +ENTRY(call_rwsem_down_read_failed) + CFI_STARTPROC + pushl_cfi %ecx + CFI_REL_OFFSET ecx,0 + pushl_cfi %edx + CFI_REL_OFFSET edx,0 + call rwsem_down_read_failed + popl_cfi %edx + popl_cfi %ecx + ret + CFI_ENDPROC + ENDPROC(call_rwsem_down_read_failed) + +ENTRY(call_rwsem_down_write_failed) + CFI_STARTPROC + pushl_cfi %ecx + CFI_REL_OFFSET ecx,0 + calll rwsem_down_write_failed + popl_cfi %ecx + ret + CFI_ENDPROC + ENDPROC(call_rwsem_down_write_failed) + +ENTRY(call_rwsem_wake) + CFI_STARTPROC + decw %dx /* do nothing if still outstanding active readers */ + jnz 1f + pushl_cfi %ecx + CFI_REL_OFFSET ecx,0 + call rwsem_wake + popl_cfi %ecx +1: ret + CFI_ENDPROC + ENDPROC(call_rwsem_wake) + +/* Fix up special calling conventions */ +ENTRY(call_rwsem_downgrade_wake) + CFI_STARTPROC + pushl_cfi %ecx + CFI_REL_OFFSET ecx,0 + pushl_cfi %edx + CFI_REL_OFFSET edx,0 + call rwsem_downgrade_wake + popl_cfi %edx + popl_cfi %ecx + ret + CFI_ENDPROC + ENDPROC(call_rwsem_downgrade_wake) + +#endif diff --git a/trunk/arch/x86/lib/thunk_64.S b/trunk/arch/x86/lib/thunk_64.S index a63efd6bb6a5..782b082c9ff7 100644 --- a/trunk/arch/x86/lib/thunk_64.S +++ b/trunk/arch/x86/lib/thunk_64.S @@ -5,41 +5,50 @@ * Added trace_hardirqs callers - Copyright 2007 Steven Rostedt, Red Hat, Inc. * Subject to the GNU public license, v.2. No warranty of any kind. */ -#include -#include -#include - /* rdi: arg1 ... normal C conventions. rax is saved/restored. */ - .macro THUNK name, func, put_ret_addr_in_rdi=0 + #include + #include + #include + #include + + /* rdi: arg1 ... normal C conventions. rax is saved/restored. */ + .macro thunk name,func .globl \name -\name: +\name: CFI_STARTPROC - - /* this one pushes 9 elems, the next one would be %rIP */ SAVE_ARGS - - .if \put_ret_addr_in_rdi - movq_cfi_restore 9*8, rdi - .endif - call \func jmp restore CFI_ENDPROC .endm #ifdef CONFIG_TRACE_IRQFLAGS - THUNK trace_hardirqs_on_thunk,trace_hardirqs_on_caller,1 - THUNK trace_hardirqs_off_thunk,trace_hardirqs_off_caller,1 + /* put return address in rdi (arg1) */ + .macro thunk_ra name,func + .globl \name +\name: + CFI_STARTPROC + SAVE_ARGS + /* SAVE_ARGS pushs 9 elements */ + /* the next element would be the rip */ + movq 9*8(%rsp), %rdi + call \func + jmp restore + CFI_ENDPROC + .endm + + thunk_ra trace_hardirqs_on_thunk,trace_hardirqs_on_caller + thunk_ra trace_hardirqs_off_thunk,trace_hardirqs_off_caller #endif #ifdef CONFIG_DEBUG_LOCK_ALLOC - THUNK lockdep_sys_exit_thunk,lockdep_sys_exit + thunk lockdep_sys_exit_thunk,lockdep_sys_exit #endif - + /* SAVE_ARGS below is used only for the .cfi directives it contains. */ CFI_STARTPROC SAVE_ARGS restore: RESTORE_ARGS - ret + ret CFI_ENDPROC diff --git a/trunk/arch/x86/lib/usercopy.c b/trunk/arch/x86/lib/usercopy.c deleted file mode 100644 index 97be9cb54483..000000000000 --- a/trunk/arch/x86/lib/usercopy.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * User address space access functions. - * - * For licencing details see kernel-base/COPYING - */ - -#include -#include - -/* - * best effort, GUP based copy_from_user() that is NMI-safe - */ -unsigned long -copy_from_user_nmi(void *to, const void __user *from, unsigned long n) -{ - unsigned long offset, addr = (unsigned long)from; - unsigned long size, len = 0; - struct page *page; - void *map; - int ret; - - do { - ret = __get_user_pages_fast(addr, 1, 0, &page); - if (!ret) - break; - - offset = addr & (PAGE_SIZE - 1); - size = min(PAGE_SIZE - offset, n - len); - - map = kmap_atomic(page); - memcpy(to, map+offset, size); - kunmap_atomic(map); - put_page(page); - - len += size; - to += size; - addr += size; - - } while (len < n); - - return len; -} -EXPORT_SYMBOL_GPL(copy_from_user_nmi); diff --git a/trunk/arch/x86/mm/fault.c b/trunk/arch/x86/mm/fault.c index 4d09df054e39..2dbf6bf4c7e5 100644 --- a/trunk/arch/x86/mm/fault.c +++ b/trunk/arch/x86/mm/fault.c @@ -1059,7 +1059,7 @@ do_page_fault(struct pt_regs *regs, unsigned long error_code) if (unlikely(error_code & PF_RSVD)) pgtable_bad(regs, error_code, address); - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address); + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address); /* * If we're in an interrupt, have no user context or are running @@ -1161,11 +1161,11 @@ do_page_fault(struct pt_regs *regs, unsigned long error_code) if (flags & FAULT_FLAG_ALLOW_RETRY) { if (fault & VM_FAULT_MAJOR) { tsk->maj_flt++; - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0, regs, address); } else { tsk->min_flt++; - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0, regs, address); } if (fault & VM_FAULT_RETRY) { diff --git a/trunk/arch/x86/mm/kmemcheck/error.c b/trunk/arch/x86/mm/kmemcheck/error.c index dab41876cdd5..704a37cedddb 100644 --- a/trunk/arch/x86/mm/kmemcheck/error.c +++ b/trunk/arch/x86/mm/kmemcheck/error.c @@ -185,7 +185,7 @@ void kmemcheck_error_save(enum kmemcheck_shadow state, e->trace.entries = e->trace_entries; e->trace.max_entries = ARRAY_SIZE(e->trace_entries); e->trace.skip = 0; - save_stack_trace_regs(regs, &e->trace); + save_stack_trace_regs(&e->trace, regs); /* Round address down to nearest 16 bytes */ shadow_copy = kmemcheck_shadow_lookup(address diff --git a/trunk/arch/x86/mm/numa.c b/trunk/arch/x86/mm/numa.c index fbeaaf416610..f5510d889a22 100644 --- a/trunk/arch/x86/mm/numa.c +++ b/trunk/arch/x86/mm/numa.c @@ -496,7 +496,6 @@ static bool __init numa_meminfo_cover_memory(const struct numa_meminfo *mi) static int __init numa_register_memblks(struct numa_meminfo *mi) { - unsigned long uninitialized_var(pfn_align); int i, nid; /* Account for nodes with cpus and no memory */ @@ -512,20 +511,6 @@ static int __init numa_register_memblks(struct numa_meminfo *mi) /* for out of order entries */ sort_node_map(); - - /* - * If sections array is gonna be used for pfn -> nid mapping, check - * whether its granularity is fine enough. - */ -#ifdef NODE_NOT_IN_PAGE_FLAGS - pfn_align = node_map_pfn_alignment(); - if (pfn_align && pfn_align < PAGES_PER_SECTION) { - printk(KERN_WARNING "Node alignment %LuMB < min %LuMB, rejecting NUMA config\n", - PFN_PHYS(pfn_align) >> 20, - PFN_PHYS(PAGES_PER_SECTION) >> 20); - return -EINVAL; - } -#endif if (!numa_meminfo_cover_memory(mi)) return -EINVAL; diff --git a/trunk/arch/x86/mm/numa_32.c b/trunk/arch/x86/mm/numa_32.c index 3adebe7e536a..849a975d3fa0 100644 --- a/trunk/arch/x86/mm/numa_32.c +++ b/trunk/arch/x86/mm/numa_32.c @@ -41,7 +41,7 @@ * physnode_map[16-31] = 1; * physnode_map[32- ] = -1; */ -s8 physnode_map[MAX_SECTIONS] __read_mostly = { [0 ... (MAX_SECTIONS - 1)] = -1}; +s8 physnode_map[MAX_ELEMENTS] __read_mostly = { [0 ... (MAX_ELEMENTS - 1)] = -1}; EXPORT_SYMBOL(physnode_map); void memory_present(int nid, unsigned long start, unsigned long end) @@ -52,8 +52,8 @@ void memory_present(int nid, unsigned long start, unsigned long end) nid, start, end); printk(KERN_DEBUG " Setting physnode_map array to node %d for pfns:\n", nid); printk(KERN_DEBUG " "); - for (pfn = start; pfn < end; pfn += PAGES_PER_SECTION) { - physnode_map[pfn / PAGES_PER_SECTION] = nid; + for (pfn = start; pfn < end; pfn += PAGES_PER_ELEMENT) { + physnode_map[pfn / PAGES_PER_ELEMENT] = nid; printk(KERN_CONT "%lx ", pfn); } printk(KERN_CONT "\n"); diff --git a/trunk/arch/x86/mm/pageattr-test.c b/trunk/arch/x86/mm/pageattr-test.c index b0086567271c..e1d106909218 100644 --- a/trunk/arch/x86/mm/pageattr-test.c +++ b/trunk/arch/x86/mm/pageattr-test.c @@ -123,11 +123,12 @@ static int pageattr_test(void) if (print) printk(KERN_INFO "CPA self-test:\n"); - bm = vzalloc((max_pfn_mapped + 7) / 8); + bm = vmalloc((max_pfn_mapped + 7) / 8); if (!bm) { printk(KERN_ERR "CPA Cannot vmalloc bitmap\n"); return -ENOMEM; } + memset(bm, 0, (max_pfn_mapped + 7) / 8); failed += print_split(&sa); srandom32(100); diff --git a/trunk/arch/x86/oprofile/backtrace.c b/trunk/arch/x86/oprofile/backtrace.c index bff89dfe3619..a5b64ab4cd6e 100644 --- a/trunk/arch/x86/oprofile/backtrace.c +++ b/trunk/arch/x86/oprofile/backtrace.c @@ -11,11 +11,10 @@ #include #include #include -#include -#include - #include +#include #include +#include static int backtrace_stack(void *data, char *name) { @@ -41,13 +40,13 @@ static struct stacktrace_ops backtrace_ops = { static struct stack_frame_ia32 * dump_user_backtrace_32(struct stack_frame_ia32 *head) { - /* Also check accessibility of one struct frame_head beyond: */ struct stack_frame_ia32 bufhead[2]; struct stack_frame_ia32 *fp; - unsigned long bytes; - bytes = copy_from_user_nmi(bufhead, head, sizeof(bufhead)); - if (bytes != sizeof(bufhead)) + /* Also check accessibility of one struct frame_head beyond */ + if (!access_ok(VERIFY_READ, head, sizeof(bufhead))) + return NULL; + if (__copy_from_user_inatomic(bufhead, head, sizeof(bufhead))) return NULL; fp = (struct stack_frame_ia32 *) compat_ptr(bufhead[0].next_frame); @@ -88,12 +87,12 @@ x86_backtrace_32(struct pt_regs * const regs, unsigned int depth) static struct stack_frame *dump_user_backtrace(struct stack_frame *head) { - /* Also check accessibility of one struct frame_head beyond: */ struct stack_frame bufhead[2]; - unsigned long bytes; - bytes = copy_from_user_nmi(bufhead, head, sizeof(bufhead)); - if (bytes != sizeof(bufhead)) + /* Also check accessibility of one struct stack_frame beyond */ + if (!access_ok(VERIFY_READ, head, sizeof(bufhead))) + return NULL; + if (__copy_from_user_inatomic(bufhead, head, sizeof(bufhead))) return NULL; oprofile_add_trace(bufhead[0].return_address); diff --git a/trunk/arch/x86/pci/mmconfig-shared.c b/trunk/arch/x86/pci/mmconfig-shared.c index 301e325992f6..750c346ef50a 100644 --- a/trunk/arch/x86/pci/mmconfig-shared.c +++ b/trunk/arch/x86/pci/mmconfig-shared.c @@ -519,8 +519,7 @@ static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg, if (cfg->address < 0xFFFFFFFF) return 0; - if (!strcmp(mcfg->header.oem_id, "SGI") || - !strcmp(mcfg->header.oem_id, "SGI2")) + if (!strcmp(mcfg->header.oem_id, "SGI")) return 0; if (mcfg->header.revision >= 1) { diff --git a/trunk/arch/x86/platform/efi/efi.c b/trunk/arch/x86/platform/efi/efi.c index 3ae4128013e6..899e393d8e73 100644 --- a/trunk/arch/x86/platform/efi/efi.c +++ b/trunk/arch/x86/platform/efi/efi.c @@ -51,17 +51,7 @@ int efi_enabled; EXPORT_SYMBOL(efi_enabled); -struct efi __read_mostly efi = { - .mps = EFI_INVALID_TABLE_ADDR, - .acpi = EFI_INVALID_TABLE_ADDR, - .acpi20 = EFI_INVALID_TABLE_ADDR, - .smbios = EFI_INVALID_TABLE_ADDR, - .sal_systab = EFI_INVALID_TABLE_ADDR, - .boot_info = EFI_INVALID_TABLE_ADDR, - .hcdp = EFI_INVALID_TABLE_ADDR, - .uga = EFI_INVALID_TABLE_ADDR, - .uv_systab = EFI_INVALID_TABLE_ADDR, -}; +struct efi efi; EXPORT_SYMBOL(efi); struct efi_memory_map memmap; @@ -89,50 +79,26 @@ early_param("add_efi_memmap", setup_add_efi_memmap); static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc) { - unsigned long flags; - efi_status_t status; - - spin_lock_irqsave(&rtc_lock, flags); - status = efi_call_virt2(get_time, tm, tc); - spin_unlock_irqrestore(&rtc_lock, flags); - return status; + return efi_call_virt2(get_time, tm, tc); } static efi_status_t virt_efi_set_time(efi_time_t *tm) { - unsigned long flags; - efi_status_t status; - - spin_lock_irqsave(&rtc_lock, flags); - status = efi_call_virt1(set_time, tm); - spin_unlock_irqrestore(&rtc_lock, flags); - return status; + return efi_call_virt1(set_time, tm); } static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled, efi_bool_t *pending, efi_time_t *tm) { - unsigned long flags; - efi_status_t status; - - spin_lock_irqsave(&rtc_lock, flags); - status = efi_call_virt3(get_wakeup_time, - enabled, pending, tm); - spin_unlock_irqrestore(&rtc_lock, flags); - return status; + return efi_call_virt3(get_wakeup_time, + enabled, pending, tm); } static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm) { - unsigned long flags; - efi_status_t status; - - spin_lock_irqsave(&rtc_lock, flags); - status = efi_call_virt2(set_wakeup_time, - enabled, tm); - spin_unlock_irqrestore(&rtc_lock, flags); - return status; + return efi_call_virt2(set_wakeup_time, + enabled, tm); } static efi_status_t virt_efi_get_variable(efi_char16_t *name, @@ -156,7 +122,7 @@ static efi_status_t virt_efi_get_next_variable(unsigned long *name_size, static efi_status_t virt_efi_set_variable(efi_char16_t *name, efi_guid_t *vendor, - u32 attr, + unsigned long attr, unsigned long data_size, void *data) { @@ -165,18 +131,6 @@ static efi_status_t virt_efi_set_variable(efi_char16_t *name, data_size, data); } -static efi_status_t virt_efi_query_variable_info(u32 attr, - u64 *storage_space, - u64 *remaining_space, - u64 *max_variable_size) -{ - if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) - return EFI_UNSUPPORTED; - - return efi_call_virt4(query_variable_info, attr, storage_space, - remaining_space, max_variable_size); -} - static efi_status_t virt_efi_get_next_high_mono_count(u32 *count) { return efi_call_virt1(get_next_high_mono_count, count); @@ -191,28 +145,6 @@ static void virt_efi_reset_system(int reset_type, data_size, data); } -static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules, - unsigned long count, - unsigned long sg_list) -{ - if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) - return EFI_UNSUPPORTED; - - return efi_call_virt3(update_capsule, capsules, count, sg_list); -} - -static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules, - unsigned long count, - u64 *max_size, - int *reset_type) -{ - if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) - return EFI_UNSUPPORTED; - - return efi_call_virt4(query_capsule_caps, capsules, count, max_size, - reset_type); -} - static efi_status_t __init phys_efi_set_virtual_address_map( unsigned long memory_map_size, unsigned long descriptor_size, @@ -232,14 +164,11 @@ static efi_status_t __init phys_efi_set_virtual_address_map( static efi_status_t __init phys_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc) { - unsigned long flags; efi_status_t status; - spin_lock_irqsave(&rtc_lock, flags); efi_call_phys_prelog(); status = efi_call_phys2(efi_phys.get_time, tm, tc); efi_call_phys_epilog(); - spin_unlock_irqrestore(&rtc_lock, flags); return status; } @@ -740,9 +669,6 @@ void __init efi_enter_virtual_mode(void) efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count; efi.reset_system = virt_efi_reset_system; efi.set_virtual_address_map = NULL; - efi.query_variable_info = virt_efi_query_variable_info; - efi.update_capsule = virt_efi_update_capsule; - efi.query_capsule_caps = virt_efi_query_capsule_caps; if (__supported_pte_mask & _PAGE_NX) runtime_code_page_mkexec(); early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size); diff --git a/trunk/arch/x86/platform/uv/tlb_uv.c b/trunk/arch/x86/platform/uv/tlb_uv.c index db8b915f54bc..68e467f69fec 100644 --- a/trunk/arch/x86/platform/uv/tlb_uv.c +++ b/trunk/arch/x86/platform/uv/tlb_uv.c @@ -296,18 +296,14 @@ static void bau_process_message(struct msg_desc *mdp, } /* - * Determine the first cpu on a pnode. + * Determine the first cpu on a uvhub. */ -static int pnode_to_first_cpu(int pnode, struct bau_control *smaster) +static int uvhub_to_first_cpu(int uvhub) { int cpu; - struct hub_and_pnode *hpp; - - for_each_present_cpu(cpu) { - hpp = &smaster->thp[cpu]; - if (pnode == hpp->pnode) + for_each_present_cpu(cpu) + if (uvhub == uv_cpu_to_blade_id(cpu)) return cpu; - } return -1; } @@ -370,32 +366,28 @@ static void do_reset(void *ptr) * Use IPI to get all target uvhubs to release resources held by * a given sending cpu number. */ -static void reset_with_ipi(struct pnmask *distribution, struct bau_control *bcp) +static void reset_with_ipi(struct bau_targ_hubmask *distribution, int sender) { - int pnode; - int apnode; + int uvhub; int maskbits; - int sender = bcp->cpu; - cpumask_t *mask = bcp->uvhub_master->cpumask; - struct bau_control *smaster = bcp->socket_master; + cpumask_t mask; struct reset_args reset_args; reset_args.sender = sender; - cpus_clear(*mask); + cpus_clear(mask); /* find a single cpu for each uvhub in this distribution mask */ - maskbits = sizeof(struct pnmask) * BITSPERBYTE; - /* each bit is a pnode relative to the partition base pnode */ - for (pnode = 0; pnode < maskbits; pnode++) { + maskbits = sizeof(struct bau_targ_hubmask) * BITSPERBYTE; + for (uvhub = 0; uvhub < maskbits; uvhub++) { int cpu; - if (!bau_uvhub_isset(pnode, distribution)) + if (!bau_uvhub_isset(uvhub, distribution)) continue; - apnode = pnode + bcp->partition_base_pnode; - cpu = pnode_to_first_cpu(apnode, smaster); - cpu_set(cpu, *mask); + /* find a cpu for this uvhub */ + cpu = uvhub_to_first_cpu(uvhub); + cpu_set(cpu, mask); } /* IPI all cpus; preemption is already disabled */ - smp_call_function_many(mask, do_reset, (void *)&reset_args, 1); + smp_call_function_many(&mask, do_reset, (void *)&reset_args, 1); return; } @@ -612,7 +604,7 @@ static void destination_plugged(struct bau_desc *bau_desc, quiesce_local_uvhub(hmaster); spin_lock(&hmaster->queue_lock); - reset_with_ipi(&bau_desc->distribution, bcp); + reset_with_ipi(&bau_desc->distribution, bcp->cpu); spin_unlock(&hmaster->queue_lock); end_uvhub_quiesce(hmaster); @@ -634,7 +626,7 @@ static void destination_timeout(struct bau_desc *bau_desc, quiesce_local_uvhub(hmaster); spin_lock(&hmaster->queue_lock); - reset_with_ipi(&bau_desc->distribution, bcp); + reset_with_ipi(&bau_desc->distribution, bcp->cpu); spin_unlock(&hmaster->queue_lock); end_uvhub_quiesce(hmaster); @@ -1342,10 +1334,9 @@ static ssize_t tunables_write(struct file *file, const char __user *user, instr[count] = '\0'; - cpu = get_cpu(); - bcp = &per_cpu(bau_control, cpu); + bcp = &per_cpu(bau_control, smp_processor_id()); + ret = parse_tunables_write(bcp, instr, count); - put_cpu(); if (ret) return ret; @@ -1695,16 +1686,6 @@ static void make_per_cpu_thp(struct bau_control *smaster) } } -/* - * Each uvhub is to get a local cpumask. - */ -static void make_per_hub_cpumask(struct bau_control *hmaster) -{ - int sz = sizeof(cpumask_t); - - hmaster->cpumask = kzalloc_node(sz, GFP_KERNEL, hmaster->osnode); -} - /* * Initialize all the per_cpu information for the cpu's on a given socket, * given what has been gathered into the socket_desc struct. @@ -1770,12 +1751,11 @@ static int __init summarize_uvhub_sockets(int nuvhubs, sdp = &bdp->socket[socket]; if (scan_sock(sdp, bdp, &smaster, &hmaster)) return 1; - make_per_cpu_thp(smaster); } socket++; socket_mask = (socket_mask >> 1); + make_per_cpu_thp(smaster); } - make_per_hub_cpumask(hmaster); } return 0; } @@ -1797,20 +1777,15 @@ static int __init init_per_cpu(int nuvhubs, int base_part_pnode) uvhub_mask = kzalloc((nuvhubs+7)/8, GFP_KERNEL); if (get_cpu_topology(base_part_pnode, uvhub_descs, uvhub_mask)) - goto fail; + return 1; if (summarize_uvhub_sockets(nuvhubs, uvhub_descs, uvhub_mask)) - goto fail; + return 1; kfree(uvhub_descs); kfree(uvhub_mask); init_per_cpu_tunables(); return 0; - -fail: - kfree(uvhub_descs); - kfree(uvhub_mask); - return 1; } /* diff --git a/trunk/arch/x86/vdso/Makefile b/trunk/arch/x86/vdso/Makefile index 5d179502a52c..bef0bc962400 100644 --- a/trunk/arch/x86/vdso/Makefile +++ b/trunk/arch/x86/vdso/Makefile @@ -26,7 +26,6 @@ targets += vdso.so vdso.so.dbg vdso.lds $(vobjs-y) export CPPFLAGS_vdso.lds += -P -C VDSO_LDFLAGS_vdso.lds = -m64 -Wl,-soname=linux-vdso.so.1 \ - -Wl,--no-undefined \ -Wl,-z,max-page-size=4096 -Wl,-z,common-page-size=4096 $(obj)/vdso.o: $(src)/vdso.S $(obj)/vdso.so diff --git a/trunk/arch/x86/vdso/vclock_gettime.c b/trunk/arch/x86/vdso/vclock_gettime.c index 6bc0e723b6e8..a724905fdae7 100644 --- a/trunk/arch/x86/vdso/vclock_gettime.c +++ b/trunk/arch/x86/vdso/vclock_gettime.c @@ -6,6 +6,7 @@ * * The code should have no internal unresolved relocations. * Check with readelf after changing. + * Also alternative() doesn't work. */ /* Disable profiling for userspace code: */ @@ -16,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -25,43 +25,6 @@ #define gtod (&VVAR(vsyscall_gtod_data)) -notrace static cycle_t vread_tsc(void) -{ - cycle_t ret; - u64 last; - - /* - * Empirically, a fence (of type that depends on the CPU) - * before rdtsc is enough to ensure that rdtsc is ordered - * with respect to loads. The various CPU manuals are unclear - * as to whether rdtsc can be reordered with later loads, - * but no one has ever seen it happen. - */ - rdtsc_barrier(); - ret = (cycle_t)vget_cycles(); - - last = VVAR(vsyscall_gtod_data).clock.cycle_last; - - if (likely(ret >= last)) - return ret; - - /* - * GCC likes to generate cmov here, but this branch is extremely - * predictable (it's just a funciton of time and the likely is - * very likely) and there's a data dependence, so force GCC - * to generate a branch instead. I don't barrier() because - * we don't actually need a barrier, and if this function - * ever gets inlined it will generate worse code. - */ - asm volatile (""); - return last; -} - -static notrace cycle_t vread_hpet(void) -{ - return readl((const void __iomem *)fix_to_virt(VSYSCALL_HPET) + 0xf0); -} - notrace static long vdso_fallback_gettime(long clock, struct timespec *ts) { long ret; @@ -73,12 +36,9 @@ notrace static long vdso_fallback_gettime(long clock, struct timespec *ts) notrace static inline long vgetns(void) { long v; - cycles_t cycles; - if (gtod->clock.vclock_mode == VCLOCK_TSC) - cycles = vread_tsc(); - else - cycles = vread_hpet(); - v = (cycles - gtod->clock.cycle_last) & gtod->clock.mask; + cycles_t (*vread)(void); + vread = gtod->clock.vread; + v = (vread() - gtod->clock.cycle_last) & gtod->clock.mask; return (v * gtod->clock.mult) >> gtod->clock.shift; } @@ -156,21 +116,21 @@ notrace static noinline int do_monotonic_coarse(struct timespec *ts) notrace int __vdso_clock_gettime(clockid_t clock, struct timespec *ts) { - switch (clock) { - case CLOCK_REALTIME: - if (likely(gtod->clock.vclock_mode != VCLOCK_NONE)) - return do_realtime(ts); - break; - case CLOCK_MONOTONIC: - if (likely(gtod->clock.vclock_mode != VCLOCK_NONE)) - return do_monotonic(ts); - break; - case CLOCK_REALTIME_COARSE: - return do_realtime_coarse(ts); - case CLOCK_MONOTONIC_COARSE: - return do_monotonic_coarse(ts); - } - + if (likely(gtod->sysctl_enabled)) + switch (clock) { + case CLOCK_REALTIME: + if (likely(gtod->clock.vread)) + return do_realtime(ts); + break; + case CLOCK_MONOTONIC: + if (likely(gtod->clock.vread)) + return do_monotonic(ts); + break; + case CLOCK_REALTIME_COARSE: + return do_realtime_coarse(ts); + case CLOCK_MONOTONIC_COARSE: + return do_monotonic_coarse(ts); + } return vdso_fallback_gettime(clock, ts); } int clock_gettime(clockid_t, struct timespec *) @@ -179,7 +139,7 @@ int clock_gettime(clockid_t, struct timespec *) notrace int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz) { long ret; - if (likely(gtod->clock.vclock_mode != VCLOCK_NONE)) { + if (likely(gtod->sysctl_enabled && gtod->clock.vread)) { if (likely(tv != NULL)) { BUILD_BUG_ON(offsetof(struct timeval, tv_usec) != offsetof(struct timespec, tv_nsec) || @@ -201,14 +161,27 @@ notrace int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz) int gettimeofday(struct timeval *, struct timezone *) __attribute__((weak, alias("__vdso_gettimeofday"))); -/* - * This will break when the xtime seconds get inaccurate, but that is - * unlikely - */ +/* This will break when the xtime seconds get inaccurate, but that is + * unlikely */ + +static __always_inline long time_syscall(long *t) +{ + long secs; + asm volatile("syscall" + : "=a" (secs) + : "0" (__NR_time), "D" (t) : "cc", "r11", "cx", "memory"); + return secs; +} + notrace time_t __vdso_time(time_t *t) { + time_t result; + + if (unlikely(!VVAR(vsyscall_gtod_data).sysctl_enabled)) + return time_syscall(t); + /* This is atomic on x86_64 so we don't need any locks. */ - time_t result = ACCESS_ONCE(VVAR(vsyscall_gtod_data).wall_time_sec); + result = ACCESS_ONCE(VVAR(vsyscall_gtod_data).wall_time_sec); if (t) *t = result; diff --git a/trunk/arch/x86/vdso/vdso.S b/trunk/arch/x86/vdso/vdso.S index 1b979c12ba85..1d3aa6b87181 100644 --- a/trunk/arch/x86/vdso/vdso.S +++ b/trunk/arch/x86/vdso/vdso.S @@ -1,21 +1,10 @@ -#include -#include #include -__PAGE_ALIGNED_DATA +__INITDATA .globl vdso_start, vdso_end - .align PAGE_SIZE vdso_start: .incbin "arch/x86/vdso/vdso.so" vdso_end: -.previous - - .globl vdso_pages - .bss - .align 8 - .type vdso_pages, @object -vdso_pages: - .zero (vdso_end - vdso_start + PAGE_SIZE - 1) / PAGE_SIZE * 8 - .size vdso_pages, .-vdso_pages +__FINIT diff --git a/trunk/arch/x86/vdso/vma.c b/trunk/arch/x86/vdso/vma.c index 316fbca3490e..7abd2be0f9b9 100644 --- a/trunk/arch/x86/vdso/vma.c +++ b/trunk/arch/x86/vdso/vma.c @@ -14,61 +14,41 @@ #include #include #include -#include unsigned int __read_mostly vdso_enabled = 1; extern char vdso_start[], vdso_end[]; extern unsigned short vdso_sync_cpuid; -extern struct page *vdso_pages[]; +static struct page **vdso_pages; static unsigned vdso_size; -static void __init patch_vdso(void *vdso, size_t len) -{ - Elf64_Ehdr *hdr = vdso; - Elf64_Shdr *sechdrs, *alt_sec = 0; - char *secstrings; - void *alt_data; - int i; - - BUG_ON(len < sizeof(Elf64_Ehdr)); - BUG_ON(memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0); - - sechdrs = (void *)hdr + hdr->e_shoff; - secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; - - for (i = 1; i < hdr->e_shnum; i++) { - Elf64_Shdr *shdr = &sechdrs[i]; - if (!strcmp(secstrings + shdr->sh_name, ".altinstructions")) { - alt_sec = shdr; - goto found; - } - } - - /* If we get here, it's probably a bug. */ - pr_warning("patch_vdso: .altinstructions not found\n"); - return; /* nothing to patch */ - -found: - alt_data = (void *)hdr + alt_sec->sh_offset; - apply_alternatives(alt_data, alt_data + alt_sec->sh_size); -} - -static int __init init_vdso(void) +static int __init init_vdso_vars(void) { int npages = (vdso_end - vdso_start + PAGE_SIZE - 1) / PAGE_SIZE; int i; - patch_vdso(vdso_start, vdso_end - vdso_start); - vdso_size = npages << PAGE_SHIFT; - for (i = 0; i < npages; i++) - vdso_pages[i] = virt_to_page(vdso_start + i*PAGE_SIZE); + vdso_pages = kmalloc(sizeof(struct page *) * npages, GFP_KERNEL); + if (!vdso_pages) + goto oom; + for (i = 0; i < npages; i++) { + struct page *p; + p = alloc_page(GFP_KERNEL); + if (!p) + goto oom; + vdso_pages[i] = p; + copy_page(page_address(p), vdso_start + i*PAGE_SIZE); + } return 0; + + oom: + printk("Cannot allocate vdso\n"); + vdso_enabled = 0; + return -ENOMEM; } -subsys_initcall(init_vdso); +subsys_initcall(init_vdso_vars); struct linux_binprm; diff --git a/trunk/arch/x86/xen/Makefile b/trunk/arch/x86/xen/Makefile index ccf73b2f3e69..a6575b949b11 100644 --- a/trunk/arch/x86/xen/Makefile +++ b/trunk/arch/x86/xen/Makefile @@ -13,7 +13,7 @@ CFLAGS_mmu.o := $(nostackp) obj-y := enlighten.o setup.o multicalls.o mmu.o irq.o \ time.o xen-asm.o xen-asm_$(BITS).o \ grant-table.o suspend.o platform-pci-unplug.o \ - p2m.o trace.o + p2m.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_PARAVIRT_SPINLOCKS)+= spinlock.o diff --git a/trunk/arch/x86/xen/enlighten.c b/trunk/arch/x86/xen/enlighten.c index 974a528458a0..53257421082b 100644 --- a/trunk/arch/x86/xen/enlighten.c +++ b/trunk/arch/x86/xen/enlighten.c @@ -341,8 +341,6 @@ static void xen_set_ldt(const void *addr, unsigned entries) struct mmuext_op *op; struct multicall_space mcs = xen_mc_entry(sizeof(*op)); - trace_xen_cpu_set_ldt(addr, entries); - op = mcs.args; op->cmd = MMUEXT_SET_LDT; op->arg1.linear_addr = (unsigned long)addr; @@ -498,8 +496,6 @@ static void xen_write_ldt_entry(struct desc_struct *dt, int entrynum, xmaddr_t mach_lp = arbitrary_virt_to_machine(&dt[entrynum]); u64 entry = *(u64 *)ptr; - trace_xen_cpu_write_ldt_entry(dt, entrynum, entry); - preempt_disable(); xen_mc_flush(); @@ -569,8 +565,6 @@ static void xen_write_idt_entry(gate_desc *dt, int entrynum, const gate_desc *g) unsigned long p = (unsigned long)&dt[entrynum]; unsigned long start, end; - trace_xen_cpu_write_idt_entry(dt, entrynum, g); - preempt_disable(); start = __this_cpu_read(idt_desc.address); @@ -625,8 +619,6 @@ static void xen_load_idt(const struct desc_ptr *desc) static DEFINE_SPINLOCK(lock); static struct trap_info traps[257]; - trace_xen_cpu_load_idt(desc); - spin_lock(&lock); __get_cpu_var(idt_desc) = *desc; @@ -645,8 +637,6 @@ static void xen_load_idt(const struct desc_ptr *desc) static void xen_write_gdt_entry(struct desc_struct *dt, int entry, const void *desc, int type) { - trace_xen_cpu_write_gdt_entry(dt, entry, desc, type); - preempt_disable(); switch (type) { @@ -675,8 +665,6 @@ static void xen_write_gdt_entry(struct desc_struct *dt, int entry, static void __init xen_write_gdt_entry_boot(struct desc_struct *dt, int entry, const void *desc, int type) { - trace_xen_cpu_write_gdt_entry(dt, entry, desc, type); - switch (type) { case DESC_LDT: case DESC_TSS: @@ -696,9 +684,7 @@ static void __init xen_write_gdt_entry_boot(struct desc_struct *dt, int entry, static void xen_load_sp0(struct tss_struct *tss, struct thread_struct *thread) { - struct multicall_space mcs; - - mcs = xen_mc_entry(0); + struct multicall_space mcs = xen_mc_entry(0); MULTI_stack_switch(mcs.mc, __KERNEL_DS, thread->sp0); xen_mc_issue(PARAVIRT_LAZY_CPU); } diff --git a/trunk/arch/x86/xen/mmu.c b/trunk/arch/x86/xen/mmu.c index f987bde77c49..0ccccb67a993 100644 --- a/trunk/arch/x86/xen/mmu.c +++ b/trunk/arch/x86/xen/mmu.c @@ -48,8 +48,6 @@ #include #include -#include - #include #include #include @@ -196,8 +194,6 @@ void xen_set_domain_pte(pte_t *ptep, pte_t pteval, unsigned domid) struct multicall_space mcs; struct mmu_update *u; - trace_xen_mmu_set_domain_pte(ptep, pteval, domid); - mcs = xen_mc_entry(sizeof(*u)); u = mcs.args; @@ -229,24 +225,6 @@ static void xen_extend_mmu_update(const struct mmu_update *update) *u = *update; } -static void xen_extend_mmuext_op(const struct mmuext_op *op) -{ - struct multicall_space mcs; - struct mmuext_op *u; - - mcs = xen_mc_extend_args(__HYPERVISOR_mmuext_op, sizeof(*u)); - - if (mcs.mc != NULL) { - mcs.mc->args[1]++; - } else { - mcs = __xen_mc_entry(sizeof(*u)); - MULTI_mmuext_op(mcs.mc, mcs.args, 1, NULL, DOMID_SELF); - } - - u = mcs.args; - *u = *op; -} - static void xen_set_pmd_hyper(pmd_t *ptr, pmd_t val) { struct mmu_update u; @@ -267,8 +245,6 @@ static void xen_set_pmd_hyper(pmd_t *ptr, pmd_t val) static void xen_set_pmd(pmd_t *ptr, pmd_t val) { - trace_xen_mmu_set_pmd(ptr, val); - /* If page is not pinned, we can just update the entry directly */ if (!xen_page_pinned(ptr)) { @@ -306,30 +282,22 @@ static bool xen_batched_set_pte(pte_t *ptep, pte_t pteval) return true; } -static inline void __xen_set_pte(pte_t *ptep, pte_t pteval) +static void xen_set_pte(pte_t *ptep, pte_t pteval) { if (!xen_batched_set_pte(ptep, pteval)) native_set_pte(ptep, pteval); } -static void xen_set_pte(pte_t *ptep, pte_t pteval) -{ - trace_xen_mmu_set_pte(ptep, pteval); - __xen_set_pte(ptep, pteval); -} - static void xen_set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pteval) { - trace_xen_mmu_set_pte_at(mm, addr, ptep, pteval); - __xen_set_pte(ptep, pteval); + xen_set_pte(ptep, pteval); } pte_t xen_ptep_modify_prot_start(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { /* Just return the pte as-is. We preserve the bits on commit */ - trace_xen_mmu_ptep_modify_prot_start(mm, addr, ptep, *ptep); return *ptep; } @@ -338,7 +306,6 @@ void xen_ptep_modify_prot_commit(struct mm_struct *mm, unsigned long addr, { struct mmu_update u; - trace_xen_mmu_ptep_modify_prot_commit(mm, addr, ptep, pte); xen_mc_batch(); u.ptr = virt_to_machine(ptep).maddr | MMU_PT_UPDATE_PRESERVE_AD; @@ -563,8 +530,6 @@ static void xen_set_pud_hyper(pud_t *ptr, pud_t val) static void xen_set_pud(pud_t *ptr, pud_t val) { - trace_xen_mmu_set_pud(ptr, val); - /* If page is not pinned, we can just update the entry directly */ if (!xen_page_pinned(ptr)) { @@ -578,20 +543,17 @@ static void xen_set_pud(pud_t *ptr, pud_t val) #ifdef CONFIG_X86_PAE static void xen_set_pte_atomic(pte_t *ptep, pte_t pte) { - trace_xen_mmu_set_pte_atomic(ptep, pte); set_64bit((u64 *)ptep, native_pte_val(pte)); } static void xen_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { - trace_xen_mmu_pte_clear(mm, addr, ptep); if (!xen_batched_set_pte(ptep, native_make_pte(0))) native_pte_clear(mm, addr, ptep); } static void xen_pmd_clear(pmd_t *pmdp) { - trace_xen_mmu_pmd_clear(pmdp); set_pmd(pmdp, __pmd(0)); } #endif /* CONFIG_X86_PAE */ @@ -667,8 +629,6 @@ static void xen_set_pgd(pgd_t *ptr, pgd_t val) { pgd_t *user_ptr = xen_get_user_pgd(ptr); - trace_xen_mmu_set_pgd(ptr, user_ptr, val); - /* If page is not pinned, we can just update the entry directly */ if (!xen_page_pinned(ptr)) { @@ -828,12 +788,14 @@ static void xen_pte_unlock(void *v) static void xen_do_pin(unsigned level, unsigned long pfn) { - struct mmuext_op op; - - op.cmd = level; - op.arg1.mfn = pfn_to_mfn(pfn); + struct mmuext_op *op; + struct multicall_space mcs; - xen_extend_mmuext_op(&op); + mcs = __xen_mc_entry(sizeof(*op)); + op = mcs.args; + op->cmd = level; + op->arg1.mfn = pfn_to_mfn(pfn); + MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF); } static int xen_pin_page(struct mm_struct *mm, struct page *page, @@ -901,8 +863,6 @@ static int xen_pin_page(struct mm_struct *mm, struct page *page, read-only, and can be pinned. */ static void __xen_pgd_pin(struct mm_struct *mm, pgd_t *pgd) { - trace_xen_mmu_pgd_pin(mm, pgd); - xen_mc_batch(); if (__xen_pgd_walk(mm, pgd, xen_pin_page, USER_LIMIT)) { @@ -1028,8 +988,6 @@ static int xen_unpin_page(struct mm_struct *mm, struct page *page, /* Release a pagetables pages back as normal RW */ static void __xen_pgd_unpin(struct mm_struct *mm, pgd_t *pgd) { - trace_xen_mmu_pgd_unpin(mm, pgd); - xen_mc_batch(); xen_do_pin(MMUEXT_UNPIN_TABLE, PFN_DOWN(__pa(pgd))); @@ -1238,8 +1196,6 @@ static void xen_flush_tlb(void) struct mmuext_op *op; struct multicall_space mcs; - trace_xen_mmu_flush_tlb(0); - preempt_disable(); mcs = xen_mc_entry(sizeof(*op)); @@ -1258,8 +1214,6 @@ static void xen_flush_tlb_single(unsigned long addr) struct mmuext_op *op; struct multicall_space mcs; - trace_xen_mmu_flush_tlb_single(addr); - preempt_disable(); mcs = xen_mc_entry(sizeof(*op)); @@ -1286,8 +1240,6 @@ static void xen_flush_tlb_others(const struct cpumask *cpus, } *args; struct multicall_space mcs; - trace_xen_mmu_flush_tlb_others(cpus, mm, va); - if (cpumask_empty(cpus)) return; /* nothing to do */ @@ -1323,11 +1275,10 @@ static void set_current_cr3(void *v) static void __xen_write_cr3(bool kernel, unsigned long cr3) { - struct mmuext_op op; + struct mmuext_op *op; + struct multicall_space mcs; unsigned long mfn; - trace_xen_mmu_write_cr3(kernel, cr3); - if (cr3) mfn = pfn_to_mfn(PFN_DOWN(cr3)); else @@ -1335,10 +1286,13 @@ static void __xen_write_cr3(bool kernel, unsigned long cr3) WARN_ON(mfn == 0 && kernel); - op.cmd = kernel ? MMUEXT_NEW_BASEPTR : MMUEXT_NEW_USER_BASEPTR; - op.arg1.mfn = mfn; + mcs = __xen_mc_entry(sizeof(*op)); + + op = mcs.args; + op->cmd = kernel ? MMUEXT_NEW_BASEPTR : MMUEXT_NEW_USER_BASEPTR; + op->arg1.mfn = mfn; - xen_extend_mmuext_op(&op); + MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF); if (kernel) { percpu_write(xen_cr3, cr3); @@ -1497,52 +1451,19 @@ static void __init xen_release_pmd_init(unsigned long pfn) make_lowmem_page_readwrite(__va(PFN_PHYS(pfn))); } -static inline void __pin_pagetable_pfn(unsigned cmd, unsigned long pfn) -{ - struct multicall_space mcs; - struct mmuext_op *op; - - mcs = __xen_mc_entry(sizeof(*op)); - op = mcs.args; - op->cmd = cmd; - op->arg1.mfn = pfn_to_mfn(pfn); - - MULTI_mmuext_op(mcs.mc, mcs.args, 1, NULL, DOMID_SELF); -} - -static inline void __set_pfn_prot(unsigned long pfn, pgprot_t prot) -{ - struct multicall_space mcs; - unsigned long addr = (unsigned long)__va(pfn << PAGE_SHIFT); - - mcs = __xen_mc_entry(0); - MULTI_update_va_mapping(mcs.mc, (unsigned long)addr, - pfn_pte(pfn, prot), 0); -} - /* This needs to make sure the new pte page is pinned iff its being attached to a pinned pagetable. */ -static inline void xen_alloc_ptpage(struct mm_struct *mm, unsigned long pfn, - unsigned level) +static void xen_alloc_ptpage(struct mm_struct *mm, unsigned long pfn, unsigned level) { - bool pinned = PagePinned(virt_to_page(mm->pgd)); - - trace_xen_mmu_alloc_ptpage(mm, pfn, level, pinned); - - if (pinned) { - struct page *page = pfn_to_page(pfn); + struct page *page = pfn_to_page(pfn); + if (PagePinned(virt_to_page(mm->pgd))) { SetPagePinned(page); if (!PageHighMem(page)) { - xen_mc_batch(); - - __set_pfn_prot(pfn, PAGE_KERNEL_RO); - + make_lowmem_page_readonly(__va(PFN_PHYS((unsigned long)pfn))); if (level == PT_PTE && USE_SPLIT_PTLOCKS) - __pin_pagetable_pfn(MMUEXT_PIN_L1_TABLE, pfn); - - xen_mc_issue(PARAVIRT_LAZY_MMU); + pin_pagetable_pfn(MMUEXT_PIN_L1_TABLE, pfn); } else { /* make sure there are no stray mappings of this page */ @@ -1562,23 +1483,15 @@ static void xen_alloc_pmd(struct mm_struct *mm, unsigned long pfn) } /* This should never happen until we're OK to use struct page */ -static inline void xen_release_ptpage(unsigned long pfn, unsigned level) +static void xen_release_ptpage(unsigned long pfn, unsigned level) { struct page *page = pfn_to_page(pfn); - bool pinned = PagePinned(page); - trace_xen_mmu_release_ptpage(pfn, level, pinned); - - if (pinned) { + if (PagePinned(page)) { if (!PageHighMem(page)) { - xen_mc_batch(); - if (level == PT_PTE && USE_SPLIT_PTLOCKS) - __pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, pfn); - - __set_pfn_prot(pfn, PAGE_KERNEL); - - xen_mc_issue(PARAVIRT_LAZY_MMU); + pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, pfn); + make_lowmem_page_readwrite(__va(PFN_PHYS(pfn))); } ClearPagePinned(page); } diff --git a/trunk/arch/x86/xen/multicalls.c b/trunk/arch/x86/xen/multicalls.c index 0d82003e76ad..1b2b73ff0a6e 100644 --- a/trunk/arch/x86/xen/multicalls.c +++ b/trunk/arch/x86/xen/multicalls.c @@ -30,13 +30,12 @@ #define MC_BATCH 32 -#define MC_DEBUG 0 +#define MC_DEBUG 1 #define MC_ARGS (MC_BATCH * 16) struct mc_buffer { - unsigned mcidx, argidx, cbidx; struct multicall_entry entries[MC_BATCH]; #if MC_DEBUG struct multicall_entry debug[MC_BATCH]; @@ -47,15 +46,85 @@ struct mc_buffer { void (*fn)(void *); void *data; } callbacks[MC_BATCH]; + unsigned mcidx, argidx, cbidx; }; static DEFINE_PER_CPU(struct mc_buffer, mc_buffer); DEFINE_PER_CPU(unsigned long, xen_mc_irq_flags); +/* flush reasons 0- slots, 1- args, 2- callbacks */ +enum flush_reasons +{ + FL_SLOTS, + FL_ARGS, + FL_CALLBACKS, + + FL_N_REASONS +}; + +#ifdef CONFIG_XEN_DEBUG_FS +#define NHYPERCALLS 40 /* not really */ + +static struct { + unsigned histo[MC_BATCH+1]; + + unsigned issued; + unsigned arg_total; + unsigned hypercalls; + unsigned histo_hypercalls[NHYPERCALLS]; + + unsigned flush[FL_N_REASONS]; +} mc_stats; + +static u8 zero_stats; + +static inline void check_zero(void) +{ + if (unlikely(zero_stats)) { + memset(&mc_stats, 0, sizeof(mc_stats)); + zero_stats = 0; + } +} + +static void mc_add_stats(const struct mc_buffer *mc) +{ + int i; + + check_zero(); + + mc_stats.issued++; + mc_stats.hypercalls += mc->mcidx; + mc_stats.arg_total += mc->argidx; + + mc_stats.histo[mc->mcidx]++; + for(i = 0; i < mc->mcidx; i++) { + unsigned op = mc->entries[i].op; + if (op < NHYPERCALLS) + mc_stats.histo_hypercalls[op]++; + } +} + +static void mc_stats_flush(enum flush_reasons idx) +{ + check_zero(); + + mc_stats.flush[idx]++; +} + +#else /* !CONFIG_XEN_DEBUG_FS */ + +static inline void mc_add_stats(const struct mc_buffer *mc) +{ +} + +static inline void mc_stats_flush(enum flush_reasons idx) +{ +} +#endif /* CONFIG_XEN_DEBUG_FS */ + void xen_mc_flush(void) { struct mc_buffer *b = &__get_cpu_var(mc_buffer); - struct multicall_entry *mc; int ret = 0; unsigned long flags; int i; @@ -66,26 +135,9 @@ void xen_mc_flush(void) something in the middle */ local_irq_save(flags); - trace_xen_mc_flush(b->mcidx, b->argidx, b->cbidx); - - switch (b->mcidx) { - case 0: - /* no-op */ - BUG_ON(b->argidx != 0); - break; - - case 1: - /* Singleton multicall - bypass multicall machinery - and just do the call directly. */ - mc = &b->entries[0]; - - mc->result = privcmd_call(mc->op, - mc->args[0], mc->args[1], mc->args[2], - mc->args[3], mc->args[4]); - ret = mc->result < 0; - break; + mc_add_stats(b); - default: + if (b->mcidx) { #if MC_DEBUG memcpy(b->debug, b->entries, b->mcidx * sizeof(struct multicall_entry)); @@ -112,10 +164,11 @@ void xen_mc_flush(void) } } #endif - } - b->mcidx = 0; - b->argidx = 0; + b->mcidx = 0; + b->argidx = 0; + } else + BUG_ON(b->argidx != 0); for (i = 0; i < b->cbidx; i++) { struct callback *cb = &b->callbacks[i]; @@ -135,21 +188,18 @@ struct multicall_space __xen_mc_entry(size_t args) struct multicall_space ret; unsigned argidx = roundup(b->argidx, sizeof(u64)); - trace_xen_mc_entry_alloc(args); - BUG_ON(preemptible()); BUG_ON(b->argidx >= MC_ARGS); - if (unlikely(b->mcidx == MC_BATCH || - (argidx + args) >= MC_ARGS)) { - trace_xen_mc_flush_reason((b->mcidx == MC_BATCH) ? - XEN_MC_FL_BATCH : XEN_MC_FL_ARGS); + if (b->mcidx == MC_BATCH || + (argidx + args) >= MC_ARGS) { + mc_stats_flush(b->mcidx == MC_BATCH ? FL_SLOTS : FL_ARGS); xen_mc_flush(); argidx = roundup(b->argidx, sizeof(u64)); } ret.mc = &b->entries[b->mcidx]; -#if MC_DEBUG +#ifdef MC_DEBUG b->caller[b->mcidx] = __builtin_return_address(0); #endif b->mcidx++; @@ -168,25 +218,20 @@ struct multicall_space xen_mc_extend_args(unsigned long op, size_t size) BUG_ON(preemptible()); BUG_ON(b->argidx >= MC_ARGS); - if (unlikely(b->mcidx == 0 || - b->entries[b->mcidx - 1].op != op)) { - trace_xen_mc_extend_args(op, size, XEN_MC_XE_BAD_OP); - goto out; - } + if (b->mcidx == 0) + return ret; - if (unlikely((b->argidx + size) >= MC_ARGS)) { - trace_xen_mc_extend_args(op, size, XEN_MC_XE_NO_SPACE); - goto out; - } + if (b->entries[b->mcidx - 1].op != op) + return ret; + + if ((b->argidx + size) >= MC_ARGS) + return ret; ret.mc = &b->entries[b->mcidx - 1]; ret.args = &b->args[b->argidx]; b->argidx += size; BUG_ON(b->argidx >= MC_ARGS); - - trace_xen_mc_extend_args(op, size, XEN_MC_XE_OK); -out: return ret; } @@ -196,13 +241,43 @@ void xen_mc_callback(void (*fn)(void *), void *data) struct callback *cb; if (b->cbidx == MC_BATCH) { - trace_xen_mc_flush_reason(XEN_MC_FL_CALLBACK); + mc_stats_flush(FL_CALLBACKS); xen_mc_flush(); } - trace_xen_mc_callback(fn, data); - cb = &b->callbacks[b->cbidx++]; cb->fn = fn; cb->data = data; } + +#ifdef CONFIG_XEN_DEBUG_FS + +static struct dentry *d_mc_debug; + +static int __init xen_mc_debugfs(void) +{ + struct dentry *d_xen = xen_init_debugfs(); + + if (d_xen == NULL) + return -ENOMEM; + + d_mc_debug = debugfs_create_dir("multicalls", d_xen); + + debugfs_create_u8("zero_stats", 0644, d_mc_debug, &zero_stats); + + debugfs_create_u32("batches", 0444, d_mc_debug, &mc_stats.issued); + debugfs_create_u32("hypercalls", 0444, d_mc_debug, &mc_stats.hypercalls); + debugfs_create_u32("arg_total", 0444, d_mc_debug, &mc_stats.arg_total); + + xen_debugfs_create_u32_array("batch_histo", 0444, d_mc_debug, + mc_stats.histo, MC_BATCH); + xen_debugfs_create_u32_array("hypercall_histo", 0444, d_mc_debug, + mc_stats.histo_hypercalls, NHYPERCALLS); + xen_debugfs_create_u32_array("flush_reasons", 0444, d_mc_debug, + mc_stats.flush, FL_N_REASONS); + + return 0; +} +fs_initcall(xen_mc_debugfs); + +#endif /* CONFIG_XEN_DEBUG_FS */ diff --git a/trunk/arch/x86/xen/multicalls.h b/trunk/arch/x86/xen/multicalls.h index dee79b78a90f..4ec8035e3216 100644 --- a/trunk/arch/x86/xen/multicalls.h +++ b/trunk/arch/x86/xen/multicalls.h @@ -1,8 +1,6 @@ #ifndef _XEN_MULTICALLS_H #define _XEN_MULTICALLS_H -#include - #include "xen-ops.h" /* Multicalls */ @@ -22,10 +20,8 @@ DECLARE_PER_CPU(unsigned long, xen_mc_irq_flags); static inline void xen_mc_batch(void) { unsigned long flags; - /* need to disable interrupts until this entry is complete */ local_irq_save(flags); - trace_xen_mc_batch(paravirt_get_lazy_mode()); __this_cpu_write(xen_mc_irq_flags, flags); } @@ -41,8 +37,6 @@ void xen_mc_flush(void); /* Issue a multicall if we're not in a lazy mode */ static inline void xen_mc_issue(unsigned mode) { - trace_xen_mc_issue(mode); - if ((paravirt_get_lazy_mode() & mode) == 0) xen_mc_flush(); diff --git a/trunk/arch/x86/xen/trace.c b/trunk/arch/x86/xen/trace.c deleted file mode 100644 index 734beba2a08c..000000000000 --- a/trunk/arch/x86/xen/trace.c +++ /dev/null @@ -1,61 +0,0 @@ -#include - -#define N(x) [__HYPERVISOR_##x] = "("#x")" -static const char *xen_hypercall_names[] = { - N(set_trap_table), - N(mmu_update), - N(set_gdt), - N(stack_switch), - N(set_callbacks), - N(fpu_taskswitch), - N(sched_op_compat), - N(dom0_op), - N(set_debugreg), - N(get_debugreg), - N(update_descriptor), - N(memory_op), - N(multicall), - N(update_va_mapping), - N(set_timer_op), - N(event_channel_op_compat), - N(xen_version), - N(console_io), - N(physdev_op_compat), - N(grant_table_op), - N(vm_assist), - N(update_va_mapping_otherdomain), - N(iret), - N(vcpu_op), - N(set_segment_base), - N(mmuext_op), - N(acm_op), - N(nmi_op), - N(sched_op), - N(callback_op), - N(xenoprof_op), - N(event_channel_op), - N(physdev_op), - N(hvm_op), - -/* Architecture-specific hypercall definitions. */ - N(arch_0), - N(arch_1), - N(arch_2), - N(arch_3), - N(arch_4), - N(arch_5), - N(arch_6), - N(arch_7), -}; -#undef N - -static const char *xen_hypercall_name(unsigned op) -{ - if (op < ARRAY_SIZE(xen_hypercall_names) && xen_hypercall_names[op] != NULL) - return xen_hypercall_names[op]; - - return ""; -} - -#define CREATE_TRACE_POINTS -#include diff --git a/trunk/arch/xtensa/Kconfig b/trunk/arch/xtensa/Kconfig index c346ccdce0df..5d43c1f8ada8 100644 --- a/trunk/arch/xtensa/Kconfig +++ b/trunk/arch/xtensa/Kconfig @@ -80,7 +80,18 @@ config XTENSA_UNALIGNED_USER Say Y here to enable unaligned memory access in user space. -source "kernel/Kconfig.preempt" +config PREEMPT + bool "Preemptible Kernel" + help + This option reduces the latency of the kernel when reacting to + real-time or interactive events by allowing a low priority process to + be preempted even if it is in kernel mode executing a system call. + Unfortunately the kernel code has some race conditions if both + CONFIG_SMP and CONFIG_PREEMPT are enabled, so this option is + currently disabled if you are building an SMP kernel. + + Say Y here if you are building a kernel for a desktop, embedded + or real-time system. Say N if you are unsure. config MATH_EMULATION bool "Math emulation" diff --git a/trunk/arch/xtensa/kernel/module.c b/trunk/arch/xtensa/kernel/module.c index 451dda928c93..c1accea8cb56 100644 --- a/trunk/arch/xtensa/kernel/module.c +++ b/trunk/arch/xtensa/kernel/module.c @@ -24,6 +24,26 @@ #undef DEBUG_RELOCATE +void *module_alloc(unsigned long size) +{ + if (size == 0) + return NULL; + return vmalloc_exec(size); +} + +void module_free(struct module *mod, void *module_region) +{ + vfree(module_region); +} + +int module_frob_arch_sections(Elf32_Ehdr *hdr, + Elf32_Shdr *sechdrs, + char *secstrings, + struct module *mod) +{ + return 0; +} + static int decode_calln_opcode (unsigned char *location) { @@ -46,6 +66,18 @@ decode_l32r_opcode (unsigned char *location) #endif } +int apply_relocate(Elf32_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *mod) +{ + printk(KERN_ERR "module %s: REL RELOCATION unsupported\n", + mod->name); + return -ENOEXEC; + +} + int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, @@ -190,3 +222,14 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, } return 0; } + +int module_finalize(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + struct module *mod) +{ + return 0; +} + +void module_arch_cleanup(struct module *mod) +{ +} diff --git a/trunk/block/blk-core.c b/trunk/block/blk-core.c index 1d49e1c7c905..d2f8f4049abd 100644 --- a/trunk/block/blk-core.c +++ b/trunk/block/blk-core.c @@ -839,9 +839,6 @@ struct request *blk_get_request(struct request_queue *q, int rw, gfp_t gfp_mask) { struct request *rq; - if (unlikely(test_bit(QUEUE_FLAG_DEAD, &q->queue_flags))) - return NULL; - BUG_ON(rw != READ && rw != WRITE); spin_lock_irq(q->queue_lock); diff --git a/trunk/block/blk-exec.c b/trunk/block/blk-exec.c index a1ebceb332f9..8a0e7ec056e7 100644 --- a/trunk/block/blk-exec.c +++ b/trunk/block/blk-exec.c @@ -50,13 +50,6 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk, { int where = at_head ? ELEVATOR_INSERT_FRONT : ELEVATOR_INSERT_BACK; - if (unlikely(test_bit(QUEUE_FLAG_DEAD, &q->queue_flags))) { - rq->errors = -ENXIO; - if (rq->end_io) - rq->end_io(rq, rq->errors); - return; - } - rq->rq_disk = bd_disk; rq->end_io = done; WARN_ON(irqs_disabled()); diff --git a/trunk/block/genhd.c b/trunk/block/genhd.c index 6024b82e3209..3608289c8ecd 100644 --- a/trunk/block/genhd.c +++ b/trunk/block/genhd.c @@ -1018,6 +1018,14 @@ static const struct attribute_group *disk_attr_groups[] = { NULL }; +static void disk_free_ptbl_rcu_cb(struct rcu_head *head) +{ + struct disk_part_tbl *ptbl = + container_of(head, struct disk_part_tbl, rcu_head); + + kfree(ptbl); +} + /** * disk_replace_part_tbl - replace disk->part_tbl in RCU-safe way * @disk: disk to replace part_tbl for @@ -1038,7 +1046,7 @@ static void disk_replace_part_tbl(struct gendisk *disk, if (old_ptbl) { rcu_assign_pointer(old_ptbl->last_lookup, NULL); - kfree_rcu(old_ptbl, rcu_head); + call_rcu(&old_ptbl->rcu_head, disk_free_ptbl_rcu_cb); } } diff --git a/trunk/crypto/Kconfig b/trunk/crypto/Kconfig index 2af81552d65b..87b22ca9c223 100644 --- a/trunk/crypto/Kconfig +++ b/trunk/crypto/Kconfig @@ -458,7 +458,7 @@ config CRYPTO_WP512 config CRYPTO_GHASH_CLMUL_NI_INTEL tristate "GHASH digest algorithm (CLMUL-NI accelerated)" - depends on X86 && 64BIT + depends on (X86 || UML_X86) && 64BIT select CRYPTO_SHASH select CRYPTO_CRYPTD help @@ -533,7 +533,7 @@ config CRYPTO_AES_X86_64 config CRYPTO_AES_NI_INTEL tristate "AES cipher algorithms (AES-NI)" - depends on X86 + depends on (X86 || UML_X86) select CRYPTO_AES_X86_64 if 64BIT select CRYPTO_AES_586 if !64BIT select CRYPTO_CRYPTD diff --git a/trunk/crypto/algif_hash.c b/trunk/crypto/algif_hash.c index ef5356cd280a..62122a1a2f7a 100644 --- a/trunk/crypto/algif_hash.c +++ b/trunk/crypto/algif_hash.c @@ -68,10 +68,8 @@ static int hash_sendmsg(struct kiocb *unused, struct socket *sock, int newlen; newlen = af_alg_make_sg(&ctx->sgl, from, len, 0); - if (newlen < 0) { - err = copied ? 0 : newlen; + if (newlen < 0) goto unlock; - } ahash_request_set_crypt(&ctx->req, ctx->sgl.sg, NULL, newlen); diff --git a/trunk/crypto/arc4.c b/trunk/crypto/arc4.c index 0d12a96da1d8..8be47e13a9e3 100644 --- a/trunk/crypto/arc4.c +++ b/trunk/crypto/arc4.c @@ -1,4 +1,4 @@ -/* +/* * Cryptographic API * * ARC4 Cipher Algorithm @@ -33,15 +33,16 @@ static int arc4_set_key(struct crypto_tfm *tfm, const u8 *in_key, ctx->x = 1; ctx->y = 0; - for (i = 0; i < 256; i++) + for(i = 0; i < 256; i++) ctx->S[i] = i; - for (i = 0; i < 256; i++) { + for(i = 0; i < 256; i++) + { u8 a = ctx->S[i]; j = (j + in_key[k] + a) & 0xff; ctx->S[i] = ctx->S[j]; ctx->S[j] = a; - if (++k >= key_len) + if(++k >= key_len) k = 0; } @@ -79,9 +80,9 @@ static struct crypto_alg arc4_alg = { .cra_u = { .cipher = { .cia_min_keysize = ARC4_MIN_KEY_SIZE, .cia_max_keysize = ARC4_MAX_KEY_SIZE, - .cia_setkey = arc4_set_key, - .cia_encrypt = arc4_crypt, - .cia_decrypt = arc4_crypt } } + .cia_setkey = arc4_set_key, + .cia_encrypt = arc4_crypt, + .cia_decrypt = arc4_crypt } } }; static int __init arc4_init(void) diff --git a/trunk/crypto/crc32c.c b/trunk/crypto/crc32c.c index 3f9ad2801052..de9e55c29794 100644 --- a/trunk/crypto/crc32c.c +++ b/trunk/crypto/crc32c.c @@ -224,11 +224,11 @@ static int crc32c_cra_init(struct crypto_tfm *tfm) static struct shash_alg alg = { .digestsize = CHKSUM_DIGEST_SIZE, .setkey = chksum_setkey, - .init = chksum_init, - .update = chksum_update, - .final = chksum_final, - .finup = chksum_finup, - .digest = chksum_digest, + .init = chksum_init, + .update = chksum_update, + .final = chksum_final, + .finup = chksum_finup, + .digest = chksum_digest, .descsize = sizeof(struct chksum_desc_ctx), .base = { .cra_name = "crc32c", diff --git a/trunk/crypto/gf128mul.c b/trunk/crypto/gf128mul.c index 5276607c72d0..df35e4ccd07e 100644 --- a/trunk/crypto/gf128mul.c +++ b/trunk/crypto/gf128mul.c @@ -182,7 +182,7 @@ void gf128mul_lle(be128 *r, const be128 *b) for (i = 0; i < 7; ++i) gf128mul_x_lle(&p[i + 1], &p[i]); - memset(r, 0, sizeof(*r)); + memset(r, 0, sizeof(r)); for (i = 0;;) { u8 ch = ((u8 *)b)[15 - i]; @@ -220,7 +220,7 @@ void gf128mul_bbe(be128 *r, const be128 *b) for (i = 0; i < 7; ++i) gf128mul_x_bbe(&p[i + 1], &p[i]); - memset(r, 0, sizeof(*r)); + memset(r, 0, sizeof(r)); for (i = 0;;) { u8 ch = ((u8 *)b)[i]; diff --git a/trunk/crypto/sha1_generic.c b/trunk/crypto/sha1_generic.c index 00ae60eb9254..0416091bf45a 100644 --- a/trunk/crypto/sha1_generic.c +++ b/trunk/crypto/sha1_generic.c @@ -43,26 +43,25 @@ static int sha1_update(struct shash_desc *desc, const u8 *data, unsigned int partial, done; const u8 *src; - partial = sctx->count % SHA1_BLOCK_SIZE; + partial = sctx->count & 0x3f; sctx->count += len; done = 0; src = data; - if ((partial + len) >= SHA1_BLOCK_SIZE) { + if ((partial + len) > 63) { u32 temp[SHA_WORKSPACE_WORDS]; if (partial) { done = -partial; - memcpy(sctx->buffer + partial, data, - done + SHA1_BLOCK_SIZE); + memcpy(sctx->buffer + partial, data, done + 64); src = sctx->buffer; } do { sha_transform(sctx->state, src, temp); - done += SHA1_BLOCK_SIZE; + done += 64; src = data + done; - } while (done + SHA1_BLOCK_SIZE <= len); + } while (done + 63 < len); memset(temp, 0, sizeof(temp)); partial = 0; diff --git a/trunk/crypto/testmgr.h b/trunk/crypto/testmgr.h index 27adc92842ba..27e60619538e 100644 --- a/trunk/crypto/testmgr.h +++ b/trunk/crypto/testmgr.h @@ -2976,8 +2976,8 @@ static struct cipher_testvec cast6_dec_tv_template[] = { #define AES_CBC_DEC_TEST_VECTORS 4 #define AES_LRW_ENC_TEST_VECTORS 8 #define AES_LRW_DEC_TEST_VECTORS 8 -#define AES_XTS_ENC_TEST_VECTORS 5 -#define AES_XTS_DEC_TEST_VECTORS 5 +#define AES_XTS_ENC_TEST_VECTORS 4 +#define AES_XTS_DEC_TEST_VECTORS 4 #define AES_CTR_ENC_TEST_VECTORS 3 #define AES_CTR_DEC_TEST_VECTORS 3 #define AES_OFB_ENC_TEST_VECTORS 1 @@ -3926,150 +3926,6 @@ static struct cipher_testvec aes_xts_enc_tv_template[] = { "\x0a\x28\x2d\xf9\x20\x14\x7b\xea" "\xbe\x42\x1e\xe5\x31\x9d\x05\x68", .rlen = 512, - }, { /* XTS-AES 10, XTS-AES-256, data unit 512 bytes */ - .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", - "\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 = "\x1c\x3b\x3a\x10\x2f\x77\x03\x86" - "\xe4\x83\x6c\x99\xe3\x70\xcf\x9b" - "\xea\x00\x80\x3f\x5e\x48\x23\x57" - "\xa4\xae\x12\xd4\x14\xa3\xe6\x3b" - "\x5d\x31\xe2\x76\xf8\xfe\x4a\x8d" - "\x66\xb3\x17\xf9\xac\x68\x3f\x44" - "\x68\x0a\x86\xac\x35\xad\xfc\x33" - "\x45\xbe\xfe\xcb\x4b\xb1\x88\xfd" - "\x57\x76\x92\x6c\x49\xa3\x09\x5e" - "\xb1\x08\xfd\x10\x98\xba\xec\x70" - "\xaa\xa6\x69\x99\xa7\x2a\x82\xf2" - "\x7d\x84\x8b\x21\xd4\xa7\x41\xb0" - "\xc5\xcd\x4d\x5f\xff\x9d\xac\x89" - "\xae\xba\x12\x29\x61\xd0\x3a\x75" - "\x71\x23\xe9\x87\x0f\x8a\xcf\x10" - "\x00\x02\x08\x87\x89\x14\x29\xca" - "\x2a\x3e\x7a\x7d\x7d\xf7\xb1\x03" - "\x55\x16\x5c\x8b\x9a\x6d\x0a\x7d" - "\xe8\xb0\x62\xc4\x50\x0d\xc4\xcd" - "\x12\x0c\x0f\x74\x18\xda\xe3\xd0" - "\xb5\x78\x1c\x34\x80\x3f\xa7\x54" - "\x21\xc7\x90\xdf\xe1\xde\x18\x34" - "\xf2\x80\xd7\x66\x7b\x32\x7f\x6c" - "\x8c\xd7\x55\x7e\x12\xac\x3a\x0f" - "\x93\xec\x05\xc5\x2e\x04\x93\xef" - "\x31\xa1\x2d\x3d\x92\x60\xf7\x9a" - "\x28\x9d\x6a\x37\x9b\xc7\x0c\x50" - "\x84\x14\x73\xd1\xa8\xcc\x81\xec" - "\x58\x3e\x96\x45\xe0\x7b\x8d\x96" - "\x70\x65\x5b\xa5\xbb\xcf\xec\xc6" - "\xdc\x39\x66\x38\x0a\xd8\xfe\xcb" - "\x17\xb6\xba\x02\x46\x9a\x02\x0a" - "\x84\xe1\x8e\x8f\x84\x25\x20\x70" - "\xc1\x3e\x9f\x1f\x28\x9b\xe5\x4f" - "\xbc\x48\x14\x57\x77\x8f\x61\x60" - "\x15\xe1\x32\x7a\x02\xb1\x40\xf1" - "\x50\x5e\xb3\x09\x32\x6d\x68\x37" - "\x8f\x83\x74\x59\x5c\x84\x9d\x84" - "\xf4\xc3\x33\xec\x44\x23\x88\x51" - "\x43\xcb\x47\xbd\x71\xc5\xed\xae" - "\x9b\xe6\x9a\x2f\xfe\xce\xb1\xbe" - "\xc9\xde\x24\x4f\xbe\x15\x99\x2b" - "\x11\xb7\x7c\x04\x0f\x12\xbd\x8f" - "\x6a\x97\x5a\x44\xa0\xf9\x0c\x29" - "\xa9\xab\xc3\xd4\xd8\x93\x92\x72" - "\x84\xc5\x87\x54\xcc\xe2\x94\x52" - "\x9f\x86\x14\xdc\xd2\xab\xa9\x91" - "\x92\x5f\xed\xc4\xae\x74\xff\xac" - "\x6e\x33\x3b\x93\xeb\x4a\xff\x04" - "\x79\xda\x9a\x41\x0e\x44\x50\xe0" - "\xdd\x7a\xe4\xc6\xe2\x91\x09\x00" - "\x57\x5d\xa4\x01\xfc\x07\x05\x9f" - "\x64\x5e\x8b\x7e\x9b\xfd\xef\x33" - "\x94\x30\x54\xff\x84\x01\x14\x93" - "\xc2\x7b\x34\x29\xea\xed\xb4\xed" - "\x53\x76\x44\x1a\x77\xed\x43\x85" - "\x1a\xd7\x7f\x16\xf5\x41\xdf\xd2" - "\x69\xd5\x0d\x6a\x5f\x14\xfb\x0a" - "\xab\x1c\xbb\x4c\x15\x50\xbe\x97" - "\xf7\xab\x40\x66\x19\x3c\x4c\xaa" - "\x77\x3d\xad\x38\x01\x4b\xd2\x09" - "\x2f\xa7\x55\xc8\x24\xbb\x5e\x54" - "\xc4\xf3\x6f\xfd\xa9\xfc\xea\x70" - "\xb9\xc6\xe6\x93\xe1\x48\xc1\x51", - .rlen = 512, } }; @@ -4267,151 +4123,6 @@ static struct cipher_testvec aes_xts_dec_tv_template[] = { "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", .rlen = 512, - }, { /* XTS-AES 10, XTS-AES-256, data unit 512 bytes */ - .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", - "\x00\x00\x00\x00\x00\x00\x00\x00", - "\x00\x00\x00\x00\x00\x00\x00\x00", - .input = "\x1c\x3b\x3a\x10\x2f\x77\x03\x86" - "\xe4\x83\x6c\x99\xe3\x70\xcf\x9b" - "\xea\x00\x80\x3f\x5e\x48\x23\x57" - "\xa4\xae\x12\xd4\x14\xa3\xe6\x3b" - "\x5d\x31\xe2\x76\xf8\xfe\x4a\x8d" - "\x66\xb3\x17\xf9\xac\x68\x3f\x44" - "\x68\x0a\x86\xac\x35\xad\xfc\x33" - "\x45\xbe\xfe\xcb\x4b\xb1\x88\xfd" - "\x57\x76\x92\x6c\x49\xa3\x09\x5e" - "\xb1\x08\xfd\x10\x98\xba\xec\x70" - "\xaa\xa6\x69\x99\xa7\x2a\x82\xf2" - "\x7d\x84\x8b\x21\xd4\xa7\x41\xb0" - "\xc5\xcd\x4d\x5f\xff\x9d\xac\x89" - "\xae\xba\x12\x29\x61\xd0\x3a\x75" - "\x71\x23\xe9\x87\x0f\x8a\xcf\x10" - "\x00\x02\x08\x87\x89\x14\x29\xca" - "\x2a\x3e\x7a\x7d\x7d\xf7\xb1\x03" - "\x55\x16\x5c\x8b\x9a\x6d\x0a\x7d" - "\xe8\xb0\x62\xc4\x50\x0d\xc4\xcd" - "\x12\x0c\x0f\x74\x18\xda\xe3\xd0" - "\xb5\x78\x1c\x34\x80\x3f\xa7\x54" - "\x21\xc7\x90\xdf\xe1\xde\x18\x34" - "\xf2\x80\xd7\x66\x7b\x32\x7f\x6c" - "\x8c\xd7\x55\x7e\x12\xac\x3a\x0f" - "\x93\xec\x05\xc5\x2e\x04\x93\xef" - "\x31\xa1\x2d\x3d\x92\x60\xf7\x9a" - "\x28\x9d\x6a\x37\x9b\xc7\x0c\x50" - "\x84\x14\x73\xd1\xa8\xcc\x81\xec" - "\x58\x3e\x96\x45\xe0\x7b\x8d\x96" - "\x70\x65\x5b\xa5\xbb\xcf\xec\xc6" - "\xdc\x39\x66\x38\x0a\xd8\xfe\xcb" - "\x17\xb6\xba\x02\x46\x9a\x02\x0a" - "\x84\xe1\x8e\x8f\x84\x25\x20\x70" - "\xc1\x3e\x9f\x1f\x28\x9b\xe5\x4f" - "\xbc\x48\x14\x57\x77\x8f\x61\x60" - "\x15\xe1\x32\x7a\x02\xb1\x40\xf1" - "\x50\x5e\xb3\x09\x32\x6d\x68\x37" - "\x8f\x83\x74\x59\x5c\x84\x9d\x84" - "\xf4\xc3\x33\xec\x44\x23\x88\x51" - "\x43\xcb\x47\xbd\x71\xc5\xed\xae" - "\x9b\xe6\x9a\x2f\xfe\xce\xb1\xbe" - "\xc9\xde\x24\x4f\xbe\x15\x99\x2b" - "\x11\xb7\x7c\x04\x0f\x12\xbd\x8f" - "\x6a\x97\x5a\x44\xa0\xf9\x0c\x29" - "\xa9\xab\xc3\xd4\xd8\x93\x92\x72" - "\x84\xc5\x87\x54\xcc\xe2\x94\x52" - "\x9f\x86\x14\xdc\xd2\xab\xa9\x91" - "\x92\x5f\xed\xc4\xae\x74\xff\xac" - "\x6e\x33\x3b\x93\xeb\x4a\xff\x04" - "\x79\xda\x9a\x41\x0e\x44\x50\xe0" - "\xdd\x7a\xe4\xc6\xe2\x91\x09\x00" - "\x57\x5d\xa4\x01\xfc\x07\x05\x9f" - "\x64\x5e\x8b\x7e\x9b\xfd\xef\x33" - "\x94\x30\x54\xff\x84\x01\x14\x93" - "\xc2\x7b\x34\x29\xea\xed\xb4\xed" - "\x53\x76\x44\x1a\x77\xed\x43\x85" - "\x1a\xd7\x7f\x16\xf5\x41\xdf\xd2" - "\x69\xd5\x0d\x6a\x5f\x14\xfb\x0a" - "\xab\x1c\xbb\x4c\x15\x50\xbe\x97" - "\xf7\xab\x40\x66\x19\x3c\x4c\xaa" - "\x77\x3d\xad\x38\x01\x4b\xd2\x09" - "\x2f\xa7\x55\xc8\x24\xbb\x5e\x54" - "\xc4\xf3\x6f\xfd\xa9\xfc\xea\x70" - "\xb9\xc6\xe6\x93\xe1\x48\xc1\x51", - .ilen = 512, - .result = "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" - "\x10\x11\x12\x13\x14\x15\x16\x17" - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" - "\x20\x21\x22\x23\x24\x25\x26\x27" - "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" - "\x30\x31\x32\x33\x34\x35\x36\x37" - "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" - "\x40\x41\x42\x43\x44\x45\x46\x47" - "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" - "\x50\x51\x52\x53\x54\x55\x56\x57" - "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" - "\x60\x61\x62\x63\x64\x65\x66\x67" - "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" - "\x70\x71\x72\x73\x74\x75\x76\x77" - "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" - "\x80\x81\x82\x83\x84\x85\x86\x87" - "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" - "\x90\x91\x92\x93\x94\x95\x96\x97" - "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" - "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" - "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" - "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" - "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" - "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" - "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" - "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" - "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" - "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" - "\xe8\xe9\xea\xeb\xec\xed\xee\xef" - "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" - "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" - "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" - "\x10\x11\x12\x13\x14\x15\x16\x17" - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" - "\x20\x21\x22\x23\x24\x25\x26\x27" - "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" - "\x30\x31\x32\x33\x34\x35\x36\x37" - "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" - "\x40\x41\x42\x43\x44\x45\x46\x47" - "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" - "\x50\x51\x52\x53\x54\x55\x56\x57" - "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" - "\x60\x61\x62\x63\x64\x65\x66\x67" - "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" - "\x70\x71\x72\x73\x74\x75\x76\x77" - "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" - "\x80\x81\x82\x83\x84\x85\x86\x87" - "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" - "\x90\x91\x92\x93\x94\x95\x96\x97" - "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" - "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" - "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" - "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" - "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" - "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" - "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" - "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" - "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" - "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" - "\xe8\xe9\xea\xeb\xec\xed\xee\xef" - "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" - "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", - .rlen = 512, - } }; diff --git a/trunk/drivers/Kconfig b/trunk/drivers/Kconfig index 9e7a4f5b5c2e..258473ce8d01 100644 --- a/trunk/drivers/Kconfig +++ b/trunk/drivers/Kconfig @@ -112,8 +112,6 @@ source "drivers/uio/Kconfig" source "drivers/vlynq/Kconfig" -source "drivers/virtio/Kconfig" - source "drivers/xen/Kconfig" source "drivers/staging/Kconfig" @@ -126,6 +124,4 @@ source "drivers/hwspinlock/Kconfig" source "drivers/clocksource/Kconfig" -source "drivers/iommu/Kconfig" - endmenu diff --git a/trunk/drivers/Makefile b/trunk/drivers/Makefile index 939fcdeb2d31..1bc896571a3a 100644 --- a/trunk/drivers/Makefile +++ b/trunk/drivers/Makefile @@ -123,4 +123,3 @@ obj-y += clk/ obj-$(CONFIG_HWSPINLOCK) += hwspinlock/ obj-$(CONFIG_NFC) += nfc/ -obj-$(CONFIG_IOMMU_SUPPORT) += iommu/ diff --git a/trunk/drivers/ata/Kconfig b/trunk/drivers/ata/Kconfig index ca3e6be44a04..75afa75a515e 100644 --- a/trunk/drivers/ata/Kconfig +++ b/trunk/drivers/ata/Kconfig @@ -313,7 +313,6 @@ config PATA_AMD config PATA_ARASAN_CF tristate "ARASAN CompactFlash PATA Controller Support" - depends on DMADEVICES select DMA_ENGINE help Say Y here to support the ARASAN CompactFlash PATA controller diff --git a/trunk/drivers/ata/acard-ahci.c b/trunk/drivers/ata/acard-ahci.c index 3bc8c79bf2c7..ae22be4157b5 100644 --- a/trunk/drivers/ata/acard-ahci.c +++ b/trunk/drivers/ata/acard-ahci.c @@ -135,8 +135,8 @@ static int acard_ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg if (mesg.event & PM_EVENT_SUSPEND && hpriv->flags & AHCI_HFLAG_NO_SUSPEND) { - dev_err(&pdev->dev, - "BIOS update required for suspend/resume\n"); + dev_printk(KERN_ERR, &pdev->dev, + "BIOS update required for suspend/resume\n"); return -EIO; } @@ -187,7 +187,7 @@ static int acard_ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac) if (rc) { rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); if (rc) { - dev_err(&pdev->dev, + dev_printk(KERN_ERR, &pdev->dev, "64-bit DMA enable failed\n"); return rc; } @@ -195,13 +195,14 @@ static int acard_ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac) } else { rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (rc) { - dev_err(&pdev->dev, "32-bit DMA enable failed\n"); + dev_printk(KERN_ERR, &pdev->dev, + "32-bit DMA enable failed\n"); return rc; } rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); if (rc) { - dev_err(&pdev->dev, - "32-bit consistent DMA enable failed\n"); + dev_printk(KERN_ERR, &pdev->dev, + "32-bit consistent DMA enable failed\n"); return rc; } } @@ -342,12 +343,14 @@ static int acard_ahci_port_start(struct ata_port *ap) if (cmd & PORT_CMD_FBSCP) pp->fbs_supported = true; else if (hpriv->flags & AHCI_HFLAG_YES_FBS) { - dev_info(dev, "port %d can do FBS, forcing FBSCP\n", - ap->port_no); + dev_printk(KERN_INFO, dev, + "port %d can do FBS, forcing FBSCP\n", + ap->port_no); pp->fbs_supported = true; } else - dev_warn(dev, "port %d is not capable of FBS\n", - ap->port_no); + dev_printk(KERN_WARNING, dev, + "port %d is not capable of FBS\n", + ap->port_no); } if (pp->fbs_supported) { @@ -403,6 +406,7 @@ static int acard_ahci_port_start(struct ata_port *ap) static int acard_ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { + static int printed_version; unsigned int board_id = ent->driver_data; struct ata_port_info pi = acard_ahci_port_info[board_id]; const struct ata_port_info *ppi[] = { &pi, NULL }; @@ -415,7 +419,8 @@ static int acard_ahci_init_one(struct pci_dev *pdev, const struct pci_device_id WARN_ON((int)ATA_MAX_QUEUE > AHCI_MAX_CMDS); - ata_print_version_once(&pdev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); /* acquire resources */ rc = pcim_enable_device(pdev); diff --git a/trunk/drivers/ata/ahci.c b/trunk/drivers/ata/ahci.c index fb7b90b05922..71afe0371311 100644 --- a/trunk/drivers/ata/ahci.c +++ b/trunk/drivers/ata/ahci.c @@ -79,6 +79,8 @@ enum board_ids { }; static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); +static int ahci_sb600_softreset(struct ata_link *link, unsigned int *class, + unsigned long deadline); static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline); static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class, @@ -102,6 +104,12 @@ static struct ata_port_operations ahci_p5wdh_ops = { .hardreset = ahci_p5wdh_hardreset, }; +static struct ata_port_operations ahci_sb600_ops = { + .inherits = &ahci_ops, + .softreset = ahci_sb600_softreset, + .pmp_softreset = ahci_sb600_softreset, +}; + #define AHCI_HFLAGS(flags) .private_data = (void *)(flags) static const struct ata_port_info ahci_port_info[] = { @@ -180,7 +188,7 @@ static const struct ata_port_info ahci_port_info[] = { .flags = AHCI_FLAG_COMMON, .pio_mask = ATA_PIO4, .udma_mask = ATA_UDMA6, - .port_ops = &ahci_pmp_retry_srst_ops, + .port_ops = &ahci_sb600_ops, }, [board_ahci_sb700] = /* for SB700 and SB800 */ { @@ -188,7 +196,7 @@ static const struct ata_port_info ahci_port_info[] = { .flags = AHCI_FLAG_COMMON, .pio_mask = ATA_PIO4, .udma_mask = ATA_UDMA6, - .port_ops = &ahci_pmp_retry_srst_ops, + .port_ops = &ahci_sb600_ops, }, [board_ahci_vt8251] = { @@ -259,7 +267,6 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x1e05), board_ahci }, /* Panther Point RAID */ { PCI_VDEVICE(INTEL, 0x1e06), board_ahci }, /* Panther Point RAID */ { PCI_VDEVICE(INTEL, 0x1e07), board_ahci }, /* Panther Point RAID */ - { PCI_VDEVICE(INTEL, 0x1e0e), board_ahci }, /* Panther Point RAID */ /* JMicron 360/1/3/5/6, match class to avoid IDE function */ { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, @@ -495,6 +502,55 @@ static void ahci_pci_init_controller(struct ata_host *host) ahci_init_controller(host); } +static int ahci_sb600_check_ready(struct ata_link *link) +{ + void __iomem *port_mmio = ahci_port_base(link->ap); + u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF; + u32 irq_status = readl(port_mmio + PORT_IRQ_STAT); + + /* + * There is no need to check TFDATA if BAD PMP is found due to HW bug, + * which can save timeout delay. + */ + if (irq_status & PORT_IRQ_BAD_PMP) + return -EIO; + + return ata_check_ready(status); +} + +static int ahci_sb600_softreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) +{ + struct ata_port *ap = link->ap; + void __iomem *port_mmio = ahci_port_base(ap); + int pmp = sata_srst_pmp(link); + int rc; + u32 irq_sts; + + DPRINTK("ENTER\n"); + + rc = ahci_do_softreset(link, class, pmp, deadline, + ahci_sb600_check_ready); + + /* + * Soft reset fails on some ATI chips with IPMS set when PMP + * is enabled but SATA HDD/ODD is connected to SATA port, + * do soft reset again to port 0. + */ + if (rc == -EIO) { + irq_sts = readl(port_mmio + PORT_IRQ_STAT); + if (irq_sts & PORT_IRQ_BAD_PMP) { + ata_link_printk(link, KERN_WARNING, + "applying SB600 PMP SRST workaround " + "and retrying\n"); + rc = ahci_do_softreset(link, class, 0, deadline, + ahci_check_ready); + } + } + + return rc; +} + static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { @@ -573,8 +629,8 @@ static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg) if (mesg.event & PM_EVENT_SUSPEND && hpriv->flags & AHCI_HFLAG_NO_SUSPEND) { - dev_err(&pdev->dev, - "BIOS update required for suspend/resume\n"); + dev_printk(KERN_ERR, &pdev->dev, + "BIOS update required for suspend/resume\n"); return -EIO; } @@ -625,21 +681,22 @@ static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac) if (rc) { rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); if (rc) { - dev_err(&pdev->dev, - "64-bit DMA enable failed\n"); + dev_printk(KERN_ERR, &pdev->dev, + "64-bit DMA enable failed\n"); return rc; } } } else { rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (rc) { - dev_err(&pdev->dev, "32-bit DMA enable failed\n"); + dev_printk(KERN_ERR, &pdev->dev, + "32-bit DMA enable failed\n"); return rc; } rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); if (rc) { - dev_err(&pdev->dev, - "32-bit consistent DMA enable failed\n"); + dev_printk(KERN_ERR, &pdev->dev, + "32-bit consistent DMA enable failed\n"); return rc; } } @@ -702,8 +759,8 @@ static void ahci_p5wdh_workaround(struct ata_host *host) dmi_check_system(sysids)) { struct ata_port *ap = host->ports[1]; - dev_info(&pdev->dev, - "enabling ASUS P5W DH Deluxe on-board SIMG4726 workaround\n"); + dev_printk(KERN_INFO, &pdev->dev, "enabling ASUS P5W DH " + "Deluxe on-board SIMG4726 workaround\n"); ap->ops = &ahci_p5wdh_ops; ap->link.flags |= ATA_LFLAG_NO_SRST | ATA_LFLAG_ASSUME_ATA; @@ -754,18 +811,6 @@ static bool ahci_sb600_enable_64bit(struct pci_dev *pdev) DMI_MATCH(DMI_BOARD_NAME, "MS-7376"), }, }, - /* - * All BIOS versions for the Asus M3A support 64bit DMA. - * (all release versions from 0301 to 1206 were tested) - */ - { - .ident = "ASUS M3A", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, - "ASUSTeK Computer INC."), - DMI_MATCH(DMI_BOARD_NAME, "M3A"), - }, - }, { } }; const struct dmi_system_id *match; @@ -786,14 +831,14 @@ static bool ahci_sb600_enable_64bit(struct pci_dev *pdev) if (strcmp(buf, match->driver_data) >= 0) goto enable_64bit; else { - dev_warn(&pdev->dev, - "%s: BIOS too old, forcing 32bit DMA, update BIOS\n", - match->ident); + dev_printk(KERN_WARNING, &pdev->dev, "%s: BIOS too old, " + "forcing 32bit DMA, update BIOS\n", match->ident); return false; } enable_64bit: - dev_warn(&pdev->dev, "%s: enabling 64bit DMA\n", match->ident); + dev_printk(KERN_WARNING, &pdev->dev, "%s: enabling 64bit DMA\n", + match->ident); return true; } @@ -996,8 +1041,9 @@ static void ahci_gtf_filter_workaround(struct ata_host *host) return; filter = (unsigned long)dmi->driver_data; - dev_info(host->dev, "applying extra ACPI _GTF filter 0x%x for %s\n", - filter, dmi->ident); + dev_printk(KERN_INFO, host->dev, + "applying extra ACPI _GTF filter 0x%x for %s\n", + filter, dmi->ident); for (i = 0; i < host->n_ports; i++) { struct ata_port *ap = host->ports[i]; @@ -1016,6 +1062,7 @@ static inline void ahci_gtf_filter_workaround(struct ata_host *host) static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { + static int printed_version; unsigned int board_id = ent->driver_data; struct ata_port_info pi = ahci_port_info[board_id]; const struct ata_port_info *ppi[] = { &pi, NULL }; @@ -1028,7 +1075,8 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) WARN_ON((int)ATA_MAX_QUEUE > AHCI_MAX_CMDS); - ata_print_version_once(&pdev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); /* The AHCI driver can only drive the SATA ports, the PATA driver can drive them all so if both drivers are selected make sure @@ -1051,8 +1099,8 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) * that for SAS drives they're out of luck. */ if (pdev->vendor == PCI_VENDOR_ID_PROMISE) - dev_info(&pdev->dev, - "PDC42819 can only drive SATA devices with this driver\n"); + dev_printk(KERN_INFO, &pdev->dev, "PDC42819 " + "can only drive SATA devices with this driver\n"); /* acquire resources */ rc = pcim_enable_device(pdev); @@ -1078,8 +1126,8 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) */ pci_read_config_byte(pdev, ICH_MAP, &map); if (map & 0x3) { - dev_info(&pdev->dev, - "controller is in combined mode, can't enable AHCI mode\n"); + dev_printk(KERN_INFO, &pdev->dev, "controller is in " + "combined mode, can't enable AHCI mode\n"); return -ENODEV; } } @@ -1136,8 +1184,8 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (ahci_broken_suspend(pdev)) { hpriv->flags |= AHCI_HFLAG_NO_SUSPEND; - dev_warn(&pdev->dev, - "BIOS update required for suspend/resume\n"); + dev_printk(KERN_WARNING, &pdev->dev, + "BIOS update required for suspend/resume\n"); } if (ahci_broken_online(pdev)) { diff --git a/trunk/drivers/ata/ahci.h b/trunk/drivers/ata/ahci.h index b1750007c8dc..12c5282e7fca 100644 --- a/trunk/drivers/ata/ahci.h +++ b/trunk/drivers/ata/ahci.h @@ -312,7 +312,6 @@ extern struct device_attribute *ahci_sdev_attrs[]; .sdev_attrs = ahci_sdev_attrs extern struct ata_port_operations ahci_ops; -extern struct ata_port_operations ahci_pmp_retry_srst_ops; void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag, u32 opts); diff --git a/trunk/drivers/ata/ata_generic.c b/trunk/drivers/ata/ata_generic.c index 7df56ec31819..721d38bfa339 100644 --- a/trunk/drivers/ata/ata_generic.c +++ b/trunk/drivers/ata/ata_generic.c @@ -81,13 +81,14 @@ static int generic_set_mode(struct ata_link *link, struct ata_device **unused) xfer_mask |= ata_xfer_mode2mask(XFER_MW_DMA_0); } - ata_dev_info(dev, "configured for %s\n", name); + ata_dev_printk(dev, KERN_INFO, "configured for %s\n", + name); dev->xfer_mode = ata_xfer_mask2mode(xfer_mask); dev->xfer_shift = ata_xfer_mode2shift(dev->xfer_mode); dev->flags &= ~ATA_DFLAG_PIO; } else { - ata_dev_info(dev, "configured for PIO\n"); + ata_dev_printk(dev, KERN_INFO, "configured for PIO\n"); dev->xfer_mode = XFER_PIO_0; dev->xfer_shift = ATA_SHIFT_PIO; dev->flags |= ATA_DFLAG_PIO; diff --git a/trunk/drivers/ata/ata_piix.c b/trunk/drivers/ata/ata_piix.c index 43107e9415da..6f6e7718b05c 100644 --- a/trunk/drivers/ata/ata_piix.c +++ b/trunk/drivers/ata/ata_piix.c @@ -1225,9 +1225,8 @@ static int piix_pci_device_resume(struct pci_dev *pdev) */ rc = pci_reenable_device(pdev); if (rc) - dev_err(&pdev->dev, - "failed to enable device after resume (%d)\n", - rc); + dev_printk(KERN_ERR, &pdev->dev, "failed to enable " + "device after resume (%d)\n", rc); } else rc = ata_pci_device_do_resume(pdev); @@ -1304,11 +1303,9 @@ static int __devinit piix_check_450nx_errata(struct pci_dev *ata_dev) no_piix_dma = 2; } if (no_piix_dma) - dev_warn(&ata_dev->dev, - "450NX errata present, disabling IDE DMA%s\n", - no_piix_dma == 2 ? " - a BIOS update may resolve this" - : ""); - + dev_printk(KERN_WARNING, &ata_dev->dev, "450NX errata present, disabling IDE DMA.\n"); + if (no_piix_dma == 2) + dev_printk(KERN_WARNING, &ata_dev->dev, "A BIOS update may resolve this.\n"); return no_piix_dma; } @@ -1341,36 +1338,37 @@ static const int *__devinit piix_init_sata_map(struct pci_dev *pdev, map = map_db->map[map_value & map_db->mask]; - dev_info(&pdev->dev, "MAP ["); + dev_printk(KERN_INFO, &pdev->dev, "MAP ["); for (i = 0; i < 4; i++) { switch (map[i]) { case RV: invalid_map = 1; - pr_cont(" XX"); + printk(" XX"); break; case NA: - pr_cont(" --"); + printk(" --"); break; case IDE: WARN_ON((i & 1) || map[i + 1] != IDE); pinfo[i / 2] = piix_port_info[ich_pata_100]; i++; - pr_cont(" IDE IDE"); + printk(" IDE IDE"); break; default: - pr_cont(" P%d", map[i]); + printk(" P%d", map[i]); if (i & 1) pinfo[i / 2].flags |= ATA_FLAG_SLAVE_POSS; break; } } - pr_cont(" ]\n"); + printk(" ]\n"); if (invalid_map) - dev_err(&pdev->dev, "invalid MAP value %u\n", map_value); + dev_printk(KERN_ERR, &pdev->dev, + "invalid MAP value %u\n", map_value); return map; } @@ -1400,8 +1398,8 @@ static bool piix_no_sidpr(struct ata_host *host) if (pdev->vendor == PCI_VENDOR_ID_INTEL && pdev->device == 0x2920 && pdev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG && pdev->subsystem_device == 0xb049) { - dev_warn(host->dev, - "Samsung DB-P70 detected, disabling SIDPR\n"); + dev_printk(KERN_WARNING, host->dev, + "Samsung DB-P70 detected, disabling SIDPR\n"); return true; } @@ -1453,8 +1451,8 @@ static int __devinit piix_init_sidpr(struct ata_host *host) piix_sidpr_scr_read(link0, SCR_CONTROL, &scontrol); if ((scontrol & 0xf00) != 0x300) { - dev_info(host->dev, - "SCR access via SIDPR is available but doesn't work\n"); + dev_printk(KERN_INFO, host->dev, "SCR access via " + "SIDPR is available but doesn't work\n"); return 0; } } @@ -1503,7 +1501,8 @@ static void piix_iocfg_bit18_quirk(struct ata_host *host) * affected systems. */ if (hpriv->saved_iocfg & (1 << 18)) { - dev_info(&pdev->dev, "applying IOCFG bit18 quirk\n"); + dev_printk(KERN_INFO, &pdev->dev, + "applying IOCFG bit18 quirk\n"); pci_write_config_dword(pdev, PIIX_IOCFG, hpriv->saved_iocfg & ~(1 << 18)); } @@ -1562,6 +1561,7 @@ static bool piix_broken_system_poweroff(struct pci_dev *pdev) static int __devinit piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { + static int printed_version; struct device *dev = &pdev->dev; struct ata_port_info port_info[2]; const struct ata_port_info *ppi[] = { &port_info[0], &port_info[1] }; @@ -1571,7 +1571,9 @@ static int __devinit piix_init_one(struct pci_dev *pdev, struct piix_host_priv *hpriv; int rc; - ata_print_version_once(&pdev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, + "version " DRV_VERSION "\n"); /* no hotplugging support for later devices (FIXME) */ if (!in_module_init && ent->driver_data >= ich5_sata) diff --git a/trunk/drivers/ata/libahci.c b/trunk/drivers/ata/libahci.c index 3c92dbd751e0..41223c7f0206 100644 --- a/trunk/drivers/ata/libahci.c +++ b/trunk/drivers/ata/libahci.c @@ -82,8 +82,6 @@ static void ahci_pmp_attach(struct ata_port *ap); static void ahci_pmp_detach(struct ata_port *ap); static int ahci_softreset(struct ata_link *link, unsigned int *class, unsigned long deadline); -static int ahci_pmp_retry_softreset(struct ata_link *link, unsigned int *class, - unsigned long deadline); static int ahci_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline); static void ahci_postreset(struct ata_link *link, unsigned int *class); @@ -180,12 +178,6 @@ struct ata_port_operations ahci_ops = { }; EXPORT_SYMBOL_GPL(ahci_ops); -struct ata_port_operations ahci_pmp_retry_srst_ops = { - .inherits = &ahci_ops, - .softreset = ahci_pmp_retry_softreset, -}; -EXPORT_SYMBOL_GPL(ahci_pmp_retry_srst_ops); - int ahci_em_messages = 1; EXPORT_SYMBOL_GPL(ahci_em_messages); module_param(ahci_em_messages, int, 0444); @@ -294,10 +286,10 @@ static ssize_t ahci_read_em_buffer(struct device *dev, /* the count should not be larger than PAGE_SIZE */ if (count > PAGE_SIZE) { if (printk_ratelimit()) - ata_port_warn(ap, - "EM read buffer size too large: " - "buffer size %u, page size %lu\n", - hpriv->em_buf_sz, PAGE_SIZE); + ata_port_printk(ap, KERN_WARNING, + "EM read buffer size too large: " + "buffer size %u, page size %lu\n", + hpriv->em_buf_sz, PAGE_SIZE); count = PAGE_SIZE; } @@ -418,46 +410,51 @@ void ahci_save_initial_config(struct device *dev, /* some chips have errata preventing 64bit use */ if ((cap & HOST_CAP_64) && (hpriv->flags & AHCI_HFLAG_32BIT_ONLY)) { - dev_info(dev, "controller can't do 64bit DMA, forcing 32bit\n"); + dev_printk(KERN_INFO, dev, + "controller can't do 64bit DMA, forcing 32bit\n"); cap &= ~HOST_CAP_64; } if ((cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_NO_NCQ)) { - dev_info(dev, "controller can't do NCQ, turning off CAP_NCQ\n"); + dev_printk(KERN_INFO, dev, + "controller can't do NCQ, turning off CAP_NCQ\n"); cap &= ~HOST_CAP_NCQ; } if (!(cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_YES_NCQ)) { - dev_info(dev, "controller can do NCQ, turning on CAP_NCQ\n"); + dev_printk(KERN_INFO, dev, + "controller can do NCQ, turning on CAP_NCQ\n"); cap |= HOST_CAP_NCQ; } if ((cap & HOST_CAP_PMP) && (hpriv->flags & AHCI_HFLAG_NO_PMP)) { - dev_info(dev, "controller can't do PMP, turning off CAP_PMP\n"); + dev_printk(KERN_INFO, dev, + "controller can't do PMP, turning off CAP_PMP\n"); cap &= ~HOST_CAP_PMP; } if ((cap & HOST_CAP_SNTF) && (hpriv->flags & AHCI_HFLAG_NO_SNTF)) { - dev_info(dev, - "controller can't do SNTF, turning off CAP_SNTF\n"); + dev_printk(KERN_INFO, dev, + "controller can't do SNTF, turning off CAP_SNTF\n"); cap &= ~HOST_CAP_SNTF; } if (!(cap & HOST_CAP_FBS) && (hpriv->flags & AHCI_HFLAG_YES_FBS)) { - dev_info(dev, "controller can do FBS, turning on CAP_FBS\n"); + dev_printk(KERN_INFO, dev, + "controller can do FBS, turning on CAP_FBS\n"); cap |= HOST_CAP_FBS; } if (force_port_map && port_map != force_port_map) { - dev_info(dev, "forcing port_map 0x%x -> 0x%x\n", - port_map, force_port_map); + dev_printk(KERN_INFO, dev, "forcing port_map 0x%x -> 0x%x\n", + port_map, force_port_map); port_map = force_port_map; } if (mask_port_map) { - dev_warn(dev, "masking port_map 0x%x -> 0x%x\n", - port_map, - port_map & mask_port_map); + dev_printk(KERN_WARNING, dev, "masking port_map 0x%x -> 0x%x\n", + port_map, + port_map & mask_port_map); port_map &= mask_port_map; } @@ -473,9 +470,10 @@ void ahci_save_initial_config(struct device *dev, * port_map and let it be generated from n_ports. */ if (map_ports > ahci_nr_ports(cap)) { - dev_warn(dev, - "implemented port map (0x%x) contains more ports than nr_ports (%u), using nr_ports\n", - port_map, ahci_nr_ports(cap)); + dev_printk(KERN_WARNING, dev, + "implemented port map (0x%x) contains more " + "ports than nr_ports (%u), using nr_ports\n", + port_map, ahci_nr_ports(cap)); port_map = 0; } } @@ -483,7 +481,8 @@ void ahci_save_initial_config(struct device *dev, /* fabricate port_map from cap.nr_ports */ if (!port_map) { port_map = (1 << ahci_nr_ports(cap)) - 1; - dev_warn(dev, "forcing PORTS_IMPL to 0x%x\n", port_map); + dev_printk(KERN_WARNING, dev, + "forcing PORTS_IMPL to 0x%x\n", port_map); /* write the fixed up value to the PI register */ hpriv->saved_port_map = port_map; @@ -823,8 +822,8 @@ int ahci_reset_controller(struct ata_host *host) HOST_RESET, 10, 1000); if (tmp & HOST_RESET) { - dev_err(host->dev, "controller reset failed (0x%x)\n", - tmp); + dev_printk(KERN_ERR, host->dev, + "controller reset failed (0x%x)\n", tmp); return -EIO; } @@ -836,7 +835,8 @@ int ahci_reset_controller(struct ata_host *host) */ ahci_restore_initial_config(host); } else - dev_info(host->dev, "skipping global host reset\n"); + dev_printk(KERN_INFO, host->dev, + "skipping global host reset\n"); return 0; } @@ -1132,8 +1132,8 @@ static void ahci_dev_config(struct ata_device *dev) if (hpriv->flags & AHCI_HFLAG_SECT255) { dev->max_sectors = 255; - ata_dev_info(dev, - "SB600 AHCI: limiting to 255 sectors per cmd\n"); + ata_dev_printk(dev, KERN_INFO, + "SB600 AHCI: limiting to 255 sectors per cmd\n"); } } @@ -1257,7 +1257,8 @@ int ahci_do_softreset(struct ata_link *link, unsigned int *class, /* prepare for SRST (AHCI-1.1 10.4.1) */ rc = ahci_kick_engine(ap); if (rc && rc != -EOPNOTSUPP) - ata_link_warn(link, "failed to reset engine (errno=%d)\n", rc); + ata_link_printk(link, KERN_WARNING, + "failed to reset engine (errno=%d)\n", rc); ata_tf_init(link->device, &tf); @@ -1290,7 +1291,8 @@ int ahci_do_softreset(struct ata_link *link, unsigned int *class, * be trusted. Treat device readiness timeout as link * offline. */ - ata_link_info(link, "device not ready, treating as offline\n"); + ata_link_printk(link, KERN_INFO, + "device not ready, treating as offline\n"); *class = ATA_DEV_NONE; } else if (rc) { /* link occupied, -ENODEV too is an error */ @@ -1303,7 +1305,7 @@ int ahci_do_softreset(struct ata_link *link, unsigned int *class, return 0; fail: - ata_link_err(link, "softreset failed (%s)\n", reason); + ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason); return rc; } @@ -1327,55 +1329,6 @@ static int ahci_softreset(struct ata_link *link, unsigned int *class, } EXPORT_SYMBOL_GPL(ahci_do_softreset); -static int ahci_bad_pmp_check_ready(struct ata_link *link) -{ - void __iomem *port_mmio = ahci_port_base(link->ap); - u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF; - u32 irq_status = readl(port_mmio + PORT_IRQ_STAT); - - /* - * There is no need to check TFDATA if BAD PMP is found due to HW bug, - * which can save timeout delay. - */ - if (irq_status & PORT_IRQ_BAD_PMP) - return -EIO; - - return ata_check_ready(status); -} - -int ahci_pmp_retry_softreset(struct ata_link *link, unsigned int *class, - unsigned long deadline) -{ - struct ata_port *ap = link->ap; - void __iomem *port_mmio = ahci_port_base(ap); - int pmp = sata_srst_pmp(link); - int rc; - u32 irq_sts; - - DPRINTK("ENTER\n"); - - rc = ahci_do_softreset(link, class, pmp, deadline, - ahci_bad_pmp_check_ready); - - /* - * Soft reset fails with IPMS set when PMP is enabled but - * SATA HDD/ODD is connected to SATA port, do soft reset - * again to port 0. - */ - if (rc == -EIO) { - irq_sts = readl(port_mmio + PORT_IRQ_STAT); - if (irq_sts & PORT_IRQ_BAD_PMP) { - ata_link_printk(link, KERN_WARNING, - "applying PMP SRST workaround " - "and retrying\n"); - rc = ahci_do_softreset(link, class, 0, deadline, - ahci_check_ready); - } - } - - return rc; -} - static int ahci_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { @@ -1521,7 +1474,8 @@ static void ahci_fbs_dec_intr(struct ata_port *ap) } if (fbs & PORT_FBS_DEC) - dev_err(ap->host->dev, "failed to clear device error\n"); + dev_printk(KERN_ERR, ap->host->dev, + "failed to clear device error\n"); } static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) @@ -1759,8 +1713,8 @@ irqreturn_t ahci_interrupt(int irq, void *dev_instance) } else { VPRINTK("port %u (no irq)\n", i); if (ata_ratelimit()) - dev_warn(host->dev, - "interrupt on disabled port %u\n", i); + dev_printk(KERN_WARNING, host->dev, + "interrupt on disabled port %u\n", i); } handled = 1; @@ -1911,11 +1865,11 @@ static void ahci_enable_fbs(struct ata_port *ap) writel(fbs | PORT_FBS_EN, port_mmio + PORT_FBS); fbs = readl(port_mmio + PORT_FBS); if (fbs & PORT_FBS_EN) { - dev_info(ap->host->dev, "FBS is enabled\n"); + dev_printk(KERN_INFO, ap->host->dev, "FBS is enabled.\n"); pp->fbs_enabled = true; pp->fbs_last_dev = -1; /* initialization */ } else - dev_err(ap->host->dev, "Failed to enable FBS\n"); + dev_printk(KERN_ERR, ap->host->dev, "Failed to enable FBS\n"); ahci_start_engine(ap); } @@ -1943,9 +1897,9 @@ static void ahci_disable_fbs(struct ata_port *ap) writel(fbs & ~PORT_FBS_EN, port_mmio + PORT_FBS); fbs = readl(port_mmio + PORT_FBS); if (fbs & PORT_FBS_EN) - dev_err(ap->host->dev, "Failed to disable FBS\n"); + dev_printk(KERN_ERR, ap->host->dev, "Failed to disable FBS\n"); else { - dev_info(ap->host->dev, "FBS is disabled\n"); + dev_printk(KERN_INFO, ap->host->dev, "FBS is disabled.\n"); pp->fbs_enabled = false; } @@ -2021,7 +1975,7 @@ static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg) if (rc == 0) ahci_power_down(ap); else { - ata_port_err(ap, "%s (%d)\n", emsg, rc); + ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc); ahci_start_port(ap); } @@ -2049,12 +2003,14 @@ static int ahci_port_start(struct ata_port *ap) if (cmd & PORT_CMD_FBSCP) pp->fbs_supported = true; else if (hpriv->flags & AHCI_HFLAG_YES_FBS) { - dev_info(dev, "port %d can do FBS, forcing FBSCP\n", - ap->port_no); + dev_printk(KERN_INFO, dev, + "port %d can do FBS, forcing FBSCP\n", + ap->port_no); pp->fbs_supported = true; } else - dev_warn(dev, "port %d is not capable of FBS\n", - ap->port_no); + dev_printk(KERN_WARNING, dev, + "port %d is not capable of FBS\n", + ap->port_no); } if (pp->fbs_supported) { @@ -2116,7 +2072,7 @@ static void ahci_port_stop(struct ata_port *ap) /* de-initialize port */ rc = ahci_deinit_port(ap, &emsg); if (rc) - ata_port_warn(ap, "%s (%d)\n", emsg, rc); + ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc); } void ahci_print_info(struct ata_host *host, const char *scc_s) diff --git a/trunk/drivers/ata/libata-acpi.c b/trunk/drivers/ata/libata-acpi.c index e0a5b555cee1..a791b8ce6294 100644 --- a/trunk/drivers/ata/libata-acpi.c +++ b/trunk/drivers/ata/libata-acpi.c @@ -332,22 +332,25 @@ int ata_acpi_gtm(struct ata_port *ap, struct ata_acpi_gtm *gtm) rc = -EINVAL; if (ACPI_FAILURE(status)) { - ata_port_err(ap, "ACPI get timing mode failed (AE 0x%x)\n", - status); + ata_port_printk(ap, KERN_ERR, + "ACPI get timing mode failed (AE 0x%x)\n", + status); goto out_free; } out_obj = output.pointer; if (out_obj->type != ACPI_TYPE_BUFFER) { - ata_port_warn(ap, "_GTM returned unexpected object type 0x%x\n", - out_obj->type); + ata_port_printk(ap, KERN_WARNING, + "_GTM returned unexpected object type 0x%x\n", + out_obj->type); goto out_free; } if (out_obj->buffer.length != sizeof(struct ata_acpi_gtm)) { - ata_port_err(ap, "_GTM returned invalid length %d\n", - out_obj->buffer.length); + ata_port_printk(ap, KERN_ERR, + "_GTM returned invalid length %d\n", + out_obj->buffer.length); goto out_free; } @@ -399,8 +402,8 @@ int ata_acpi_stm(struct ata_port *ap, const struct ata_acpi_gtm *stm) if (status == AE_NOT_FOUND) return -ENOENT; if (ACPI_FAILURE(status)) { - ata_port_err(ap, "ACPI set timing mode failed (status=0x%x)\n", - status); + ata_port_printk(ap, KERN_ERR, + "ACPI set timing mode failed (status=0x%x)\n", status); return -EINVAL; } return 0; @@ -447,8 +450,8 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf) output.pointer = NULL; /* ACPI-CA sets this; save/free it later */ if (ata_msg_probe(ap)) - ata_dev_dbg(dev, "%s: ENTER: port#: %d\n", - __func__, ap->port_no); + ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER: port#: %d\n", + __func__, ap->port_no); /* _GTF has no input parameters */ status = acpi_evaluate_object(dev->acpi_handle, "_GTF", NULL, &output); @@ -456,8 +459,9 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf) if (ACPI_FAILURE(status)) { if (status != AE_NOT_FOUND) { - ata_dev_warn(dev, "_GTF evaluation failed (AE 0x%x)\n", - status); + ata_dev_printk(dev, KERN_WARNING, + "_GTF evaluation failed (AE 0x%x)\n", + status); rc = -EINVAL; } goto out_free; @@ -465,24 +469,27 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf) if (!output.length || !output.pointer) { if (ata_msg_probe(ap)) - ata_dev_dbg(dev, "%s: Run _GTF: length or ptr is NULL (0x%llx, 0x%p)\n", - __func__, - (unsigned long long)output.length, - output.pointer); + ata_dev_printk(dev, KERN_DEBUG, "%s: Run _GTF: " + "length or ptr is NULL (0x%llx, 0x%p)\n", + __func__, + (unsigned long long)output.length, + output.pointer); rc = -EINVAL; goto out_free; } if (out_obj->type != ACPI_TYPE_BUFFER) { - ata_dev_warn(dev, "_GTF unexpected object type 0x%x\n", - out_obj->type); + ata_dev_printk(dev, KERN_WARNING, + "_GTF unexpected object type 0x%x\n", + out_obj->type); rc = -EINVAL; goto out_free; } if (out_obj->buffer.length % REGS_PER_GTF) { - ata_dev_warn(dev, "unexpected _GTF length (%d)\n", - out_obj->buffer.length); + ata_dev_printk(dev, KERN_WARNING, + "unexpected _GTF length (%d)\n", + out_obj->buffer.length); rc = -EINVAL; goto out_free; } @@ -492,8 +499,9 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf) if (gtf) { *gtf = (void *)out_obj->buffer.pointer; if (ata_msg_probe(ap)) - ata_dev_dbg(dev, "%s: returning gtf=%p, gtf_count=%d\n", - __func__, *gtf, rc); + ata_dev_printk(dev, KERN_DEBUG, + "%s: returning gtf=%p, gtf_count=%d\n", + __func__, *gtf, rc); } return rc; @@ -803,8 +811,8 @@ static int ata_acpi_push_id(struct ata_device *dev) union acpi_object in_params[1]; if (ata_msg_probe(ap)) - ata_dev_dbg(dev, "%s: ix = %d, port#: %d\n", - __func__, dev->devno, ap->port_no); + ata_dev_printk(dev, KERN_DEBUG, "%s: ix = %d, port#: %d\n", + __func__, dev->devno, ap->port_no); /* Give the drive Identify data to the drive via the _SDD method */ /* _SDD: set up input parameters */ @@ -824,7 +832,8 @@ static int ata_acpi_push_id(struct ata_device *dev) return -ENOENT; if (ACPI_FAILURE(status)) { - ata_dev_warn(dev, "ACPI _SDD failed (AE 0x%x)\n", status); + ata_dev_printk(dev, KERN_WARNING, + "ACPI _SDD failed (AE 0x%x)\n", status); return -EIO; } @@ -974,8 +983,8 @@ int ata_acpi_on_devcfg(struct ata_device *dev) if (nr_executed) { rc = ata_dev_reread_id(dev, 0); if (rc < 0) { - ata_dev_err(dev, - "failed to IDENTIFY after ACPI commands\n"); + ata_dev_printk(dev, KERN_ERR, "failed to IDENTIFY " + "after ACPI commands\n"); return rc; } } @@ -993,7 +1002,8 @@ int ata_acpi_on_devcfg(struct ata_device *dev) return rc; } - ata_dev_warn(dev, "ACPI: failed the second time, disabled\n"); + ata_dev_printk(dev, KERN_WARNING, + "ACPI: failed the second time, disabled\n"); dev->acpi_handle = NULL; /* We can safely continue if no _GTF command has been executed diff --git a/trunk/drivers/ata/libata-core.c b/trunk/drivers/ata/libata-core.c index 4a3a5ae7bb45..000d03ae6653 100644 --- a/trunk/drivers/ata/libata-core.c +++ b/trunk/drivers/ata/libata-core.c @@ -335,7 +335,8 @@ void ata_force_cbl(struct ata_port *ap) continue; ap->cbl = fe->param.cbl; - ata_port_notice(ap, "FORCE: cable set to %s\n", fe->param.name); + ata_port_printk(ap, KERN_NOTICE, + "FORCE: cable set to %s\n", fe->param.name); return; } } @@ -377,7 +378,8 @@ static void ata_force_link_limits(struct ata_link *link) /* only honor the first spd limit */ if (!did_spd && fe->param.spd_limit) { link->hw_sata_spd_limit = (1 << fe->param.spd_limit) - 1; - ata_link_notice(link, "FORCE: PHY spd limit set to %s\n", + ata_link_printk(link, KERN_NOTICE, + "FORCE: PHY spd limit set to %s\n", fe->param.name); did_spd = true; } @@ -385,7 +387,7 @@ static void ata_force_link_limits(struct ata_link *link) /* let lflags stack */ if (fe->param.lflags) { link->flags |= fe->param.lflags; - ata_link_notice(link, + ata_link_printk(link, KERN_NOTICE, "FORCE: link flag 0x%x forced -> 0x%x\n", fe->param.lflags, link->flags); } @@ -440,8 +442,8 @@ static void ata_force_xfermask(struct ata_device *dev) dev->pio_mask = pio_mask; } - ata_dev_notice(dev, "FORCE: xfer_mask set to %s\n", - fe->param.name); + ata_dev_printk(dev, KERN_NOTICE, + "FORCE: xfer_mask set to %s\n", fe->param.name); return; } } @@ -484,8 +486,8 @@ static void ata_force_horkage(struct ata_device *dev) dev->horkage |= fe->param.horkage_on; dev->horkage &= ~fe->param.horkage_off; - ata_dev_notice(dev, "FORCE: horkage modified (%s)\n", - fe->param.name); + ata_dev_printk(dev, KERN_NOTICE, + "FORCE: horkage modified (%s)\n", fe->param.name); } } @@ -709,8 +711,8 @@ u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev) sect = tf->lbal; if (!sect) { - ata_dev_warn(dev, - "device reported invalid CHS sector 0\n"); + ata_dev_printk(dev, KERN_WARNING, "device reported " + "invalid CHS sector 0\n"); sect = 1; /* oh well */ } @@ -1228,9 +1230,8 @@ static int ata_read_native_max_address(struct ata_device *dev, u64 *max_sectors) err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); if (err_mask) { - ata_dev_warn(dev, - "failed to read native max address (err_mask=0x%x)\n", - err_mask); + ata_dev_printk(dev, KERN_WARNING, "failed to read native " + "max address (err_mask=0x%x)\n", err_mask); if (err_mask == AC_ERR_DEV && (tf.feature & ATA_ABORTED)) return -EACCES; return -EIO; @@ -1291,9 +1292,8 @@ static int ata_set_max_sectors(struct ata_device *dev, u64 new_sectors) err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); if (err_mask) { - ata_dev_warn(dev, - "failed to set max address (err_mask=0x%x)\n", - err_mask); + ata_dev_printk(dev, KERN_WARNING, "failed to set " + "max address (err_mask=0x%x)\n", err_mask); if (err_mask == AC_ERR_DEV && (tf.feature & (ATA_ABORTED | ATA_IDNF))) return -EACCES; @@ -1336,8 +1336,8 @@ static int ata_hpa_resize(struct ata_device *dev) * be unlocked, skip HPA resizing. */ if (rc == -EACCES || !unlock_hpa) { - ata_dev_warn(dev, - "HPA support seems broken, skipping HPA handling\n"); + ata_dev_printk(dev, KERN_WARNING, "HPA support seems " + "broken, skipping HPA handling\n"); dev->horkage |= ATA_HORKAGE_BROKEN_HPA; /* we can continue if device aborted the command */ @@ -1355,13 +1355,14 @@ static int ata_hpa_resize(struct ata_device *dev) return 0; if (native_sectors > sectors) - ata_dev_info(dev, + ata_dev_printk(dev, KERN_INFO, "HPA detected: current %llu, native %llu\n", (unsigned long long)sectors, (unsigned long long)native_sectors); else if (native_sectors < sectors) - ata_dev_warn(dev, - "native sectors (%llu) is smaller than sectors (%llu)\n", + ata_dev_printk(dev, KERN_WARNING, + "native sectors (%llu) is smaller than " + "sectors (%llu)\n", (unsigned long long)native_sectors, (unsigned long long)sectors); return 0; @@ -1371,10 +1372,10 @@ static int ata_hpa_resize(struct ata_device *dev) rc = ata_set_max_sectors(dev, native_sectors); if (rc == -EACCES) { /* if device aborted the command, skip HPA resizing */ - ata_dev_warn(dev, - "device aborted resize (%llu -> %llu), skipping HPA handling\n", - (unsigned long long)sectors, - (unsigned long long)native_sectors); + ata_dev_printk(dev, KERN_WARNING, "device aborted resize " + "(%llu -> %llu), skipping HPA handling\n", + (unsigned long long)sectors, + (unsigned long long)native_sectors); dev->horkage |= ATA_HORKAGE_BROKEN_HPA; return 0; } else if (rc) @@ -1383,14 +1384,14 @@ static int ata_hpa_resize(struct ata_device *dev) /* re-read IDENTIFY data */ rc = ata_dev_reread_id(dev, 0); if (rc) { - ata_dev_err(dev, - "failed to re-read IDENTIFY data after HPA resizing\n"); + ata_dev_printk(dev, KERN_ERR, "failed to re-read IDENTIFY " + "data after HPA resizing\n"); return rc; } if (print_info) { u64 new_sectors = ata_id_n_sectors(dev->id); - ata_dev_info(dev, + ata_dev_printk(dev, KERN_INFO, "HPA unlocked: %llu -> %llu, native %llu\n", (unsigned long long)sectors, (unsigned long long)new_sectors, @@ -1654,8 +1655,8 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, ata_qc_complete(qc); if (ata_msg_warn(ap)) - ata_dev_warn(dev, "qc timeout (cmd 0x%x)\n", - command); + ata_dev_printk(dev, KERN_WARNING, + "qc timeout (cmd 0x%x)\n", command); } spin_unlock_irqrestore(ap->lock, flags); @@ -1869,7 +1870,7 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, int rc; if (ata_msg_ctl(ap)) - ata_dev_dbg(dev, "%s: ENTER\n", __func__); + ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER\n", __func__); retry: ata_tf_init(dev, &tf); @@ -1908,13 +1909,14 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, if (err_mask) { if (err_mask & AC_ERR_NODEV_HINT) { - ata_dev_dbg(dev, "NODEV after polling detection\n"); + ata_dev_printk(dev, KERN_DEBUG, + "NODEV after polling detection\n"); return -ENOENT; } if (is_semb) { - ata_dev_info(dev, - "IDENTIFY failed on device w/ SEMB sig, disabled\n"); + ata_dev_printk(dev, KERN_INFO, "IDENTIFY failed on " + "device w/ SEMB sig, disabled\n"); /* SEMB is not supported yet */ *p_class = ATA_DEV_SEMB_UNSUP; return 0; @@ -1940,8 +1942,8 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, * both flavors of IDENTIFYs which happens * sometimes with phantom devices. */ - ata_dev_dbg(dev, - "both IDENTIFYs aborted, assuming NODEV\n"); + ata_dev_printk(dev, KERN_DEBUG, + "both IDENTIFYs aborted, assuming NODEV\n"); return -ENOENT; } @@ -1951,9 +1953,9 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, } if (dev->horkage & ATA_HORKAGE_DUMP_ID) { - ata_dev_dbg(dev, "dumping IDENTIFY data, " - "class=%d may_fallback=%d tried_spinup=%d\n", - class, may_fallback, tried_spinup); + ata_dev_printk(dev, KERN_DEBUG, "dumping IDENTIFY data, " + "class=%d may_fallback=%d tried_spinup=%d\n", + class, may_fallback, tried_spinup); print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 16, 2, id, ATA_ID_WORDS * sizeof(*id), true); } @@ -2032,8 +2034,8 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, err_out: if (ata_msg_warn(ap)) - ata_dev_warn(dev, "failed to IDENTIFY (%s, err_mask=0x%x)\n", - reason, err_mask); + ata_dev_printk(dev, KERN_WARNING, "failed to IDENTIFY " + "(%s, err_mask=0x%x)\n", reason, err_mask); return rc; } @@ -2063,8 +2065,9 @@ static int ata_do_link_spd_horkage(struct ata_device *dev) * guaranteed by setting sata_spd_limit to target_limit above. */ if (plink->sata_spd > target) { - ata_dev_info(dev, "applying link speed limit horkage to %s\n", - sata_spd_string(target)); + ata_dev_printk(dev, KERN_INFO, + "applying link speed limit horkage to %s\n", + sata_spd_string(target)); return -EAGAIN; } return 0; @@ -2107,9 +2110,8 @@ static int ata_dev_config_ncq(struct ata_device *dev, err_mask = ata_dev_set_feature(dev, SETFEATURES_SATA_ENABLE, SATA_FPDMA_AA); if (err_mask) { - ata_dev_err(dev, - "failed to enable AA (error_mask=0x%x)\n", - err_mask); + ata_dev_printk(dev, KERN_ERR, "failed to enable AA" + "(error_mask=0x%x)\n", err_mask); if (err_mask != AC_ERR_DEV) { dev->horkage |= ATA_HORKAGE_BROKEN_FPDMA_AA; return -EIO; @@ -2152,28 +2154,31 @@ int ata_dev_configure(struct ata_device *dev) int rc; if (!ata_dev_enabled(dev) && ata_msg_info(ap)) { - ata_dev_info(dev, "%s: ENTER/EXIT -- nodev\n", __func__); + ata_dev_printk(dev, KERN_INFO, "%s: ENTER/EXIT -- nodev\n", + __func__); return 0; } if (ata_msg_probe(ap)) - ata_dev_dbg(dev, "%s: ENTER\n", __func__); + ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER\n", __func__); /* set horkage */ dev->horkage |= ata_dev_blacklisted(dev); ata_force_horkage(dev); if (dev->horkage & ATA_HORKAGE_DISABLE) { - ata_dev_info(dev, "unsupported device, disabling\n"); + ata_dev_printk(dev, KERN_INFO, + "unsupported device, disabling\n"); ata_dev_disable(dev); return 0; } if ((!atapi_enabled || (ap->flags & ATA_FLAG_NO_ATAPI)) && dev->class == ATA_DEV_ATAPI) { - ata_dev_warn(dev, "WARNING: ATAPI is %s, device ignored\n", - atapi_enabled ? "not supported with this driver" - : "disabled"); + ata_dev_printk(dev, KERN_WARNING, + "WARNING: ATAPI is %s, device ignored.\n", + atapi_enabled ? "not supported with this driver" + : "disabled"); ata_dev_disable(dev); return 0; } @@ -2194,12 +2199,12 @@ int ata_dev_configure(struct ata_device *dev) /* print device capabilities */ if (ata_msg_probe(ap)) - ata_dev_dbg(dev, - "%s: cfg 49:%04x 82:%04x 83:%04x 84:%04x " - "85:%04x 86:%04x 87:%04x 88:%04x\n", - __func__, - id[49], id[82], id[83], id[84], - id[85], id[86], id[87], id[88]); + ata_dev_printk(dev, KERN_DEBUG, + "%s: cfg 49:%04x 82:%04x 83:%04x 84:%04x " + "85:%04x 86:%04x 87:%04x 88:%04x\n", + __func__, + id[49], id[82], id[83], id[84], + id[85], id[86], id[87], id[88]); /* initialize to-be-configured parameters */ dev->flags &= ~ATA_DFLAG_CFG_MASK; @@ -2233,15 +2238,17 @@ int ata_dev_configure(struct ata_device *dev) if (ata_id_is_cfa(id)) { /* CPRM may make this media unusable */ if (id[ATA_ID_CFA_KEY_MGMT] & 1) - ata_dev_warn(dev, - "supports DRM functions and may not be fully accessible\n"); + ata_dev_printk(dev, KERN_WARNING, + "supports DRM functions and may " + "not be fully accessible.\n"); snprintf(revbuf, 7, "CFA"); } else { snprintf(revbuf, 7, "ATA-%d", ata_id_major_version(id)); /* Warn the user if the device has TPM extensions */ if (ata_id_has_tpm(id)) - ata_dev_warn(dev, - "supports DRM functions and may not be fully accessible\n"); + ata_dev_printk(dev, KERN_WARNING, + "supports DRM functions and may " + "not be fully accessible.\n"); } dev->n_sectors = ata_id_n_sectors(id); @@ -2278,11 +2285,12 @@ int ata_dev_configure(struct ata_device *dev) /* print device info to dmesg */ if (ata_msg_drv(ap) && print_info) { - ata_dev_info(dev, "%s: %s, %s, max %s\n", - revbuf, modelbuf, fwrevbuf, - ata_mode_string(xfer_mask)); - ata_dev_info(dev, - "%llu sectors, multi %u: %s %s\n", + ata_dev_printk(dev, KERN_INFO, + "%s: %s, %s, max %s\n", + revbuf, modelbuf, fwrevbuf, + ata_mode_string(xfer_mask)); + ata_dev_printk(dev, KERN_INFO, + "%Lu sectors, multi %u: %s %s\n", (unsigned long long)dev->n_sectors, dev->multi_count, lba_desc, ncq_desc); } @@ -2303,14 +2311,15 @@ int ata_dev_configure(struct ata_device *dev) /* print device info to dmesg */ if (ata_msg_drv(ap) && print_info) { - ata_dev_info(dev, "%s: %s, %s, max %s\n", - revbuf, modelbuf, fwrevbuf, - ata_mode_string(xfer_mask)); - ata_dev_info(dev, - "%llu sectors, multi %u, CHS %u/%u/%u\n", - (unsigned long long)dev->n_sectors, - dev->multi_count, dev->cylinders, - dev->heads, dev->sectors); + ata_dev_printk(dev, KERN_INFO, + "%s: %s, %s, max %s\n", + revbuf, modelbuf, fwrevbuf, + ata_mode_string(xfer_mask)); + ata_dev_printk(dev, KERN_INFO, + "%Lu sectors, multi %u, CHS %u/%u/%u\n", + (unsigned long long)dev->n_sectors, + dev->multi_count, dev->cylinders, + dev->heads, dev->sectors); } } @@ -2327,7 +2336,8 @@ int ata_dev_configure(struct ata_device *dev) rc = atapi_cdb_len(id); if ((rc < 12) || (rc > ATAPI_CDB_LEN)) { if (ata_msg_warn(ap)) - ata_dev_warn(dev, "unsupported CDB len\n"); + ata_dev_printk(dev, KERN_WARNING, + "unsupported CDB len\n"); rc = -EINVAL; goto err_out_nosup; } @@ -2348,9 +2358,9 @@ int ata_dev_configure(struct ata_device *dev) err_mask = ata_dev_set_feature(dev, SETFEATURES_SATA_ENABLE, SATA_AN); if (err_mask) - ata_dev_err(dev, - "failed to enable ATAPI AN (err_mask=0x%x)\n", - err_mask); + ata_dev_printk(dev, KERN_ERR, + "failed to enable ATAPI AN " + "(err_mask=0x%x)\n", err_mask); else { dev->flags |= ATA_DFLAG_AN; atapi_an_string = ", ATAPI AN"; @@ -2369,12 +2379,12 @@ int ata_dev_configure(struct ata_device *dev) /* print device info to dmesg */ if (ata_msg_drv(ap) && print_info) - ata_dev_info(dev, - "ATAPI: %s, %s, max %s%s%s%s\n", - modelbuf, fwrevbuf, - ata_mode_string(xfer_mask), - cdb_intr_string, atapi_an_string, - dma_dir_string); + ata_dev_printk(dev, KERN_INFO, + "ATAPI: %s, %s, max %s%s%s%s\n", + modelbuf, fwrevbuf, + ata_mode_string(xfer_mask), + cdb_intr_string, atapi_an_string, + dma_dir_string); } /* determine max_sectors */ @@ -2386,7 +2396,8 @@ int ata_dev_configure(struct ata_device *dev) 200 sectors */ if (ata_dev_knobble(dev)) { if (ata_msg_drv(ap) && print_info) - ata_dev_info(dev, "applying bridge limits\n"); + ata_dev_printk(dev, KERN_INFO, + "applying bridge limits\n"); dev->udma_mask &= ATA_UDMA5; dev->max_sectors = ATA_MAX_SECTORS; } @@ -2412,23 +2423,26 @@ int ata_dev_configure(struct ata_device *dev) bugs */ if (print_info) { - ata_dev_warn(dev, + ata_dev_printk(dev, KERN_WARNING, "Drive reports diagnostics failure. This may indicate a drive\n"); - ata_dev_warn(dev, + ata_dev_printk(dev, KERN_WARNING, "fault or invalid emulation. Contact drive vendor for information.\n"); } } if ((dev->horkage & ATA_HORKAGE_FIRMWARE_WARN) && print_info) { - ata_dev_warn(dev, "WARNING: device requires firmware update to be fully functional\n"); - ata_dev_warn(dev, " contact the vendor or visit http://ata.wiki.kernel.org\n"); + ata_dev_printk(dev, KERN_WARNING, "WARNING: device requires " + "firmware update to be fully functional.\n"); + ata_dev_printk(dev, KERN_WARNING, " contact the vendor " + "or visit http://ata.wiki.kernel.org.\n"); } return 0; err_out_nosup: if (ata_msg_probe(ap)) - ata_dev_dbg(dev, "%s: EXIT, err\n", __func__); + ata_dev_printk(dev, KERN_DEBUG, + "%s: EXIT, err\n", __func__); return rc; } @@ -2649,11 +2663,13 @@ static void sata_print_link_status(struct ata_link *link) if (ata_phys_link_online(link)) { tmp = (sstatus >> 4) & 0xf; - ata_link_info(link, "SATA link up %s (SStatus %X SControl %X)\n", - sata_spd_string(tmp), sstatus, scontrol); + ata_link_printk(link, KERN_INFO, + "SATA link up %s (SStatus %X SControl %X)\n", + sata_spd_string(tmp), sstatus, scontrol); } else { - ata_link_info(link, "SATA link down (SStatus %X SControl %X)\n", - sstatus, scontrol); + ata_link_printk(link, KERN_INFO, + "SATA link down (SStatus %X SControl %X)\n", + sstatus, scontrol); } } @@ -2742,8 +2758,8 @@ int sata_down_spd_limit(struct ata_link *link, u32 spd_limit) link->sata_spd_limit = mask; - ata_link_warn(link, "limiting SATA link speed to %s\n", - sata_spd_string(fls(mask))); + ata_link_printk(link, KERN_WARNING, "limiting SATA link speed to %s\n", + sata_spd_string(fls(mask))); return 0; } @@ -3120,7 +3136,8 @@ int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel) snprintf(buf, sizeof(buf), "%s", ata_mode_string(xfer_mask)); - ata_dev_warn(dev, "limiting speed to %s\n", buf); + ata_dev_printk(dev, KERN_WARNING, + "limiting speed to %s\n", buf); } ata_unpack_xfermask(xfer_mask, &dev->pio_mask, &dev->mwdma_mask, @@ -3147,9 +3164,9 @@ static int ata_dev_set_mode(struct ata_device *dev) dev_err_whine = " (SET_XFERMODE skipped)"; else { if (nosetxfer) - ata_dev_warn(dev, - "NOSETXFER but PATA detected - can't " - "skip SETXFER, might malfunction\n"); + ata_dev_printk(dev, KERN_WARNING, + "NOSETXFER but PATA detected - can't " + "skip SETXFER, might malfunction\n"); err_mask = ata_dev_set_xfermode(dev); } @@ -3199,14 +3216,15 @@ static int ata_dev_set_mode(struct ata_device *dev) DPRINTK("xfer_shift=%u, xfer_mode=0x%x\n", dev->xfer_shift, (int)dev->xfer_mode); - ata_dev_info(dev, "configured for %s%s\n", - ata_mode_string(ata_xfer_mode2mask(dev->xfer_mode)), - dev_err_whine); + ata_dev_printk(dev, KERN_INFO, "configured for %s%s\n", + ata_mode_string(ata_xfer_mode2mask(dev->xfer_mode)), + dev_err_whine); return 0; fail: - ata_dev_err(dev, "failed to set xfermode (err_mask=0x%x)\n", err_mask); + ata_dev_printk(dev, KERN_ERR, "failed to set xfermode " + "(err_mask=0x%x)\n", err_mask); return -EIO; } @@ -3268,7 +3286,7 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev) /* step 2: always set host PIO timings */ ata_for_each_dev(dev, link, ENABLED) { if (dev->pio_mode == 0xff) { - ata_dev_warn(dev, "no PIO support\n"); + ata_dev_printk(dev, KERN_WARNING, "no PIO support\n"); rc = -EINVAL; goto out; } @@ -3386,7 +3404,7 @@ int ata_wait_ready(struct ata_link *link, unsigned long deadline, if (!warned && time_after(now, start + 5 * HZ) && (deadline - now > 3 * HZ)) { - ata_link_warn(link, + ata_link_printk(link, KERN_WARNING, "link is slow to respond, please be patient " "(ready=%d)\n", tmp); warned = 1; @@ -3534,14 +3552,16 @@ int sata_link_resume(struct ata_link *link, const unsigned long *params, } while ((scontrol & 0xf0f) != 0x300 && --tries); if ((scontrol & 0xf0f) != 0x300) { - ata_link_warn(link, "failed to resume link (SControl %X)\n", - scontrol); + ata_link_printk(link, KERN_ERR, + "failed to resume link (SControl %X)\n", + scontrol); return 0; } if (tries < ATA_LINK_RESUME_TRIES) - ata_link_warn(link, "link resume succeeded after %d retries\n", - ATA_LINK_RESUME_TRIES - tries); + ata_link_printk(link, KERN_WARNING, + "link resume succeeded after %d retries\n", + ATA_LINK_RESUME_TRIES - tries); if ((rc = sata_link_debounce(link, params, deadline))) return rc; @@ -3658,9 +3678,8 @@ int ata_std_prereset(struct ata_link *link, unsigned long deadline) rc = sata_link_resume(link, timing, deadline); /* whine about phy resume failure but proceed */ if (rc && rc != -EOPNOTSUPP) - ata_link_warn(link, - "failed to resume link for reset (errno=%d)\n", - rc); + ata_link_printk(link, KERN_WARNING, "failed to resume " + "link for reset (errno=%d)\n", rc); } /* no point in trying softreset on offline link */ @@ -3776,7 +3795,8 @@ int sata_link_hardreset(struct ata_link *link, const unsigned long *timing, /* online is set iff link is online && reset succeeded */ if (online) *online = false; - ata_link_err(link, "COMRESET failed (errno=%d)\n", rc); + ata_link_printk(link, KERN_ERR, + "COMRESET failed (errno=%d)\n", rc); } DPRINTK("EXIT, rc=%d\n", rc); return rc; @@ -3860,8 +3880,8 @@ static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class, unsigned char serial[2][ATA_ID_SERNO_LEN + 1]; if (dev->class != new_class) { - ata_dev_info(dev, "class mismatch %d != %d\n", - dev->class, new_class); + ata_dev_printk(dev, KERN_INFO, "class mismatch %d != %d\n", + dev->class, new_class); return 0; } @@ -3871,14 +3891,14 @@ static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class, ata_id_c_string(new_id, serial[1], ATA_ID_SERNO, sizeof(serial[1])); if (strcmp(model[0], model[1])) { - ata_dev_info(dev, "model number mismatch '%s' != '%s'\n", - model[0], model[1]); + ata_dev_printk(dev, KERN_INFO, "model number mismatch " + "'%s' != '%s'\n", model[0], model[1]); return 0; } if (strcmp(serial[0], serial[1])) { - ata_dev_info(dev, "serial number mismatch '%s' != '%s'\n", - serial[0], serial[1]); + ata_dev_printk(dev, KERN_INFO, "serial number mismatch " + "'%s' != '%s'\n", serial[0], serial[1]); return 0; } @@ -3948,8 +3968,8 @@ int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class, new_class != ATA_DEV_ATA && new_class != ATA_DEV_ATAPI && new_class != ATA_DEV_SEMB) { - ata_dev_info(dev, "class mismatch %u != %u\n", - dev->class, new_class); + ata_dev_printk(dev, KERN_INFO, "class mismatch %u != %u\n", + dev->class, new_class); rc = -ENODEV; goto fail; } @@ -3970,9 +3990,9 @@ int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class, return 0; /* n_sectors has changed */ - ata_dev_warn(dev, "n_sectors mismatch %llu != %llu\n", - (unsigned long long)n_sectors, - (unsigned long long)dev->n_sectors); + ata_dev_printk(dev, KERN_WARNING, "n_sectors mismatch %llu != %llu\n", + (unsigned long long)n_sectors, + (unsigned long long)dev->n_sectors); /* * Something could have caused HPA to be unlocked @@ -3981,9 +4001,9 @@ int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class, */ if (dev->n_native_sectors == n_native_sectors && dev->n_sectors > n_sectors && dev->n_sectors == n_native_sectors) { - ata_dev_warn(dev, - "new n_sectors matches native, probably " - "late HPA unlock, n_sectors updated\n"); + ata_dev_printk(dev, KERN_WARNING, + "new n_sectors matches native, probably " + "late HPA unlock, n_sectors updated\n"); /* use the larger n_sectors */ return 0; } @@ -3997,9 +4017,9 @@ int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class, if (dev->n_native_sectors == n_native_sectors && dev->n_sectors < n_sectors && n_sectors == n_native_sectors && !(dev->horkage & ATA_HORKAGE_BROKEN_HPA)) { - ata_dev_warn(dev, - "old n_sectors matches native, probably " - "late HPA lock, will try to unlock HPA\n"); + ata_dev_printk(dev, KERN_WARNING, + "old n_sectors matches native, probably " + "late HPA lock, will try to unlock HPA\n"); /* try unlocking HPA */ dev->flags |= ATA_DFLAG_UNLOCK_HPA; rc = -EIO; @@ -4010,7 +4030,7 @@ int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class, dev->n_native_sectors = n_native_sectors; dev->n_sectors = n_sectors; fail: - ata_dev_err(dev, "revalidation failed (errno=%d)\n", rc); + ata_dev_printk(dev, KERN_ERR, "revalidation failed (errno=%d)\n", rc); return rc; } @@ -4338,15 +4358,15 @@ static void ata_dev_xfermask(struct ata_device *dev) if (ata_dma_blacklisted(dev)) { xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA); - ata_dev_warn(dev, - "device is on DMA blacklist, disabling DMA\n"); + ata_dev_printk(dev, KERN_WARNING, + "device is on DMA blacklist, disabling DMA\n"); } if ((host->flags & ATA_HOST_SIMPLEX) && host->simplex_claimed && host->simplex_claimed != ap) { xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA); - ata_dev_warn(dev, - "simplex DMA is claimed by other device, disabling DMA\n"); + ata_dev_printk(dev, KERN_WARNING, "simplex DMA is claimed by " + "other device, disabling DMA\n"); } if (ap->flags & ATA_FLAG_NO_IORDY) @@ -4366,8 +4386,8 @@ static void ata_dev_xfermask(struct ata_device *dev) if (xfer_mask & (0xF8 << ATA_SHIFT_UDMA)) /* UDMA/44 or higher would be available */ if (cable_is_40wire(ap)) { - ata_dev_warn(dev, - "limited to UDMA/33 due to 40-wire cable\n"); + ata_dev_printk(dev, KERN_WARNING, + "limited to UDMA/33 due to 40-wire cable\n"); xfer_mask &= ~(0xF8 << ATA_SHIFT_UDMA); } @@ -4934,8 +4954,8 @@ int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active) done_mask = ap->qc_active ^ qc_active; if (unlikely(done_mask & qc_active)) { - ata_port_err(ap, "illegal qc_active transition (%08x->%08x)\n", - ap->qc_active, qc_active); + ata_port_printk(ap, KERN_ERR, "illegal qc_active transition " + "(%08x->%08x)\n", ap->qc_active, qc_active); return -EINVAL; } @@ -5827,9 +5847,9 @@ int ata_host_start(struct ata_host *host) rc = ap->ops->port_start(ap); if (rc) { if (rc != -ENODEV) - dev_err(host->dev, - "failed to start port %d (errno=%d)\n", - i, rc); + dev_printk(KERN_ERR, host->dev, + "failed to start port %d " + "(errno=%d)\n", i, rc); goto err_out; } } @@ -5951,7 +5971,8 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) /* host must have been started */ if (!(host->flags & ATA_HOST_STARTED)) { - dev_err(host->dev, "BUG: trying to register unstarted host\n"); + dev_printk(KERN_ERR, host->dev, + "BUG: trying to register unstarted host\n"); WARN_ON(1); return -EINVAL; } @@ -6002,13 +6023,14 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) ap->udma_mask); if (!ata_port_is_dummy(ap)) { - ata_port_info(ap, "%cATA max %s %s\n", - (ap->flags & ATA_FLAG_SATA) ? 'S' : 'P', - ata_mode_string(xfer_mask), - ap->link.eh_info.desc); + ata_port_printk(ap, KERN_INFO, + "%cATA max %s %s\n", + (ap->flags & ATA_FLAG_SATA) ? 'S' : 'P', + ata_mode_string(xfer_mask), + ap->link.eh_info.desc); ata_ehi_clear_desc(&ap->link.eh_info); } else - ata_port_info(ap, "DUMMY\n"); + ata_port_printk(ap, KERN_INFO, "DUMMY\n"); } /* perform each probe asynchronously */ @@ -6220,8 +6242,8 @@ int ata_pci_device_do_resume(struct pci_dev *pdev) rc = pcim_enable_device(pdev); if (rc) { - dev_err(&pdev->dev, - "failed to enable device after resume (%d)\n", rc); + dev_printk(KERN_ERR, &pdev->dev, + "failed to enable device after resume (%d)\n", rc); return rc; } @@ -6577,82 +6599,6 @@ const struct ata_port_info ata_dummy_port_info = { .port_ops = &ata_dummy_port_ops, }; -/* - * Utility print functions - */ -int ata_port_printk(const struct ata_port *ap, const char *level, - const char *fmt, ...) -{ - struct va_format vaf; - va_list args; - int r; - - va_start(args, fmt); - - vaf.fmt = fmt; - vaf.va = &args; - - r = printk("%sata%u: %pV", level, ap->print_id, &vaf); - - va_end(args); - - return r; -} -EXPORT_SYMBOL(ata_port_printk); - -int ata_link_printk(const struct ata_link *link, const char *level, - const char *fmt, ...) -{ - struct va_format vaf; - va_list args; - int r; - - va_start(args, fmt); - - vaf.fmt = fmt; - vaf.va = &args; - - if (sata_pmp_attached(link->ap) || link->ap->slave_link) - r = printk("%sata%u.%02u: %pV", - level, link->ap->print_id, link->pmp, &vaf); - else - r = printk("%sata%u: %pV", - level, link->ap->print_id, &vaf); - - va_end(args); - - return r; -} -EXPORT_SYMBOL(ata_link_printk); - -int ata_dev_printk(const struct ata_device *dev, const char *level, - const char *fmt, ...) -{ - struct va_format vaf; - va_list args; - int r; - - va_start(args, fmt); - - vaf.fmt = fmt; - vaf.va = &args; - - r = printk("%sata%u.%02u: %pV", - level, dev->link->ap->print_id, dev->link->pmp + dev->devno, - &vaf); - - va_end(args); - - return r; -} -EXPORT_SYMBOL(ata_dev_printk); - -void ata_print_version(const struct device *dev, const char *version) -{ - dev_printk(KERN_DEBUG, dev, "version %s\n", version); -} -EXPORT_SYMBOL(ata_print_version); - /* * libata is essentially a library of internal helper functions for * low-level ATA host controller drivers. As such, the API/ABI is diff --git a/trunk/drivers/ata/libata-eh.c b/trunk/drivers/ata/libata-eh.c index ed16fbedaabd..7f099d6e4e0b 100644 --- a/trunk/drivers/ata/libata-eh.c +++ b/trunk/drivers/ata/libata-eh.c @@ -782,9 +782,8 @@ void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap) spin_unlock_irqrestore(ap->lock, flags); goto repeat; } - ata_port_err(ap, - "EH pending after %d tries, giving up\n", - ATA_EH_MAX_TRIES); + ata_port_printk(ap, KERN_ERR, "EH pending after %d " + "tries, giving up\n", ATA_EH_MAX_TRIES); ap->pflags &= ~ATA_PFLAG_EH_PENDING; } @@ -817,7 +816,7 @@ void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap) schedule_delayed_work(&ap->hotplug_task, 0); if (ap->pflags & ATA_PFLAG_RECOVERED) - ata_port_info(ap, "EH complete\n"); + ata_port_printk(ap, KERN_INFO, "EH complete\n"); ap->pflags &= ~(ATA_PFLAG_SCSI_HOTPLUG | ATA_PFLAG_RECOVERED); @@ -1311,7 +1310,7 @@ void ata_dev_disable(struct ata_device *dev) return; if (ata_msg_drv(dev->link->ap)) - ata_dev_warn(dev, "disabled\n"); + ata_dev_printk(dev, KERN_WARNING, "disabled\n"); ata_acpi_on_disable(dev); ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO0 | ATA_DNXFER_QUIET); dev->class++; @@ -1516,8 +1515,8 @@ static int ata_eh_read_log_10h(struct ata_device *dev, for (i = 0; i < ATA_SECT_SIZE; i++) csum += buf[i]; if (csum) - ata_dev_warn(dev, "invalid checksum 0x%x on log page 10h\n", - csum); + ata_dev_printk(dev, KERN_WARNING, + "invalid checksum 0x%x on log page 10h\n", csum); if (buf[0] & 0x80) return -ENOENT; @@ -1717,14 +1716,14 @@ void ata_eh_analyze_ncq_error(struct ata_link *link) memset(&tf, 0, sizeof(tf)); rc = ata_eh_read_log_10h(dev, &tag, &tf); if (rc) { - ata_link_err(link, "failed to read log page 10h (errno=%d)\n", - rc); + ata_link_printk(link, KERN_ERR, "failed to read log page 10h " + "(errno=%d)\n", rc); return; } if (!(link->sactive & (1 << tag))) { - ata_link_err(link, "log page 10h reported inactive tag %d\n", - tag); + ata_link_printk(link, KERN_ERR, "log page 10h reported " + "inactive tag %d\n", tag); return; } @@ -1989,7 +1988,8 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, (dev->flags & (ATA_DFLAG_PIO | ATA_DFLAG_NCQ | ATA_DFLAG_NCQ_OFF)) == ATA_DFLAG_NCQ) { dev->flags |= ATA_DFLAG_NCQ_OFF; - ata_dev_warn(dev, "NCQ disabled due to excessive errors\n"); + ata_dev_printk(dev, KERN_WARNING, + "NCQ disabled due to excessive errors\n"); goto done; } @@ -2374,24 +2374,24 @@ static void ata_eh_link_report(struct ata_link *link) ap->eh_tries); if (ehc->i.dev) { - ata_dev_err(ehc->i.dev, "exception Emask 0x%x " - "SAct 0x%x SErr 0x%x action 0x%x%s%s\n", - ehc->i.err_mask, link->sactive, ehc->i.serror, - ehc->i.action, frozen, tries_buf); + ata_dev_printk(ehc->i.dev, KERN_ERR, "exception Emask 0x%x " + "SAct 0x%x SErr 0x%x action 0x%x%s%s\n", + ehc->i.err_mask, link->sactive, ehc->i.serror, + ehc->i.action, frozen, tries_buf); if (desc) - ata_dev_err(ehc->i.dev, "%s\n", desc); + ata_dev_printk(ehc->i.dev, KERN_ERR, "%s\n", desc); } else { - ata_link_err(link, "exception Emask 0x%x " - "SAct 0x%x SErr 0x%x action 0x%x%s%s\n", - ehc->i.err_mask, link->sactive, ehc->i.serror, - ehc->i.action, frozen, tries_buf); + ata_link_printk(link, KERN_ERR, "exception Emask 0x%x " + "SAct 0x%x SErr 0x%x action 0x%x%s%s\n", + ehc->i.err_mask, link->sactive, ehc->i.serror, + ehc->i.action, frozen, tries_buf); if (desc) - ata_link_err(link, "%s\n", desc); + ata_link_printk(link, KERN_ERR, "%s\n", desc); } #ifdef CONFIG_ATA_VERBOSE_ERROR if (ehc->i.serror) - ata_link_err(link, + ata_link_printk(link, KERN_ERR, "SError: { %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s}\n", ehc->i.serror & SERR_DATA_RECOVERED ? "RecovData " : "", ehc->i.serror & SERR_COMM_RECOVERED ? "RecovComm " : "", @@ -2456,11 +2456,11 @@ static void ata_eh_link_report(struct ata_link *link) } else { const char *descr = ata_get_cmd_descript(cmd->command); if (descr) - ata_dev_err(qc->dev, "failed command: %s\n", - descr); + ata_dev_printk(qc->dev, KERN_ERR, + "failed command: %s\n", descr); } - ata_dev_err(qc->dev, + ata_dev_printk(qc->dev, KERN_ERR, "cmd %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x " "tag %d%s\n %s" "res %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x " @@ -2481,9 +2481,11 @@ static void ata_eh_link_report(struct ata_link *link) if (res->command & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ | ATA_ERR)) { if (res->command & ATA_BUSY) - ata_dev_err(qc->dev, "status: { Busy }\n"); + ata_dev_printk(qc->dev, KERN_ERR, + "status: { Busy }\n"); else - ata_dev_err(qc->dev, "status: { %s%s%s%s}\n", + ata_dev_printk(qc->dev, KERN_ERR, + "status: { %s%s%s%s}\n", res->command & ATA_DRDY ? "DRDY " : "", res->command & ATA_DF ? "DF " : "", res->command & ATA_DRQ ? "DRQ " : "", @@ -2493,7 +2495,8 @@ static void ata_eh_link_report(struct ata_link *link) if (cmd->command != ATA_CMD_PACKET && (res->feature & (ATA_ICRC | ATA_UNC | ATA_IDNF | ATA_ABORTED))) - ata_dev_err(qc->dev, "error: { %s%s%s%s}\n", + ata_dev_printk(qc->dev, KERN_ERR, + "error: { %s%s%s%s}\n", res->feature & ATA_ICRC ? "ICRC " : "", res->feature & ATA_UNC ? "UNC " : "", res->feature & ATA_IDNF ? "IDNF " : "", @@ -2647,7 +2650,8 @@ int ata_eh_reset(struct ata_link *link, int classify, if (rc) { if (rc == -ENOENT) { - ata_link_dbg(link, "port disabled--ignoring\n"); + ata_link_printk(link, KERN_DEBUG, + "port disabled. ignoring.\n"); ehc->i.action &= ~ATA_EH_RESET; ata_for_each_dev(dev, link, ALL) @@ -2655,9 +2659,8 @@ int ata_eh_reset(struct ata_link *link, int classify, rc = 0; } else - ata_link_err(link, - "prereset failed (errno=%d)\n", - rc); + ata_link_printk(link, KERN_ERR, + "prereset failed (errno=%d)\n", rc); goto out; } @@ -2686,8 +2689,8 @@ int ata_eh_reset(struct ata_link *link, int classify, if (reset) { if (verbose) - ata_link_info(link, "%s resetting link\n", - reset == softreset ? "soft" : "hard"); + ata_link_printk(link, KERN_INFO, "%s resetting link\n", + reset == softreset ? "soft" : "hard"); /* mark that this EH session started with reset */ ehc->last_reset = jiffies; @@ -2707,7 +2710,8 @@ int ata_eh_reset(struct ata_link *link, int classify, int tmp; if (verbose) - ata_link_info(slave, "hard resetting link\n"); + ata_link_printk(slave, KERN_INFO, + "hard resetting link\n"); ata_eh_about_to_do(slave, NULL, ATA_EH_RESET); tmp = ata_do_reset(slave, reset, classes, deadline, @@ -2730,8 +2734,9 @@ int ata_eh_reset(struct ata_link *link, int classify, reset = softreset; if (!reset) { - ata_link_err(link, - "follow-up softreset required but no softreset available\n"); + ata_link_printk(link, KERN_ERR, + "follow-up softreset required " + "but no softreset available\n"); failed_link = link; rc = -EINVAL; goto fail; @@ -2746,8 +2751,8 @@ int ata_eh_reset(struct ata_link *link, int classify, } } else { if (verbose) - ata_link_info(link, - "no reset method available, skipping reset\n"); + ata_link_printk(link, KERN_INFO, "no reset method " + "available, skipping reset\n"); if (!(lflags & ATA_LFLAG_ASSUME_CLASS)) lflags |= ATA_LFLAG_ASSUME_ATA; } @@ -2825,35 +2830,36 @@ int ata_eh_reset(struct ata_link *link, int classify, ata_for_each_dev(dev, link, ALL) { if (ata_phys_link_online(ata_dev_phys_link(dev))) { if (classes[dev->devno] == ATA_DEV_UNKNOWN) { - ata_dev_dbg(dev, "link online but device misclassified\n"); + ata_dev_printk(dev, KERN_DEBUG, "link online " + "but device misclassifed\n"); classes[dev->devno] = ATA_DEV_NONE; nr_unknown++; } } else if (ata_phys_link_offline(ata_dev_phys_link(dev))) { if (ata_class_enabled(classes[dev->devno])) - ata_dev_dbg(dev, - "link offline, clearing class %d to NONE\n", - classes[dev->devno]); + ata_dev_printk(dev, KERN_DEBUG, "link offline, " + "clearing class %d to NONE\n", + classes[dev->devno]); classes[dev->devno] = ATA_DEV_NONE; } else if (classes[dev->devno] == ATA_DEV_UNKNOWN) { - ata_dev_dbg(dev, - "link status unknown, clearing UNKNOWN to NONE\n"); + ata_dev_printk(dev, KERN_DEBUG, "link status unknown, " + "clearing UNKNOWN to NONE\n"); classes[dev->devno] = ATA_DEV_NONE; } } if (classify && nr_unknown) { if (try < max_tries) { - ata_link_warn(link, - "link online but %d devices misclassified, retrying\n", - nr_unknown); + ata_link_printk(link, KERN_WARNING, "link online but " + "%d devices misclassified, retrying\n", + nr_unknown); failed_link = link; rc = -EAGAIN; goto fail; } - ata_link_warn(link, - "link online but %d devices misclassified, " - "device detection might fail\n", nr_unknown); + ata_link_printk(link, KERN_WARNING, + "link online but %d devices misclassified, " + "device detection might fail\n", nr_unknown); } /* reset successful, schedule revalidation */ @@ -2883,23 +2889,14 @@ int ata_eh_reset(struct ata_link *link, int classify, sata_scr_read(link, SCR_STATUS, &sstatus)) rc = -ERESTART; - if (rc == -ERESTART || try >= max_tries) { - /* - * Thaw host port even if reset failed, so that the port - * can be retried on the next phy event. This risks - * repeated EH runs but seems to be a better tradeoff than - * shutting down a port after a botched hotplug attempt. - */ - if (ata_is_host_link(link)) - ata_eh_thaw_port(ap); + if (rc == -ERESTART || try >= max_tries) goto out; - } now = jiffies; if (time_before(now, deadline)) { unsigned long delta = deadline - now; - ata_link_warn(failed_link, + ata_link_printk(failed_link, KERN_WARNING, "reset failed (errno=%d), retrying in %u secs\n", rc, DIV_ROUND_UP(jiffies_to_msecs(delta), 1000)); @@ -2990,7 +2987,7 @@ static void ata_eh_park_issue_cmd(struct ata_device *dev, int park) tf.protocol |= ATA_PROT_NODATA; err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); if (park && (err_mask || tf.lbal != 0xc4)) { - ata_dev_err(dev, "head unload failed!\n"); + ata_dev_printk(dev, KERN_ERR, "head unload failed!\n"); ehc->unloaded_mask &= ~(1 << dev->devno); } } @@ -3201,9 +3198,8 @@ static int atapi_eh_clear_ua(struct ata_device *dev) err_mask = atapi_eh_tur(dev, &sense_key); if (err_mask != 0 && err_mask != AC_ERR_DEV) { - ata_dev_warn(dev, - "TEST_UNIT_READY failed (err_mask=0x%x)\n", - err_mask); + ata_dev_printk(dev, KERN_WARNING, "TEST_UNIT_READY " + "failed (err_mask=0x%x)\n", err_mask); return -EIO; } @@ -3212,14 +3208,14 @@ static int atapi_eh_clear_ua(struct ata_device *dev) err_mask = atapi_eh_request_sense(dev, sense_buffer, sense_key); if (err_mask) { - ata_dev_warn(dev, "failed to clear " + ata_dev_printk(dev, KERN_WARNING, "failed to clear " "UNIT ATTENTION (err_mask=0x%x)\n", err_mask); return -EIO; } } - ata_dev_warn(dev, "UNIT ATTENTION persists after %d tries\n", - ATA_EH_UA_TRIES); + ata_dev_printk(dev, KERN_WARNING, + "UNIT ATTENTION persists after %d tries\n", ATA_EH_UA_TRIES); return 0; } @@ -3270,7 +3266,7 @@ static int ata_eh_maybe_retry_flush(struct ata_device *dev) tf.flags |= ATA_TFLAG_DEVICE; tf.protocol = ATA_PROT_NODATA; - ata_dev_warn(dev, "retrying FLUSH 0x%x Emask 0x%x\n", + ata_dev_printk(dev, KERN_WARNING, "retrying FLUSH 0x%x Emask 0x%x\n", tf.command, qc->err_mask); err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); @@ -3285,7 +3281,7 @@ static int ata_eh_maybe_retry_flush(struct ata_device *dev) */ qc->scsicmd->allowed = max(qc->scsicmd->allowed, 1); } else { - ata_dev_warn(dev, "FLUSH failed Emask 0x%x\n", + ata_dev_printk(dev, KERN_WARNING, "FLUSH failed Emask 0x%x\n", err_mask); rc = -EIO; @@ -3359,9 +3355,9 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, err_mask = ata_dev_set_feature(dev, SETFEATURES_SATA_DISABLE, SATA_DIPM); if (err_mask && err_mask != AC_ERR_DEV) { - ata_dev_warn(dev, - "failed to disable DIPM, Emask 0x%x\n", - err_mask); + ata_dev_printk(dev, KERN_WARNING, + "failed to disable DIPM, Emask 0x%x\n", + err_mask); rc = -EIO; goto fail; } @@ -3403,7 +3399,7 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, err_mask = ata_dev_set_feature(dev, SETFEATURES_SATA_ENABLE, SATA_DIPM); if (err_mask && err_mask != AC_ERR_DEV) { - ata_dev_warn(dev, + ata_dev_printk(dev, KERN_WARNING, "failed to enable DIPM, Emask 0x%x\n", err_mask); rc = -EIO; @@ -3422,7 +3418,8 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, /* if no device or only one more chance is left, disable LPM */ if (!dev || ehc->tries[dev->devno] <= 2) { - ata_link_warn(link, "disabling LPM on the link\n"); + ata_link_printk(link, KERN_WARNING, + "disabling LPM on the link\n"); link->flags |= ATA_LFLAG_NO_LPM; } if (r_failed_dev) @@ -3693,7 +3690,8 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, rc = ata_eh_reset(link, ata_link_nr_vacant(link), prereset, softreset, hardreset, postreset); if (rc) { - ata_link_err(link, "reset failed, giving up\n"); + ata_link_printk(link, KERN_ERR, + "reset failed, giving up\n"); goto out; } } diff --git a/trunk/drivers/ata/libata-pmp.c b/trunk/drivers/ata/libata-pmp.c index 3eb2b816eb2a..f06b7ea590d3 100644 --- a/trunk/drivers/ata/libata-pmp.c +++ b/trunk/drivers/ata/libata-pmp.c @@ -147,8 +147,8 @@ int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *r_val) err_mask = sata_pmp_read(link, reg, r_val); if (err_mask) { - ata_link_warn(link, "failed to read SCR %d (Emask=0x%x)\n", - reg, err_mask); + ata_link_printk(link, KERN_WARNING, "failed to read SCR %d " + "(Emask=0x%x)\n", reg, err_mask); return -EIO; } return 0; @@ -178,8 +178,8 @@ int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val) err_mask = sata_pmp_write(link, reg, val); if (err_mask) { - ata_link_warn(link, "failed to write SCR %d (Emask=0x%x)\n", - reg, err_mask); + ata_link_printk(link, KERN_WARNING, "failed to write SCR %d " + "(Emask=0x%x)\n", reg, err_mask); return -EIO; } return 0; @@ -231,8 +231,8 @@ static int sata_pmp_read_gscr(struct ata_device *dev, u32 *gscr) err_mask = sata_pmp_read(dev->link, reg, &gscr[reg]); if (err_mask) { - ata_dev_err(dev, "failed to read PMP GSCR[%d] (Emask=0x%x)\n", - reg, err_mask); + ata_dev_printk(dev, KERN_ERR, "failed to read PMP " + "GSCR[%d] (Emask=0x%x)\n", reg, err_mask); return -EIO; } } @@ -311,25 +311,26 @@ static int sata_pmp_configure(struct ata_device *dev, int print_info) } if (print_info) { - ata_dev_info(dev, "Port Multiplier %s, " - "0x%04x:0x%04x r%d, %d ports, feat 0x%x/0x%x\n", - sata_pmp_spec_rev_str(gscr), vendor, devid, - sata_pmp_gscr_rev(gscr), - nr_ports, gscr[SATA_PMP_GSCR_FEAT_EN], - gscr[SATA_PMP_GSCR_FEAT]); + ata_dev_printk(dev, KERN_INFO, "Port Multiplier %s, " + "0x%04x:0x%04x r%d, %d ports, feat 0x%x/0x%x\n", + sata_pmp_spec_rev_str(gscr), vendor, devid, + sata_pmp_gscr_rev(gscr), + nr_ports, gscr[SATA_PMP_GSCR_FEAT_EN], + gscr[SATA_PMP_GSCR_FEAT]); if (!(dev->flags & ATA_DFLAG_AN)) - ata_dev_info(dev, + ata_dev_printk(dev, KERN_INFO, "Asynchronous notification not supported, " - "hotplug won't work on fan-out ports. Use warm-plug instead.\n"); + "hotplug won't\n work on fan-out " + "ports. Use warm-plug instead.\n"); } return 0; fail: - ata_dev_err(dev, - "failed to configure Port Multiplier (%s, Emask=0x%x)\n", - reason, err_mask); + ata_dev_printk(dev, KERN_ERR, + "failed to configure Port Multiplier (%s, Emask=0x%x)\n", + reason, err_mask); return rc; } @@ -484,17 +485,20 @@ int sata_pmp_attach(struct ata_device *dev) /* is it hanging off the right place? */ if (!sata_pmp_supported(ap)) { - ata_dev_err(dev, "host does not support Port Multiplier\n"); + ata_dev_printk(dev, KERN_ERR, + "host does not support Port Multiplier\n"); return -EINVAL; } if (!ata_is_host_link(link)) { - ata_dev_err(dev, "Port Multipliers cannot be nested\n"); + ata_dev_printk(dev, KERN_ERR, + "Port Multipliers cannot be nested\n"); return -EINVAL; } if (dev->devno) { - ata_dev_err(dev, "Port Multiplier must be the first device\n"); + ata_dev_printk(dev, KERN_ERR, + "Port Multiplier must be the first device\n"); return -EINVAL; } @@ -513,7 +517,8 @@ int sata_pmp_attach(struct ata_device *dev) rc = sata_pmp_init_links(ap, sata_pmp_gscr_ports(dev->gscr)); if (rc) { - ata_dev_info(dev, "failed to initialize PMP links\n"); + ata_dev_printk(dev, KERN_INFO, + "failed to initialize PMP links\n"); goto fail; } @@ -557,7 +562,7 @@ static void sata_pmp_detach(struct ata_device *dev) struct ata_link *tlink; unsigned long flags; - ata_dev_info(dev, "Port Multiplier detaching\n"); + ata_dev_printk(dev, KERN_INFO, "Port Multiplier detaching\n"); WARN_ON(!ata_is_host_link(link) || dev->devno || link->pmp != SATA_PMP_CTRL_PORT); @@ -604,23 +609,23 @@ static int sata_pmp_same_pmp(struct ata_device *dev, const u32 *new_gscr) new_nr_ports = sata_pmp_gscr_ports(new_gscr); if (old_vendor != new_vendor) { - ata_dev_info(dev, - "Port Multiplier vendor mismatch '0x%x' != '0x%x'\n", - old_vendor, new_vendor); + ata_dev_printk(dev, KERN_INFO, "Port Multiplier " + "vendor mismatch '0x%x' != '0x%x'\n", + old_vendor, new_vendor); return 0; } if (old_devid != new_devid) { - ata_dev_info(dev, - "Port Multiplier device ID mismatch '0x%x' != '0x%x'\n", - old_devid, new_devid); + ata_dev_printk(dev, KERN_INFO, "Port Multiplier " + "device ID mismatch '0x%x' != '0x%x'\n", + old_devid, new_devid); return 0; } if (old_nr_ports != new_nr_ports) { - ata_dev_info(dev, - "Port Multiplier nr_ports mismatch '0x%x' != '0x%x'\n", - old_nr_ports, new_nr_ports); + ata_dev_printk(dev, KERN_INFO, "Port Multiplier " + "nr_ports mismatch '0x%x' != '0x%x'\n", + old_nr_ports, new_nr_ports); return 0; } @@ -686,7 +691,8 @@ static int sata_pmp_revalidate(struct ata_device *dev, unsigned int new_class) return 0; fail: - ata_dev_err(dev, "PMP revalidation failed (errno=%d)\n", rc); + ata_dev_printk(dev, KERN_ERR, + "PMP revalidation failed (errno=%d)\n", rc); DPRINTK("EXIT, rc=%d\n", rc); return rc; } @@ -710,14 +716,13 @@ static int sata_pmp_revalidate_quick(struct ata_device *dev) err_mask = sata_pmp_read(dev->link, SATA_PMP_GSCR_PROD_ID, &prod_id); if (err_mask) { - ata_dev_err(dev, - "failed to read PMP product ID (Emask=0x%x)\n", - err_mask); + ata_dev_printk(dev, KERN_ERR, "failed to read PMP product ID " + "(Emask=0x%x)\n", err_mask); return -EIO; } if (prod_id != dev->gscr[SATA_PMP_GSCR_PROD_ID]) { - ata_dev_err(dev, "PMP product ID mismatch\n"); + ata_dev_printk(dev, KERN_ERR, "PMP product ID mismatch\n"); /* something weird is going on, request full PMP recovery */ return -EIO; } @@ -772,7 +777,8 @@ static int sata_pmp_eh_recover_pmp(struct ata_port *ap, rc = ata_eh_reset(link, 0, prereset, softreset, hardreset, postreset); if (rc) { - ata_link_err(link, "failed to reset PMP, giving up\n"); + ata_link_printk(link, KERN_ERR, + "failed to reset PMP, giving up\n"); goto fail; } @@ -813,9 +819,9 @@ static int sata_pmp_eh_recover_pmp(struct ata_port *ap, ehc->i.action |= ATA_EH_RESET; goto retry; } else { - ata_dev_err(dev, - "failed to recover PMP after %d tries, giving up\n", - ATA_EH_PMP_TRIES); + ata_dev_printk(dev, KERN_ERR, "failed to recover PMP " + "after %d tries, giving up\n", + ATA_EH_PMP_TRIES); goto fail; } } @@ -861,9 +867,8 @@ static int sata_pmp_eh_handle_disabled_links(struct ata_port *ap) /* unconditionally clear SError.N */ rc = sata_scr_write(link, SCR_ERROR, SERR_PHYRDY_CHG); if (rc) { - ata_link_err(link, - "failed to clear SError.N (errno=%d)\n", - rc); + ata_link_printk(link, KERN_ERR, "failed to clear " + "SError.N (errno=%d)\n", rc); return rc; } @@ -885,7 +890,7 @@ static int sata_pmp_handle_link_fail(struct ata_link *link, int *link_tries) /* disable this link */ if (!(link->flags & ATA_LFLAG_DISABLED)) { - ata_link_warn(link, + ata_link_printk(link, KERN_WARNING, "failed to recover link after %d tries, disabling\n", ATA_EH_PMP_LINK_TRIES); @@ -969,7 +974,7 @@ static int sata_pmp_eh_recover(struct ata_port *ap) err_mask = sata_pmp_write(pmp_link, SATA_PMP_GSCR_FEAT_EN, gscr[SATA_PMP_GSCR_FEAT_EN]); if (err_mask) { - ata_link_warn(pmp_link, + ata_link_printk(pmp_link, KERN_WARNING, "failed to disable NOTIFY (err_mask=0x%x)\n", err_mask); goto pmp_fail; @@ -1013,9 +1018,8 @@ static int sata_pmp_eh_recover(struct ata_port *ap) err_mask = sata_pmp_write(pmp_link, SATA_PMP_GSCR_FEAT_EN, gscr[SATA_PMP_GSCR_FEAT_EN]); if (err_mask) { - ata_dev_err(pmp_dev, - "failed to write PMP_FEAT_EN (Emask=0x%x)\n", - err_mask); + ata_dev_printk(pmp_dev, KERN_ERR, "failed to write " + "PMP_FEAT_EN (Emask=0x%x)\n", err_mask); rc = -EIO; goto pmp_fail; } @@ -1024,9 +1028,8 @@ static int sata_pmp_eh_recover(struct ata_port *ap) /* check GSCR_ERROR */ err_mask = sata_pmp_read(pmp_link, SATA_PMP_GSCR_ERROR, &gscr_error); if (err_mask) { - ata_dev_err(pmp_dev, - "failed to read PMP_GSCR_ERROR (Emask=0x%x)\n", - err_mask); + ata_dev_printk(pmp_dev, KERN_ERR, "failed to read " + "PMP_GSCR_ERROR (Emask=0x%x)\n", err_mask); rc = -EIO; goto pmp_fail; } @@ -1040,16 +1043,17 @@ static int sata_pmp_eh_recover(struct ata_port *ap) ata_ehi_hotplugged(&link->eh_context.i); cnt++; } else { - ata_link_warn(link, - "PHY status changed but maxed out on retries, giving up\n"); - ata_link_warn(link, - "Manually issue scan to resume this link\n"); + ata_link_printk(link, KERN_WARNING, + "PHY status changed but maxed out on retries, " + "giving up\n"); + ata_link_printk(link, KERN_WARNING, + "Manully issue scan to resume this link\n"); } } if (cnt) { - ata_port_info(ap, - "PMP SError.N set for some ports, repeating recovery\n"); + ata_port_printk(ap, KERN_INFO, "PMP SError.N set for some " + "ports, repeating recovery\n"); goto retry; } @@ -1077,8 +1081,9 @@ static int sata_pmp_eh_recover(struct ata_port *ap) goto retry; } - ata_port_err(ap, "failed to recover PMP after %d tries, giving up\n", - ATA_EH_PMP_TRIES); + ata_port_printk(ap, KERN_ERR, + "failed to recover PMP after %d tries, giving up\n", + ATA_EH_PMP_TRIES); sata_pmp_detach(pmp_dev); ata_dev_disable(pmp_dev); diff --git a/trunk/drivers/ata/libata-scsi.c b/trunk/drivers/ata/libata-scsi.c index 46d087f08607..927f968e99d9 100644 --- a/trunk/drivers/ata/libata-scsi.c +++ b/trunk/drivers/ata/libata-scsi.c @@ -1108,7 +1108,8 @@ static int ata_scsi_dev_config(struct scsi_device *sdev, /* configure draining */ buf = kmalloc(ATAPI_MAX_DRAIN, q->bounce_gfp | GFP_KERNEL); if (!buf) { - ata_dev_err(dev, "drain buffer allocation failed\n"); + ata_dev_printk(dev, KERN_ERR, + "drain buffer allocation failed\n"); return -ENOMEM; } @@ -1126,7 +1127,7 @@ static int ata_scsi_dev_config(struct scsi_device *sdev, * IDENTIFY_PACKET is executed as ATA_PROT_PIO. */ if (sdev->sector_size > PAGE_SIZE) - ata_dev_warn(dev, + ata_dev_printk(dev, KERN_WARNING, "sector_size=%u > PAGE_SIZE, PIO may malfunction\n", sdev->sector_size); @@ -1783,7 +1784,8 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd, if (cmd->sc_data_direction == DMA_FROM_DEVICE || cmd->sc_data_direction == DMA_TO_DEVICE) { if (unlikely(scsi_bufflen(cmd) < 1)) { - ata_dev_warn(dev, "WARNING: zero len r/w req\n"); + ata_dev_printk(dev, KERN_WARNING, + "WARNING: zero len r/w req\n"); goto err_did; } @@ -2967,8 +2969,9 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) * with the cached multi_count of libata */ if (multi_count != dev->multi_count) - ata_dev_warn(dev, "invalid multi_count %u ignored\n", - multi_count); + ata_dev_printk(dev, KERN_WARNING, + "invalid multi_count %u ignored\n", + multi_count); } /* @@ -3463,8 +3466,9 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync) goto repeat; } - ata_port_err(ap, - "WARNING: synchronous SCSI scan failed without making any progress, switching to async\n"); + ata_port_printk(ap, KERN_ERR, "WARNING: synchronous SCSI scan " + "failed without making any progress,\n" + " switching to async\n"); } queue_delayed_work(system_long_wq, &ap->hotplug_task, @@ -3546,8 +3550,8 @@ static void ata_scsi_remove_dev(struct ata_device *dev) mutex_unlock(&ap->scsi_host->scan_mutex); if (sdev) { - ata_dev_info(dev, "detaching (SCSI %s)\n", - dev_name(&sdev->sdev_gendev)); + ata_dev_printk(dev, KERN_INFO, "detaching (SCSI %s)\n", + dev_name(&sdev->sdev_gendev)); scsi_remove_device(sdev); scsi_device_put(sdev); diff --git a/trunk/drivers/ata/libata-sff.c b/trunk/drivers/ata/libata-sff.c index c24127dd6ef2..b1b926c55a72 100644 --- a/trunk/drivers/ata/libata-sff.c +++ b/trunk/drivers/ata/libata-sff.c @@ -227,9 +227,9 @@ int ata_sff_busy_sleep(struct ata_port *ap, } if (status != 0xff && (status & ATA_BUSY)) - ata_port_warn(ap, - "port is slow to respond, please be patient (Status 0x%x)\n", - status); + ata_port_printk(ap, KERN_WARNING, + "port is slow to respond, please be patient " + "(Status 0x%x)\n", status); timeout = ata_deadline(timer_start, tmout); while (status != 0xff && (status & ATA_BUSY) && @@ -242,9 +242,9 @@ int ata_sff_busy_sleep(struct ata_port *ap, return -ENODEV; if (status & ATA_BUSY) { - ata_port_err(ap, - "port failed to respond (%lu secs, Status 0x%x)\n", - DIV_ROUND_UP(tmout, 1000), status); + ata_port_printk(ap, KERN_ERR, "port failed to respond " + "(%lu secs, Status 0x%x)\n", + DIV_ROUND_UP(tmout, 1000), status); return -EBUSY; } @@ -350,8 +350,8 @@ static void ata_dev_select(struct ata_port *ap, unsigned int device, unsigned int wait, unsigned int can_sleep) { if (ata_msg_probe(ap)) - ata_port_info(ap, "ata_dev_select: ENTER, device %u, wait %u\n", - device, wait); + ata_port_printk(ap, KERN_INFO, "ata_dev_select: ENTER, " + "device %u, wait %u\n", device, wait); if (wait) ata_wait_idle(ap); @@ -1333,10 +1333,9 @@ void ata_sff_flush_pio_task(struct ata_port *ap) cancel_delayed_work_sync(&ap->sff_pio_task); ap->hsm_task_state = HSM_ST_IDLE; - ap->sff_pio_task_link = NULL; if (ata_msg_ctl(ap)) - ata_port_dbg(ap, "%s: EXIT\n", __func__); + ata_port_printk(ap, KERN_DEBUG, "%s: EXIT\n", __func__); } static void ata_sff_pio_task(struct work_struct *work) @@ -1514,7 +1513,7 @@ static unsigned int ata_sff_idle_irq(struct ata_port *ap) ap->ops->sff_check_status(ap); if (ap->ops->sff_irq_clear) ap->ops->sff_irq_clear(ap); - ata_port_warn(ap, "irq trap\n"); + ata_port_printk(ap, KERN_WARNING, "irq trap\n"); return 1; } #endif @@ -1712,7 +1711,7 @@ void ata_sff_lost_interrupt(struct ata_port *ap) /* There was a command running, we are no longer busy and we have no interrupt. */ - ata_port_warn(ap, "lost interrupt (Status 0x%x)\n", + ata_port_printk(ap, KERN_WARNING, "lost interrupt (Status 0x%x)\n", status); /* Run the host interrupt logic as if the interrupt had not been lost */ @@ -1799,9 +1798,8 @@ int ata_sff_prereset(struct ata_link *link, unsigned long deadline) if (!ata_link_offline(link)) { rc = ata_sff_wait_ready(link, deadline); if (rc && rc != -ENODEV) { - ata_link_warn(link, - "device not ready (errno=%d), forcing hardreset\n", - rc); + ata_link_printk(link, KERN_WARNING, "device not ready " + "(errno=%d), forcing hardreset\n", rc); ehc->i.action |= ATA_EH_HARDRESET; } } @@ -2058,7 +2056,7 @@ int ata_sff_softreset(struct ata_link *link, unsigned int *classes, rc = ata_bus_softreset(ap, devmask, deadline); /* if link is occupied, -ENODEV too is an error */ if (rc && (rc != -ENODEV || sata_scr_valid(link))) { - ata_link_err(link, "SRST failed (errno=%d)\n", rc); + ata_link_printk(link, KERN_ERR, "SRST failed (errno=%d)\n", rc); return rc; } @@ -2172,7 +2170,8 @@ void ata_sff_drain_fifo(struct ata_queued_cmd *qc) /* Can become DEBUG later */ if (count) - ata_port_dbg(ap, "drained %d bytes to clear DRQ\n", count); + ata_port_printk(ap, KERN_DEBUG, + "drained %d bytes to clear DRQ.\n", count); } EXPORT_SYMBOL_GPL(ata_sff_drain_fifo); @@ -2317,9 +2316,9 @@ int ata_pci_sff_init_host(struct ata_host *host) rc = pcim_iomap_regions(pdev, 0x3 << base, dev_driver_string(gdev)); if (rc) { - dev_warn(gdev, - "failed to request/iomap BARs for port %d (errno=%d)\n", - i, rc); + dev_printk(KERN_WARNING, gdev, + "failed to request/iomap BARs for port %d " + "(errno=%d)\n", i, rc); if (rc == -EBUSY) pcim_pin_device(pdev); ap->ops = &ata_dummy_port_ops; @@ -2341,7 +2340,7 @@ int ata_pci_sff_init_host(struct ata_host *host) } if (!mask) { - dev_err(gdev, "no available native port\n"); + dev_printk(KERN_ERR, gdev, "no available native port\n"); return -ENODEV; } @@ -2376,7 +2375,8 @@ int ata_pci_sff_prepare_host(struct pci_dev *pdev, host = ata_host_alloc_pinfo(&pdev->dev, ppi, 2); if (!host) { - dev_err(&pdev->dev, "failed to allocate ATA host\n"); + dev_printk(KERN_ERR, &pdev->dev, + "failed to allocate ATA host\n"); rc = -ENOMEM; goto err_out; } @@ -2542,7 +2542,8 @@ int ata_pci_sff_init_one(struct pci_dev *pdev, pi = ata_sff_find_valid_pi(ppi); if (!pi) { - dev_err(&pdev->dev, "no valid port_info specified\n"); + dev_printk(KERN_ERR, &pdev->dev, + "no valid port_info specified\n"); return -EINVAL; } @@ -3163,7 +3164,8 @@ static void ata_bmdma_nodma(struct ata_host *host, const char *reason) { int i; - dev_err(host->dev, "BMDMA: %s, falling back to PIO\n", reason); + dev_printk(KERN_ERR, host->dev, "BMDMA: %s, falling back to PIO\n", + reason); for (i = 0; i < 2; i++) { host->ports[i]->mwdma_mask = 0; @@ -3295,7 +3297,8 @@ int ata_pci_bmdma_init_one(struct pci_dev *pdev, pi = ata_sff_find_valid_pi(ppi); if (!pi) { - dev_err(&pdev->dev, "no valid port_info specified\n"); + dev_printk(KERN_ERR, &pdev->dev, + "no valid port_info specified\n"); return -EINVAL; } diff --git a/trunk/drivers/ata/pata_acpi.c b/trunk/drivers/ata/pata_acpi.c index 54145edf50e8..91949d997555 100644 --- a/trunk/drivers/ata/pata_acpi.c +++ b/trunk/drivers/ata/pata_acpi.c @@ -195,6 +195,8 @@ static int pacpi_port_start(struct ata_port *ap) struct pci_dev *pdev = to_pci_dev(ap->host->dev); struct pata_acpi *acpi; + int ret; + if (ap->acpi_handle == NULL) return -ENODEV; @@ -203,7 +205,11 @@ static int pacpi_port_start(struct ata_port *ap) return -ENOMEM; acpi->mask[0] = pacpi_discover_modes(ap, &ap->link.device[0]); acpi->mask[1] = pacpi_discover_modes(ap, &ap->link.device[1]); - return ata_bmdma_port_start(ap); + ret = ata_bmdma_port_start(ap); + if (ret < 0) + return ret; + + return ret; } static struct scsi_host_template pacpi_sht = { diff --git a/trunk/drivers/ata/pata_ali.c b/trunk/drivers/ata/pata_ali.c index cadd67998bac..794ec6e3275d 100644 --- a/trunk/drivers/ata/pata_ali.c +++ b/trunk/drivers/ata/pata_ali.c @@ -287,10 +287,10 @@ static void ali_warn_atapi_dma(struct ata_device *adev) int print_info = ehc->i.flags & ATA_EHI_PRINTINFO; if (print_info && adev->class == ATA_DEV_ATAPI && !ali_atapi_dma) { - ata_dev_warn(adev, - "WARNING: ATAPI DMA disabled for reliability issues. It can be enabled\n"); - ata_dev_warn(adev, - "WARNING: via pata_ali.atapi_dma modparam or corresponding sysfs node.\n"); + ata_dev_printk(adev, KERN_WARNING, + "WARNING: ATAPI DMA disabled for reliability issues. It can be enabled\n"); + ata_dev_printk(adev, KERN_WARNING, + "WARNING: via pata_ali.atapi_dma modparam or corresponding sysfs node.\n"); } } diff --git a/trunk/drivers/ata/pata_amd.c b/trunk/drivers/ata/pata_amd.c index dc6b5dae0463..b0975a5ad8c4 100644 --- a/trunk/drivers/ata/pata_amd.c +++ b/trunk/drivers/ata/pata_amd.c @@ -60,7 +60,7 @@ static void timing_setup(struct ata_port *ap, struct ata_device *adev, int offse UT = T / 2; if (ata_timing_compute(adev, speed, &at, T, UT) < 0) { - dev_err(&pdev->dev, "unknown mode %d\n", speed); + dev_printk(KERN_ERR, &pdev->dev, "unknown mode %d.\n", speed); return; } @@ -311,7 +311,7 @@ static unsigned long nv_mode_filter(struct ata_device *dev, cable detection result */ limit |= ata_pack_xfermask(ATA_PIO4, ATA_MWDMA2, ATA_UDMA2); - ata_port_dbg(ap, "nv_mode_filter: 0x%lx&0x%lx->0x%lx, " + ata_port_printk(ap, KERN_DEBUG, "nv_mode_filter: 0x%lx&0x%lx->0x%lx, " "BIOS=0x%lx (0x%x) ACPI=0x%lx%s\n", xfer_mask, limit, xfer_mask & limit, bios_limit, saved_udma, acpi_limit, acpi_str); @@ -530,12 +530,14 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) } }; const struct ata_port_info *ppi[] = { NULL, NULL }; + static int printed_version; int type = id->driver_data; void *hpriv = NULL; u8 fifo; int rc; - ata_print_version_once(&pdev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); rc = pcim_enable_device(pdev); if (rc) diff --git a/trunk/drivers/ata/pata_artop.c b/trunk/drivers/ata/pata_artop.c index 78a93b690959..2215632e4b31 100644 --- a/trunk/drivers/ata/pata_artop.c +++ b/trunk/drivers/ata/pata_artop.c @@ -346,6 +346,7 @@ static struct ata_port_operations artop6260_ops = { static int artop_init_one (struct pci_dev *pdev, const struct pci_device_id *id) { + static int printed_version; static const struct ata_port_info info_6210 = { .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = ATA_PIO4, @@ -377,7 +378,9 @@ static int artop_init_one (struct pci_dev *pdev, const struct pci_device_id *id) const struct ata_port_info *ppi[] = { NULL, NULL }; int rc; - ata_print_version_once(&pdev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, + "version " DRV_VERSION "\n"); rc = pcim_enable_device(pdev); if (rc) diff --git a/trunk/drivers/ata/pata_atp867x.c b/trunk/drivers/ata/pata_atp867x.c index 3cfabb262af2..95295935dd95 100644 --- a/trunk/drivers/ata/pata_atp867x.c +++ b/trunk/drivers/ata/pata_atp867x.c @@ -470,7 +470,7 @@ static int atp867x_ata_pci_sff_init_host(struct ata_host *host) } if (!mask) { - dev_err(gdev, "no available native port\n"); + dev_printk(KERN_ERR, gdev, "no available native port\n"); return -ENODEV; } @@ -487,6 +487,7 @@ static int atp867x_ata_pci_sff_init_host(struct ata_host *host) static int atp867x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) { + static int printed_version; static const struct ata_port_info info_867x = { .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = ATA_PIO4, @@ -498,7 +499,8 @@ static int atp867x_init_one(struct pci_dev *pdev, const struct ata_port_info *ppi[] = { &info_867x, NULL }; int rc; - ata_print_version_once(&pdev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n"); rc = pcim_enable_device(pdev); if (rc) @@ -509,14 +511,15 @@ static int atp867x_init_one(struct pci_dev *pdev, host = ata_host_alloc_pinfo(&pdev->dev, ppi, ATP867X_NUM_PORTS); if (!host) { - dev_err(&pdev->dev, "failed to allocate ATA host\n"); + dev_printk(KERN_ERR, &pdev->dev, + "failed to allocate ATA host\n"); rc = -ENOMEM; goto err_out; } rc = atp867x_ata_pci_sff_init_host(host); if (rc) { - dev_err(&pdev->dev, "failed to init host\n"); + dev_printk(KERN_ERR, &pdev->dev, "failed to init host\n"); goto err_out; } @@ -525,7 +528,7 @@ static int atp867x_init_one(struct pci_dev *pdev, rc = ata_host_activate(host, pdev->irq, ata_bmdma_interrupt, IRQF_SHARED, &atp867x_sht); if (rc) - dev_err(&pdev->dev, "failed to activate host\n"); + dev_printk(KERN_ERR, &pdev->dev, "failed to activate host\n"); err_out: return rc; diff --git a/trunk/drivers/ata/pata_bf54x.c b/trunk/drivers/ata/pata_bf54x.c index bd987bb082eb..ea64967000ff 100644 --- a/trunk/drivers/ata/pata_bf54x.c +++ b/trunk/drivers/ata/pata_bf54x.c @@ -1129,7 +1129,7 @@ static int bfin_softreset(struct ata_link *link, unsigned int *classes, /* issue bus reset */ err_mask = bfin_bus_softreset(ap, devmask); if (err_mask) { - ata_port_err(ap, "SRST failed (err_mask=0x%x)\n", + ata_port_printk(ap, KERN_ERR, "SRST failed (err_mask=0x%x)\n", err_mask); return -EIO; } @@ -1382,7 +1382,7 @@ static unsigned int bfin_ata_host_intr(struct ata_port *ap, #ifdef ATA_IRQ_TRAP if ((ap->stats.idle_irq % 1000) == 0) { ap->ops->irq_ack(ap, 0); /* debug trap */ - ata_port_warn(ap, "irq trap\n"); + ata_port_printk(ap, KERN_WARNING, "irq trap\n"); return 1; } #endif diff --git a/trunk/drivers/ata/pata_cs5520.c b/trunk/drivers/ata/pata_cs5520.c index 9ddcddc66a20..e3254fcff0f1 100644 --- a/trunk/drivers/ata/pata_cs5520.c +++ b/trunk/drivers/ata/pata_cs5520.c @@ -149,7 +149,8 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi ppi[1] = π if ((pcicfg & 0x40) == 0) { - dev_warn(&pdev->dev, "DMA mode disabled. Enabling.\n"); + dev_printk(KERN_WARNING, &pdev->dev, + "DMA mode disabled. Enabling.\n"); pci_write_config_byte(pdev, 0x60, pcicfg | 0x40); } diff --git a/trunk/drivers/ata/pata_efar.c b/trunk/drivers/ata/pata_efar.c index aca47e4e29ea..a08834758ea2 100644 --- a/trunk/drivers/ata/pata_efar.c +++ b/trunk/drivers/ata/pata_efar.c @@ -263,6 +263,7 @@ static struct ata_port_operations efar_ops = { static int efar_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { + static int printed_version; static const struct ata_port_info info = { .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = ATA_PIO4, @@ -272,7 +273,9 @@ static int efar_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) }; const struct ata_port_info *ppi[] = { &info, &info }; - ata_print_version_once(&pdev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, + "version " DRV_VERSION "\n"); return ata_pci_bmdma_init_one(pdev, ppi, &efar_sht, NULL, ATA_HOST_PARALLEL_SCAN); diff --git a/trunk/drivers/ata/pata_hpt3x3.c b/trunk/drivers/ata/pata_hpt3x3.c index b3042dab08bb..24d7df81546b 100644 --- a/trunk/drivers/ata/pata_hpt3x3.c +++ b/trunk/drivers/ata/pata_hpt3x3.c @@ -185,6 +185,7 @@ static void hpt3x3_init_chipset(struct pci_dev *dev) static int hpt3x3_init_one(struct pci_dev *pdev, const struct pci_device_id *id) { + static int printed_version; static const struct ata_port_info info = { .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = ATA_PIO4, @@ -205,7 +206,8 @@ static int hpt3x3_init_one(struct pci_dev *pdev, const struct pci_device_id *id) hpt3x3_init_chipset(pdev); - ata_print_version_once(&pdev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); host = ata_host_alloc_pinfo(&pdev->dev, ppi, 2); if (!host) diff --git a/trunk/drivers/ata/pata_icside.c b/trunk/drivers/ata/pata_icside.c index 52e7e7b8c74f..9f2889fe43b2 100644 --- a/trunk/drivers/ata/pata_icside.c +++ b/trunk/drivers/ata/pata_icside.c @@ -210,8 +210,8 @@ static void pata_icside_set_dmamode(struct ata_port *ap, struct ata_device *adev else iomd_type = 'A', cycle = 562; - ata_dev_info(adev, "timings: act %dns rec %dns cyc %dns (%c)\n", - t.active, t.recover, t.cycle, iomd_type); + ata_dev_printk(adev, KERN_INFO, "timings: act %dns rec %dns cyc %dns (%c)\n", + t.active, t.recover, t.cycle, iomd_type); state->port[ap->port_no].speed[adev->devno] = cycle; } diff --git a/trunk/drivers/ata/pata_it8213.c b/trunk/drivers/ata/pata_it8213.c index 998af0e629b1..4d142a2ab8fd 100644 --- a/trunk/drivers/ata/pata_it8213.c +++ b/trunk/drivers/ata/pata_it8213.c @@ -258,6 +258,7 @@ static struct ata_port_operations it8213_ops = { static int it8213_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { + static int printed_version; static const struct ata_port_info info = { .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = ATA_PIO4, @@ -268,7 +269,9 @@ static int it8213_init_one (struct pci_dev *pdev, const struct pci_device_id *en /* Current IT8213 stuff is single port */ const struct ata_port_info *ppi[] = { &info, &ata_dummy_port_info }; - ata_print_version_once(&pdev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, + "version " DRV_VERSION "\n"); return ata_pci_bmdma_init_one(pdev, ppi, &it8213_sht, NULL, 0); } diff --git a/trunk/drivers/ata/pata_it821x.c b/trunk/drivers/ata/pata_it821x.c index 62c5d00abd2e..2d15f2548a10 100644 --- a/trunk/drivers/ata/pata_it821x.c +++ b/trunk/drivers/ata/pata_it821x.c @@ -473,12 +473,12 @@ static int it821x_smart_set_mode(struct ata_link *link, struct ata_device **unus /* We do need the right mode information for DMA or PIO and this comes from the current configuration flags */ if (ata_id_has_dma(dev->id)) { - ata_dev_info(dev, "configured for DMA\n"); + ata_dev_printk(dev, KERN_INFO, "configured for DMA\n"); dev->xfer_mode = XFER_MW_DMA_0; dev->xfer_shift = ATA_SHIFT_MWDMA; dev->flags &= ~ATA_DFLAG_PIO; } else { - ata_dev_info(dev, "configured for PIO\n"); + ata_dev_printk(dev, KERN_INFO, "configured for PIO\n"); dev->xfer_mode = XFER_PIO_0; dev->xfer_shift = ATA_SHIFT_PIO; dev->flags |= ATA_DFLAG_PIO; @@ -508,12 +508,12 @@ static void it821x_dev_config(struct ata_device *adev) if (strstr(model_num, "Integrated Technology Express")) { /* RAID mode */ - ata_dev_info(adev, "%sRAID%d volume", - adev->id[147] ? "Bootable " : "", - adev->id[129]); + ata_dev_printk(adev, KERN_INFO, "%sRAID%d volume", + adev->id[147]?"Bootable ":"", + adev->id[129]); if (adev->id[129] != 1) - pr_cont("(%dK stripe)", adev->id[146]); - pr_cont("\n"); + printk("(%dK stripe)", adev->id[146]); + printk(".\n"); } /* This is a controller firmware triggered funny, don't report the drive faulty! */ @@ -610,7 +610,7 @@ static void it821x_display_disk(int n, u8 *buf) char *cbl = "(40 wire cable)"; static const char *types[5] = { - "RAID0", "RAID1", "RAID 0+1", "JBOD", "DISK" + "RAID0", "RAID1" "RAID 0+1", "JBOD", "DISK" }; if (buf[52] > 4) /* No Disk */ diff --git a/trunk/drivers/ata/pata_ixp4xx_cf.c b/trunk/drivers/ata/pata_ixp4xx_cf.c index 15b64311fe0a..f6b3f995f58a 100644 --- a/trunk/drivers/ata/pata_ixp4xx_cf.c +++ b/trunk/drivers/ata/pata_ixp4xx_cf.c @@ -31,7 +31,7 @@ static int ixp4xx_set_mode(struct ata_link *link, struct ata_device **error) struct ata_device *dev; ata_for_each_dev(dev, link, ENABLED) { - ata_dev_info(dev, "configured for PIO0\n"); + ata_dev_printk(dev, KERN_INFO, "configured for PIO0\n"); dev->pio_mode = XFER_PIO_0; dev->xfer_mode = XFER_PIO_0; dev->xfer_shift = ATA_SHIFT_PIO; @@ -181,7 +181,7 @@ static __devinit int ixp4xx_pata_probe(struct platform_device *pdev) ixp4xx_setup_port(ap, data, cs0->start, cs1->start); - ata_print_version_once(&pdev->dev, DRV_VERSION); + dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n"); /* activate host */ return ata_host_activate(host, irq, ata_sff_interrupt, 0, &ixp4xx_sht); diff --git a/trunk/drivers/ata/pata_legacy.c b/trunk/drivers/ata/pata_legacy.c index d960f8e9e8b1..6bd9425ba5ab 100644 --- a/trunk/drivers/ata/pata_legacy.c +++ b/trunk/drivers/ata/pata_legacy.c @@ -213,7 +213,7 @@ static int legacy_set_mode(struct ata_link *link, struct ata_device **unused) struct ata_device *dev; ata_for_each_dev(dev, link, ENABLED) { - ata_dev_info(dev, "configured for PIO\n"); + ata_dev_printk(dev, KERN_INFO, "configured for PIO\n"); dev->pio_mode = XFER_PIO_0; dev->xfer_mode = XFER_PIO_0; dev->xfer_shift = ATA_SHIFT_PIO; diff --git a/trunk/drivers/ata/pata_macio.c b/trunk/drivers/ata/pata_macio.c index b057e3fa44bc..46f589edccdb 100644 --- a/trunk/drivers/ata/pata_macio.c +++ b/trunk/drivers/ata/pata_macio.c @@ -772,9 +772,8 @@ static void pata_macio_reset_hw(struct pata_macio_priv *priv, int resume) pci_restore_state(priv->pdev); rc = pcim_enable_device(priv->pdev); if (rc) - dev_err(&priv->pdev->dev, - "Failed to enable device after resume (%d)\n", - rc); + dev_printk(KERN_ERR, &priv->pdev->dev, + "Failed to enable device after resume (%d)\n", rc); else pci_set_master(priv->pdev); } @@ -813,7 +812,7 @@ static int pata_macio_slave_config(struct scsi_device *sdev) blk_queue_update_dma_pad(sdev->request_queue, 31); /* Tell the world about it */ - ata_dev_info(dev, "OHare alignment limits applied\n"); + ata_dev_printk(dev, KERN_INFO, "OHare alignment limits applied\n"); return 0; } @@ -839,7 +838,8 @@ static int pata_macio_slave_config(struct scsi_device *sdev) cmd | PCI_COMMAND_INVALIDATE); /* Tell the world about it */ - ata_dev_info(dev, "K2/Shasta alignment limits applied\n"); + ata_dev_printk(dev, KERN_INFO, + "K2/Shasta alignment limits applied\n"); } return 0; diff --git a/trunk/drivers/ata/pata_mpiix.c b/trunk/drivers/ata/pata_mpiix.c index 9dc16df84191..d8d9c5807740 100644 --- a/trunk/drivers/ata/pata_mpiix.c +++ b/trunk/drivers/ata/pata_mpiix.c @@ -152,13 +152,15 @@ static struct ata_port_operations mpiix_port_ops = { static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id) { /* Single threaded by the PCI probe logic */ + static int printed_version; struct ata_host *host; struct ata_port *ap; void __iomem *cmd_addr, *ctl_addr; u16 idetim; int cmd, ctl, irq; - ata_print_version_once(&dev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n"); host = ata_host_alloc(&dev->dev, 1); if (!host) diff --git a/trunk/drivers/ata/pata_netcell.c b/trunk/drivers/ata/pata_netcell.c index 9979a43bc596..3eb921c746a1 100644 --- a/trunk/drivers/ata/pata_netcell.c +++ b/trunk/drivers/ata/pata_netcell.c @@ -57,6 +57,7 @@ static struct ata_port_operations netcell_ops = { static int netcell_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { + static int printed_version; static const struct ata_port_info info = { .flags = ATA_FLAG_SLAVE_POSS, /* Actually we don't really care about these as the @@ -69,7 +70,9 @@ static int netcell_init_one (struct pci_dev *pdev, const struct pci_device_id *e const struct ata_port_info *port_info[] = { &info, NULL }; int rc; - ata_print_version_once(&pdev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, + "version " DRV_VERSION "\n"); rc = pcim_enable_device(pdev); if (rc) diff --git a/trunk/drivers/ata/pata_ns87410.c b/trunk/drivers/ata/pata_ns87410.c index 31d5986537a3..2110863bb3db 100644 --- a/trunk/drivers/ata/pata_ns87410.c +++ b/trunk/drivers/ata/pata_ns87410.c @@ -86,7 +86,7 @@ static void ns87410_set_piomode(struct ata_port *ap, struct ata_device *adev) idefr &= ~0x04; if (ata_timing_compute(adev, adev->pio_mode, &at, 30303, 1) < 0) { - dev_err(&pdev->dev, "unknown mode %d\n", adev->pio_mode); + dev_printk(KERN_ERR, &pdev->dev, "unknown mode %d.\n", adev->pio_mode); return; } diff --git a/trunk/drivers/ata/pata_ns87415.c b/trunk/drivers/ata/pata_ns87415.c index f1d517bc5b49..605f198f958c 100644 --- a/trunk/drivers/ata/pata_ns87415.c +++ b/trunk/drivers/ata/pata_ns87415.c @@ -350,6 +350,7 @@ static void ns87415_fixup(struct pci_dev *pdev) static int ns87415_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { + static int printed_version; static const struct ata_port_info info = { .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = ATA_PIO4, @@ -369,7 +370,9 @@ static int ns87415_init_one (struct pci_dev *pdev, const struct pci_device_id *e if (PCI_SLOT(pdev->devfn) == 0x0E) ppi[0] = &info87560; #endif - ata_print_version_once(&pdev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, + "version " DRV_VERSION "\n"); rc = pcim_enable_device(pdev); if (rc) diff --git a/trunk/drivers/ata/pata_octeon_cf.c b/trunk/drivers/ata/pata_octeon_cf.c index 1d61d5d278fa..220ddc90608f 100644 --- a/trunk/drivers/ata/pata_octeon_cf.c +++ b/trunk/drivers/ata/pata_octeon_cf.c @@ -405,7 +405,7 @@ static int octeon_cf_softreset16(struct ata_link *link, unsigned int *classes, rc = ata_sff_wait_after_reset(link, 1, deadline); if (rc) { - ata_link_err(link, "SRST failed (errno=%d)\n", rc); + ata_link_printk(link, KERN_ERR, "SRST failed (errno=%d)\n", rc); return rc; } @@ -807,7 +807,6 @@ static int __devinit octeon_cf_probe(struct platform_device *pdev) irq_handler_t irq_handler = NULL; void __iomem *base; struct octeon_cf_port *cf_port; - char version[32]; res_cs0 = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -906,11 +905,10 @@ static int __devinit octeon_cf_probe(struct platform_device *pdev) ata_port_desc(ap, "cmd %p ctl %p", base, ap->ioaddr.ctl_addr); - snprintf(version, sizeof(version), "%s %d bit%s", - DRV_VERSION, + dev_info(&pdev->dev, "version " DRV_VERSION" %d bit%s.\n", (ocd->is16bit) ? 16 : 8, (cs1) ? ", True IDE" : ""); - ata_print_version_once(&pdev->dev, version); + return ata_host_activate(host, irq, irq_handler, 0, &octeon_cf_sht); diff --git a/trunk/drivers/ata/pata_oldpiix.c b/trunk/drivers/ata/pata_oldpiix.c index 98cdf50e4065..b811c1636204 100644 --- a/trunk/drivers/ata/pata_oldpiix.c +++ b/trunk/drivers/ata/pata_oldpiix.c @@ -235,6 +235,7 @@ static struct ata_port_operations oldpiix_pata_ops = { static int oldpiix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { + static int printed_version; static const struct ata_port_info info = { .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = ATA_PIO4, @@ -243,7 +244,9 @@ static int oldpiix_init_one (struct pci_dev *pdev, const struct pci_device_id *e }; const struct ata_port_info *ppi[] = { &info, NULL }; - ata_print_version_once(&pdev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, + "version " DRV_VERSION "\n"); return ata_pci_bmdma_init_one(pdev, ppi, &oldpiix_sht, NULL, 0); } diff --git a/trunk/drivers/ata/pata_opti.c b/trunk/drivers/ata/pata_opti.c index accc033faf77..00c5a02a94fc 100644 --- a/trunk/drivers/ata/pata_opti.c +++ b/trunk/drivers/ata/pata_opti.c @@ -167,8 +167,10 @@ static int opti_init_one(struct pci_dev *dev, const struct pci_device_id *id) .port_ops = &opti_port_ops }; const struct ata_port_info *ppi[] = { &info, NULL }; + static int printed_version; - ata_print_version_once(&dev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n"); return ata_pci_sff_init_one(dev, ppi, &opti_sht, NULL, 0); } diff --git a/trunk/drivers/ata/pata_optidma.c b/trunk/drivers/ata/pata_optidma.c index 77cb91408632..0852cd07de08 100644 --- a/trunk/drivers/ata/pata_optidma.c +++ b/trunk/drivers/ata/pata_optidma.c @@ -411,9 +411,11 @@ static int optidma_init_one(struct pci_dev *dev, const struct pci_device_id *id) .port_ops = &optiplus_port_ops }; const struct ata_port_info *ppi[] = { &info_82c700, NULL }; + static int printed_version; int rc; - ata_print_version_once(&dev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n"); rc = pcim_enable_device(dev); if (rc) diff --git a/trunk/drivers/ata/pata_pcmcia.c b/trunk/drivers/ata/pata_pcmcia.c index a808ba03bd7f..021abe6d8527 100644 --- a/trunk/drivers/ata/pata_pcmcia.c +++ b/trunk/drivers/ata/pata_pcmcia.c @@ -68,7 +68,7 @@ static int pcmcia_set_mode(struct ata_link *link, struct ata_device **r_failed_d the same vendor - check serial */ if (memcmp(master->id + ATA_ID_SERNO, slave->id + ATA_ID_SERNO, ATA_ID_SERNO_LEN) == 0 && master->id[ATA_ID_SERNO] >> 8) { - ata_dev_warn(slave, "is a ghost device, ignoring\n"); + ata_dev_printk(slave, KERN_WARNING, "is a ghost device, ignoring.\n"); ata_dev_disable(slave); } } @@ -142,7 +142,8 @@ static void pcmcia_8bit_drain_fifo(struct ata_queued_cmd *qc) ioread8(ap->ioaddr.data_addr); if (count) - ata_port_warn(ap, "drained %d bytes to clear DRQ\n", count); + ata_port_printk(ap, KERN_WARNING, "drained %d bytes to clear DRQ.\n", + count); } diff --git a/trunk/drivers/ata/pata_pdc2027x.c b/trunk/drivers/ata/pata_pdc2027x.c index b1511f38b0e8..9765ace16921 100644 --- a/trunk/drivers/ata/pata_pdc2027x.c +++ b/trunk/drivers/ata/pata_pdc2027x.c @@ -655,7 +655,7 @@ static int pdc_hardware_init(struct ata_host *host, unsigned int board_idx) */ pll_clock = pdc_detect_pll_input_clock(host); - dev_info(host->dev, "PLL input clock %ld kHz\n", pll_clock/1000); + dev_printk(KERN_INFO, host->dev, "PLL input clock %ld kHz\n", pll_clock/1000); /* Adjust PLL control register */ pdc_adjust_pll(host, pll_clock, board_idx); @@ -697,6 +697,7 @@ static void pdc_ata_setup_port(struct ata_ioports *port, void __iomem *base) */ static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { + static int printed_version; static const unsigned long cmd_offset[] = { 0x17c0, 0x15c0 }; static const unsigned long bmdma_offset[] = { 0x1000, 0x1008 }; unsigned int board_idx = (unsigned int) ent->driver_data; @@ -706,7 +707,8 @@ static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_de void __iomem *mmio_base; int i, rc; - ata_print_version_once(&pdev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); /* alloc host */ host = ata_host_alloc_pinfo(&pdev->dev, ppi, 2); diff --git a/trunk/drivers/ata/pata_platform.c b/trunk/drivers/ata/pata_platform.c index 2067308f683f..50400fa120fe 100644 --- a/trunk/drivers/ata/pata_platform.c +++ b/trunk/drivers/ata/pata_platform.c @@ -39,7 +39,7 @@ static int pata_platform_set_mode(struct ata_link *link, struct ata_device **unu dev->pio_mode = dev->xfer_mode = XFER_PIO_0; dev->xfer_shift = ATA_SHIFT_PIO; dev->flags |= ATA_DFLAG_PIO; - ata_dev_info(dev, "configured for PIO\n"); + ata_dev_printk(dev, KERN_INFO, "configured for PIO\n"); } return 0; } diff --git a/trunk/drivers/ata/pata_radisys.c b/trunk/drivers/ata/pata_radisys.c index b2d3a2bb4e60..8574b31f1773 100644 --- a/trunk/drivers/ata/pata_radisys.c +++ b/trunk/drivers/ata/pata_radisys.c @@ -213,6 +213,7 @@ static struct ata_port_operations radisys_pata_ops = { static int radisys_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { + static int printed_version; static const struct ata_port_info info = { .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = ATA_PIO4, @@ -222,7 +223,9 @@ static int radisys_init_one (struct pci_dev *pdev, const struct pci_device_id *e }; const struct ata_port_info *ppi[] = { &info, NULL }; - ata_print_version_once(&pdev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, + "version " DRV_VERSION "\n"); return ata_pci_bmdma_init_one(pdev, ppi, &radisys_sht, NULL, 0); } diff --git a/trunk/drivers/ata/pata_rdc.c b/trunk/drivers/ata/pata_rdc.c index 4d318f86ae86..5fbe9b166c69 100644 --- a/trunk/drivers/ata/pata_rdc.c +++ b/trunk/drivers/ata/pata_rdc.c @@ -312,6 +312,7 @@ static struct scsi_host_template rdc_sht = { static int __devinit rdc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { + static int printed_version; struct device *dev = &pdev->dev; struct ata_port_info port_info[2]; const struct ata_port_info *ppi[] = { &port_info[0], &port_info[1] }; @@ -320,7 +321,9 @@ static int __devinit rdc_init_one(struct pci_dev *pdev, struct rdc_host_priv *hpriv; int rc; - ata_print_version_once(&pdev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, + "version " DRV_VERSION "\n"); port_info[0] = rdc_port_info; port_info[1] = rdc_port_info; diff --git a/trunk/drivers/ata/pata_rz1000.c b/trunk/drivers/ata/pata_rz1000.c index aca321e1e6a2..4d04471794b6 100644 --- a/trunk/drivers/ata/pata_rz1000.c +++ b/trunk/drivers/ata/pata_rz1000.c @@ -44,7 +44,7 @@ static int rz1000_set_mode(struct ata_link *link, struct ata_device **unused) dev->xfer_mode = XFER_PIO_0; dev->xfer_shift = ATA_SHIFT_PIO; dev->flags |= ATA_DFLAG_PIO; - ata_dev_info(dev, "configured for PIO\n"); + ata_dev_printk(dev, KERN_INFO, "configured for PIO\n"); } return 0; } @@ -92,7 +92,7 @@ static int rz1000_init_one (struct pci_dev *pdev, const struct pci_device_id *en }; const struct ata_port_info *ppi[] = { &info, NULL }; - ata_print_version_once(&pdev->dev, DRV_VERSION); + printk_once(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); if (rz1000_fifo_disable(pdev) == 0) return ata_pci_sff_init_one(pdev, ppi, &rz1000_sht, NULL, 0); diff --git a/trunk/drivers/ata/pata_samsung_cf.c b/trunk/drivers/ata/pata_samsung_cf.c index 1b372c297195..c446ae6055a3 100644 --- a/trunk/drivers/ata/pata_samsung_cf.c +++ b/trunk/drivers/ata/pata_samsung_cf.c @@ -376,7 +376,7 @@ static int pata_s3c_softreset(struct ata_link *link, unsigned int *classes, rc = pata_s3c_bus_softreset(ap, deadline); /* if link is occupied, -ENODEV too is an error */ if (rc && rc != -ENODEV) { - ata_link_err(link, "SRST failed (errno=%d)\n", rc); + ata_link_printk(link, KERN_ERR, "SRST failed (errno=%d)\n", rc); return rc; } diff --git a/trunk/drivers/ata/pata_scc.c b/trunk/drivers/ata/pata_scc.c index eb748e327143..88ea9b677b47 100644 --- a/trunk/drivers/ata/pata_scc.c +++ b/trunk/drivers/ata/pata_scc.c @@ -637,7 +637,8 @@ static int scc_softreset(struct ata_link *link, unsigned int *classes, DPRINTK("about to softreset, devmask=%x\n", devmask); err_mask = scc_bus_softreset(ap, devmask, deadline); if (err_mask) { - ata_port_err(ap, "SRST failed (err_mask=0x%x)\n", err_mask); + ata_port_printk(ap, KERN_ERR, "SRST failed (err_mask=0x%x)\n", + err_mask); return -EIO; } @@ -1071,12 +1072,15 @@ static int scc_host_init(struct ata_host *host) static int scc_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { + static int printed_version; unsigned int board_idx = (unsigned int) ent->driver_data; const struct ata_port_info *ppi[] = { &scc_port_info[board_idx], NULL }; struct ata_host *host; int rc; - ata_print_version_once(&pdev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, + "version " DRV_VERSION "\n"); host = ata_host_alloc_pinfo(&pdev->dev, ppi, 1); if (!host) diff --git a/trunk/drivers/ata/pata_sch.c b/trunk/drivers/ata/pata_sch.c index 7c78b9993627..e97b32f03a6e 100644 --- a/trunk/drivers/ata/pata_sch.c +++ b/trunk/drivers/ata/pata_sch.c @@ -172,9 +172,12 @@ static void sch_set_dmamode(struct ata_port *ap, struct ata_device *adev) static int __devinit sch_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { + static int printed_version; const struct ata_port_info *ppi[] = { &sch_port_info, NULL }; - ata_print_version_once(&pdev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, + "version " DRV_VERSION "\n"); return ata_pci_bmdma_init_one(pdev, ppi, &sch_sht, NULL, 0); } diff --git a/trunk/drivers/ata/pata_sil680.c b/trunk/drivers/ata/pata_sil680.c index 31f759b0ab71..118787caa93f 100644 --- a/trunk/drivers/ata/pata_sil680.c +++ b/trunk/drivers/ata/pata_sil680.c @@ -327,11 +327,13 @@ static int __devinit sil680_init_one(struct pci_dev *pdev, .port_ops = &sil680_port_ops }; const struct ata_port_info *ppi[] = { &info, NULL }; + static int printed_version; struct ata_host *host; void __iomem *mmio_base; int rc, try_mmio; - ata_print_version_once(&pdev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); rc = pcim_enable_device(pdev); if (rc) diff --git a/trunk/drivers/ata/pata_sis.c b/trunk/drivers/ata/pata_sis.c index 533f2aefab87..be08ff92db17 100644 --- a/trunk/drivers/ata/pata_sis.c +++ b/trunk/drivers/ata/pata_sis.c @@ -681,6 +681,7 @@ static void sis_fixup(struct pci_dev *pdev, struct sis_chipset *sis) static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { + static int printed_version; const struct ata_port_info *ppi[] = { NULL, NULL }; struct pci_dev *host = NULL; struct sis_chipset *chipset = NULL; @@ -734,7 +735,9 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) 0x0, &sis_info100 }; - ata_print_version_once(&pdev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, + "version " DRV_VERSION "\n"); rc = pcim_enable_device(pdev); if (rc) diff --git a/trunk/drivers/ata/pata_sl82c105.c b/trunk/drivers/ata/pata_sl82c105.c index c06ce8ced566..7f5d020ed56c 100644 --- a/trunk/drivers/ata/pata_sl82c105.c +++ b/trunk/drivers/ata/pata_sl82c105.c @@ -317,11 +317,9 @@ static int sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id rev = sl82c105_bridge_revision(dev); if (rev == -1) - dev_warn(&dev->dev, - "pata_sl82c105: Unable to find bridge, disabling DMA\n"); + dev_printk(KERN_WARNING, &dev->dev, "pata_sl82c105: Unable to find bridge, disabling DMA.\n"); else if (rev <= 5) - dev_warn(&dev->dev, - "pata_sl82c105: Early bridge revision, no DMA available\n"); + dev_printk(KERN_WARNING, &dev->dev, "pata_sl82c105: Early bridge revision, no DMA available.\n"); else ppi[0] = &info_dma; diff --git a/trunk/drivers/ata/pata_triflex.c b/trunk/drivers/ata/pata_triflex.c index 28da1c6becf1..b3e0c9432283 100644 --- a/trunk/drivers/ata/pata_triflex.c +++ b/trunk/drivers/ata/pata_triflex.c @@ -196,8 +196,10 @@ static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id) .port_ops = &triflex_port_ops }; const struct ata_port_info *ppi[] = { &info, NULL }; + static int printed_version; - ata_print_version_once(&dev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n"); return ata_pci_bmdma_init_one(dev, ppi, &triflex_sht, NULL, 0); } diff --git a/trunk/drivers/ata/pata_via.c b/trunk/drivers/ata/pata_via.c index 65e4be6be220..ac8d7d97e408 100644 --- a/trunk/drivers/ata/pata_via.c +++ b/trunk/drivers/ata/pata_via.c @@ -350,8 +350,8 @@ static unsigned long via_mode_filter(struct ata_device *dev, unsigned long mask) if (config->id == PCI_DEVICE_ID_VIA_82C586_0) { ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num)); if (strcmp(model_num, "TS64GSSD25-M") == 0) { - ata_dev_warn(dev, - "disabling UDMA mode due to reported lockups with this device\n"); + ata_dev_printk(dev, KERN_WARNING, + "disabling UDMA mode due to reported lockups with this device.\n"); mask &= ~ ATA_MASK_UDMA; } } @@ -551,12 +551,14 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) const struct ata_port_info *ppi[] = { NULL, NULL }; struct pci_dev *isa; const struct via_isa_bridge *config; + static int printed_version; u8 enable; u32 timing; unsigned long flags = id->driver_data; int rc; - ata_print_version_once(&pdev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); rc = pcim_enable_device(pdev); if (rc) diff --git a/trunk/drivers/ata/pdc_adma.c b/trunk/drivers/ata/pdc_adma.c index 04911d52f59d..1111712b3d7d 100644 --- a/trunk/drivers/ata/pdc_adma.c +++ b/trunk/drivers/ata/pdc_adma.c @@ -596,12 +596,14 @@ static int adma_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base) rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (rc) { - dev_err(&pdev->dev, "32-bit DMA enable failed\n"); + dev_printk(KERN_ERR, &pdev->dev, + "32-bit DMA enable failed\n"); return rc; } rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); if (rc) { - dev_err(&pdev->dev, "32-bit consistent DMA enable failed\n"); + dev_printk(KERN_ERR, &pdev->dev, + "32-bit consistent DMA enable failed\n"); return rc; } return 0; @@ -610,13 +612,15 @@ static int adma_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base) static int adma_ata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { + static int printed_version; unsigned int board_idx = (unsigned int) ent->driver_data; const struct ata_port_info *ppi[] = { &adma_port_info[board_idx], NULL }; struct ata_host *host; void __iomem *mmio_base; int rc, port_no; - ata_print_version_once(&pdev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); /* alloc host */ host = ata_host_alloc_pinfo(&pdev->dev, ppi, ADMA_PORTS); diff --git a/trunk/drivers/ata/sata_dwc_460ex.c b/trunk/drivers/ata/sata_dwc_460ex.c index b02c4ffa4db0..dc88a39e7db8 100644 --- a/trunk/drivers/ata/sata_dwc_460ex.c +++ b/trunk/drivers/ata/sata_dwc_460ex.c @@ -766,15 +766,11 @@ static int dma_dwc_xfer_setup(struct scatterlist *sg, int num_elems, static void dma_dwc_exit(struct sata_dwc_device *hsdev) { dev_dbg(host_pvt.dwc_dev, "%s:\n", __func__); - if (host_pvt.sata_dma_regs) { + if (host_pvt.sata_dma_regs) iounmap(host_pvt.sata_dma_regs); - host_pvt.sata_dma_regs = NULL; - } - if (hsdev->irq_dma) { + if (hsdev->irq_dma) free_irq(hsdev->irq_dma, hsdev); - hsdev->irq_dma = 0; - } } /* @@ -1646,7 +1642,7 @@ static int sata_dwc_probe(struct platform_device *ofdev) if (hsdev == NULL) { dev_err(&ofdev->dev, "kmalloc failed for hsdev\n"); err = -ENOMEM; - goto error; + goto error_out; } memset(hsdev, 0, sizeof(*hsdev)); @@ -1656,7 +1652,7 @@ static int sata_dwc_probe(struct platform_device *ofdev) dev_err(&ofdev->dev, "ioremap failed for SATA register" " address\n"); err = -ENODEV; - goto error_kmalloc; + goto error_out; } hsdev->reg_base = base; dev_dbg(&ofdev->dev, "ioremap done for SATA register address\n"); @@ -1669,7 +1665,7 @@ static int sata_dwc_probe(struct platform_device *ofdev) if (!host) { dev_err(&ofdev->dev, "ata_host_alloc_pinfo failed\n"); err = -ENOMEM; - goto error_iomap; + goto error_out; } host->private_data = hsdev; @@ -1737,11 +1733,8 @@ static int sata_dwc_probe(struct platform_device *ofdev) /* Free SATA DMA resources */ dma_dwc_exit(hsdev); -error_iomap: - iounmap(base); -error_kmalloc: - kfree(hsdev); -error: + if (base) + iounmap(base); return err; } diff --git a/trunk/drivers/ata/sata_fsl.c b/trunk/drivers/ata/sata_fsl.c index 78ae7b67b09e..35a71d875d0e 100644 --- a/trunk/drivers/ata/sata_fsl.c +++ b/trunk/drivers/ata/sata_fsl.c @@ -346,11 +346,12 @@ static unsigned int sata_fsl_fill_sg(struct ata_queued_cmd *qc, void *cmd_desc, /* warn if each s/g element is not dword aligned */ if (sg_addr & 0x03) - ata_port_err(qc->ap, "s/g addr unaligned : 0x%llx\n", - (unsigned long long)sg_addr); + ata_port_printk(qc->ap, KERN_ERR, + "s/g addr unaligned : 0x%llx\n", + (unsigned long long)sg_addr); if (sg_len & 0x03) - ata_port_err(qc->ap, "s/g len unaligned : 0x%x\n", - sg_len); + ata_port_printk(qc->ap, KERN_ERR, + "s/g len unaligned : 0x%x\n", sg_len); if (num_prde == (SATA_FSL_MAX_PRD_DIRECT - 1) && sg_next(sg) != NULL) { @@ -660,7 +661,8 @@ static int sata_fsl_port_start(struct ata_port *ap) sata_fsl_scr_write(&ap->link, SCR_CONTROL, temp); sata_fsl_scr_read(&ap->link, SCR_CONTROL, &temp); - dev_warn(dev, "scr_control, speed limited to %x\n", temp); + dev_printk(KERN_WARNING, dev, "scr_control, speed limited to %x\n", + temp); #endif return 0; @@ -738,7 +740,8 @@ static int sata_fsl_hardreset(struct ata_link *link, unsigned int *class, 1, 500); if (temp & ONLINE) { - ata_port_err(ap, "Hardreset failed, not off-lined %d\n", i); + ata_port_printk(ap, KERN_ERR, + "Hardreset failed, not off-lined %d\n", i); /* * Try to offline controller atleast twice @@ -774,7 +777,8 @@ static int sata_fsl_hardreset(struct ata_link *link, unsigned int *class, temp = ata_wait_register(ap, hcr_base + HSTATUS, ONLINE, 0, 1, 500); if (!(temp & ONLINE)) { - ata_port_err(ap, "Hardreset failed, not on-lined\n"); + ata_port_printk(ap, KERN_ERR, + "Hardreset failed, not on-lined\n"); goto err; } @@ -790,8 +794,9 @@ static int sata_fsl_hardreset(struct ata_link *link, unsigned int *class, temp = ata_wait_register(ap, hcr_base + HSTATUS, 0xFF, 0, 1, 500); if ((!(temp & 0x10)) || ata_link_offline(link)) { - ata_port_warn(ap, "No Device OR PHYRDY change,Hstatus = 0x%x\n", - ioread32(hcr_base + HSTATUS)); + ata_port_printk(ap, KERN_WARNING, + "No Device OR PHYRDY change,Hstatus = 0x%x\n", + ioread32(hcr_base + HSTATUS)); *class = ATA_DEV_NONE; return 0; } @@ -804,12 +809,13 @@ static int sata_fsl_hardreset(struct ata_link *link, unsigned int *class, 500, jiffies_to_msecs(deadline - start_jiffies)); if ((temp & 0xFF) != 0x18) { - ata_port_warn(ap, "No Signature Update\n"); + ata_port_printk(ap, KERN_WARNING, "No Signature Update\n"); *class = ATA_DEV_NONE; goto do_followup_srst; } else { - ata_port_info(ap, "Signature Update detected @ %d msecs\n", - jiffies_to_msecs(jiffies - start_jiffies)); + ata_port_printk(ap, KERN_INFO, + "Signature Update detected @ %d msecs\n", + jiffies_to_msecs(jiffies - start_jiffies)); *class = sata_fsl_dev_classify(ap); return 0; } @@ -884,7 +890,7 @@ static int sata_fsl_softreset(struct ata_link *link, unsigned int *class, temp = ata_wait_register(ap, CQ + hcr_base, 0x1, 0x1, 1, 5000); if (temp & 0x1) { - ata_port_warn(ap, "ATA_SRST issue failed\n"); + ata_port_printk(ap, KERN_WARNING, "ATA_SRST issue failed\n"); DPRINTK("Softreset@5000,CQ=0x%x,CA=0x%x,CC=0x%x\n", ioread32(CQ + hcr_base), @@ -1196,7 +1202,8 @@ static irqreturn_t sata_fsl_interrupt(int irq, void *dev_instance) if (ap) { sata_fsl_host_intr(ap); } else { - dev_warn(host->dev, "interrupt on disabled port 0\n"); + dev_printk(KERN_WARNING, host->dev, + "interrupt on disabled port 0\n"); } iowrite32(interrupt_enables, hcr_base + HSTATUS); @@ -1310,7 +1317,8 @@ static int sata_fsl_probe(struct platform_device *ofdev) struct ata_port_info pi = sata_fsl_port_info[0]; const struct ata_port_info *ppi[] = { &pi, NULL }; - dev_info(&ofdev->dev, "Sata FSL Platform/CSB Driver init\n"); + dev_printk(KERN_INFO, &ofdev->dev, + "Sata FSL Platform/CSB Driver init\n"); hcr_base = of_iomap(ofdev->dev.of_node, 0); if (!hcr_base) @@ -1339,7 +1347,7 @@ static int sata_fsl_probe(struct platform_device *ofdev) irq = irq_of_parse_and_map(ofdev->dev.of_node, 0); if (irq < 0) { - dev_err(&ofdev->dev, "invalid irq from platform\n"); + dev_printk(KERN_ERR, &ofdev->dev, "invalid irq from platform\n"); goto error_exit_with_cleanup; } host_priv->irq = irq; @@ -1414,7 +1422,8 @@ static int sata_fsl_resume(struct platform_device *op) ret = sata_fsl_init_controller(host); if (ret) { - dev_err(&op->dev, "Error initializing hardware\n"); + dev_printk(KERN_ERR, &op->dev, + "Error initialize hardware\n"); return ret; } diff --git a/trunk/drivers/ata/sata_inic162x.c b/trunk/drivers/ata/sata_inic162x.c index 5c7d70c03bf0..83a44471b189 100644 --- a/trunk/drivers/ata/sata_inic162x.c +++ b/trunk/drivers/ata/sata_inic162x.c @@ -396,8 +396,9 @@ static void inic_host_intr(struct ata_port *ap) } spurious: - ata_port_warn(ap, "unhandled interrupt: cmd=0x%x irq_stat=0x%x idma_stat=0x%x\n", - qc ? qc->tf.command : 0xff, irq_stat, idma_stat); + ata_port_printk(ap, KERN_WARNING, "unhandled interrupt: " + "cmd=0x%x irq_stat=0x%x idma_stat=0x%x\n", + qc ? qc->tf.command : 0xff, irq_stat, idma_stat); } static irqreturn_t inic_interrupt(int irq, void *dev_instance) @@ -618,9 +619,8 @@ static int inic_hardreset(struct ata_link *link, unsigned int *class, rc = sata_link_resume(link, timing, deadline); if (rc) { - ata_link_warn(link, - "failed to resume link after reset (errno=%d)\n", - rc); + ata_link_printk(link, KERN_WARNING, "failed to resume " + "link after reset (errno=%d)\n", rc); return rc; } @@ -632,9 +632,8 @@ static int inic_hardreset(struct ata_link *link, unsigned int *class, rc = ata_wait_after_reset(link, deadline, inic_check_ready); /* link occupied, -ENODEV too is an error */ if (rc) { - ata_link_warn(link, - "device not ready after hardreset (errno=%d)\n", - rc); + ata_link_printk(link, KERN_WARNING, "device not ready " + "after hardreset (errno=%d)\n", rc); return rc; } @@ -800,6 +799,7 @@ static int inic_pci_device_resume(struct pci_dev *pdev) static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { + static int printed_version; const struct ata_port_info *ppi[] = { &inic_port_info, NULL }; struct ata_host *host; struct inic_host_priv *hpriv; @@ -807,7 +807,8 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) int mmio_bar; int i, rc; - ata_print_version_once(&pdev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); /* alloc host */ host = ata_host_alloc_pinfo(&pdev->dev, ppi, NR_PORTS); @@ -846,13 +847,15 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* Set dma_mask. This devices doesn't support 64bit addressing. */ rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (rc) { - dev_err(&pdev->dev, "32-bit DMA enable failed\n"); + dev_printk(KERN_ERR, &pdev->dev, + "32-bit DMA enable failed\n"); return rc; } rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); if (rc) { - dev_err(&pdev->dev, "32-bit consistent DMA enable failed\n"); + dev_printk(KERN_ERR, &pdev->dev, + "32-bit consistent DMA enable failed\n"); return rc; } @@ -863,13 +866,15 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) */ rc = pci_set_dma_max_seg_size(pdev, 65536 - 512); if (rc) { - dev_err(&pdev->dev, "failed to set the maximum segment size\n"); + dev_printk(KERN_ERR, &pdev->dev, + "failed to set the maximum segment size.\n"); return rc; } rc = init_controller(hpriv->mmio_base, hpriv->cached_hctl); if (rc) { - dev_err(&pdev->dev, "failed to initialize controller\n"); + dev_printk(KERN_ERR, &pdev->dev, + "failed to initialize controller\n"); return rc; } diff --git a/trunk/drivers/ata/sata_mv.c b/trunk/drivers/ata/sata_mv.c index 4b6b2090784b..b52c0519ad0b 100644 --- a/trunk/drivers/ata/sata_mv.c +++ b/trunk/drivers/ata/sata_mv.c @@ -1190,7 +1190,7 @@ static void mv_wait_for_edma_empty_idle(struct ata_port *ap) break; udelay(per_loop); } - /* ata_port_info(ap, "%s: %u+ usecs\n", __func__, i); */ + /* ata_port_printk(ap, KERN_INFO, "%s: %u+ usecs\n", __func__, i); */ } /** @@ -1228,7 +1228,7 @@ static int mv_stop_edma(struct ata_port *ap) pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN; mv_wait_for_edma_empty_idle(ap); if (mv_stop_edma_engine(port_mmio)) { - ata_port_err(ap, "Unable to stop eDMA\n"); + ata_port_printk(ap, KERN_ERR, "Unable to stop eDMA\n"); err = -EIO; } mv_edma_cfg(ap, 0, 0); @@ -1382,7 +1382,7 @@ static void mv6_dev_config(struct ata_device *adev) if (adev->flags & ATA_DFLAG_NCQ) { if (sata_pmp_attached(adev->link->ap)) { adev->flags &= ~ATA_DFLAG_NCQ; - ata_dev_info(adev, + ata_dev_printk(adev, KERN_INFO, "NCQ disabled for command-based switching\n"); } } @@ -2225,8 +2225,9 @@ static unsigned int mv_send_fis(struct ata_port *ap, u32 *fis, int nwords) /* See if it worked */ if ((ifstat & 0x3000) != 0x1000) { - ata_port_warn(ap, "%s transmission error, ifstat=%08x\n", - __func__, ifstat); + ata_port_printk(ap, KERN_WARNING, + "%s transmission error, ifstat=%08x\n", + __func__, ifstat); return AC_ERR_OTHER; } return 0; @@ -2341,9 +2342,9 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd *qc) */ if (limit_warnings > 0 && (qc->nbytes / qc->sect_size) > 1) { --limit_warnings; - ata_link_warn(qc->dev->link, DRV_NAME - ": attempting PIO w/multiple DRQ: " - "this may fail due to h/w errata\n"); + ata_link_printk(qc->dev->link, KERN_WARNING, DRV_NAME + ": attempting PIO w/multiple DRQ: " + "this may fail due to h/w errata\n"); } /* drop through */ case ATA_PROT_NODATA: @@ -2498,20 +2499,20 @@ static int mv_handle_fbs_ncq_dev_err(struct ata_port *ap) } failed_links = hweight16(new_map); - ata_port_info(ap, - "%s: pmp_map=%04x qc_map=%04x failed_links=%d nr_active_links=%d\n", - __func__, pp->delayed_eh_pmp_map, - ap->qc_active, failed_links, - ap->nr_active_links); + ata_port_printk(ap, KERN_INFO, "%s: pmp_map=%04x qc_map=%04x " + "failed_links=%d nr_active_links=%d\n", + __func__, pp->delayed_eh_pmp_map, + ap->qc_active, failed_links, + ap->nr_active_links); if (ap->nr_active_links <= failed_links && mv_req_q_empty(ap)) { mv_process_crpb_entries(ap, pp); mv_stop_edma(ap); mv_eh_freeze(ap); - ata_port_info(ap, "%s: done\n", __func__); + ata_port_printk(ap, KERN_INFO, "%s: done\n", __func__); return 1; /* handled */ } - ata_port_info(ap, "%s: waiting\n", __func__); + ata_port_printk(ap, KERN_INFO, "%s: waiting\n", __func__); return 1; /* handled */ } @@ -2553,8 +2554,9 @@ static int mv_handle_dev_err(struct ata_port *ap, u32 edma_err_cause) * and we cannot handle it here. */ if (edma_err_cause & EDMA_ERR_SELF_DIS) { - ata_port_warn(ap, "%s: err_cause=0x%x pp_flags=0x%x\n", - __func__, edma_err_cause, pp->pp_flags); + ata_port_printk(ap, KERN_WARNING, + "%s: err_cause=0x%x pp_flags=0x%x\n", + __func__, edma_err_cause, pp->pp_flags); return 0; /* not handled */ } return mv_handle_fbs_ncq_dev_err(ap); @@ -2565,8 +2567,9 @@ static int mv_handle_dev_err(struct ata_port *ap, u32 edma_err_cause) * and we cannot handle it here. */ if (!(edma_err_cause & EDMA_ERR_SELF_DIS)) { - ata_port_warn(ap, "%s: err_cause=0x%x pp_flags=0x%x\n", - __func__, edma_err_cause, pp->pp_flags); + ata_port_printk(ap, KERN_WARNING, + "%s: err_cause=0x%x pp_flags=0x%x\n", + __func__, edma_err_cause, pp->pp_flags); return 0; /* not handled */ } return mv_handle_fbs_non_ncq_dev_err(ap); @@ -2927,7 +2930,8 @@ static int mv_pci_error(struct ata_host *host, void __iomem *mmio) err_cause = readl(mmio + hpriv->irq_cause_offset); - dev_err(host->dev, "PCI ERROR; PCI IRQ cause=0x%08x\n", err_cause); + dev_printk(KERN_ERR, host->dev, "PCI ERROR; PCI IRQ cause=0x%08x\n", + err_cause); DPRINTK("All regs @ PCI error\n"); mv_dump_all_regs(mmio, -1, to_pci_dev(host->dev)); @@ -3756,8 +3760,8 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx) hp_flags |= MV_HP_ERRATA_50XXB2; break; default: - dev_warn(&pdev->dev, - "Applying 50XXB2 workarounds to unknown rev\n"); + dev_printk(KERN_WARNING, &pdev->dev, + "Applying 50XXB2 workarounds to unknown rev\n"); hp_flags |= MV_HP_ERRATA_50XXB2; break; } @@ -3776,8 +3780,8 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx) hp_flags |= MV_HP_ERRATA_50XXB2; break; default: - dev_warn(&pdev->dev, - "Applying B2 workarounds to unknown rev\n"); + dev_printk(KERN_WARNING, &pdev->dev, + "Applying B2 workarounds to unknown rev\n"); hp_flags |= MV_HP_ERRATA_50XXB2; break; } @@ -3797,8 +3801,8 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx) hp_flags |= MV_HP_ERRATA_60X1C0; break; default: - dev_warn(&pdev->dev, - "Applying B2 workarounds to unknown rev\n"); + dev_printk(KERN_WARNING, &pdev->dev, + "Applying B2 workarounds to unknown rev\n"); hp_flags |= MV_HP_ERRATA_60X1B2; break; } @@ -3847,8 +3851,8 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx) hp_flags |= MV_HP_ERRATA_60X1C0; break; default: - dev_warn(&pdev->dev, - "Applying 60X1C0 workarounds to unknown rev\n"); + dev_printk(KERN_WARNING, &pdev->dev, + "Applying 60X1C0 workarounds to unknown rev\n"); hp_flags |= MV_HP_ERRATA_60X1C0; break; } @@ -3863,7 +3867,8 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx) break; default: - dev_err(host->dev, "BUG: invalid board index %u\n", board_idx); + dev_printk(KERN_ERR, host->dev, + "BUG: invalid board index %u\n", board_idx); return 1; } @@ -4018,6 +4023,7 @@ static void mv_conf_mbus_windows(struct mv_host_priv *hpriv, */ static int mv_platform_probe(struct platform_device *pdev) { + static int printed_version; const struct mv_sata_platform_data *mv_platform_data; const struct ata_port_info *ppi[] = { &mv_port_info[chip_soc], NULL }; @@ -4026,7 +4032,8 @@ static int mv_platform_probe(struct platform_device *pdev) struct resource *res; int n_ports, rc; - ata_print_version_once(&pdev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n"); /* * Simple resource validation .. @@ -4084,8 +4091,9 @@ static int mv_platform_probe(struct platform_device *pdev) if (rc) goto err; - dev_info(&pdev->dev, "slots %u ports %d\n", - (unsigned)MV_MAX_Q_DEPTH, host->n_ports); + dev_printk(KERN_INFO, &pdev->dev, + "slots %u ports %d\n", (unsigned)MV_MAX_Q_DEPTH, + host->n_ports); return ata_host_activate(host, platform_get_irq(pdev, 0), mv_interrupt, IRQF_SHARED, &mv6_sht); @@ -4209,21 +4217,22 @@ static int pci_go_64(struct pci_dev *pdev) if (rc) { rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); if (rc) { - dev_err(&pdev->dev, - "64-bit DMA enable failed\n"); + dev_printk(KERN_ERR, &pdev->dev, + "64-bit DMA enable failed\n"); return rc; } } } else { rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (rc) { - dev_err(&pdev->dev, "32-bit DMA enable failed\n"); + dev_printk(KERN_ERR, &pdev->dev, + "32-bit DMA enable failed\n"); return rc; } rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); if (rc) { - dev_err(&pdev->dev, - "32-bit consistent DMA enable failed\n"); + dev_printk(KERN_ERR, &pdev->dev, + "32-bit consistent DMA enable failed\n"); return rc; } } @@ -4267,9 +4276,10 @@ static void mv_print_info(struct ata_host *host) else gen = "?"; - dev_info(&pdev->dev, "Gen-%s %u slots %u ports %s mode IRQ via %s\n", - gen, (unsigned)MV_MAX_Q_DEPTH, host->n_ports, - scc_s, (MV_HP_FLAG_MSI & hpriv->hp_flags) ? "MSI" : "INTx"); + dev_printk(KERN_INFO, &pdev->dev, + "Gen-%s %u slots %u ports %s mode IRQ via %s\n", + gen, (unsigned)MV_MAX_Q_DEPTH, host->n_ports, + scc_s, (MV_HP_FLAG_MSI & hpriv->hp_flags) ? "MSI" : "INTx"); } /** @@ -4283,13 +4293,15 @@ static void mv_print_info(struct ata_host *host) static int mv_pci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { + static int printed_version; unsigned int board_idx = (unsigned int)ent->driver_data; const struct ata_port_info *ppi[] = { &mv_port_info[board_idx], NULL }; struct ata_host *host; struct mv_host_priv *hpriv; int n_ports, port, rc; - ata_print_version_once(&pdev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n"); /* allocate host */ n_ports = mv_get_hc_count(ppi[0]->flags) * MV_PORTS_PER_HC; diff --git a/trunk/drivers/ata/sata_nv.c b/trunk/drivers/ata/sata_nv.c index e0bc9646a38e..f173ef3bfc10 100644 --- a/trunk/drivers/ata/sata_nv.c +++ b/trunk/drivers/ata/sata_nv.c @@ -620,8 +620,9 @@ static void nv_adma_register_mode(struct ata_port *ap) count++; } if (count == 20) - ata_port_warn(ap, "timeout waiting for ADMA IDLE, stat=0x%hx\n", - status); + ata_port_printk(ap, KERN_WARNING, + "timeout waiting for ADMA IDLE, stat=0x%hx\n", + status); tmp = readw(mmio + NV_ADMA_CTL); writew(tmp & ~NV_ADMA_CTL_GO, mmio + NV_ADMA_CTL); @@ -634,9 +635,9 @@ static void nv_adma_register_mode(struct ata_port *ap) count++; } if (count == 20) - ata_port_warn(ap, - "timeout waiting for ADMA LEGACY, stat=0x%hx\n", - status); + ata_port_printk(ap, KERN_WARNING, + "timeout waiting for ADMA LEGACY, stat=0x%hx\n", + status); pp->flags |= NV_ADMA_PORT_REGISTER_MODE; } @@ -664,7 +665,7 @@ static void nv_adma_mode(struct ata_port *ap) count++; } if (count == 20) - ata_port_warn(ap, + ata_port_printk(ap, KERN_WARNING, "timeout waiting for ADMA LEGACY clear and IDLE, stat=0x%hx\n", status); @@ -771,10 +772,10 @@ static int nv_adma_slave_config(struct scsi_device *sdev) blk_queue_segment_boundary(sdev->request_queue, segment_boundary); blk_queue_max_segments(sdev->request_queue, sg_tablesize); - ata_port_info(ap, - "DMA mask 0x%llX, segment boundary 0x%lX, hw segs %hu\n", - (unsigned long long)*ap->host->dev->dma_mask, - segment_boundary, sg_tablesize); + ata_port_printk(ap, KERN_INFO, + "DMA mask 0x%llX, segment boundary 0x%lX, hw segs %hu\n", + (unsigned long long)*ap->host->dev->dma_mask, + segment_boundary, sg_tablesize); spin_unlock_irqrestore(ap->lock, flags); @@ -1442,7 +1443,8 @@ static unsigned int nv_adma_qc_issue(struct ata_queued_cmd *qc) existing commands. */ if (unlikely(qc->tf.protocol == ATA_PROT_NCQ && (qc->flags & ATA_QCFLAG_RESULT_TF))) { - ata_dev_err(qc->dev, "NCQ w/ RESULT_TF not allowed\n"); + ata_dev_printk(qc->dev, KERN_ERR, + "NCQ w/ RESULT_TF not allowed\n"); return AC_ERR_SYSTEM; } @@ -1579,15 +1581,15 @@ static int nv_hardreset(struct ata_link *link, unsigned int *class, int rc; if (!(ehc->i.flags & ATA_EHI_QUIET)) - ata_link_info(link, - "nv: skipping hardreset on occupied port\n"); + ata_link_printk(link, KERN_INFO, "nv: skipping " + "hardreset on occupied port\n"); /* make sure the link is online */ rc = sata_link_resume(link, timing, deadline); /* whine about phy resume failure but proceed */ if (rc && rc != -EOPNOTSUPP) - ata_link_warn(link, "failed to resume link (errno=%d)\n", - rc); + ata_link_printk(link, KERN_WARNING, "failed to resume " + "link (errno=%d)\n", rc); } /* device signature acquisition is unreliable */ @@ -1684,7 +1686,7 @@ static void nv_adma_error_handler(struct ata_port *ap) u8 cpb_count = readb(mmio + NV_ADMA_CPB_COUNT); u8 next_cpb_idx = readb(mmio + NV_ADMA_NEXT_CPB_IDX); - ata_port_err(ap, + ata_port_printk(ap, KERN_ERR, "EH in ADMA mode, notifier 0x%X " "notifier_error 0x%X gen_ctl 0x%X status 0x%X " "next cpb count 0x%X next cpb idx 0x%x\n", @@ -1695,7 +1697,7 @@ static void nv_adma_error_handler(struct ata_port *ap) struct nv_adma_cpb *cpb = &pp->cpb[i]; if ((ata_tag_valid(ap->link.active_tag) && i == ap->link.active_tag) || ap->link.sactive & (1 << i)) - ata_port_err(ap, + ata_port_printk(ap, KERN_ERR, "CPB %d: ctl_flags 0x%x, resp_flags 0x%x\n", i, cpb->ctl_flags, cpb->resp_flags); } @@ -1797,22 +1799,23 @@ static void nv_swncq_ncq_stop(struct ata_port *ap) u32 sactive; u32 done_mask; - ata_port_err(ap, "EH in SWNCQ mode,QC:qc_active 0x%X sactive 0x%X\n", - ap->qc_active, ap->link.sactive); - ata_port_err(ap, + ata_port_printk(ap, KERN_ERR, + "EH in SWNCQ mode,QC:qc_active 0x%X sactive 0x%X\n", + ap->qc_active, ap->link.sactive); + ata_port_printk(ap, KERN_ERR, "SWNCQ:qc_active 0x%X defer_bits 0x%X last_issue_tag 0x%x\n " "dhfis 0x%X dmafis 0x%X sdbfis 0x%X\n", pp->qc_active, pp->defer_queue.defer_bits, pp->last_issue_tag, pp->dhfis_bits, pp->dmafis_bits, pp->sdbfis_bits); - ata_port_err(ap, "ATA_REG 0x%X ERR_REG 0x%X\n", - ap->ops->sff_check_status(ap), - ioread8(ap->ioaddr.error_addr)); + ata_port_printk(ap, KERN_ERR, "ATA_REG 0x%X ERR_REG 0x%X\n", + ap->ops->sff_check_status(ap), + ioread8(ap->ioaddr.error_addr)); sactive = readl(pp->sactive_block); done_mask = pp->qc_active ^ sactive; - ata_port_err(ap, "tag : dhfis dmafis sdbfis sactive\n"); + ata_port_printk(ap, KERN_ERR, "tag : dhfis dmafis sdbfis sacitve\n"); for (i = 0; i < ATA_MAX_QUEUE; i++) { u8 err = 0; if (pp->qc_active & (1 << i)) @@ -1822,13 +1825,13 @@ static void nv_swncq_ncq_stop(struct ata_port *ap) else continue; - ata_port_err(ap, - "tag 0x%x: %01x %01x %01x %01x %s\n", i, - (pp->dhfis_bits >> i) & 0x1, - (pp->dmafis_bits >> i) & 0x1, - (pp->sdbfis_bits >> i) & 0x1, - (sactive >> i) & 0x1, - (err ? "error! tag doesn't exit" : " ")); + ata_port_printk(ap, KERN_ERR, + "tag 0x%x: %01x %01x %01x %01x %s\n", i, + (pp->dhfis_bits >> i) & 0x1, + (pp->dmafis_bits >> i) & 0x1, + (pp->sdbfis_bits >> i) & 0x1, + (sactive >> i) & 0x1, + (err ? "error! tag doesn't exit" : " ")); } nv_swncq_pp_reinit(ap); @@ -1953,8 +1956,8 @@ static int nv_swncq_slave_config(struct scsi_device *sdev) if (strncmp(model_num, "Maxtor", 6) == 0) { ata_scsi_change_queue_depth(sdev, 1, SCSI_QDEPTH_DEFAULT); - ata_dev_notice(dev, "Disabling SWNCQ mode (depth %x)\n", - sdev->queue_depth); + ata_dev_printk(dev, KERN_NOTICE, + "Disabling SWNCQ mode (depth %x)\n", sdev->queue_depth); } return rc; @@ -2353,6 +2356,7 @@ static irqreturn_t nv_swncq_interrupt(int irq, void *dev_instance) static int nv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { + static int printed_version; const struct ata_port_info *ppi[] = { NULL, NULL }; struct nv_pi_priv *ipriv; struct ata_host *host; @@ -2369,7 +2373,8 @@ static int nv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (pci_resource_start(pdev, bar) == 0) return -ENODEV; - ata_print_version_once(&pdev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); rc = pcim_enable_device(pdev); if (rc) @@ -2377,10 +2382,10 @@ static int nv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* determine type and allocate host */ if (type == CK804 && adma_enabled) { - dev_notice(&pdev->dev, "Using ADMA mode\n"); + dev_printk(KERN_NOTICE, &pdev->dev, "Using ADMA mode\n"); type = ADMA; } else if (type == MCP5x && swncq_enabled) { - dev_notice(&pdev->dev, "Using SWNCQ mode\n"); + dev_printk(KERN_NOTICE, &pdev->dev, "Using SWNCQ mode\n"); type = SWNCQ; } @@ -2424,7 +2429,7 @@ static int nv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) nv_swncq_host_init(host); if (msi_enabled) { - dev_notice(&pdev->dev, "Using MSI\n"); + dev_printk(KERN_NOTICE, &pdev->dev, "Using MSI\n"); pci_enable_msi(pdev); } diff --git a/trunk/drivers/ata/sata_promise.c b/trunk/drivers/ata/sata_promise.c index 000fcc99e01d..a004b1e0ea6d 100644 --- a/trunk/drivers/ata/sata_promise.c +++ b/trunk/drivers/ata/sata_promise.c @@ -1179,6 +1179,7 @@ static void pdc_host_init(struct ata_host *host) static int pdc_ata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { + static int printed_version; const struct ata_port_info *pi = &pdc_port_info[ent->driver_data]; const struct ata_port_info *ppi[PDC_MAX_PORTS]; struct ata_host *host; @@ -1186,7 +1187,8 @@ static int pdc_ata_init_one(struct pci_dev *pdev, int n_ports, i, rc; int is_sataii_tx4; - ata_print_version_once(&pdev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); /* enable and acquire resources */ rc = pcim_enable_device(pdev); @@ -1215,7 +1217,7 @@ static int pdc_ata_init_one(struct pci_dev *pdev, host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports); if (!host) { - dev_err(&pdev->dev, "failed to allocate host\n"); + dev_printk(KERN_ERR, &pdev->dev, "failed to allocate host\n"); return -ENOMEM; } host->iomap = pcim_iomap_table(pdev); diff --git a/trunk/drivers/ata/sata_qstor.c b/trunk/drivers/ata/sata_qstor.c index 9d1a47bb21b3..c5603265fa58 100644 --- a/trunk/drivers/ata/sata_qstor.c +++ b/trunk/drivers/ata/sata_qstor.c @@ -563,20 +563,21 @@ static int qs_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base) if (rc) { rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); if (rc) { - dev_err(&pdev->dev, - "64-bit DMA enable failed\n"); + dev_printk(KERN_ERR, &pdev->dev, + "64-bit DMA enable failed\n"); return rc; } } } else { rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (rc) { - dev_err(&pdev->dev, "32-bit DMA enable failed\n"); + dev_printk(KERN_ERR, &pdev->dev, + "32-bit DMA enable failed\n"); return rc; } rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); if (rc) { - dev_err(&pdev->dev, + dev_printk(KERN_ERR, &pdev->dev, "32-bit consistent DMA enable failed\n"); return rc; } @@ -587,12 +588,14 @@ static int qs_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base) static int qs_ata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { + static int printed_version; unsigned int board_idx = (unsigned int) ent->driver_data; const struct ata_port_info *ppi[] = { &qs_port_info[board_idx], NULL }; struct ata_host *host; int rc, port_no; - ata_print_version_once(&pdev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); /* alloc host */ host = ata_host_alloc_pinfo(&pdev->dev, ppi, QS_PORTS); diff --git a/trunk/drivers/ata/sata_sil.c b/trunk/drivers/ata/sata_sil.c index 98c1d780f552..b42edaaf3a53 100644 --- a/trunk/drivers/ata/sata_sil.c +++ b/trunk/drivers/ata/sata_sil.c @@ -643,8 +643,8 @@ static void sil_dev_config(struct ata_device *dev) ((ap->flags & SIL_FLAG_MOD15WRITE) && (quirks & SIL_QUIRK_MOD15WRITE))) { if (print_info) - ata_dev_info(dev, - "applying Seagate errata fix (mod15write workaround)\n"); + ata_dev_printk(dev, KERN_INFO, "applying Seagate " + "errata fix (mod15write workaround)\n"); dev->max_sectors = 15; return; } @@ -652,8 +652,8 @@ static void sil_dev_config(struct ata_device *dev) /* limit to udma5 */ if (quirks & SIL_QUIRK_UDMA5MAX) { if (print_info) - ata_dev_info(dev, "applying Maxtor errata fix %s\n", - model_num); + ata_dev_printk(dev, KERN_INFO, "applying Maxtor " + "errata fix %s\n", model_num); dev->udma_mask &= ATA_UDMA5; return; } @@ -676,8 +676,8 @@ static void sil_init_controller(struct ata_host *host) writew(cls << 8 | cls, mmio_base + sil_port[i].fifo_cfg); } else - dev_warn(&pdev->dev, - "cache line size not set. Driver may not function\n"); + dev_printk(KERN_WARNING, &pdev->dev, + "cache line size not set. Driver may not function\n"); /* Apply R_ERR on DMA activate FIS errata workaround */ if (host->ports[0]->flags & SIL_FLAG_RERR_ON_DMA_ACT) { @@ -688,8 +688,9 @@ static void sil_init_controller(struct ata_host *host) if ((tmp & 0x3) != 0x01) continue; if (!cnt) - dev_info(&pdev->dev, - "Applying R_ERR on DMA activate FIS errata fix\n"); + dev_printk(KERN_INFO, &pdev->dev, + "Applying R_ERR on DMA activate " + "FIS errata fix\n"); writel(tmp & ~0x3, mmio_base + sil_port[i].sfis_cfg); cnt++; } @@ -732,6 +733,7 @@ static bool sil_broken_system_poweroff(struct pci_dev *pdev) static int sil_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { + static int printed_version; int board_id = ent->driver_data; struct ata_port_info pi = sil_port_info[board_id]; const struct ata_port_info *ppi[] = { &pi, NULL }; @@ -740,7 +742,8 @@ static int sil_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) int n_ports, rc; unsigned int i; - ata_print_version_once(&pdev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); /* allocate host */ n_ports = 2; diff --git a/trunk/drivers/ata/sata_sil24.c b/trunk/drivers/ata/sata_sil24.c index 55470f337e51..06c564e55051 100644 --- a/trunk/drivers/ata/sata_sil24.c +++ b/trunk/drivers/ata/sata_sil24.c @@ -694,7 +694,7 @@ static int sil24_softreset(struct ata_link *link, unsigned int *class, return 0; err: - ata_link_err(link, "softreset failed (%s)\n", reason); + ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason); return -EIO; } @@ -714,8 +714,8 @@ static int sil24_hardreset(struct ata_link *link, unsigned int *class, * This happens often after PM DMA CS errata. */ if (pp->do_port_rst) { - ata_port_warn(ap, - "controller in dubious state, performing PORT_RST\n"); + ata_port_printk(ap, KERN_WARNING, "controller in dubious " + "state, performing PORT_RST\n"); writel(PORT_CS_PORT_RST, port + PORT_CTRL_STAT); ata_msleep(ap, 10); @@ -773,7 +773,7 @@ static int sil24_hardreset(struct ata_link *link, unsigned int *class, goto retry; } - ata_link_err(link, "hardreset failed (%s)\n", reason); + ata_link_printk(link, KERN_ERR, "hardreset failed (%s)\n", reason); return -EIO; } @@ -925,7 +925,7 @@ static void sil24_pmp_attach(struct ata_port *ap) if (sata_pmp_gscr_vendor(gscr) == 0x11ab && sata_pmp_gscr_devid(gscr) == 0x4140) { - ata_port_info(ap, + ata_port_printk(ap, KERN_INFO, "disabling NCQ support due to sil24-mv4140 quirk\n"); ap->flags &= ~ATA_FLAG_NCQ; } @@ -946,7 +946,8 @@ static int sil24_pmp_hardreset(struct ata_link *link, unsigned int *class, rc = sil24_init_port(link->ap); if (rc) { - ata_link_err(link, "hardreset failed (port not ready)\n"); + ata_link_printk(link, KERN_ERR, + "hardreset failed (port not ready)\n"); return rc; } @@ -1140,8 +1141,8 @@ static inline void sil24_host_intr(struct ata_port *ap) /* spurious interrupts are expected if PCIX_IRQ_WOC */ if (!(ap->flags & SIL24_FLAG_PCIX_IRQ_WOC) && ata_ratelimit()) - ata_port_info(ap, - "spurious interrupt (slot_stat 0x%x active_tag %d sactive 0x%x)\n", + ata_port_printk(ap, KERN_INFO, "spurious interrupt " + "(slot_stat 0x%x active_tag %d sactive 0x%x)\n", slot_stat, ap->link.active_tag, ap->link.sactive); } @@ -1255,8 +1256,8 @@ static void sil24_init_controller(struct ata_host *host) PORT_CS_PORT_RST, PORT_CS_PORT_RST, 10, 100); if (tmp & PORT_CS_PORT_RST) - dev_err(host->dev, - "failed to clear port RST\n"); + dev_printk(KERN_ERR, host->dev, + "failed to clear port RST\n"); } /* configure port */ @@ -1270,6 +1271,7 @@ static void sil24_init_controller(struct ata_host *host) static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { extern int __MARKER__sil24_cmd_block_is_sized_wrongly; + static int printed_version; struct ata_port_info pi = sil24_port_info[ent->driver_data]; const struct ata_port_info *ppi[] = { &pi, NULL }; void __iomem * const *iomap; @@ -1281,7 +1283,8 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (sizeof(union sil24_cmd_block) != PAGE_SIZE) __MARKER__sil24_cmd_block_is_sized_wrongly = 1; - ata_print_version_once(&pdev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); /* acquire resources */ rc = pcim_enable_device(pdev); @@ -1299,8 +1302,9 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (pi.flags & SIL24_FLAG_PCIX_IRQ_WOC) { tmp = readl(iomap[SIL24_HOST_BAR] + HOST_CTRL); if (tmp & (HOST_CTRL_TRDY | HOST_CTRL_STOP | HOST_CTRL_DEVSEL)) - dev_info(&pdev->dev, - "Applying completion IRQ loss on PCI-X errata fix\n"); + dev_printk(KERN_INFO, &pdev->dev, + "Applying completion IRQ loss on PCI-X " + "errata fix\n"); else pi.flags &= ~SIL24_FLAG_PCIX_IRQ_WOC; } @@ -1318,21 +1322,22 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) { rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); if (rc) { - dev_err(&pdev->dev, - "64-bit DMA enable failed\n"); + dev_printk(KERN_ERR, &pdev->dev, + "64-bit DMA enable failed\n"); return rc; } } } else { rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (rc) { - dev_err(&pdev->dev, "32-bit DMA enable failed\n"); + dev_printk(KERN_ERR, &pdev->dev, + "32-bit DMA enable failed\n"); return rc; } rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); if (rc) { - dev_err(&pdev->dev, - "32-bit consistent DMA enable failed\n"); + dev_printk(KERN_ERR, &pdev->dev, + "32-bit consistent DMA enable failed\n"); return rc; } } @@ -1345,7 +1350,7 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) sil24_init_controller(host); if (sata_sil24_msi && !pci_enable_msi(pdev)) { - dev_info(&pdev->dev, "Using MSI\n"); + dev_printk(KERN_INFO, &pdev->dev, "Using MSI\n"); pci_intx(pdev, 0); } diff --git a/trunk/drivers/ata/sata_sis.c b/trunk/drivers/ata/sata_sis.c index 447d9c05fb5a..cdcc13e9cf51 100644 --- a/trunk/drivers/ata/sata_sis.c +++ b/trunk/drivers/ata/sata_sis.c @@ -193,6 +193,7 @@ static int sis_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val) static int sis_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { + static int printed_version; struct ata_port_info pi = sis_port_info; const struct ata_port_info *ppi[] = { &pi, &pi }; struct ata_host *host; @@ -201,7 +202,8 @@ static int sis_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) u8 port2_start = 0x20; int i, rc; - ata_print_version_once(&pdev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n"); rc = pcim_enable_device(pdev); if (rc) @@ -239,12 +241,12 @@ static int sis_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) break; } if ((pmr & SIS_PMR_COMBINED) == 0) { - dev_info(&pdev->dev, - "Detected SiS 180/181/964 chipset in SATA mode\n"); + dev_printk(KERN_INFO, &pdev->dev, + "Detected SiS 180/181/964 chipset in SATA mode\n"); port2_start = 64; } else { - dev_info(&pdev->dev, - "Detected SiS 180/181 chipset in combined mode\n"); + dev_printk(KERN_INFO, &pdev->dev, + "Detected SiS 180/181 chipset in combined mode\n"); port2_start = 0; pi.flags |= ATA_FLAG_SLAVE_POSS; } @@ -254,22 +256,24 @@ static int sis_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) case 0x0183: pci_read_config_dword(pdev, 0x6C, &val); if (val & (1L << 31)) { - dev_info(&pdev->dev, "Detected SiS 182/965 chipset\n"); + dev_printk(KERN_INFO, &pdev->dev, + "Detected SiS 182/965 chipset\n"); pi.flags |= ATA_FLAG_SLAVE_POSS; } else { - dev_info(&pdev->dev, "Detected SiS 182/965L chipset\n"); + dev_printk(KERN_INFO, &pdev->dev, + "Detected SiS 182/965L chipset\n"); } break; case 0x1182: - dev_info(&pdev->dev, - "Detected SiS 1182/966/680 SATA controller\n"); + dev_printk(KERN_INFO, &pdev->dev, + "Detected SiS 1182/966/680 SATA controller\n"); pi.flags |= ATA_FLAG_SLAVE_POSS; break; case 0x1183: - dev_info(&pdev->dev, - "Detected SiS 1183/966/966L/968/680 controller in PATA mode\n"); + dev_printk(KERN_INFO, &pdev->dev, + "Detected SiS 1183/966/966L/968/680 controller in PATA mode\n"); ppi[0] = &sis_info133_for_sata; ppi[1] = &sis_info133_for_sata; break; diff --git a/trunk/drivers/ata/sata_svw.c b/trunk/drivers/ata/sata_svw.c index c646118943ff..35eabcf34568 100644 --- a/trunk/drivers/ata/sata_svw.c +++ b/trunk/drivers/ata/sata_svw.c @@ -414,13 +414,15 @@ static void k2_sata_setup_port(struct ata_ioports *port, void __iomem *base) static int k2_sata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { + static int printed_version; const struct ata_port_info *ppi[] = { &k2_port_info[ent->driver_data], NULL }; struct ata_host *host; void __iomem *mmio_base; int n_ports, i, rc, bar_pos; - ata_print_version_once(&pdev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); /* allocate host */ n_ports = 4; diff --git a/trunk/drivers/ata/sata_sx4.c b/trunk/drivers/ata/sata_sx4.c index cdaebbe3d184..8fd3b7252bda 100644 --- a/trunk/drivers/ata/sata_sx4.c +++ b/trunk/drivers/ata/sata_sx4.c @@ -1440,13 +1440,15 @@ static void pdc_20621_init(struct ata_host *host) static int pdc_sata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { + static int printed_version; const struct ata_port_info *ppi[] = { &pdc_port_info[ent->driver_data], NULL }; struct ata_host *host; struct pdc_host_priv *hpriv; int i, rc; - ata_print_version_once(&pdev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); /* allocate host */ host = ata_host_alloc_pinfo(&pdev->dev, ppi, 4); diff --git a/trunk/drivers/ata/sata_uli.c b/trunk/drivers/ata/sata_uli.c index b54ebfcdda32..235be717a713 100644 --- a/trunk/drivers/ata/sata_uli.c +++ b/trunk/drivers/ata/sata_uli.c @@ -145,6 +145,7 @@ static int uli_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val) static int uli_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { + static int printed_version; const struct ata_port_info *ppi[] = { &uli_port_info, NULL }; unsigned int board_idx = (unsigned int) ent->driver_data; struct ata_host *host; @@ -153,7 +154,8 @@ static int uli_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) struct ata_ioports *ioaddr; int n_ports, rc; - ata_print_version_once(&pdev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n"); rc = pcim_enable_device(pdev); if (rc) diff --git a/trunk/drivers/ata/sata_via.c b/trunk/drivers/ata/sata_via.c index f93e43b0ccd8..54434db15b12 100644 --- a/trunk/drivers/ata/sata_via.c +++ b/trunk/drivers/ata/sata_via.c @@ -360,9 +360,9 @@ static int vt6420_prereset(struct ata_link *link, unsigned long deadline) online = (sstatus & 0xf) == 0x3; - ata_port_info(ap, - "SATA link %s 1.5 Gbps (SStatus %X SControl %X)\n", - online ? "up" : "down", sstatus, scontrol); + ata_port_printk(ap, KERN_INFO, + "SATA link %s 1.5 Gbps (SStatus %X SControl %X)\n", + online ? "up" : "down", sstatus, scontrol); /* SStatus is read one more time */ svia_scr_read(link, SCR_STATUS, &sstatus); @@ -469,7 +469,7 @@ static int vt6420_prepare_host(struct pci_dev *pdev, struct ata_host **r_host) rc = pcim_iomap_regions(pdev, 1 << 5, DRV_NAME); if (rc) { - dev_err(&pdev->dev, "failed to iomap PCI BAR 5\n"); + dev_printk(KERN_ERR, &pdev->dev, "failed to iomap PCI BAR 5\n"); return rc; } @@ -488,14 +488,14 @@ static int vt6421_prepare_host(struct pci_dev *pdev, struct ata_host **r_host) *r_host = host = ata_host_alloc_pinfo(&pdev->dev, ppi, ARRAY_SIZE(ppi)); if (!host) { - dev_err(&pdev->dev, "failed to allocate host\n"); + dev_printk(KERN_ERR, &pdev->dev, "failed to allocate host\n"); return -ENOMEM; } rc = pcim_iomap_regions(pdev, 0x3f, DRV_NAME); if (rc) { - dev_err(&pdev->dev, "failed to request/iomap PCI BARs (errno=%d)\n", - rc); + dev_printk(KERN_ERR, &pdev->dev, "failed to request/iomap " + "PCI BARs (errno=%d)\n", rc); return rc; } host->iomap = pcim_iomap_table(pdev); @@ -526,7 +526,7 @@ static int vt8251_prepare_host(struct pci_dev *pdev, struct ata_host **r_host) rc = pcim_iomap_regions(pdev, 1 << 5, DRV_NAME); if (rc) { - dev_err(&pdev->dev, "failed to iomap PCI BAR 5\n"); + dev_printk(KERN_ERR, &pdev->dev, "failed to iomap PCI BAR 5\n"); return rc; } @@ -542,14 +542,15 @@ static void svia_configure(struct pci_dev *pdev, int board_id) u8 tmp8; pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &tmp8); - dev_info(&pdev->dev, "routed to hard irq line %d\n", - (int) (tmp8 & 0xf0) == 0xf0 ? 0 : tmp8 & 0x0f); + dev_printk(KERN_INFO, &pdev->dev, "routed to hard irq line %d\n", + (int) (tmp8 & 0xf0) == 0xf0 ? 0 : tmp8 & 0x0f); /* make sure SATA channels are enabled */ pci_read_config_byte(pdev, SATA_CHAN_ENAB, &tmp8); if ((tmp8 & ALL_PORTS) != ALL_PORTS) { - dev_dbg(&pdev->dev, "enabling SATA channels (0x%x)\n", - (int)tmp8); + dev_printk(KERN_DEBUG, &pdev->dev, + "enabling SATA channels (0x%x)\n", + (int) tmp8); tmp8 |= ALL_PORTS; pci_write_config_byte(pdev, SATA_CHAN_ENAB, tmp8); } @@ -557,8 +558,9 @@ static void svia_configure(struct pci_dev *pdev, int board_id) /* make sure interrupts for each channel sent to us */ pci_read_config_byte(pdev, SATA_INT_GATE, &tmp8); if ((tmp8 & ALL_PORTS) != ALL_PORTS) { - dev_dbg(&pdev->dev, "enabling SATA channel interrupts (0x%x)\n", - (int) tmp8); + dev_printk(KERN_DEBUG, &pdev->dev, + "enabling SATA channel interrupts (0x%x)\n", + (int) tmp8); tmp8 |= ALL_PORTS; pci_write_config_byte(pdev, SATA_INT_GATE, tmp8); } @@ -566,9 +568,9 @@ static void svia_configure(struct pci_dev *pdev, int board_id) /* make sure native mode is enabled */ pci_read_config_byte(pdev, SATA_NATIVE_MODE, &tmp8); if ((tmp8 & NATIVE_MODE_ALL) != NATIVE_MODE_ALL) { - dev_dbg(&pdev->dev, - "enabling SATA channel native mode (0x%x)\n", - (int) tmp8); + dev_printk(KERN_DEBUG, &pdev->dev, + "enabling SATA channel native mode (0x%x)\n", + (int) tmp8); tmp8 |= NATIVE_MODE_ALL; pci_write_config_byte(pdev, SATA_NATIVE_MODE, tmp8); } @@ -604,13 +606,15 @@ static void svia_configure(struct pci_dev *pdev, int board_id) static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { + static int printed_version; unsigned int i; int rc; struct ata_host *host = NULL; int board_id = (int) ent->driver_data; const unsigned *bar_sizes; - ata_print_version_once(&pdev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); rc = pcim_enable_device(pdev); if (rc) @@ -624,7 +628,7 @@ static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) for (i = 0; i < ARRAY_SIZE(svia_bar_sizes); i++) if ((pci_resource_start(pdev, i) == 0) || (pci_resource_len(pdev, i) < bar_sizes[i])) { - dev_err(&pdev->dev, + dev_printk(KERN_ERR, &pdev->dev, "invalid PCI BAR %u (sz 0x%llx, val 0x%llx)\n", i, (unsigned long long)pci_resource_start(pdev, i), diff --git a/trunk/drivers/ata/sata_vsc.c b/trunk/drivers/ata/sata_vsc.c index 6135a5288695..7c987371136e 100644 --- a/trunk/drivers/ata/sata_vsc.c +++ b/trunk/drivers/ata/sata_vsc.c @@ -273,8 +273,9 @@ static irqreturn_t vsc_sata_interrupt(int irq, void *dev_instance) if (unlikely(status == 0xffffffff || status == 0)) { if (status) - dev_err(host->dev, - ": IRQ status == 0xffffffff, PCI fault or device removal?\n"); + dev_printk(KERN_ERR, host->dev, + ": IRQ status == 0xffffffff, " + "PCI fault or device removal?\n"); goto out; } @@ -346,12 +347,14 @@ static int __devinit vsc_sata_init_one(struct pci_dev *pdev, .port_ops = &vsc_sata_ops, }; const struct ata_port_info *ppi[] = { &pi, NULL }; + static int printed_version; struct ata_host *host; void __iomem *mmio_base; int i, rc; u8 cls; - ata_print_version_once(&pdev->dev, DRV_VERSION); + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); /* allocate host */ host = ata_host_alloc_pinfo(&pdev->dev, ppi, 4); diff --git a/trunk/drivers/base/Kconfig b/trunk/drivers/base/Kconfig index b605d01f5d45..d57e8d0fb823 100644 --- a/trunk/drivers/base/Kconfig +++ b/trunk/drivers/base/Kconfig @@ -168,6 +168,4 @@ config SYS_HYPERVISOR bool default n -source "drivers/base/regmap/Kconfig" - endmenu diff --git a/trunk/drivers/base/Makefile b/trunk/drivers/base/Makefile index 99a375ad2cc9..4c5701c15f53 100644 --- a/trunk/drivers/base/Makefile +++ b/trunk/drivers/base/Makefile @@ -13,11 +13,11 @@ obj-$(CONFIG_FW_LOADER) += firmware_class.o obj-$(CONFIG_NUMA) += node.o obj-$(CONFIG_MEMORY_HOTPLUG_SPARSE) += memory.o obj-$(CONFIG_SMP) += topology.o +obj-$(CONFIG_IOMMU_API) += iommu.o ifeq ($(CONFIG_SYSFS),y) obj-$(CONFIG_MODULES) += module.o endif obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o -obj-$(CONFIG_REGMAP) += regmap/ ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG diff --git a/trunk/drivers/base/devtmpfs.c b/trunk/drivers/base/devtmpfs.c index 6d678c99512e..82bbb5967aa9 100644 --- a/trunk/drivers/base/devtmpfs.c +++ b/trunk/drivers/base/devtmpfs.c @@ -21,11 +21,12 @@ #include #include #include +#include #include +#include #include -#include -static struct task_struct *thread; +static struct vfsmount *dev_mnt; #if defined CONFIG_DEVTMPFS_MOUNT static int mount_dev = 1; @@ -33,16 +34,7 @@ static int mount_dev = 1; static int mount_dev; #endif -static DEFINE_SPINLOCK(req_lock); - -static struct req { - struct req *next; - struct completion done; - int err; - const char *name; - mode_t mode; /* 0 => delete */ - struct device *dev; -} *requests; +static DEFINE_MUTEX(dirlock); static int __init mount_param(char *str) { @@ -76,152 +68,131 @@ static inline int is_blockdev(struct device *dev) static inline int is_blockdev(struct device *dev) { return 0; } #endif -int devtmpfs_create_node(struct device *dev) -{ - const char *tmp = NULL; - struct req req; - - if (!thread) - return 0; - - req.mode = 0; - req.name = device_get_devnode(dev, &req.mode, &tmp); - if (!req.name) - return -ENOMEM; - - if (req.mode == 0) - req.mode = 0600; - if (is_blockdev(dev)) - req.mode |= S_IFBLK; - else - req.mode |= S_IFCHR; - - req.dev = dev; - - init_completion(&req.done); - - spin_lock(&req_lock); - req.next = requests; - requests = &req; - spin_unlock(&req_lock); - - wake_up_process(thread); - wait_for_completion(&req.done); - - kfree(tmp); - - return req.err; -} - -int devtmpfs_delete_node(struct device *dev) -{ - const char *tmp = NULL; - struct req req; - - if (!thread) - return 0; - - req.name = device_get_devnode(dev, NULL, &tmp); - if (!req.name) - return -ENOMEM; - - req.mode = 0; - req.dev = dev; - - init_completion(&req.done); - - spin_lock(&req_lock); - req.next = requests; - requests = &req; - spin_unlock(&req_lock); - - wake_up_process(thread); - wait_for_completion(&req.done); - - kfree(tmp); - return req.err; -} - static int dev_mkdir(const char *name, mode_t mode) { + struct nameidata nd; struct dentry *dentry; - struct path path; int err; - dentry = kern_path_create(AT_FDCWD, name, &path, 1); - if (IS_ERR(dentry)) - return PTR_ERR(dentry); - - err = vfs_mkdir(path.dentry->d_inode, dentry, mode); - if (!err) - /* mark as kernel-created inode */ - dentry->d_inode->i_private = &thread; - dput(dentry); - mutex_unlock(&path.dentry->d_inode->i_mutex); - path_put(&path); + err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, + name, LOOKUP_PARENT, &nd); + if (err) + return err; + + dentry = lookup_create(&nd, 1); + if (!IS_ERR(dentry)) { + err = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode); + if (!err) + /* mark as kernel-created inode */ + dentry->d_inode->i_private = &dev_mnt; + dput(dentry); + } else { + err = PTR_ERR(dentry); + } + + mutex_unlock(&nd.path.dentry->d_inode->i_mutex); + path_put(&nd.path); return err; } static int create_path(const char *nodepath) { - char *path; - char *s; int err; - /* parent directories do not exist, create them */ - path = kstrdup(nodepath, GFP_KERNEL); - if (!path) - return -ENOMEM; - - s = path; - for (;;) { - s = strchr(s, '/'); - if (!s) - break; - s[0] = '\0'; - err = dev_mkdir(path, 0755); - if (err && err != -EEXIST) - break; - s[0] = '/'; - s++; + mutex_lock(&dirlock); + err = dev_mkdir(nodepath, 0755); + if (err == -ENOENT) { + char *path; + char *s; + + /* parent directories do not exist, create them */ + path = kstrdup(nodepath, GFP_KERNEL); + if (!path) { + err = -ENOMEM; + goto out; + } + s = path; + for (;;) { + s = strchr(s, '/'); + if (!s) + break; + s[0] = '\0'; + err = dev_mkdir(path, 0755); + if (err && err != -EEXIST) + break; + s[0] = '/'; + s++; + } + kfree(path); } - kfree(path); +out: + mutex_unlock(&dirlock); return err; } -static int handle_create(const char *nodename, mode_t mode, struct device *dev) +int devtmpfs_create_node(struct device *dev) { + const char *tmp = NULL; + const char *nodename; + const struct cred *curr_cred; + mode_t mode = 0; + struct nameidata nd; struct dentry *dentry; - struct path path; int err; - dentry = kern_path_create(AT_FDCWD, nodename, &path, 0); - if (dentry == ERR_PTR(-ENOENT)) { + if (!dev_mnt) + return 0; + + nodename = device_get_devnode(dev, &mode, &tmp); + if (!nodename) + return -ENOMEM; + + if (mode == 0) + mode = 0600; + if (is_blockdev(dev)) + mode |= S_IFBLK; + else + mode |= S_IFCHR; + + curr_cred = override_creds(&init_cred); + + err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, + nodename, LOOKUP_PARENT, &nd); + if (err == -ENOENT) { create_path(nodename); - dentry = kern_path_create(AT_FDCWD, nodename, &path, 0); + err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, + nodename, LOOKUP_PARENT, &nd); } - if (IS_ERR(dentry)) - return PTR_ERR(dentry); - - err = vfs_mknod(path.dentry->d_inode, - dentry, mode, dev->devt); - if (!err) { - struct iattr newattrs; - - /* fixup possibly umasked mode */ - newattrs.ia_mode = mode; - newattrs.ia_valid = ATTR_MODE; - mutex_lock(&dentry->d_inode->i_mutex); - notify_change(dentry, &newattrs); - mutex_unlock(&dentry->d_inode->i_mutex); - - /* mark as kernel-created inode */ - dentry->d_inode->i_private = &thread; + if (err) + goto out; + + dentry = lookup_create(&nd, 0); + if (!IS_ERR(dentry)) { + err = vfs_mknod(nd.path.dentry->d_inode, + dentry, mode, dev->devt); + if (!err) { + struct iattr newattrs; + + /* fixup possibly umasked mode */ + newattrs.ia_mode = mode; + newattrs.ia_valid = ATTR_MODE; + mutex_lock(&dentry->d_inode->i_mutex); + notify_change(dentry, &newattrs); + mutex_unlock(&dentry->d_inode->i_mutex); + + /* mark as kernel-created inode */ + dentry->d_inode->i_private = &dev_mnt; + } + dput(dentry); + } else { + err = PTR_ERR(dentry); } - dput(dentry); - mutex_unlock(&path.dentry->d_inode->i_mutex); - path_put(&path); + mutex_unlock(&nd.path.dentry->d_inode->i_mutex); + path_put(&nd.path); +out: + kfree(tmp); + revert_creds(curr_cred); return err; } @@ -231,7 +202,8 @@ static int dev_rmdir(const char *name) struct dentry *dentry; int err; - err = kern_path_parent(name, &nd); + err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, + name, LOOKUP_PARENT, &nd); if (err) return err; @@ -239,7 +211,7 @@ static int dev_rmdir(const char *name) dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len); if (!IS_ERR(dentry)) { if (dentry->d_inode) { - if (dentry->d_inode->i_private == &thread) + if (dentry->d_inode->i_private == &dev_mnt) err = vfs_rmdir(nd.path.dentry->d_inode, dentry); else @@ -266,6 +238,7 @@ static int delete_path(const char *nodepath) if (!path) return -ENOMEM; + mutex_lock(&dirlock); for (;;) { char *base; @@ -277,6 +250,7 @@ static int delete_path(const char *nodepath) if (err) break; } + mutex_unlock(&dirlock); kfree(path); return err; @@ -285,7 +259,7 @@ static int delete_path(const char *nodepath) static int dev_mynode(struct device *dev, struct inode *inode, struct kstat *stat) { /* did we create it */ - if (inode->i_private != &thread) + if (inode->i_private != &dev_mnt) return 0; /* does the dev_t match */ @@ -303,17 +277,29 @@ static int dev_mynode(struct device *dev, struct inode *inode, struct kstat *sta return 1; } -static int handle_remove(const char *nodename, struct device *dev) +int devtmpfs_delete_node(struct device *dev) { + const char *tmp = NULL; + const char *nodename; + const struct cred *curr_cred; struct nameidata nd; struct dentry *dentry; struct kstat stat; int deleted = 1; int err; - err = kern_path_parent(nodename, &nd); + if (!dev_mnt) + return 0; + + nodename = device_get_devnode(dev, NULL, &tmp); + if (!nodename) + return -ENOMEM; + + curr_cred = override_creds(&init_cred); + err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, + nodename, LOOKUP_PARENT, &nd); if (err) - return err; + goto out; mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len); @@ -351,6 +337,9 @@ static int handle_remove(const char *nodename, struct device *dev) path_put(&nd.path); if (deleted && strchr(nodename, '/')) delete_path(nodename); +out: + kfree(tmp); + revert_creds(curr_cred); return err; } @@ -365,7 +354,7 @@ int devtmpfs_mount(const char *mntdir) if (!mount_dev) return 0; - if (!thread) + if (!dev_mnt) return 0; err = sys_mount("devtmpfs", (char *)mntdir, "devtmpfs", MS_SILENT, NULL); @@ -376,79 +365,31 @@ int devtmpfs_mount(const char *mntdir) return err; } -static __initdata DECLARE_COMPLETION(setup_done); - -static int handle(const char *name, mode_t mode, struct device *dev) -{ - if (mode) - return handle_create(name, mode, dev); - else - return handle_remove(name, dev); -} - -static int devtmpfsd(void *p) -{ - char options[] = "mode=0755"; - int *err = p; - *err = sys_unshare(CLONE_NEWNS); - if (*err) - goto out; - *err = sys_mount("devtmpfs", "/", "devtmpfs", MS_SILENT, options); - if (*err) - goto out; - sys_chdir("/.."); /* will traverse into overmounted root */ - sys_chroot("."); - complete(&setup_done); - while (1) { - spin_lock(&req_lock); - while (requests) { - struct req *req = requests; - requests = NULL; - spin_unlock(&req_lock); - while (req) { - req->err = handle(req->name, req->mode, req->dev); - complete(&req->done); - req = req->next; - } - spin_lock(&req_lock); - } - set_current_state(TASK_INTERRUPTIBLE); - spin_unlock(&req_lock); - schedule(); - __set_current_state(TASK_RUNNING); - } - return 0; -out: - complete(&setup_done); - return *err; -} - /* * Create devtmpfs instance, driver-core devices will add their device * nodes here. */ int __init devtmpfs_init(void) { - int err = register_filesystem(&dev_fs_type); + int err; + struct vfsmount *mnt; + char options[] = "mode=0755"; + + err = register_filesystem(&dev_fs_type); if (err) { printk(KERN_ERR "devtmpfs: unable to register devtmpfs " "type %i\n", err); return err; } - thread = kthread_run(devtmpfsd, &err, "kdevtmpfs"); - if (!IS_ERR(thread)) { - wait_for_completion(&setup_done); - } else { - err = PTR_ERR(thread); - thread = NULL; - } - - if (err) { + mnt = kern_mount_data(&dev_fs_type, options); + if (IS_ERR(mnt)) { + err = PTR_ERR(mnt); printk(KERN_ERR "devtmpfs: unable to create devtmpfs %i\n", err); unregister_filesystem(&dev_fs_type); return err; } + dev_mnt = mnt; printk(KERN_INFO "devtmpfs: initialized\n"); return 0; diff --git a/trunk/drivers/iommu/iommu.c b/trunk/drivers/base/iommu.c similarity index 100% rename from trunk/drivers/iommu/iommu.c rename to trunk/drivers/base/iommu.c diff --git a/trunk/drivers/base/regmap/Kconfig b/trunk/drivers/base/regmap/Kconfig deleted file mode 100644 index fabbf6cc5367..000000000000 --- a/trunk/drivers/base/regmap/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -# Generic register map support. There are no user servicable options here, -# this is an API intended to be used by other kernel subsystems. These -# subsystems should select the appropriate symbols. - -config REGMAP - default y if (REGMAP_I2C || REGMAP_SPI) - bool - -config REGMAP_I2C - tristate - -config REGMAP_SPI - tristate diff --git a/trunk/drivers/base/regmap/Makefile b/trunk/drivers/base/regmap/Makefile deleted file mode 100644 index f476f4571295..000000000000 --- a/trunk/drivers/base/regmap/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -obj-$(CONFIG_REGMAP) += regmap.o -obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o -obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o diff --git a/trunk/drivers/base/regmap/regmap-i2c.c b/trunk/drivers/base/regmap/regmap-i2c.c deleted file mode 100644 index c2231ff06cbc..000000000000 --- a/trunk/drivers/base/regmap/regmap-i2c.c +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Register map access API - I2C support - * - * Copyright 2011 Wolfson Microelectronics plc - * - * Author: Mark Brown - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include - -static int regmap_i2c_write(struct device *dev, const void *data, size_t count) -{ - struct i2c_client *i2c = to_i2c_client(dev); - int ret; - - ret = i2c_master_send(i2c, data, count); - if (ret == count) - return 0; - else if (ret < 0) - return ret; - else - return -EIO; -} - -static int regmap_i2c_gather_write(struct device *dev, - const void *reg, size_t reg_size, - const void *val, size_t val_size) -{ - struct i2c_client *i2c = to_i2c_client(dev); - struct i2c_msg xfer[2]; - int ret; - - /* If the I2C controller can't do a gather tell the core, it - * will substitute in a linear write for us. - */ - if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_PROTOCOL_MANGLING)) - return -ENOTSUPP; - - xfer[0].addr = i2c->addr; - xfer[0].flags = 0; - xfer[0].len = reg_size; - xfer[0].buf = (void *)reg; - - xfer[1].addr = i2c->addr; - xfer[1].flags = I2C_M_NOSTART; - xfer[1].len = val_size; - xfer[1].buf = (void *)val; - - ret = i2c_transfer(i2c->adapter, xfer, 2); - if (ret == 2) - return 0; - if (ret < 0) - return ret; - else - return -EIO; -} - -static int regmap_i2c_read(struct device *dev, - const void *reg, size_t reg_size, - void *val, size_t val_size) -{ - struct i2c_client *i2c = to_i2c_client(dev); - struct i2c_msg xfer[2]; - int ret; - - xfer[0].addr = i2c->addr; - xfer[0].flags = 0; - xfer[0].len = reg_size; - xfer[0].buf = (void *)reg; - - xfer[1].addr = i2c->addr; - xfer[1].flags = I2C_M_RD; - xfer[1].len = val_size; - xfer[1].buf = val; - - ret = i2c_transfer(i2c->adapter, xfer, 2); - if (ret == 2) - return 0; - else if (ret < 0) - return ret; - else - return -EIO; -} - -static struct regmap_bus regmap_i2c = { - .type = &i2c_bus_type, - .write = regmap_i2c_write, - .gather_write = regmap_i2c_gather_write, - .read = regmap_i2c_read, - .owner = THIS_MODULE, -}; - -/** - * regmap_init_i2c(): Initialise register map - * - * @i2c: Device that will be interacted with - * @config: Configuration for register map - * - * The return value will be an ERR_PTR() on error or a valid pointer to - * a struct regmap. - */ -struct regmap *regmap_init_i2c(struct i2c_client *i2c, - const struct regmap_config *config) -{ - return regmap_init(&i2c->dev, ®map_i2c, config); -} -EXPORT_SYMBOL_GPL(regmap_init_i2c); - diff --git a/trunk/drivers/base/regmap/regmap-spi.c b/trunk/drivers/base/regmap/regmap-spi.c deleted file mode 100644 index 4deba0621bc7..000000000000 --- a/trunk/drivers/base/regmap/regmap-spi.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Register map access API - SPI support - * - * Copyright 2011 Wolfson Microelectronics plc - * - * Author: Mark Brown - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include - -static int regmap_spi_write(struct device *dev, const void *data, size_t count) -{ - struct spi_device *spi = to_spi_device(dev); - - return spi_write(spi, data, count); -} - -static int regmap_spi_gather_write(struct device *dev, - const void *reg, size_t reg_len, - const void *val, size_t val_len) -{ - struct spi_device *spi = to_spi_device(dev); - struct spi_message m; - struct spi_transfer t[2] = { { .tx_buf = reg, .len = reg_len, }, - { .tx_buf = val, .len = val_len, }, }; - - spi_message_init(&m); - spi_message_add_tail(&t[0], &m); - spi_message_add_tail(&t[1], &m); - - return spi_sync(spi, &m); -} - -static int regmap_spi_read(struct device *dev, - const void *reg, size_t reg_size, - void *val, size_t val_size) -{ - struct spi_device *spi = to_spi_device(dev); - - return spi_write_then_read(spi, reg, reg_size, val, val_size); -} - -static struct regmap_bus regmap_spi = { - .type = &spi_bus_type, - .write = regmap_spi_write, - .gather_write = regmap_spi_gather_write, - .read = regmap_spi_read, - .owner = THIS_MODULE, - .read_flag_mask = 0x80, -}; - -/** - * regmap_init_spi(): Initialise register map - * - * @spi: Device that will be interacted with - * @config: Configuration for register map - * - * The return value will be an ERR_PTR() on error or a valid pointer to - * a struct regmap. - */ -struct regmap *regmap_init_spi(struct spi_device *spi, - const struct regmap_config *config) -{ - return regmap_init(&spi->dev, ®map_spi, config); -} -EXPORT_SYMBOL_GPL(regmap_init_spi); diff --git a/trunk/drivers/base/regmap/regmap.c b/trunk/drivers/base/regmap/regmap.c deleted file mode 100644 index cf3565cae93d..000000000000 --- a/trunk/drivers/base/regmap/regmap.c +++ /dev/null @@ -1,455 +0,0 @@ -/* - * Register map access API - * - * Copyright 2011 Wolfson Microelectronics plc - * - * Author: Mark Brown - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include - -#include - -struct regmap; - -struct regmap_format { - size_t buf_size; - size_t reg_bytes; - size_t val_bytes; - void (*format_write)(struct regmap *map, - unsigned int reg, unsigned int val); - void (*format_reg)(void *buf, unsigned int reg); - void (*format_val)(void *buf, unsigned int val); - unsigned int (*parse_val)(void *buf); -}; - -struct regmap { - struct mutex lock; - - struct device *dev; /* Device we do I/O on */ - void *work_buf; /* Scratch buffer used to format I/O */ - struct regmap_format format; /* Buffer format */ - const struct regmap_bus *bus; -}; - -static void regmap_format_4_12_write(struct regmap *map, - unsigned int reg, unsigned int val) -{ - __be16 *out = map->work_buf; - *out = cpu_to_be16((reg << 12) | val); -} - -static void regmap_format_7_9_write(struct regmap *map, - unsigned int reg, unsigned int val) -{ - __be16 *out = map->work_buf; - *out = cpu_to_be16((reg << 9) | val); -} - -static void regmap_format_8(void *buf, unsigned int val) -{ - u8 *b = buf; - - b[0] = val; -} - -static void regmap_format_16(void *buf, unsigned int val) -{ - __be16 *b = buf; - - b[0] = cpu_to_be16(val); -} - -static unsigned int regmap_parse_8(void *buf) -{ - u8 *b = buf; - - return b[0]; -} - -static unsigned int regmap_parse_16(void *buf) -{ - __be16 *b = buf; - - b[0] = be16_to_cpu(b[0]); - - return b[0]; -} - -/** - * regmap_init(): Initialise register map - * - * @dev: Device that will be interacted with - * @bus: Bus-specific callbacks to use with device - * @config: Configuration for register map - * - * The return value will be an ERR_PTR() on error or a valid pointer to - * a struct regmap. This function should generally not be called - * directly, it should be called by bus-specific init functions. - */ -struct regmap *regmap_init(struct device *dev, - const struct regmap_bus *bus, - const struct regmap_config *config) -{ - struct regmap *map; - int ret = -EINVAL; - - if (!bus || !config) - return NULL; - - map = kzalloc(sizeof(*map), GFP_KERNEL); - if (map == NULL) { - ret = -ENOMEM; - goto err; - } - - mutex_init(&map->lock); - map->format.buf_size = (config->reg_bits + config->val_bits) / 8; - map->format.reg_bytes = config->reg_bits / 8; - map->format.val_bytes = config->val_bits / 8; - map->dev = dev; - map->bus = bus; - - switch (config->reg_bits) { - case 4: - switch (config->val_bits) { - case 12: - map->format.format_write = regmap_format_4_12_write; - break; - default: - goto err_map; - } - break; - - case 7: - switch (config->val_bits) { - case 9: - map->format.format_write = regmap_format_7_9_write; - break; - default: - goto err_map; - } - break; - - case 8: - map->format.format_reg = regmap_format_8; - break; - - case 16: - map->format.format_reg = regmap_format_16; - break; - - default: - goto err_map; - } - - switch (config->val_bits) { - case 8: - map->format.format_val = regmap_format_8; - map->format.parse_val = regmap_parse_8; - break; - case 16: - map->format.format_val = regmap_format_16; - map->format.parse_val = regmap_parse_16; - break; - } - - if (!map->format.format_write && - !(map->format.format_reg && map->format.format_val)) - goto err_map; - - map->work_buf = kmalloc(map->format.buf_size, GFP_KERNEL); - if (map->work_buf == NULL) { - ret = -ENOMEM; - goto err_bus; - } - - return map; - -err_bus: - module_put(map->bus->owner); -err_map: - kfree(map); -err: - return ERR_PTR(ret); -} -EXPORT_SYMBOL_GPL(regmap_init); - -/** - * regmap_exit(): Free a previously allocated register map - */ -void regmap_exit(struct regmap *map) -{ - kfree(map->work_buf); - module_put(map->bus->owner); - kfree(map); -} -EXPORT_SYMBOL_GPL(regmap_exit); - -static int _regmap_raw_write(struct regmap *map, unsigned int reg, - const void *val, size_t val_len) -{ - void *buf; - int ret = -ENOTSUPP; - size_t len; - - map->format.format_reg(map->work_buf, reg); - - /* Try to do a gather write if we can */ - if (map->bus->gather_write) - ret = map->bus->gather_write(map->dev, map->work_buf, - map->format.reg_bytes, - val, val_len); - - /* Otherwise fall back on linearising by hand. */ - if (ret == -ENOTSUPP) { - len = map->format.reg_bytes + val_len; - buf = kmalloc(len, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - memcpy(buf, map->work_buf, map->format.reg_bytes); - memcpy(buf + map->format.reg_bytes, val, val_len); - ret = map->bus->write(map->dev, buf, len); - - kfree(buf); - } - - return ret; -} - -static int _regmap_write(struct regmap *map, unsigned int reg, - unsigned int val) -{ - BUG_ON(!map->format.format_write && !map->format.format_val); - - if (map->format.format_write) { - map->format.format_write(map, reg, val); - - return map->bus->write(map->dev, map->work_buf, - map->format.buf_size); - } else { - map->format.format_val(map->work_buf + map->format.reg_bytes, - val); - return _regmap_raw_write(map, reg, - map->work_buf + map->format.reg_bytes, - map->format.val_bytes); - } -} - -/** - * regmap_write(): Write a value to a single register - * - * @map: Register map to write to - * @reg: Register to write to - * @val: Value to be written - * - * A value of zero will be returned on success, a negative errno will - * be returned in error cases. - */ -int regmap_write(struct regmap *map, unsigned int reg, unsigned int val) -{ - int ret; - - mutex_lock(&map->lock); - - ret = _regmap_write(map, reg, val); - - mutex_unlock(&map->lock); - - return ret; -} -EXPORT_SYMBOL_GPL(regmap_write); - -/** - * regmap_raw_write(): Write raw values to one or more registers - * - * @map: Register map to write to - * @reg: Initial register to write to - * @val: Block of data to be written, laid out for direct transmission to the - * device - * @val_len: Length of data pointed to by val. - * - * This function is intended to be used for things like firmware - * download where a large block of data needs to be transferred to the - * device. No formatting will be done on the data provided. - * - * A value of zero will be returned on success, a negative errno will - * be returned in error cases. - */ -int regmap_raw_write(struct regmap *map, unsigned int reg, - const void *val, size_t val_len) -{ - int ret; - - mutex_lock(&map->lock); - - ret = _regmap_raw_write(map, reg, val, val_len); - - mutex_unlock(&map->lock); - - return ret; -} -EXPORT_SYMBOL_GPL(regmap_raw_write); - -static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, - unsigned int val_len) -{ - u8 *u8 = map->work_buf; - int ret; - - map->format.format_reg(map->work_buf, reg); - - /* - * Some buses flag reads by setting the high bits in the - * register addresss; since it's always the high bits for all - * current formats we can do this here rather than in - * formatting. This may break if we get interesting formats. - */ - if (map->bus->read_flag_mask) - u8[0] |= map->bus->read_flag_mask; - - ret = map->bus->read(map->dev, map->work_buf, map->format.reg_bytes, - val, map->format.val_bytes); - if (ret != 0) - return ret; - - return 0; -} - -static int _regmap_read(struct regmap *map, unsigned int reg, - unsigned int *val) -{ - int ret; - - if (!map->format.parse_val) - return -EINVAL; - - ret = _regmap_raw_read(map, reg, map->work_buf, map->format.val_bytes); - if (ret == 0) - *val = map->format.parse_val(map->work_buf); - - return ret; -} - -/** - * regmap_read(): Read a value from a single register - * - * @map: Register map to write to - * @reg: Register to be read from - * @val: Pointer to store read value - * - * A value of zero will be returned on success, a negative errno will - * be returned in error cases. - */ -int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val) -{ - int ret; - - mutex_lock(&map->lock); - - ret = _regmap_read(map, reg, val); - - mutex_unlock(&map->lock); - - return ret; -} -EXPORT_SYMBOL_GPL(regmap_read); - -/** - * regmap_raw_read(): Read raw data from the device - * - * @map: Register map to write to - * @reg: First register to be read from - * @val: Pointer to store read value - * @val_len: Size of data to read - * - * A value of zero will be returned on success, a negative errno will - * be returned in error cases. - */ -int regmap_raw_read(struct regmap *map, unsigned int reg, void *val, - size_t val_len) -{ - int ret; - - mutex_lock(&map->lock); - - ret = _regmap_raw_read(map, reg, val, val_len); - - mutex_unlock(&map->lock); - - return ret; -} -EXPORT_SYMBOL_GPL(regmap_raw_read); - -/** - * regmap_bulk_read(): Read multiple registers from the device - * - * @map: Register map to write to - * @reg: First register to be read from - * @val: Pointer to store read value, in native register size for device - * @val_count: Number of registers to read - * - * A value of zero will be returned on success, a negative errno will - * be returned in error cases. - */ -int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, - size_t val_count) -{ - int ret, i; - size_t val_bytes = map->format.val_bytes; - - if (!map->format.parse_val) - return -EINVAL; - - ret = regmap_raw_read(map, reg, val, val_bytes * val_count); - if (ret != 0) - return ret; - - for (i = 0; i < val_count * val_bytes; i += val_bytes) - map->format.parse_val(val + i); - - return 0; -} -EXPORT_SYMBOL_GPL(regmap_bulk_read); - -/** - * remap_update_bits: Perform a read/modify/write cycle on the register map - * - * @map: Register map to update - * @reg: Register to update - * @mask: Bitmask to change - * @val: New value for bitmask - * - * Returns zero for success, a negative number on error. - */ -int regmap_update_bits(struct regmap *map, unsigned int reg, - unsigned int mask, unsigned int val) -{ - int ret; - unsigned int tmp; - - mutex_lock(&map->lock); - - ret = _regmap_read(map, reg, &tmp); - if (ret != 0) - goto out; - - tmp &= ~mask; - tmp |= val & mask; - - ret = _regmap_write(map, reg, tmp); - -out: - mutex_unlock(&map->lock); - - return ret; -} -EXPORT_SYMBOL_GPL(regmap_update_bits); diff --git a/trunk/drivers/block/hd.c b/trunk/drivers/block/hd.c index b52c9ca146fc..007c630904c1 100644 --- a/trunk/drivers/block/hd.c +++ b/trunk/drivers/block/hd.c @@ -155,7 +155,7 @@ else \ #if (HD_DELAY > 0) -#include +#include unsigned long last_req; diff --git a/trunk/drivers/block/pktcdvd.c b/trunk/drivers/block/pktcdvd.c index e133f094ab08..07a382eaf0a8 100644 --- a/trunk/drivers/block/pktcdvd.c +++ b/trunk/drivers/block/pktcdvd.c @@ -1206,7 +1206,7 @@ static int pkt_start_recovery(struct packet_data *pkt) if (!sb) return 0; - if (!sb->s_op->relocate_blocks) + if (!sb->s_op || !sb->s_op->relocate_blocks) goto out; old_block = pkt->sector / (CD_FRAMESIZE >> 9); diff --git a/trunk/drivers/char/generic_nvram.c b/trunk/drivers/char/generic_nvram.c index 6c4f4b5a9dd3..0e941b57482e 100644 --- a/trunk/drivers/char/generic_nvram.c +++ b/trunk/drivers/char/generic_nvram.c @@ -34,16 +34,12 @@ static ssize_t nvram_len; static loff_t nvram_llseek(struct file *file, loff_t offset, int origin) { switch (origin) { - case 0: - break; case 1: offset += file->f_pos; break; case 2: offset += nvram_len; break; - default: - offset = -1; } if (offset < 0) return -EINVAL; diff --git a/trunk/drivers/char/hpet.c b/trunk/drivers/char/hpet.c index 0833896cf6f2..34d6a1cab8de 100644 --- a/trunk/drivers/char/hpet.c +++ b/trunk/drivers/char/hpet.c @@ -952,7 +952,7 @@ int hpet_alloc(struct hpet_data *hdp) #ifdef CONFIG_IA64 if (!hpet_clocksource) { hpet_mctr = (void __iomem *)&hpetp->hp_hpet->hpet_mc; - clocksource_hpet.archdata.fsys_mmio = hpet_mctr; + CLKSRC_FSYS_MMIO_SET(clocksource_hpet.fsys_mmio, hpet_mctr); clocksource_register_hz(&clocksource_hpet, hpetp->hp_tick_freq); hpetp->hp_clocksource = &clocksource_hpet; hpet_clocksource = &clocksource_hpet; diff --git a/trunk/drivers/char/hw_random/Kconfig b/trunk/drivers/char/hw_random/Kconfig index 1d2ebc7a4947..a60043b3e409 100644 --- a/trunk/drivers/char/hw_random/Kconfig +++ b/trunk/drivers/char/hw_random/Kconfig @@ -210,15 +210,3 @@ config HW_RANDOM_PICOXCELL module will be called picoxcell-rng. If unsure, say Y. - -config HW_RANDOM_PPC4XX - tristate "PowerPC 4xx generic true random number generator support" - depends on HW_RANDOM && PPC && 4xx - ---help--- - This driver provides the kernel-side support for the TRNG hardware - found in the security function of some PowerPC 4xx SoCs. - - To compile this driver as a module, choose M here: the - module will be called ppc4xx-rng. - - If unsure, say N. diff --git a/trunk/drivers/char/hw_random/Makefile b/trunk/drivers/char/hw_random/Makefile index c88f244c8a71..3db4eb8b19c0 100644 --- a/trunk/drivers/char/hw_random/Makefile +++ b/trunk/drivers/char/hw_random/Makefile @@ -20,4 +20,3 @@ obj-$(CONFIG_HW_RANDOM_MXC_RNGA) += mxc-rnga.o obj-$(CONFIG_HW_RANDOM_OCTEON) += octeon-rng.o obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o obj-$(CONFIG_HW_RANDOM_PICOXCELL) += picoxcell-rng.o -obj-$(CONFIG_HW_RANDOM_PPC4XX) += ppc4xx-rng.o diff --git a/trunk/drivers/char/hw_random/nomadik-rng.c b/trunk/drivers/char/hw_random/nomadik-rng.c index 52e08ca3ccd7..dd1d143eb8ea 100644 --- a/trunk/drivers/char/hw_random/nomadik-rng.c +++ b/trunk/drivers/char/hw_random/nomadik-rng.c @@ -55,7 +55,7 @@ static int nmk_rng_probe(struct amba_device *dev, const struct amba_id *id) ret = amba_request_regions(dev, dev->dev.init_name); if (ret) - goto out_clk; + return ret; ret = -ENOMEM; base = ioremap(dev->res.start, resource_size(&dev->res)); if (!base) @@ -70,7 +70,6 @@ static int nmk_rng_probe(struct amba_device *dev, const struct amba_id *id) iounmap(base); out_release: amba_release_regions(dev); -out_clk: clk_disable(rng_clk); clk_put(rng_clk); return ret; diff --git a/trunk/drivers/char/hw_random/omap-rng.c b/trunk/drivers/char/hw_random/omap-rng.c index b757fac3cd1f..2cc755a64302 100644 --- a/trunk/drivers/char/hw_random/omap-rng.c +++ b/trunk/drivers/char/hw_random/omap-rng.c @@ -113,10 +113,8 @@ static int __devinit omap_rng_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - ret = -ENOENT; - goto err_region; - } + if (!res) + return -ENOENT; if (!request_mem_region(res->start, resource_size(res), pdev->name)) { ret = -EBUSY; diff --git a/trunk/drivers/char/hw_random/ppc4xx-rng.c b/trunk/drivers/char/hw_random/ppc4xx-rng.c deleted file mode 100644 index b8afa6a4ff67..000000000000 --- a/trunk/drivers/char/hw_random/ppc4xx-rng.c +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Generic PowerPC 44x RNG driver - * - * Copyright 2011 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; version 2 of the License. - */ - -#include -#include -#include -#include -#include -#include -#include - -#define PPC4XX_TRNG_DEV_CTRL 0x60080 - -#define PPC4XX_TRNGE 0x00020000 -#define PPC4XX_TRNG_CTRL 0x0008 -#define PPC4XX_TRNG_CTRL_DALM 0x20 -#define PPC4XX_TRNG_STAT 0x0004 -#define PPC4XX_TRNG_STAT_B 0x1 -#define PPC4XX_TRNG_DATA 0x0000 - -#define MODULE_NAME "ppc4xx_rng" - -static int ppc4xx_rng_data_present(struct hwrng *rng, int wait) -{ - void __iomem *rng_regs = (void __iomem *) rng->priv; - int busy, i, present = 0; - - for (i = 0; i < 20; i++) { - busy = (in_le32(rng_regs + PPC4XX_TRNG_STAT) & PPC4XX_TRNG_STAT_B); - if (!busy || !wait) { - present = 1; - break; - } - udelay(10); - } - return present; -} - -static int ppc4xx_rng_data_read(struct hwrng *rng, u32 *data) -{ - void __iomem *rng_regs = (void __iomem *) rng->priv; - *data = in_le32(rng_regs + PPC4XX_TRNG_DATA); - return 4; -} - -static int ppc4xx_rng_enable(int enable) -{ - struct device_node *ctrl; - void __iomem *ctrl_reg; - int err = 0; - u32 val; - - /* Find the main crypto device node and map it to turn the TRNG on */ - ctrl = of_find_compatible_node(NULL, NULL, "amcc,ppc4xx-crypto"); - if (!ctrl) - return -ENODEV; - - ctrl_reg = of_iomap(ctrl, 0); - if (!ctrl_reg) { - err = -ENODEV; - goto out; - } - - val = in_le32(ctrl_reg + PPC4XX_TRNG_DEV_CTRL); - - if (enable) - val |= PPC4XX_TRNGE; - else - val = val & ~PPC4XX_TRNGE; - - out_le32(ctrl_reg + PPC4XX_TRNG_DEV_CTRL, val); - iounmap(ctrl_reg); - -out: - of_node_put(ctrl); - - return err; -} - -static struct hwrng ppc4xx_rng = { - .name = MODULE_NAME, - .data_present = ppc4xx_rng_data_present, - .data_read = ppc4xx_rng_data_read, -}; - -static int __devinit ppc4xx_rng_probe(struct platform_device *dev) -{ - void __iomem *rng_regs; - int err = 0; - - rng_regs = of_iomap(dev->dev.of_node, 0); - if (!rng_regs) - return -ENODEV; - - err = ppc4xx_rng_enable(1); - if (err) - return err; - - out_le32(rng_regs + PPC4XX_TRNG_CTRL, PPC4XX_TRNG_CTRL_DALM); - ppc4xx_rng.priv = (unsigned long) rng_regs; - - err = hwrng_register(&ppc4xx_rng); - - return err; -} - -static int __devexit ppc4xx_rng_remove(struct platform_device *dev) -{ - void __iomem *rng_regs = (void __iomem *) ppc4xx_rng.priv; - - hwrng_unregister(&ppc4xx_rng); - ppc4xx_rng_enable(0); - iounmap(rng_regs); - - return 0; -} - -static struct of_device_id ppc4xx_rng_match[] = { - { .compatible = "ppc4xx-rng", }, - { .compatible = "amcc,ppc460ex-rng", }, - { .compatible = "amcc,ppc440epx-rng", }, - {}, -}; - -static struct platform_driver ppc4xx_rng_driver = { - .driver = { - .name = MODULE_NAME, - .owner = THIS_MODULE, - .of_match_table = ppc4xx_rng_match, - }, - .probe = ppc4xx_rng_probe, - .remove = ppc4xx_rng_remove, -}; - -static int __init ppc4xx_rng_init(void) -{ - return platform_driver_register(&ppc4xx_rng_driver); -} -module_init(ppc4xx_rng_init); - -static void __exit ppc4xx_rng_exit(void) -{ - platform_driver_unregister(&ppc4xx_rng_driver); -} -module_exit(ppc4xx_rng_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Josh Boyer "); -MODULE_DESCRIPTION("HW RNG driver for PPC 4xx processors"); diff --git a/trunk/drivers/char/hw_random/timeriomem-rng.c b/trunk/drivers/char/hw_random/timeriomem-rng.c index a8428e6f64a9..a94e930575f2 100644 --- a/trunk/drivers/char/hw_random/timeriomem-rng.c +++ b/trunk/drivers/char/hw_random/timeriomem-rng.c @@ -100,7 +100,8 @@ static int __devinit timeriomem_rng_probe(struct platform_device *pdev) timeriomem_rng_data = pdev->dev.platform_data; - timeriomem_rng_data->address = ioremap(res->start, resource_size(res)); + timeriomem_rng_data->address = ioremap(res->start, + res->end - res->start + 1); if (!timeriomem_rng_data->address) return -EIO; diff --git a/trunk/drivers/char/nvram.c b/trunk/drivers/char/nvram.c index da3cfee782dc..166f1e7aaa7e 100644 --- a/trunk/drivers/char/nvram.c +++ b/trunk/drivers/char/nvram.c @@ -224,8 +224,6 @@ static loff_t nvram_llseek(struct file *file, loff_t offset, int origin) case 2: offset += NVRAM_BYTES; break; - default: - return -EINVAL; } return (offset >= 0) ? (file->f_pos = offset) : -EINVAL; diff --git a/trunk/drivers/char/ps3flash.c b/trunk/drivers/char/ps3flash.c index d0c57c2e2909..85c004a518ee 100644 --- a/trunk/drivers/char/ps3flash.c +++ b/trunk/drivers/char/ps3flash.c @@ -101,16 +101,12 @@ static loff_t ps3flash_llseek(struct file *file, loff_t offset, int origin) mutex_lock(&file->f_mapping->host->i_mutex); switch (origin) { - case 0: - break; case 1: offset += file->f_pos; break; case 2: offset += dev->regions[dev->region_idx].size*dev->blk_size; break; - default: - offset = -1; } if (offset < 0) { res = -EINVAL; @@ -309,14 +305,9 @@ static int ps3flash_flush(struct file *file, fl_owner_t id) return ps3flash_writeback(ps3flash_dev); } -static int ps3flash_fsync(struct file *file, loff_t start, loff_t end, int datasync) +static int ps3flash_fsync(struct file *file, int datasync) { - struct inode *inode = file->f_path.dentry->d_inode; - int err; - mutex_lock(&inode->i_mutex); - err = ps3flash_writeback(ps3flash_dev); - mutex_unlock(&inode->i_mutex); - return err; + return ps3flash_writeback(ps3flash_dev); } static irqreturn_t ps3flash_interrupt(int irq, void *data) diff --git a/trunk/drivers/clocksource/Kconfig b/trunk/drivers/clocksource/Kconfig index 34e9c4f88926..96c921910469 100644 --- a/trunk/drivers/clocksource/Kconfig +++ b/trunk/drivers/clocksource/Kconfig @@ -1,17 +1,5 @@ config CLKSRC_I8253 bool -config CLKEVT_I8253 - bool - -config I8253_LOCK - bool - -config CLKBLD_I8253 - def_bool y if CLKSRC_I8253 || CLKEVT_I8253 || I8253_LOCK - config CLKSRC_MMIO bool - -config DW_APB_TIMER - bool diff --git a/trunk/drivers/clocksource/Makefile b/trunk/drivers/clocksource/Makefile index 85ad1646a7b7..b995942a5060 100644 --- a/trunk/drivers/clocksource/Makefile +++ b/trunk/drivers/clocksource/Makefile @@ -6,6 +6,5 @@ obj-$(CONFIG_CS5535_CLOCK_EVENT_SRC) += cs5535-clockevt.o obj-$(CONFIG_SH_TIMER_CMT) += sh_cmt.o obj-$(CONFIG_SH_TIMER_MTU2) += sh_mtu2.o obj-$(CONFIG_SH_TIMER_TMU) += sh_tmu.o -obj-$(CONFIG_CLKBLD_I8253) += i8253.o +obj-$(CONFIG_CLKSRC_I8253) += i8253.o obj-$(CONFIG_CLKSRC_MMIO) += mmio.o -obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o diff --git a/trunk/drivers/clocksource/dw_apb_timer.c b/trunk/drivers/clocksource/dw_apb_timer.c deleted file mode 100644 index 580f870541a3..000000000000 --- a/trunk/drivers/clocksource/dw_apb_timer.c +++ /dev/null @@ -1,401 +0,0 @@ -/* - * (C) Copyright 2009 Intel Corporation - * Author: Jacob Pan (jacob.jun.pan@intel.com) - * - * Shared with ARM platforms, Jamie Iles, Picochip 2011 - * - * 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. - * - * Support for the Synopsys DesignWare APB Timers. - */ -#include -#include -#include -#include -#include -#include -#include - -#define APBT_MIN_PERIOD 4 -#define APBT_MIN_DELTA_USEC 200 - -#define APBTMR_N_LOAD_COUNT 0x00 -#define APBTMR_N_CURRENT_VALUE 0x04 -#define APBTMR_N_CONTROL 0x08 -#define APBTMR_N_EOI 0x0c -#define APBTMR_N_INT_STATUS 0x10 - -#define APBTMRS_INT_STATUS 0xa0 -#define APBTMRS_EOI 0xa4 -#define APBTMRS_RAW_INT_STATUS 0xa8 -#define APBTMRS_COMP_VERSION 0xac - -#define APBTMR_CONTROL_ENABLE (1 << 0) -/* 1: periodic, 0:free running. */ -#define APBTMR_CONTROL_MODE_PERIODIC (1 << 1) -#define APBTMR_CONTROL_INT (1 << 2) - -static inline struct dw_apb_clock_event_device * -ced_to_dw_apb_ced(struct clock_event_device *evt) -{ - return container_of(evt, struct dw_apb_clock_event_device, ced); -} - -static inline struct dw_apb_clocksource * -clocksource_to_dw_apb_clocksource(struct clocksource *cs) -{ - return container_of(cs, struct dw_apb_clocksource, cs); -} - -static unsigned long apbt_readl(struct dw_apb_timer *timer, unsigned long offs) -{ - return readl(timer->base + offs); -} - -static void apbt_writel(struct dw_apb_timer *timer, unsigned long val, - unsigned long offs) -{ - writel(val, timer->base + offs); -} - -static void apbt_disable_int(struct dw_apb_timer *timer) -{ - unsigned long ctrl = apbt_readl(timer, APBTMR_N_CONTROL); - - ctrl |= APBTMR_CONTROL_INT; - apbt_writel(timer, ctrl, APBTMR_N_CONTROL); -} - -/** - * dw_apb_clockevent_pause() - stop the clock_event_device from running - * - * @dw_ced: The APB clock to stop generating events. - */ -void dw_apb_clockevent_pause(struct dw_apb_clock_event_device *dw_ced) -{ - disable_irq(dw_ced->timer.irq); - apbt_disable_int(&dw_ced->timer); -} - -static void apbt_eoi(struct dw_apb_timer *timer) -{ - apbt_readl(timer, APBTMR_N_EOI); -} - -static irqreturn_t dw_apb_clockevent_irq(int irq, void *data) -{ - struct clock_event_device *evt = data; - struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt); - - if (!evt->event_handler) { - pr_info("Spurious APBT timer interrupt %d", irq); - return IRQ_NONE; - } - - if (dw_ced->eoi) - dw_ced->eoi(&dw_ced->timer); - - evt->event_handler(evt); - return IRQ_HANDLED; -} - -static void apbt_enable_int(struct dw_apb_timer *timer) -{ - unsigned long ctrl = apbt_readl(timer, APBTMR_N_CONTROL); - /* clear pending intr */ - apbt_readl(timer, APBTMR_N_EOI); - ctrl &= ~APBTMR_CONTROL_INT; - apbt_writel(timer, ctrl, APBTMR_N_CONTROL); -} - -static void apbt_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) -{ - unsigned long ctrl; - unsigned long period; - struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt); - - pr_debug("%s CPU %d mode=%d\n", __func__, first_cpu(*evt->cpumask), - mode); - - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - period = DIV_ROUND_UP(dw_ced->timer.freq, HZ); - ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL); - ctrl |= APBTMR_CONTROL_MODE_PERIODIC; - apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); - /* - * DW APB p. 46, have to disable timer before load counter, - * may cause sync problem. - */ - ctrl &= ~APBTMR_CONTROL_ENABLE; - apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); - udelay(1); - pr_debug("Setting clock period %lu for HZ %d\n", period, HZ); - apbt_writel(&dw_ced->timer, period, APBTMR_N_LOAD_COUNT); - ctrl |= APBTMR_CONTROL_ENABLE; - apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); - break; - - case CLOCK_EVT_MODE_ONESHOT: - ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL); - /* - * set free running mode, this mode will let timer reload max - * timeout which will give time (3min on 25MHz clock) to rearm - * the next event, therefore emulate the one-shot mode. - */ - ctrl &= ~APBTMR_CONTROL_ENABLE; - ctrl &= ~APBTMR_CONTROL_MODE_PERIODIC; - - apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); - /* write again to set free running mode */ - apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); - - /* - * DW APB p. 46, load counter with all 1s before starting free - * running mode. - */ - apbt_writel(&dw_ced->timer, ~0, APBTMR_N_LOAD_COUNT); - ctrl &= ~APBTMR_CONTROL_INT; - ctrl |= APBTMR_CONTROL_ENABLE; - apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); - break; - - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL); - ctrl &= ~APBTMR_CONTROL_ENABLE; - apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); - break; - - case CLOCK_EVT_MODE_RESUME: - apbt_enable_int(&dw_ced->timer); - break; - } -} - -static int apbt_next_event(unsigned long delta, - struct clock_event_device *evt) -{ - unsigned long ctrl; - struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt); - - /* Disable timer */ - ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL); - ctrl &= ~APBTMR_CONTROL_ENABLE; - apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); - /* write new count */ - apbt_writel(&dw_ced->timer, delta, APBTMR_N_LOAD_COUNT); - ctrl |= APBTMR_CONTROL_ENABLE; - apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); - - return 0; -} - -/** - * dw_apb_clockevent_init() - use an APB timer as a clock_event_device - * - * @cpu: The CPU the events will be targeted at. - * @name: The name used for the timer and the IRQ for it. - * @rating: The rating to give the timer. - * @base: I/O base for the timer registers. - * @irq: The interrupt number to use for the timer. - * @freq: The frequency that the timer counts at. - * - * This creates a clock_event_device for using with the generic clock layer - * but does not start and register it. This should be done with - * dw_apb_clockevent_register() as the next step. If this is the first time - * it has been called for a timer then the IRQ will be requested, if not it - * just be enabled to allow CPU hotplug to avoid repeatedly requesting and - * releasing the IRQ. - */ -struct dw_apb_clock_event_device * -dw_apb_clockevent_init(int cpu, const char *name, unsigned rating, - void __iomem *base, int irq, unsigned long freq) -{ - struct dw_apb_clock_event_device *dw_ced = - kzalloc(sizeof(*dw_ced), GFP_KERNEL); - int err; - - if (!dw_ced) - return NULL; - - dw_ced->timer.base = base; - dw_ced->timer.irq = irq; - dw_ced->timer.freq = freq; - - clockevents_calc_mult_shift(&dw_ced->ced, freq, APBT_MIN_PERIOD); - dw_ced->ced.max_delta_ns = clockevent_delta2ns(0x7fffffff, - &dw_ced->ced); - dw_ced->ced.min_delta_ns = clockevent_delta2ns(5000, &dw_ced->ced); - dw_ced->ced.cpumask = cpumask_of(cpu); - dw_ced->ced.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; - dw_ced->ced.set_mode = apbt_set_mode; - dw_ced->ced.set_next_event = apbt_next_event; - dw_ced->ced.irq = dw_ced->timer.irq; - dw_ced->ced.rating = rating; - dw_ced->ced.name = name; - - dw_ced->irqaction.name = dw_ced->ced.name; - dw_ced->irqaction.handler = dw_apb_clockevent_irq; - dw_ced->irqaction.dev_id = &dw_ced->ced; - dw_ced->irqaction.irq = irq; - dw_ced->irqaction.flags = IRQF_TIMER | IRQF_IRQPOLL | - IRQF_NOBALANCING | - IRQF_DISABLED; - - dw_ced->eoi = apbt_eoi; - err = setup_irq(irq, &dw_ced->irqaction); - if (err) { - pr_err("failed to request timer irq\n"); - kfree(dw_ced); - dw_ced = NULL; - } - - return dw_ced; -} - -/** - * dw_apb_clockevent_resume() - resume a clock that has been paused. - * - * @dw_ced: The APB clock to resume. - */ -void dw_apb_clockevent_resume(struct dw_apb_clock_event_device *dw_ced) -{ - enable_irq(dw_ced->timer.irq); -} - -/** - * dw_apb_clockevent_stop() - stop the clock_event_device and release the IRQ. - * - * @dw_ced: The APB clock to stop generating the events. - */ -void dw_apb_clockevent_stop(struct dw_apb_clock_event_device *dw_ced) -{ - free_irq(dw_ced->timer.irq, &dw_ced->ced); -} - -/** - * dw_apb_clockevent_register() - register the clock with the generic layer - * - * @dw_ced: The APB clock to register as a clock_event_device. - */ -void dw_apb_clockevent_register(struct dw_apb_clock_event_device *dw_ced) -{ - apbt_writel(&dw_ced->timer, 0, APBTMR_N_CONTROL); - clockevents_register_device(&dw_ced->ced); - apbt_enable_int(&dw_ced->timer); -} - -/** - * dw_apb_clocksource_start() - start the clocksource counting. - * - * @dw_cs: The clocksource to start. - * - * This is used to start the clocksource before registration and can be used - * to enable calibration of timers. - */ -void dw_apb_clocksource_start(struct dw_apb_clocksource *dw_cs) -{ - /* - * start count down from 0xffff_ffff. this is done by toggling the - * enable bit then load initial load count to ~0. - */ - unsigned long ctrl = apbt_readl(&dw_cs->timer, APBTMR_N_CONTROL); - - ctrl &= ~APBTMR_CONTROL_ENABLE; - apbt_writel(&dw_cs->timer, ctrl, APBTMR_N_CONTROL); - apbt_writel(&dw_cs->timer, ~0, APBTMR_N_LOAD_COUNT); - /* enable, mask interrupt */ - ctrl &= ~APBTMR_CONTROL_MODE_PERIODIC; - ctrl |= (APBTMR_CONTROL_ENABLE | APBTMR_CONTROL_INT); - apbt_writel(&dw_cs->timer, ctrl, APBTMR_N_CONTROL); - /* read it once to get cached counter value initialized */ - dw_apb_clocksource_read(dw_cs); -} - -static cycle_t __apbt_read_clocksource(struct clocksource *cs) -{ - unsigned long current_count; - struct dw_apb_clocksource *dw_cs = - clocksource_to_dw_apb_clocksource(cs); - - current_count = apbt_readl(&dw_cs->timer, APBTMR_N_CURRENT_VALUE); - - return (cycle_t)~current_count; -} - -static void apbt_restart_clocksource(struct clocksource *cs) -{ - struct dw_apb_clocksource *dw_cs = - clocksource_to_dw_apb_clocksource(cs); - - dw_apb_clocksource_start(dw_cs); -} - -/** - * dw_apb_clocksource_init() - use an APB timer as a clocksource. - * - * @rating: The rating to give the clocksource. - * @name: The name for the clocksource. - * @base: The I/O base for the timer registers. - * @freq: The frequency that the timer counts at. - * - * This creates a clocksource using an APB timer but does not yet register it - * with the clocksource system. This should be done with - * dw_apb_clocksource_register() as the next step. - */ -struct dw_apb_clocksource * -dw_apb_clocksource_init(unsigned rating, char *name, void __iomem *base, - unsigned long freq) -{ - struct dw_apb_clocksource *dw_cs = kzalloc(sizeof(*dw_cs), GFP_KERNEL); - - if (!dw_cs) - return NULL; - - dw_cs->timer.base = base; - dw_cs->timer.freq = freq; - dw_cs->cs.name = name; - dw_cs->cs.rating = rating; - dw_cs->cs.read = __apbt_read_clocksource; - dw_cs->cs.mask = CLOCKSOURCE_MASK(32); - dw_cs->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS; - dw_cs->cs.resume = apbt_restart_clocksource; - - return dw_cs; -} - -/** - * dw_apb_clocksource_register() - register the APB clocksource. - * - * @dw_cs: The clocksource to register. - */ -void dw_apb_clocksource_register(struct dw_apb_clocksource *dw_cs) -{ - clocksource_register_hz(&dw_cs->cs, dw_cs->timer.freq); -} - -/** - * dw_apb_clocksource_read() - read the current value of a clocksource. - * - * @dw_cs: The clocksource to read. - */ -cycle_t dw_apb_clocksource_read(struct dw_apb_clocksource *dw_cs) -{ - return (cycle_t)~apbt_readl(&dw_cs->timer, APBTMR_N_CURRENT_VALUE); -} - -/** - * dw_apb_clocksource_unregister() - unregister and free a clocksource. - * - * @dw_cs: The clocksource to unregister/free. - */ -void dw_apb_clocksource_unregister(struct dw_apb_clocksource *dw_cs) -{ - clocksource_unregister(&dw_cs->cs); - - kfree(dw_cs); -} diff --git a/trunk/drivers/clocksource/i8253.c b/trunk/drivers/clocksource/i8253.c index 27c49e60b7d6..225c1761b372 100644 --- a/trunk/drivers/clocksource/i8253.c +++ b/trunk/drivers/clocksource/i8253.c @@ -1,25 +1,14 @@ /* * i8253 PIT clocksource */ -#include +#include #include #include #include #include -#include -#include -#include -/* - * Protects access to I/O ports - * - * 0040-0043 : timer0, i8253 / i8254 - * 0061-0061 : NMI Control Register which contains two speaker control bits. - */ -DEFINE_RAW_SPINLOCK(i8253_lock); -EXPORT_SYMBOL(i8253_lock); +#include -#ifdef CONFIG_CLKSRC_I8253 /* * Since the PIT overflows every tick, its not very useful * to just read by itself. So use jiffies to emulate a free @@ -48,15 +37,15 @@ static cycle_t i8253_read(struct clocksource *cs) * count), it cannot be newer. */ jifs = jiffies; - outb_p(0x00, PIT_MODE); /* latch the count ASAP */ - count = inb_p(PIT_CH0); /* read the latched count */ - count |= inb_p(PIT_CH0) << 8; + outb_pit(0x00, PIT_MODE); /* latch the count ASAP */ + count = inb_pit(PIT_CH0); /* read the latched count */ + count |= inb_pit(PIT_CH0) << 8; /* VIA686a test code... reset the latch if count > max + 1 */ if (count > LATCH) { - outb_p(0x34, PIT_MODE); - outb_p(PIT_LATCH & 0xff, PIT_CH0); - outb_p(PIT_LATCH >> 8, PIT_CH0); + outb_pit(0x34, PIT_MODE); + outb_pit(PIT_LATCH & 0xff, PIT_CH0); + outb_pit(PIT_LATCH >> 8, PIT_CH0); count = PIT_LATCH - 1; } @@ -97,90 +86,3 @@ int __init clocksource_i8253_init(void) { return clocksource_register_hz(&i8253_cs, PIT_TICK_RATE); } -#endif - -#ifdef CONFIG_CLKEVT_I8253 -/* - * Initialize the PIT timer. - * - * This is also called after resume to bring the PIT into operation again. - */ -static void init_pit_timer(enum clock_event_mode mode, - struct clock_event_device *evt) -{ - raw_spin_lock(&i8253_lock); - - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - /* binary, mode 2, LSB/MSB, ch 0 */ - outb_p(0x34, PIT_MODE); - outb_p(LATCH & 0xff , PIT_CH0); /* LSB */ - outb_p(LATCH >> 8 , PIT_CH0); /* MSB */ - break; - - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_UNUSED: - if (evt->mode == CLOCK_EVT_MODE_PERIODIC || - evt->mode == CLOCK_EVT_MODE_ONESHOT) { - outb_p(0x30, PIT_MODE); - outb_p(0, PIT_CH0); - outb_p(0, PIT_CH0); - } - break; - - case CLOCK_EVT_MODE_ONESHOT: - /* One shot setup */ - outb_p(0x38, PIT_MODE); - break; - - case CLOCK_EVT_MODE_RESUME: - /* Nothing to do here */ - break; - } - raw_spin_unlock(&i8253_lock); -} - -/* - * Program the next event in oneshot mode - * - * Delta is given in PIT ticks - */ -static int pit_next_event(unsigned long delta, struct clock_event_device *evt) -{ - raw_spin_lock(&i8253_lock); - outb_p(delta & 0xff , PIT_CH0); /* LSB */ - outb_p(delta >> 8 , PIT_CH0); /* MSB */ - raw_spin_unlock(&i8253_lock); - - return 0; -} - -/* - * On UP the PIT can serve all of the possible timer functions. On SMP systems - * it can be solely used for the global tick. - */ -struct clock_event_device i8253_clockevent = { - .name = "pit", - .features = CLOCK_EVT_FEAT_PERIODIC, - .set_mode = init_pit_timer, - .set_next_event = pit_next_event, -}; - -/* - * Initialize the conversion factor and the min/max deltas of the clock event - * structure and register the clock event source with the framework. - */ -void __init clockevent_i8253_init(bool oneshot) -{ - if (oneshot) - i8253_clockevent.features |= CLOCK_EVT_FEAT_ONESHOT; - /* - * Start pit with the boot cpu mask. x86 might make it global - * when it is used as broadcast device later. - */ - i8253_clockevent.cpumask = cpumask_of(smp_processor_id()); - - clockevents_config_and_register(&i8253_clockevent, PIT_TICK_RATE, - 0xF, 0x7FFF); -} -#endif diff --git a/trunk/drivers/crypto/amcc/crypto4xx_core.c b/trunk/drivers/crypto/amcc/crypto4xx_core.c index 1d103f997dc2..18912521a7a5 100644 --- a/trunk/drivers/crypto/amcc/crypto4xx_core.c +++ b/trunk/drivers/crypto/amcc/crypto4xx_core.c @@ -51,7 +51,6 @@ static void crypto4xx_hw_init(struct crypto4xx_device *dev) union ce_io_threshold io_threshold; u32 rand_num; union ce_pe_dma_cfg pe_dma_cfg; - u32 device_ctrl; writel(PPC4XX_BYTE_ORDER, dev->ce_base + CRYPTO4XX_BYTE_ORDER_CFG); /* setup pe dma, include reset sg, pdr and pe, then release reset */ @@ -85,9 +84,7 @@ static void crypto4xx_hw_init(struct crypto4xx_device *dev) writel(ring_size.w, dev->ce_base + CRYPTO4XX_RING_SIZE); ring_ctrl.w = 0; writel(ring_ctrl.w, dev->ce_base + CRYPTO4XX_RING_CTRL); - device_ctrl = readl(dev->ce_base + CRYPTO4XX_DEVICE_CTRL); - device_ctrl |= PPC4XX_DC_3DES_EN; - writel(device_ctrl, dev->ce_base + CRYPTO4XX_DEVICE_CTRL); + writel(PPC4XX_DC_3DES_EN, dev->ce_base + CRYPTO4XX_DEVICE_CTRL); writel(dev->gdr_pa, dev->ce_base + CRYPTO4XX_GATH_RING_BASE); writel(dev->sdr_pa, dev->ce_base + CRYPTO4XX_SCAT_RING_BASE); part_ring_size.w = 0; diff --git a/trunk/drivers/crypto/caam/caamalg.c b/trunk/drivers/crypto/caam/caamalg.c index 4159265b453b..676d957c22b0 100644 --- a/trunk/drivers/crypto/caam/caamalg.c +++ b/trunk/drivers/crypto/caam/caamalg.c @@ -62,22 +62,10 @@ #define CAAM_MAX_IV_LENGTH 16 /* length of descriptors text */ -#define DESC_JOB_IO_LEN (CAAM_CMD_SZ * 3 + CAAM_PTR_SZ * 3) - -#define DESC_AEAD_BASE (4 * CAAM_CMD_SZ) -#define DESC_AEAD_ENC_LEN (DESC_AEAD_BASE + 16 * CAAM_CMD_SZ) -#define DESC_AEAD_DEC_LEN (DESC_AEAD_BASE + 21 * CAAM_CMD_SZ) -#define DESC_AEAD_GIVENC_LEN (DESC_AEAD_ENC_LEN + 7 * CAAM_CMD_SZ) - -#define DESC_ABLKCIPHER_BASE (3 * CAAM_CMD_SZ) -#define DESC_ABLKCIPHER_ENC_LEN (DESC_ABLKCIPHER_BASE + \ - 20 * CAAM_CMD_SZ) -#define DESC_ABLKCIPHER_DEC_LEN (DESC_ABLKCIPHER_BASE + \ - 15 * CAAM_CMD_SZ) - -#define DESC_MAX_USED_BYTES (DESC_AEAD_GIVENC_LEN + \ - CAAM_MAX_KEY_SIZE) -#define DESC_MAX_USED_LEN (DESC_MAX_USED_BYTES / CAAM_CMD_SZ) +#define DESC_AEAD_SHARED_TEXT_LEN 4 +#define DESC_AEAD_ENCRYPT_TEXT_LEN 21 +#define DESC_AEAD_DECRYPT_TEXT_LEN 24 +#define DESC_AEAD_GIVENCRYPT_TEXT_LEN 27 #ifdef DEBUG /* for print_hex_dumps with line references */ @@ -88,366 +76,30 @@ #define debug(format, arg...) #endif -/* Set DK bit in class 1 operation if shared */ -static inline void append_dec_op1(u32 *desc, u32 type) -{ - u32 *jump_cmd, *uncond_jump_cmd; - - jump_cmd = append_jump(desc, JUMP_TEST_ALL | JUMP_COND_SHRD); - append_operation(desc, type | OP_ALG_AS_INITFINAL | - OP_ALG_DECRYPT); - uncond_jump_cmd = append_jump(desc, JUMP_TEST_ALL); - set_jump_tgt_here(desc, jump_cmd); - append_operation(desc, type | OP_ALG_AS_INITFINAL | - OP_ALG_DECRYPT | OP_ALG_AAI_DK); - set_jump_tgt_here(desc, uncond_jump_cmd); -} - -/* - * Wait for completion of class 1 key loading before allowing - * error propagation - */ -static inline void append_dec_shr_done(u32 *desc) -{ - u32 *jump_cmd; - - jump_cmd = append_jump(desc, JUMP_CLASS_CLASS1 | JUMP_TEST_ALL); - set_jump_tgt_here(desc, jump_cmd); - append_cmd(desc, SET_OK_PROP_ERRORS | CMD_LOAD); -} - -/* - * For aead functions, read payload and write payload, - * both of which are specified in req->src and req->dst - */ -static inline void aead_append_src_dst(u32 *desc, u32 msg_type) -{ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_BOTH | - KEY_VLF | msg_type | FIFOLD_TYPE_LASTBOTH); - append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | KEY_VLF); -} - -/* - * For aead encrypt and decrypt, read iv for both classes - */ -static inline void aead_append_ld_iv(u32 *desc, int ivsize) -{ - append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT | - LDST_CLASS_1_CCB | ivsize); - append_move(desc, MOVE_SRC_CLASS1CTX | MOVE_DEST_CLASS2INFIFO | ivsize); -} - -/* - * For ablkcipher encrypt and decrypt, read from req->src and - * write to req->dst - */ -static inline void ablkcipher_append_src_dst(u32 *desc) -{ - append_math_add(desc, VARSEQOUTLEN, SEQINLEN, REG0, CAAM_CMD_SZ); \ - append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); \ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | \ - KEY_VLF | FIFOLD_TYPE_MSG | FIFOLD_TYPE_LAST1); \ - append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | KEY_VLF); \ -} - -/* - * If all data, including src (with assoc and iv) or dst (with iv only) are - * contiguous - */ -#define GIV_SRC_CONTIG 1 -#define GIV_DST_CONTIG (1 << 1) - /* * per-session context */ struct caam_ctx { struct device *jrdev; - u32 sh_desc_enc[DESC_MAX_USED_LEN]; - u32 sh_desc_dec[DESC_MAX_USED_LEN]; - u32 sh_desc_givenc[DESC_MAX_USED_LEN]; - dma_addr_t sh_desc_enc_dma; - dma_addr_t sh_desc_dec_dma; - dma_addr_t sh_desc_givenc_dma; + u32 *sh_desc; + dma_addr_t shared_desc_phys; u32 class1_alg_type; u32 class2_alg_type; u32 alg_op; - u8 key[CAAM_MAX_KEY_SIZE]; - dma_addr_t key_dma; + u8 *key; + dma_addr_t key_phys; unsigned int enckeylen; unsigned int split_key_len; unsigned int split_key_pad_len; unsigned int authsize; }; -static void append_key_aead(u32 *desc, struct caam_ctx *ctx, - int keys_fit_inline) -{ - if (keys_fit_inline) { - append_key_as_imm(desc, ctx->key, ctx->split_key_pad_len, - ctx->split_key_len, CLASS_2 | - KEY_DEST_MDHA_SPLIT | KEY_ENC); - append_key_as_imm(desc, (void *)ctx->key + - ctx->split_key_pad_len, ctx->enckeylen, - ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); - } else { - append_key(desc, ctx->key_dma, ctx->split_key_len, CLASS_2 | - KEY_DEST_MDHA_SPLIT | KEY_ENC); - append_key(desc, ctx->key_dma + ctx->split_key_pad_len, - ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); - } -} - -static void init_sh_desc_key_aead(u32 *desc, struct caam_ctx *ctx, - int keys_fit_inline) -{ - u32 *key_jump_cmd; - - init_sh_desc(desc, HDR_SHARE_WAIT); - - /* Skip if already shared */ - key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | - JUMP_COND_SHRD); - - append_key_aead(desc, ctx, keys_fit_inline); - - set_jump_tgt_here(desc, key_jump_cmd); - - /* Propagate errors from shared to job descriptor */ - append_cmd(desc, SET_OK_PROP_ERRORS | CMD_LOAD); -} - -static int aead_set_sh_desc(struct crypto_aead *aead) -{ - struct aead_tfm *tfm = &aead->base.crt_aead; - struct caam_ctx *ctx = crypto_aead_ctx(aead); - struct device *jrdev = ctx->jrdev; - bool keys_fit_inline = 0; - u32 *key_jump_cmd, *jump_cmd; - u32 geniv, moveiv; - u32 *desc; - - if (!ctx->enckeylen || !ctx->authsize) - return 0; - - /* - * Job Descriptor and Shared Descriptors - * must all fit into the 64-word Descriptor h/w Buffer - */ - if (DESC_AEAD_ENC_LEN + DESC_JOB_IO_LEN + - ctx->split_key_pad_len + ctx->enckeylen <= - CAAM_DESC_BYTES_MAX) - keys_fit_inline = 1; - - /* aead_encrypt shared descriptor */ - desc = ctx->sh_desc_enc; - - init_sh_desc_key_aead(desc, ctx, keys_fit_inline); - - /* Class 2 operation */ - append_operation(desc, ctx->class2_alg_type | - OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); - - /* cryptlen = seqoutlen - authsize */ - append_math_sub_imm_u32(desc, REG3, SEQOUTLEN, IMM, ctx->authsize); - - /* assoclen + cryptlen = seqinlen - ivsize */ - append_math_sub_imm_u32(desc, REG2, SEQINLEN, IMM, tfm->ivsize); - - /* assoclen + cryptlen = (assoclen + cryptlen) - cryptlen */ - append_math_sub(desc, VARSEQINLEN, REG2, REG3, CAAM_CMD_SZ); - - /* read assoc before reading payload */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_MSG | - KEY_VLF); - aead_append_ld_iv(desc, tfm->ivsize); - - /* Class 1 operation */ - append_operation(desc, ctx->class1_alg_type | - OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); - - /* Read and write cryptlen bytes */ - append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); - append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); - aead_append_src_dst(desc, FIFOLD_TYPE_MSG1OUT2); - - /* Write ICV */ - append_seq_store(desc, ctx->authsize, LDST_CLASS_2_CCB | - LDST_SRCDST_BYTE_CONTEXT); - - ctx->sh_desc_enc_dma = dma_map_single(jrdev, desc, - desc_bytes(desc), - DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, ctx->sh_desc_enc_dma)) { - dev_err(jrdev, "unable to map shared descriptor\n"); - return -ENOMEM; - } -#ifdef DEBUG - print_hex_dump(KERN_ERR, "aead enc shdesc@"xstr(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, - desc_bytes(desc), 1); -#endif - - /* - * Job Descriptor and Shared Descriptors - * must all fit into the 64-word Descriptor h/w Buffer - */ - if (DESC_AEAD_DEC_LEN + DESC_JOB_IO_LEN + - ctx->split_key_pad_len + ctx->enckeylen <= - CAAM_DESC_BYTES_MAX) - keys_fit_inline = 1; - - desc = ctx->sh_desc_dec; - - /* aead_decrypt shared descriptor */ - init_sh_desc(desc, HDR_SHARE_WAIT); - - /* Skip if already shared */ - key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | - JUMP_COND_SHRD); - - append_key_aead(desc, ctx, keys_fit_inline); - - /* Only propagate error immediately if shared */ - jump_cmd = append_jump(desc, JUMP_TEST_ALL); - set_jump_tgt_here(desc, key_jump_cmd); - append_cmd(desc, SET_OK_PROP_ERRORS | CMD_LOAD); - set_jump_tgt_here(desc, jump_cmd); - - /* Class 2 operation */ - append_operation(desc, ctx->class2_alg_type | - OP_ALG_AS_INITFINAL | OP_ALG_DECRYPT | OP_ALG_ICV_ON); - - /* assoclen + cryptlen = seqinlen - ivsize */ - append_math_sub_imm_u32(desc, REG3, SEQINLEN, IMM, - ctx->authsize + tfm->ivsize) - /* assoclen = (assoclen + cryptlen) - cryptlen */ - append_math_sub(desc, REG2, SEQOUTLEN, REG0, CAAM_CMD_SZ); - append_math_sub(desc, VARSEQINLEN, REG3, REG2, CAAM_CMD_SZ); - - /* read assoc before reading payload */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_MSG | - KEY_VLF); - - aead_append_ld_iv(desc, tfm->ivsize); - - append_dec_op1(desc, ctx->class1_alg_type); - - /* Read and write cryptlen bytes */ - append_math_add(desc, VARSEQINLEN, ZERO, REG2, CAAM_CMD_SZ); - append_math_add(desc, VARSEQOUTLEN, ZERO, REG2, CAAM_CMD_SZ); - aead_append_src_dst(desc, FIFOLD_TYPE_MSG); - - /* Load ICV */ - append_seq_fifo_load(desc, ctx->authsize, FIFOLD_CLASS_CLASS2 | - FIFOLD_TYPE_LAST2 | FIFOLD_TYPE_ICV); - append_dec_shr_done(desc); - - ctx->sh_desc_dec_dma = dma_map_single(jrdev, desc, - desc_bytes(desc), - DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, ctx->sh_desc_dec_dma)) { - dev_err(jrdev, "unable to map shared descriptor\n"); - return -ENOMEM; - } -#ifdef DEBUG - print_hex_dump(KERN_ERR, "aead dec shdesc@"xstr(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, - desc_bytes(desc), 1); -#endif - - /* - * Job Descriptor and Shared Descriptors - * must all fit into the 64-word Descriptor h/w Buffer - */ - if (DESC_AEAD_GIVENC_LEN + DESC_JOB_IO_LEN + - ctx->split_key_pad_len + ctx->enckeylen <= - CAAM_DESC_BYTES_MAX) - keys_fit_inline = 1; - - /* aead_givencrypt shared descriptor */ - desc = ctx->sh_desc_givenc; - - init_sh_desc_key_aead(desc, ctx, keys_fit_inline); - - /* Generate IV */ - geniv = NFIFOENTRY_STYPE_PAD | NFIFOENTRY_DEST_DECO | - NFIFOENTRY_DTYPE_MSG | NFIFOENTRY_LC1 | - NFIFOENTRY_PTYPE_RND | (tfm->ivsize << NFIFOENTRY_DLEN_SHIFT); - append_load_imm_u32(desc, geniv, LDST_CLASS_IND_CCB | - LDST_SRCDST_WORD_INFO_FIFO | LDST_IMM); - append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); - append_move(desc, MOVE_SRC_INFIFO | - MOVE_DEST_CLASS1CTX | (tfm->ivsize << MOVE_LEN_SHIFT)); - append_cmd(desc, CMD_LOAD | ENABLE_AUTO_INFO_FIFO); - - /* Copy IV to class 1 context */ - append_move(desc, MOVE_SRC_CLASS1CTX | - MOVE_DEST_OUTFIFO | (tfm->ivsize << MOVE_LEN_SHIFT)); - - /* Return to encryption */ - append_operation(desc, ctx->class2_alg_type | - OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); - - /* ivsize + cryptlen = seqoutlen - authsize */ - append_math_sub_imm_u32(desc, REG3, SEQOUTLEN, IMM, ctx->authsize); - - /* assoclen = seqinlen - (ivsize + cryptlen) */ - append_math_sub(desc, VARSEQINLEN, SEQINLEN, REG3, CAAM_CMD_SZ); - - /* read assoc before reading payload */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_MSG | - KEY_VLF); - - /* Copy iv from class 1 ctx to class 2 fifo*/ - moveiv = NFIFOENTRY_STYPE_OFIFO | NFIFOENTRY_DEST_CLASS2 | - NFIFOENTRY_DTYPE_MSG | (tfm->ivsize << NFIFOENTRY_DLEN_SHIFT); - append_load_imm_u32(desc, moveiv, LDST_CLASS_IND_CCB | - LDST_SRCDST_WORD_INFO_FIFO | LDST_IMM); - append_load_imm_u32(desc, tfm->ivsize, LDST_CLASS_2_CCB | - LDST_SRCDST_WORD_DATASZ_REG | LDST_IMM); - - /* Class 1 operation */ - append_operation(desc, ctx->class1_alg_type | - OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); - - /* Will write ivsize + cryptlen */ - append_math_add(desc, VARSEQOUTLEN, SEQINLEN, REG0, CAAM_CMD_SZ); - - /* Not need to reload iv */ - append_seq_fifo_load(desc, tfm->ivsize, - FIFOLD_CLASS_SKIP); - - /* Will read cryptlen */ - append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); - aead_append_src_dst(desc, FIFOLD_TYPE_MSG1OUT2); - - /* Write ICV */ - append_seq_store(desc, ctx->authsize, LDST_CLASS_2_CCB | - LDST_SRCDST_BYTE_CONTEXT); - - ctx->sh_desc_givenc_dma = dma_map_single(jrdev, desc, - desc_bytes(desc), - DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, ctx->sh_desc_givenc_dma)) { - dev_err(jrdev, "unable to map shared descriptor\n"); - return -ENOMEM; - } -#ifdef DEBUG - print_hex_dump(KERN_ERR, "aead givenc shdesc@"xstr(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, - desc_bytes(desc), 1); -#endif - - return 0; -} - -static int aead_setauthsize(struct crypto_aead *authenc, +static int aead_authenc_setauthsize(struct crypto_aead *authenc, unsigned int authsize) { struct caam_ctx *ctx = crypto_aead_ctx(authenc); ctx->authsize = authsize; - aead_set_sh_desc(authenc); return 0; } @@ -465,7 +117,6 @@ static void split_key_done(struct device *dev, u32 *desc, u32 err, #ifdef DEBUG dev_err(dev, "%s %d: err 0x%x\n", __func__, __LINE__, err); #endif - if (err) { char tmp[CAAM_ERROR_STR_MAX]; @@ -569,7 +220,73 @@ static u32 gen_split_key(struct caam_ctx *ctx, const u8 *key_in, u32 authkeylen) return ret; } -static int aead_setkey(struct crypto_aead *aead, +static int build_sh_desc_ipsec(struct caam_ctx *ctx) +{ + struct device *jrdev = ctx->jrdev; + u32 *sh_desc; + u32 *jump_cmd; + bool keys_fit_inline = 0; + + /* + * largest Job Descriptor and its Shared Descriptor + * must both fit into the 64-word Descriptor h/w Buffer + */ + if ((DESC_AEAD_GIVENCRYPT_TEXT_LEN + + DESC_AEAD_SHARED_TEXT_LEN) * CAAM_CMD_SZ + + ctx->split_key_pad_len + ctx->enckeylen <= CAAM_DESC_BYTES_MAX) + keys_fit_inline = 1; + + /* build shared descriptor for this session */ + sh_desc = kmalloc(CAAM_CMD_SZ * DESC_AEAD_SHARED_TEXT_LEN + + (keys_fit_inline ? + ctx->split_key_pad_len + ctx->enckeylen : + CAAM_PTR_SZ * 2), GFP_DMA | GFP_KERNEL); + if (!sh_desc) { + dev_err(jrdev, "could not allocate shared descriptor\n"); + return -ENOMEM; + } + + init_sh_desc(sh_desc, HDR_SAVECTX | HDR_SHARE_SERIAL); + + jump_cmd = append_jump(sh_desc, CLASS_BOTH | JUMP_TEST_ALL | + JUMP_COND_SHRD | JUMP_COND_SELF); + + /* + * process keys, starting with class 2/authentication. + */ + if (keys_fit_inline) { + append_key_as_imm(sh_desc, ctx->key, ctx->split_key_pad_len, + ctx->split_key_len, + CLASS_2 | KEY_DEST_MDHA_SPLIT | KEY_ENC); + + append_key_as_imm(sh_desc, (void *)ctx->key + + ctx->split_key_pad_len, ctx->enckeylen, + ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); + } else { + append_key(sh_desc, ctx->key_phys, ctx->split_key_len, CLASS_2 | + KEY_DEST_MDHA_SPLIT | KEY_ENC); + append_key(sh_desc, ctx->key_phys + ctx->split_key_pad_len, + ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); + } + + /* update jump cmd now that we are at the jump target */ + set_jump_tgt_here(sh_desc, jump_cmd); + + ctx->shared_desc_phys = dma_map_single(jrdev, sh_desc, + desc_bytes(sh_desc), + DMA_TO_DEVICE); + if (dma_mapping_error(jrdev, ctx->shared_desc_phys)) { + dev_err(jrdev, "unable to map shared descriptor\n"); + kfree(sh_desc); + return -ENOMEM; + } + + ctx->sh_desc = sh_desc; + + return 0; +} + +static int aead_authenc_setkey(struct crypto_aead *aead, const u8 *key, unsigned int keylen) { /* Sizes for MDHA pads (*not* keys): MD5, SHA1, 224, 256, 384, 512 */ @@ -609,19 +326,27 @@ static int aead_setkey(struct crypto_aead *aead, print_hex_dump(KERN_ERR, "key in @"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); #endif + ctx->key = kmalloc(ctx->split_key_pad_len + enckeylen, + GFP_KERNEL | GFP_DMA); + if (!ctx->key) { + dev_err(jrdev, "could not allocate key output memory\n"); + return -ENOMEM; + } ret = gen_split_key(ctx, key, authkeylen); if (ret) { + kfree(ctx->key); goto badkey; } /* postpend encryption key to auth split key */ memcpy(ctx->key + ctx->split_key_pad_len, key + authkeylen, enckeylen); - ctx->key_dma = dma_map_single(jrdev, ctx->key, ctx->split_key_pad_len + + ctx->key_phys = dma_map_single(jrdev, ctx->key, ctx->split_key_pad_len + enckeylen, DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, ctx->key_dma)) { + if (dma_mapping_error(jrdev, ctx->key_phys)) { dev_err(jrdev, "unable to map key i/o memory\n"); + kfree(ctx->key); return -ENOMEM; } #ifdef DEBUG @@ -632,10 +357,11 @@ static int aead_setkey(struct crypto_aead *aead, ctx->enckeylen = enckeylen; - ret = aead_set_sh_desc(aead); + ret = build_sh_desc_ipsec(ctx); if (ret) { - dma_unmap_single(jrdev, ctx->key_dma, ctx->split_key_pad_len + + dma_unmap_single(jrdev, ctx->key_phys, ctx->split_key_pad_len + enckeylen, DMA_TO_DEVICE); + kfree(ctx->key); } return ret; @@ -644,119 +370,6 @@ static int aead_setkey(struct crypto_aead *aead, return -EINVAL; } -static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, - const u8 *key, unsigned int keylen) -{ - struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); - struct ablkcipher_tfm *tfm = &ablkcipher->base.crt_ablkcipher; - struct device *jrdev = ctx->jrdev; - int ret = 0; - u32 *key_jump_cmd, *jump_cmd; - u32 *desc; - -#ifdef DEBUG - print_hex_dump(KERN_ERR, "key in @"xstr(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); -#endif - - memcpy(ctx->key, key, keylen); - ctx->key_dma = dma_map_single(jrdev, ctx->key, keylen, - DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, ctx->key_dma)) { - dev_err(jrdev, "unable to map key i/o memory\n"); - return -ENOMEM; - } - ctx->enckeylen = keylen; - - /* ablkcipher_encrypt shared descriptor */ - desc = ctx->sh_desc_enc; - init_sh_desc(desc, HDR_SHARE_WAIT); - /* Skip if already shared */ - key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | - JUMP_COND_SHRD); - - /* Load class1 key only */ - append_key_as_imm(desc, (void *)ctx->key, ctx->enckeylen, - ctx->enckeylen, CLASS_1 | - KEY_DEST_CLASS_REG); - - set_jump_tgt_here(desc, key_jump_cmd); - - /* Propagate errors from shared to job descriptor */ - append_cmd(desc, SET_OK_PROP_ERRORS | CMD_LOAD); - - /* Load iv */ - append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT | - LDST_CLASS_1_CCB | tfm->ivsize); - - /* Load operation */ - append_operation(desc, ctx->class1_alg_type | - OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); - - /* Perform operation */ - ablkcipher_append_src_dst(desc); - - ctx->sh_desc_enc_dma = dma_map_single(jrdev, desc, - desc_bytes(desc), - DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, ctx->sh_desc_enc_dma)) { - dev_err(jrdev, "unable to map shared descriptor\n"); - return -ENOMEM; - } -#ifdef DEBUG - print_hex_dump(KERN_ERR, "ablkcipher enc shdesc@"xstr(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, - desc_bytes(desc), 1); -#endif - /* ablkcipher_decrypt shared descriptor */ - desc = ctx->sh_desc_dec; - - init_sh_desc(desc, HDR_SHARE_WAIT); - /* Skip if already shared */ - key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | - JUMP_COND_SHRD); - - /* Load class1 key only */ - append_key_as_imm(desc, (void *)ctx->key, ctx->enckeylen, - ctx->enckeylen, CLASS_1 | - KEY_DEST_CLASS_REG); - - /* For aead, only propagate error immediately if shared */ - jump_cmd = append_jump(desc, JUMP_TEST_ALL); - set_jump_tgt_here(desc, key_jump_cmd); - append_cmd(desc, SET_OK_PROP_ERRORS | CMD_LOAD); - set_jump_tgt_here(desc, jump_cmd); - - /* load IV */ - append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT | - LDST_CLASS_1_CCB | tfm->ivsize); - - /* Choose operation */ - append_dec_op1(desc, ctx->class1_alg_type); - - /* Perform operation */ - ablkcipher_append_src_dst(desc); - - /* Wait for key to load before allowing propagating error */ - append_dec_shr_done(desc); - - ctx->sh_desc_dec_dma = dma_map_single(jrdev, desc, - desc_bytes(desc), - DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, ctx->sh_desc_enc_dma)) { - dev_err(jrdev, "unable to map shared descriptor\n"); - return -ENOMEM; - } - -#ifdef DEBUG - print_hex_dump(KERN_ERR, "ablkcipher dec shdesc@"xstr(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, - desc_bytes(desc), 1); -#endif - - return ret; -} - struct link_tbl_entry { u64 ptr; u32 len; @@ -766,109 +379,64 @@ struct link_tbl_entry { }; /* - * aead_edesc - s/w-extended aead descriptor - * @assoc_nents: number of segments in associated data (SPI+Seq) scatterlist + * ipsec_esp_edesc - s/w-extended ipsec_esp descriptor * @src_nents: number of segments in input scatterlist * @dst_nents: number of segments in output scatterlist - * @iv_dma: dma address of iv for checking continuity and link table + * @assoc_nents: number of segments in associated data (SPI+Seq) scatterlist * @desc: h/w descriptor (variable length; must not exceed MAX_CAAM_DESCSIZE) * @link_tbl_bytes: length of dma mapped link_tbl space * @link_tbl_dma: bus physical mapped address of h/w link table * @hw_desc: the h/w job descriptor followed by any referenced link tables */ -struct aead_edesc { +struct ipsec_esp_edesc { int assoc_nents; int src_nents; int dst_nents; - dma_addr_t iv_dma; int link_tbl_bytes; dma_addr_t link_tbl_dma; struct link_tbl_entry *link_tbl; u32 hw_desc[0]; }; -/* - * ablkcipher_edesc - s/w-extended ablkcipher descriptor - * @src_nents: number of segments in input scatterlist - * @dst_nents: number of segments in output scatterlist - * @iv_dma: dma address of iv for checking continuity and link table - * @desc: h/w descriptor (variable length; must not exceed MAX_CAAM_DESCSIZE) - * @link_tbl_bytes: length of dma mapped link_tbl space - * @link_tbl_dma: bus physical mapped address of h/w link table - * @hw_desc: the h/w job descriptor followed by any referenced link tables - */ -struct ablkcipher_edesc { - int src_nents; - int dst_nents; - dma_addr_t iv_dma; - int link_tbl_bytes; - dma_addr_t link_tbl_dma; - struct link_tbl_entry *link_tbl; - u32 hw_desc[0]; -}; - -static void caam_unmap(struct device *dev, struct scatterlist *src, - struct scatterlist *dst, int src_nents, int dst_nents, - dma_addr_t iv_dma, int ivsize, dma_addr_t link_tbl_dma, - int link_tbl_bytes) +static void ipsec_esp_unmap(struct device *dev, + struct ipsec_esp_edesc *edesc, + struct aead_request *areq) { - if (unlikely(dst != src)) { - dma_unmap_sg(dev, src, src_nents, DMA_TO_DEVICE); - dma_unmap_sg(dev, dst, dst_nents, DMA_FROM_DEVICE); + dma_unmap_sg(dev, areq->assoc, edesc->assoc_nents, DMA_TO_DEVICE); + + if (unlikely(areq->dst != areq->src)) { + dma_unmap_sg(dev, areq->src, edesc->src_nents, + DMA_TO_DEVICE); + dma_unmap_sg(dev, areq->dst, edesc->dst_nents, + DMA_FROM_DEVICE); } else { - dma_unmap_sg(dev, src, src_nents, DMA_BIDIRECTIONAL); + dma_unmap_sg(dev, areq->src, edesc->src_nents, + DMA_BIDIRECTIONAL); } - if (iv_dma) - dma_unmap_single(dev, iv_dma, ivsize, DMA_TO_DEVICE); - if (link_tbl_bytes) - dma_unmap_single(dev, link_tbl_dma, link_tbl_bytes, + if (edesc->link_tbl_bytes) + dma_unmap_single(dev, edesc->link_tbl_dma, + edesc->link_tbl_bytes, DMA_TO_DEVICE); } -static void aead_unmap(struct device *dev, - struct aead_edesc *edesc, - struct aead_request *req) -{ - struct crypto_aead *aead = crypto_aead_reqtfm(req); - int ivsize = crypto_aead_ivsize(aead); - - dma_unmap_sg(dev, req->assoc, edesc->assoc_nents, DMA_TO_DEVICE); - - caam_unmap(dev, req->src, req->dst, - edesc->src_nents, edesc->dst_nents, - edesc->iv_dma, ivsize, edesc->link_tbl_dma, - edesc->link_tbl_bytes); -} - -static void ablkcipher_unmap(struct device *dev, - struct ablkcipher_edesc *edesc, - struct ablkcipher_request *req) -{ - struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); - int ivsize = crypto_ablkcipher_ivsize(ablkcipher); - - caam_unmap(dev, req->src, req->dst, - edesc->src_nents, edesc->dst_nents, - edesc->iv_dma, ivsize, edesc->link_tbl_dma, - edesc->link_tbl_bytes); -} - -static void aead_encrypt_done(struct device *jrdev, u32 *desc, u32 err, +/* + * ipsec_esp descriptor callbacks + */ +static void ipsec_esp_encrypt_done(struct device *jrdev, u32 *desc, u32 err, void *context) { - struct aead_request *req = context; - struct aead_edesc *edesc; + struct aead_request *areq = context; + struct ipsec_esp_edesc *edesc; #ifdef DEBUG - struct crypto_aead *aead = crypto_aead_reqtfm(req); - struct caam_ctx *ctx = crypto_aead_ctx(aead); + struct crypto_aead *aead = crypto_aead_reqtfm(areq); int ivsize = crypto_aead_ivsize(aead); + struct caam_ctx *ctx = crypto_aead_ctx(aead); dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); #endif - - edesc = (struct aead_edesc *)((char *)desc - - offsetof(struct aead_edesc, hw_desc)); + edesc = (struct ipsec_esp_edesc *)((char *)desc - + offsetof(struct ipsec_esp_edesc, hw_desc)); if (err) { char tmp[CAAM_ERROR_STR_MAX]; @@ -876,50 +444,39 @@ static void aead_encrypt_done(struct device *jrdev, u32 *desc, u32 err, dev_err(jrdev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err)); } - aead_unmap(jrdev, edesc, req); + ipsec_esp_unmap(jrdev, edesc, areq); #ifdef DEBUG print_hex_dump(KERN_ERR, "assoc @"xstr(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->assoc), - req->assoclen , 1); + DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(areq->assoc), + areq->assoclen , 1); print_hex_dump(KERN_ERR, "dstiv @"xstr(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src) - ivsize, + DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(areq->src) - ivsize, edesc->src_nents ? 100 : ivsize, 1); print_hex_dump(KERN_ERR, "dst @"xstr(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src), - edesc->src_nents ? 100 : req->cryptlen + + DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(areq->src), + edesc->src_nents ? 100 : areq->cryptlen + ctx->authsize + 4, 1); #endif kfree(edesc); - aead_request_complete(req, err); + aead_request_complete(areq, err); } -static void aead_decrypt_done(struct device *jrdev, u32 *desc, u32 err, +static void ipsec_esp_decrypt_done(struct device *jrdev, u32 *desc, u32 err, void *context) { - struct aead_request *req = context; - struct aead_edesc *edesc; + struct aead_request *areq = context; + struct ipsec_esp_edesc *edesc; #ifdef DEBUG - struct crypto_aead *aead = crypto_aead_reqtfm(req); + struct crypto_aead *aead = crypto_aead_reqtfm(areq); struct caam_ctx *ctx = crypto_aead_ctx(aead); - int ivsize = crypto_aead_ivsize(aead); dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); #endif - - edesc = (struct aead_edesc *)((char *)desc - - offsetof(struct aead_edesc, hw_desc)); - -#ifdef DEBUG - print_hex_dump(KERN_ERR, "dstiv @"xstr(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, req->iv, - ivsize, 1); - print_hex_dump(KERN_ERR, "dst @"xstr(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->dst), - req->cryptlen, 1); -#endif + edesc = (struct ipsec_esp_edesc *)((char *)desc - + offsetof(struct ipsec_esp_edesc, hw_desc)); if (err) { char tmp[CAAM_ERROR_STR_MAX]; @@ -927,7 +484,7 @@ static void aead_decrypt_done(struct device *jrdev, u32 *desc, u32 err, dev_err(jrdev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err)); } - aead_unmap(jrdev, edesc, req); + ipsec_esp_unmap(jrdev, edesc, areq); /* * verify hw auth check passed else return -EBADMSG @@ -938,413 +495,255 @@ static void aead_decrypt_done(struct device *jrdev, u32 *desc, u32 err, #ifdef DEBUG print_hex_dump(KERN_ERR, "iphdrout@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, - ((char *)sg_virt(req->assoc) - sizeof(struct iphdr)), - sizeof(struct iphdr) + req->assoclen + - ((req->cryptlen > 1500) ? 1500 : req->cryptlen) + + ((char *)sg_virt(areq->assoc) - sizeof(struct iphdr)), + sizeof(struct iphdr) + areq->assoclen + + ((areq->cryptlen > 1500) ? 1500 : areq->cryptlen) + ctx->authsize + 36, 1); if (!err && edesc->link_tbl_bytes) { - struct scatterlist *sg = sg_last(req->src, edesc->src_nents); + struct scatterlist *sg = sg_last(areq->src, edesc->src_nents); print_hex_dump(KERN_ERR, "sglastout@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(sg), sg->length + ctx->authsize + 16, 1); } #endif - kfree(edesc); - aead_request_complete(req, err); -} - -static void ablkcipher_encrypt_done(struct device *jrdev, u32 *desc, u32 err, - void *context) -{ - struct ablkcipher_request *req = context; - struct ablkcipher_edesc *edesc; -#ifdef DEBUG - struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); - int ivsize = crypto_ablkcipher_ivsize(ablkcipher); - - dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); -#endif - - edesc = (struct ablkcipher_edesc *)((char *)desc - - offsetof(struct ablkcipher_edesc, hw_desc)); - - if (err) { - char tmp[CAAM_ERROR_STR_MAX]; - - dev_err(jrdev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err)); - } - -#ifdef DEBUG - print_hex_dump(KERN_ERR, "dstiv @"xstr(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, req->info, - edesc->src_nents > 1 ? 100 : ivsize, 1); - print_hex_dump(KERN_ERR, "dst @"xstr(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src), - edesc->dst_nents > 1 ? 100 : req->nbytes, 1); -#endif - - ablkcipher_unmap(jrdev, edesc, req); - kfree(edesc); - - ablkcipher_request_complete(req, err); -} - -static void ablkcipher_decrypt_done(struct device *jrdev, u32 *desc, u32 err, - void *context) -{ - struct ablkcipher_request *req = context; - struct ablkcipher_edesc *edesc; -#ifdef DEBUG - struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); - int ivsize = crypto_ablkcipher_ivsize(ablkcipher); - - dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); -#endif - - edesc = (struct ablkcipher_edesc *)((char *)desc - - offsetof(struct ablkcipher_edesc, hw_desc)); - if (err) { - char tmp[CAAM_ERROR_STR_MAX]; - - dev_err(jrdev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err)); - } - -#ifdef DEBUG - print_hex_dump(KERN_ERR, "dstiv @"xstr(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, req->info, - ivsize, 1); - print_hex_dump(KERN_ERR, "dst @"xstr(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src), - edesc->dst_nents > 1 ? 100 : req->nbytes, 1); -#endif - - ablkcipher_unmap(jrdev, edesc, req); - kfree(edesc); - - ablkcipher_request_complete(req, err); -} - -static void sg_to_link_tbl_one(struct link_tbl_entry *link_tbl_ptr, - dma_addr_t dma, u32 len, u32 offset) -{ - link_tbl_ptr->ptr = dma; - link_tbl_ptr->len = len; - link_tbl_ptr->reserved = 0; - link_tbl_ptr->buf_pool_id = 0; - link_tbl_ptr->offset = offset; -#ifdef DEBUG - print_hex_dump(KERN_ERR, "link_tbl_ptr@"xstr(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, link_tbl_ptr, - sizeof(struct link_tbl_entry), 1); -#endif + aead_request_complete(areq, err); } /* * convert scatterlist to h/w link table format - * but does not have final bit; instead, returns last entry + * scatterlist must have been previously dma mapped */ -static struct link_tbl_entry *sg_to_link_tbl(struct scatterlist *sg, - int sg_count, struct link_tbl_entry - *link_tbl_ptr, u32 offset) +static void sg_to_link_tbl(struct scatterlist *sg, int sg_count, + struct link_tbl_entry *link_tbl_ptr, u32 offset) { while (sg_count) { - sg_to_link_tbl_one(link_tbl_ptr, sg_dma_address(sg), - sg_dma_len(sg), offset); + link_tbl_ptr->ptr = sg_dma_address(sg); + link_tbl_ptr->len = sg_dma_len(sg); + link_tbl_ptr->reserved = 0; + link_tbl_ptr->buf_pool_id = 0; + link_tbl_ptr->offset = offset; link_tbl_ptr++; sg = sg_next(sg); sg_count--; } - return link_tbl_ptr - 1; -} - -/* - * convert scatterlist to h/w link table format - * scatterlist must have been previously dma mapped - */ -static void sg_to_link_tbl_last(struct scatterlist *sg, int sg_count, - struct link_tbl_entry *link_tbl_ptr, u32 offset) -{ - link_tbl_ptr = sg_to_link_tbl(sg, sg_count, link_tbl_ptr, offset); - link_tbl_ptr->len |= 0x40000000; -} - -/* - * Fill in aead job descriptor - */ -static void init_aead_job(u32 *sh_desc, dma_addr_t ptr, - struct aead_edesc *edesc, - struct aead_request *req, - bool all_contig, bool encrypt) -{ - struct crypto_aead *aead = crypto_aead_reqtfm(req); - struct caam_ctx *ctx = crypto_aead_ctx(aead); - int ivsize = crypto_aead_ivsize(aead); - int authsize = ctx->authsize; - u32 *desc = edesc->hw_desc; - u32 out_options = 0, in_options; - dma_addr_t dst_dma, src_dma; - int len, link_tbl_index = 0; - -#ifdef DEBUG - debug("assoclen %d cryptlen %d authsize %d\n", - req->assoclen, req->cryptlen, authsize); - print_hex_dump(KERN_ERR, "assoc @"xstr(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->assoc), - req->assoclen , 1); - print_hex_dump(KERN_ERR, "presciv@"xstr(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, req->iv, - edesc->src_nents ? 100 : ivsize, 1); - print_hex_dump(KERN_ERR, "src @"xstr(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src), - edesc->src_nents ? 100 : req->cryptlen, 1); - print_hex_dump(KERN_ERR, "shrdesc@"xstr(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, sh_desc, - desc_bytes(sh_desc), 1); -#endif - - len = desc_len(sh_desc); - init_job_desc_shared(desc, ptr, len, HDR_SHARE_DEFER | HDR_REVERSE); - - if (all_contig) { - src_dma = sg_dma_address(req->assoc); - in_options = 0; - } else { - src_dma = edesc->link_tbl_dma; - link_tbl_index += (edesc->assoc_nents ? : 1) + 1 + - (edesc->src_nents ? : 1); - in_options = LDST_SGF; - } - if (encrypt) - append_seq_in_ptr(desc, src_dma, req->assoclen + ivsize + - req->cryptlen - authsize, in_options); - else - append_seq_in_ptr(desc, src_dma, req->assoclen + ivsize + - req->cryptlen, in_options); - if (likely(req->src == req->dst)) { - if (all_contig) { - dst_dma = sg_dma_address(req->src); - } else { - dst_dma = src_dma + sizeof(struct link_tbl_entry) * - ((edesc->assoc_nents ? : 1) + 1); - out_options = LDST_SGF; - } - } else { - if (!edesc->dst_nents) { - dst_dma = sg_dma_address(req->dst); - } else { - dst_dma = edesc->link_tbl_dma + - link_tbl_index * - sizeof(struct link_tbl_entry); - out_options = LDST_SGF; - } - } - if (encrypt) - append_seq_out_ptr(desc, dst_dma, req->cryptlen, out_options); - else - append_seq_out_ptr(desc, dst_dma, req->cryptlen - authsize, - out_options); + /* set Final bit (marks end of link table) */ + link_tbl_ptr--; + link_tbl_ptr->len |= 0x40000000; } /* - * Fill in aead givencrypt job descriptor + * fill in and submit ipsec_esp job descriptor */ -static void init_aead_giv_job(u32 *sh_desc, dma_addr_t ptr, - struct aead_edesc *edesc, - struct aead_request *req, - int contig) +static int ipsec_esp(struct ipsec_esp_edesc *edesc, struct aead_request *areq, + u32 encrypt, + void (*callback) (struct device *dev, u32 *desc, + u32 err, void *context)) { - struct crypto_aead *aead = crypto_aead_reqtfm(req); + struct crypto_aead *aead = crypto_aead_reqtfm(areq); struct caam_ctx *ctx = crypto_aead_ctx(aead); + struct device *jrdev = ctx->jrdev; + u32 *desc = edesc->hw_desc, options; + int ret, sg_count, assoc_sg_count; int ivsize = crypto_aead_ivsize(aead); int authsize = ctx->authsize; - u32 *desc = edesc->hw_desc; - u32 out_options = 0, in_options; - dma_addr_t dst_dma, src_dma; - int len, link_tbl_index = 0; - + dma_addr_t ptr, dst_dma, src_dma; #ifdef DEBUG + u32 *sh_desc = ctx->sh_desc; + debug("assoclen %d cryptlen %d authsize %d\n", - req->assoclen, req->cryptlen, authsize); + areq->assoclen, areq->cryptlen, authsize); print_hex_dump(KERN_ERR, "assoc @"xstr(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->assoc), - req->assoclen , 1); + DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(areq->assoc), + areq->assoclen , 1); print_hex_dump(KERN_ERR, "presciv@"xstr(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, req->iv, ivsize, 1); + DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(areq->src) - ivsize, + edesc->src_nents ? 100 : ivsize, 1); print_hex_dump(KERN_ERR, "src @"xstr(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src), - edesc->src_nents > 1 ? 100 : req->cryptlen, 1); + DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(areq->src), + edesc->src_nents ? 100 : areq->cryptlen + authsize, 1); print_hex_dump(KERN_ERR, "shrdesc@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, sh_desc, desc_bytes(sh_desc), 1); #endif + assoc_sg_count = dma_map_sg(jrdev, areq->assoc, edesc->assoc_nents ?: 1, + DMA_TO_DEVICE); + if (areq->src == areq->dst) + sg_count = dma_map_sg(jrdev, areq->src, edesc->src_nents ? : 1, + DMA_BIDIRECTIONAL); + else + sg_count = dma_map_sg(jrdev, areq->src, edesc->src_nents ? : 1, + DMA_TO_DEVICE); - len = desc_len(sh_desc); - init_job_desc_shared(desc, ptr, len, HDR_SHARE_DEFER | HDR_REVERSE); + /* start auth operation */ + append_operation(desc, ctx->class2_alg_type | OP_ALG_AS_INITFINAL | + (encrypt ? : OP_ALG_ICV_ON)); - if (contig & GIV_SRC_CONTIG) { - src_dma = sg_dma_address(req->assoc); - in_options = 0; + /* Load FIFO with data for Class 2 CHA */ + options = FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_MSG; + if (!edesc->assoc_nents) { + ptr = sg_dma_address(areq->assoc); } else { - src_dma = edesc->link_tbl_dma; - link_tbl_index += edesc->assoc_nents + 1 + edesc->src_nents; - in_options = LDST_SGF; + sg_to_link_tbl(areq->assoc, edesc->assoc_nents, + edesc->link_tbl, 0); + ptr = edesc->link_tbl_dma; + options |= LDST_SGF; } - append_seq_in_ptr(desc, src_dma, req->assoclen + ivsize + - req->cryptlen - authsize, in_options); + append_fifo_load(desc, ptr, areq->assoclen, options); - if (contig & GIV_DST_CONTIG) { - dst_dma = edesc->iv_dma; - } else { - if (likely(req->src == req->dst)) { - dst_dma = src_dma + sizeof(struct link_tbl_entry) * - edesc->assoc_nents; - out_options = LDST_SGF; - } else { - dst_dma = edesc->link_tbl_dma + - link_tbl_index * - sizeof(struct link_tbl_entry); - out_options = LDST_SGF; - } - } + /* copy iv from cipher/class1 input context to class2 infifo */ + append_move(desc, MOVE_SRC_CLASS1CTX | MOVE_DEST_CLASS2INFIFO | ivsize); - append_seq_out_ptr(desc, dst_dma, ivsize + req->cryptlen, out_options); -} + if (!encrypt) { + u32 *jump_cmd, *uncond_jump_cmd; -/* - * Fill in ablkcipher job descriptor - */ -static void init_ablkcipher_job(u32 *sh_desc, dma_addr_t ptr, - struct ablkcipher_edesc *edesc, - struct ablkcipher_request *req, - bool iv_contig) -{ - struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); - int ivsize = crypto_ablkcipher_ivsize(ablkcipher); - u32 *desc = edesc->hw_desc; - u32 out_options = 0, in_options; - dma_addr_t dst_dma, src_dma; - int len, link_tbl_index = 0; + /* JUMP if shared */ + jump_cmd = append_jump(desc, JUMP_TEST_ALL | JUMP_COND_SHRD); -#ifdef DEBUG - print_hex_dump(KERN_ERR, "presciv@"xstr(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, req->info, - ivsize, 1); - print_hex_dump(KERN_ERR, "src @"xstr(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src), - edesc->src_nents ? 100 : req->nbytes, 1); -#endif + /* start class 1 (cipher) operation, non-shared version */ + append_operation(desc, ctx->class1_alg_type | + OP_ALG_AS_INITFINAL); + + uncond_jump_cmd = append_jump(desc, 0); + + set_jump_tgt_here(desc, jump_cmd); - len = desc_len(sh_desc); - init_job_desc_shared(desc, ptr, len, HDR_SHARE_DEFER | HDR_REVERSE); + /* start class 1 (cipher) operation, shared version */ + append_operation(desc, ctx->class1_alg_type | + OP_ALG_AS_INITFINAL | OP_ALG_AAI_DK); + set_jump_tgt_here(desc, uncond_jump_cmd); + } else + append_operation(desc, ctx->class1_alg_type | + OP_ALG_AS_INITFINAL | encrypt); - if (iv_contig) { - src_dma = edesc->iv_dma; - in_options = 0; + /* load payload & instruct to class2 to snoop class 1 if encrypting */ + options = 0; + if (!edesc->src_nents) { + src_dma = sg_dma_address(areq->src); } else { - src_dma = edesc->link_tbl_dma; - link_tbl_index += (iv_contig ? 0 : 1) + edesc->src_nents; - in_options = LDST_SGF; + sg_to_link_tbl(areq->src, edesc->src_nents, edesc->link_tbl + + edesc->assoc_nents, 0); + src_dma = edesc->link_tbl_dma + edesc->assoc_nents * + sizeof(struct link_tbl_entry); + options |= LDST_SGF; } - append_seq_in_ptr(desc, src_dma, req->nbytes + ivsize, in_options); - - if (likely(req->src == req->dst)) { - if (!edesc->src_nents && iv_contig) { - dst_dma = sg_dma_address(req->src); - } else { - dst_dma = edesc->link_tbl_dma + - sizeof(struct link_tbl_entry); - out_options = LDST_SGF; - } + append_seq_in_ptr(desc, src_dma, areq->cryptlen + authsize, options); + append_seq_fifo_load(desc, areq->cryptlen, FIFOLD_CLASS_BOTH | + FIFOLD_TYPE_LASTBOTH | + (encrypt ? FIFOLD_TYPE_MSG1OUT2 + : FIFOLD_TYPE_MSG)); + + /* specify destination */ + if (areq->src == areq->dst) { + dst_dma = src_dma; } else { + sg_count = dma_map_sg(jrdev, areq->dst, edesc->dst_nents ? : 1, + DMA_FROM_DEVICE); if (!edesc->dst_nents) { - dst_dma = sg_dma_address(req->dst); + dst_dma = sg_dma_address(areq->dst); + options = 0; } else { - dst_dma = edesc->link_tbl_dma + - link_tbl_index * sizeof(struct link_tbl_entry); - out_options = LDST_SGF; + sg_to_link_tbl(areq->dst, edesc->dst_nents, + edesc->link_tbl + edesc->assoc_nents + + edesc->src_nents, 0); + dst_dma = edesc->link_tbl_dma + (edesc->assoc_nents + + edesc->src_nents) * + sizeof(struct link_tbl_entry); + options = LDST_SGF; } } - append_seq_out_ptr(desc, dst_dma, req->nbytes, out_options); + append_seq_out_ptr(desc, dst_dma, areq->cryptlen + authsize, options); + append_seq_fifo_store(desc, areq->cryptlen, FIFOST_TYPE_MESSAGE_DATA); + + /* ICV */ + if (encrypt) + append_seq_store(desc, authsize, LDST_CLASS_2_CCB | + LDST_SRCDST_BYTE_CONTEXT); + else + append_seq_fifo_load(desc, authsize, FIFOLD_CLASS_CLASS2 | + FIFOLD_TYPE_LAST2 | FIFOLD_TYPE_ICV); + +#ifdef DEBUG + debug("job_desc_len %d\n", desc_len(desc)); + print_hex_dump(KERN_ERR, "jobdesc@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc) , 1); + print_hex_dump(KERN_ERR, "jdlinkt@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, edesc->link_tbl, + edesc->link_tbl_bytes, 1); +#endif + + ret = caam_jr_enqueue(jrdev, desc, callback, areq); + if (!ret) + ret = -EINPROGRESS; + else { + ipsec_esp_unmap(jrdev, edesc, areq); + kfree(edesc); + } + + return ret; } /* * derive number of elements in scatterlist */ -static int sg_count(struct scatterlist *sg_list, int nbytes) +static int sg_count(struct scatterlist *sg_list, int nbytes, int *chained) { struct scatterlist *sg = sg_list; int sg_nents = 0; + *chained = 0; while (nbytes > 0) { sg_nents++; nbytes -= sg->length; if (!sg_is_last(sg) && (sg + 1)->length == 0) - BUG(); /* Not support chaining */ + *chained = 1; sg = scatterwalk_sg_next(sg); } - if (likely(sg_nents == 1)) - return 0; - return sg_nents; } /* - * allocate and map the aead extended descriptor + * allocate and map the ipsec_esp extended descriptor */ -static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, - int desc_bytes, bool *all_contig_ptr) +static struct ipsec_esp_edesc *ipsec_esp_edesc_alloc(struct aead_request *areq, + int desc_bytes) { - struct crypto_aead *aead = crypto_aead_reqtfm(req); + struct crypto_aead *aead = crypto_aead_reqtfm(areq); struct caam_ctx *ctx = crypto_aead_ctx(aead); struct device *jrdev = ctx->jrdev; - gfp_t flags = (req->base.flags & (CRYPTO_TFM_REQ_MAY_BACKLOG | - CRYPTO_TFM_REQ_MAY_SLEEP)) ? GFP_KERNEL : GFP_ATOMIC; - int assoc_nents, src_nents, dst_nents = 0; - struct aead_edesc *edesc; - dma_addr_t iv_dma = 0; - int sgc; - bool all_contig = true; - int ivsize = crypto_aead_ivsize(aead); - int link_tbl_index, link_tbl_len = 0, link_tbl_bytes; - - assoc_nents = sg_count(req->assoc, req->assoclen); - src_nents = sg_count(req->src, req->cryptlen); - - if (unlikely(req->dst != req->src)) - dst_nents = sg_count(req->dst, req->cryptlen); - - sgc = dma_map_sg(jrdev, req->assoc, assoc_nents ? : 1, - DMA_BIDIRECTIONAL); - if (likely(req->src == req->dst)) { - sgc = dma_map_sg(jrdev, req->src, src_nents ? : 1, - DMA_BIDIRECTIONAL); - } else { - sgc = dma_map_sg(jrdev, req->src, src_nents ? : 1, - DMA_TO_DEVICE); - sgc = dma_map_sg(jrdev, req->dst, dst_nents ? : 1, - DMA_FROM_DEVICE); - } - - /* Check if data are contiguous */ - iv_dma = dma_map_single(jrdev, req->iv, ivsize, DMA_TO_DEVICE); - if (assoc_nents || sg_dma_address(req->assoc) + req->assoclen != - iv_dma || src_nents || iv_dma + ivsize != - sg_dma_address(req->src)) { - all_contig = false; - assoc_nents = assoc_nents ? : 1; - src_nents = src_nents ? : 1; - link_tbl_len = assoc_nents + 1 + src_nents; + gfp_t flags = areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL : + GFP_ATOMIC; + int assoc_nents, src_nents, dst_nents = 0, chained, link_tbl_bytes; + struct ipsec_esp_edesc *edesc; + + assoc_nents = sg_count(areq->assoc, areq->assoclen, &chained); + BUG_ON(chained); + if (likely(assoc_nents == 1)) + assoc_nents = 0; + + src_nents = sg_count(areq->src, areq->cryptlen + ctx->authsize, + &chained); + BUG_ON(chained); + if (src_nents == 1) + src_nents = 0; + + if (unlikely(areq->dst != areq->src)) { + dst_nents = sg_count(areq->dst, areq->cryptlen + ctx->authsize, + &chained); + BUG_ON(chained); + if (dst_nents == 1) + dst_nents = 0; } - link_tbl_len += dst_nents; - link_tbl_bytes = link_tbl_len * sizeof(struct link_tbl_entry); + link_tbl_bytes = (assoc_nents + src_nents + dst_nents) * + sizeof(struct link_tbl_entry); + debug("link_tbl_bytes %d\n", link_tbl_bytes); /* allocate space for base edesc and hw desc commands, link tables */ - edesc = kmalloc(sizeof(struct aead_edesc) + desc_bytes + + edesc = kmalloc(sizeof(struct ipsec_esp_edesc) + desc_bytes + link_tbl_bytes, GFP_DMA | flags); if (!edesc) { dev_err(jrdev, "could not allocate extended descriptor\n"); @@ -1354,450 +753,142 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, edesc->assoc_nents = assoc_nents; edesc->src_nents = src_nents; edesc->dst_nents = dst_nents; - edesc->iv_dma = iv_dma; - edesc->link_tbl_bytes = link_tbl_bytes; - edesc->link_tbl = (void *)edesc + sizeof(struct aead_edesc) + + edesc->link_tbl = (void *)edesc + sizeof(struct ipsec_esp_edesc) + desc_bytes; edesc->link_tbl_dma = dma_map_single(jrdev, edesc->link_tbl, link_tbl_bytes, DMA_TO_DEVICE); - *all_contig_ptr = all_contig; - - link_tbl_index = 0; - if (!all_contig) { - sg_to_link_tbl(req->assoc, - (assoc_nents ? : 1), - edesc->link_tbl + - link_tbl_index, 0); - link_tbl_index += assoc_nents ? : 1; - sg_to_link_tbl_one(edesc->link_tbl + link_tbl_index, - iv_dma, ivsize, 0); - link_tbl_index += 1; - sg_to_link_tbl_last(req->src, - (src_nents ? : 1), - edesc->link_tbl + - link_tbl_index, 0); - link_tbl_index += src_nents ? : 1; - } - if (dst_nents) { - sg_to_link_tbl_last(req->dst, dst_nents, - edesc->link_tbl + link_tbl_index, 0); - } + edesc->link_tbl_bytes = link_tbl_bytes; return edesc; } -static int aead_encrypt(struct aead_request *req) +static int aead_authenc_encrypt(struct aead_request *areq) { - struct aead_edesc *edesc; - struct crypto_aead *aead = crypto_aead_reqtfm(req); + struct ipsec_esp_edesc *edesc; + struct crypto_aead *aead = crypto_aead_reqtfm(areq); struct caam_ctx *ctx = crypto_aead_ctx(aead); struct device *jrdev = ctx->jrdev; - bool all_contig; + int ivsize = crypto_aead_ivsize(aead); u32 *desc; - int ret = 0; - - req->cryptlen += ctx->authsize; + dma_addr_t iv_dma; /* allocate extended descriptor */ - edesc = aead_edesc_alloc(req, DESC_JOB_IO_LEN * - CAAM_CMD_SZ, &all_contig); + edesc = ipsec_esp_edesc_alloc(areq, DESC_AEAD_ENCRYPT_TEXT_LEN * + CAAM_CMD_SZ); if (IS_ERR(edesc)) return PTR_ERR(edesc); - /* Create and submit job descriptor */ - init_aead_job(ctx->sh_desc_enc, ctx->sh_desc_enc_dma, edesc, req, - all_contig, true); -#ifdef DEBUG - print_hex_dump(KERN_ERR, "aead jobdesc@"xstr(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc, - desc_bytes(edesc->hw_desc), 1); -#endif - desc = edesc->hw_desc; - ret = caam_jr_enqueue(jrdev, desc, aead_encrypt_done, req); - if (!ret) { - ret = -EINPROGRESS; - } else { - aead_unmap(jrdev, edesc, req); - kfree(edesc); - } - - return ret; -} - -static int aead_decrypt(struct aead_request *req) -{ - struct aead_edesc *edesc; - struct crypto_aead *aead = crypto_aead_reqtfm(req); - struct caam_ctx *ctx = crypto_aead_ctx(aead); - struct device *jrdev = ctx->jrdev; - bool all_contig; - u32 *desc; - int ret = 0; - - /* allocate extended descriptor */ - edesc = aead_edesc_alloc(req, DESC_JOB_IO_LEN * - CAAM_CMD_SZ, &all_contig); - if (IS_ERR(edesc)) - return PTR_ERR(edesc); -#ifdef DEBUG - print_hex_dump(KERN_ERR, "dec src@"xstr(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src), - req->cryptlen, 1); -#endif + /* insert shared descriptor pointer */ + init_job_desc_shared(desc, ctx->shared_desc_phys, + desc_len(ctx->sh_desc), HDR_SHARE_DEFER); - /* Create and submit job descriptor*/ - init_aead_job(ctx->sh_desc_dec, - ctx->sh_desc_dec_dma, edesc, req, all_contig, false); -#ifdef DEBUG - print_hex_dump(KERN_ERR, "aead jobdesc@"xstr(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc, - desc_bytes(edesc->hw_desc), 1); -#endif + iv_dma = dma_map_single(jrdev, areq->iv, ivsize, DMA_TO_DEVICE); + /* check dma error */ - desc = edesc->hw_desc; - ret = caam_jr_enqueue(jrdev, desc, aead_decrypt_done, req); - if (!ret) { - ret = -EINPROGRESS; - } else { - aead_unmap(jrdev, edesc, req); - kfree(edesc); - } + append_load(desc, iv_dma, ivsize, + LDST_CLASS_1_CCB | LDST_SRCDST_BYTE_CONTEXT); - return ret; + return ipsec_esp(edesc, areq, OP_ALG_ENCRYPT, ipsec_esp_encrypt_done); } -/* - * allocate and map the aead extended descriptor for aead givencrypt - */ -static struct aead_edesc *aead_giv_edesc_alloc(struct aead_givcrypt_request - *greq, int desc_bytes, - u32 *contig_ptr) +static int aead_authenc_decrypt(struct aead_request *req) { - struct aead_request *req = &greq->areq; struct crypto_aead *aead = crypto_aead_reqtfm(req); - struct caam_ctx *ctx = crypto_aead_ctx(aead); - struct device *jrdev = ctx->jrdev; - gfp_t flags = (req->base.flags & (CRYPTO_TFM_REQ_MAY_BACKLOG | - CRYPTO_TFM_REQ_MAY_SLEEP)) ? GFP_KERNEL : GFP_ATOMIC; - int assoc_nents, src_nents, dst_nents = 0; - struct aead_edesc *edesc; - dma_addr_t iv_dma = 0; - int sgc; - u32 contig = GIV_SRC_CONTIG | GIV_DST_CONTIG; int ivsize = crypto_aead_ivsize(aead); - int link_tbl_index, link_tbl_len = 0, link_tbl_bytes; - - assoc_nents = sg_count(req->assoc, req->assoclen); - src_nents = sg_count(req->src, req->cryptlen); - - if (unlikely(req->dst != req->src)) - dst_nents = sg_count(req->dst, req->cryptlen); - - sgc = dma_map_sg(jrdev, req->assoc, assoc_nents ? : 1, - DMA_BIDIRECTIONAL); - if (likely(req->src == req->dst)) { - sgc = dma_map_sg(jrdev, req->src, src_nents ? : 1, - DMA_BIDIRECTIONAL); - } else { - sgc = dma_map_sg(jrdev, req->src, src_nents ? : 1, - DMA_TO_DEVICE); - sgc = dma_map_sg(jrdev, req->dst, dst_nents ? : 1, - DMA_FROM_DEVICE); - } - - /* Check if data are contiguous */ - iv_dma = dma_map_single(jrdev, greq->giv, ivsize, DMA_TO_DEVICE); - if (assoc_nents || sg_dma_address(req->assoc) + req->assoclen != - iv_dma || src_nents || iv_dma + ivsize != sg_dma_address(req->src)) - contig &= ~GIV_SRC_CONTIG; - if (dst_nents || iv_dma + ivsize != sg_dma_address(req->dst)) - contig &= ~GIV_DST_CONTIG; - if (unlikely(req->src != req->dst)) { - dst_nents = dst_nents ? : 1; - link_tbl_len += 1; - } - if (!(contig & GIV_SRC_CONTIG)) { - assoc_nents = assoc_nents ? : 1; - src_nents = src_nents ? : 1; - link_tbl_len += assoc_nents + 1 + src_nents; - if (likely(req->src == req->dst)) - contig &= ~GIV_DST_CONTIG; - } - link_tbl_len += dst_nents; - - link_tbl_bytes = link_tbl_len * sizeof(struct link_tbl_entry); - - /* allocate space for base edesc and hw desc commands, link tables */ - edesc = kmalloc(sizeof(struct aead_edesc) + desc_bytes + - link_tbl_bytes, GFP_DMA | flags); - if (!edesc) { - dev_err(jrdev, "could not allocate extended descriptor\n"); - return ERR_PTR(-ENOMEM); - } - - edesc->assoc_nents = assoc_nents; - edesc->src_nents = src_nents; - edesc->dst_nents = dst_nents; - edesc->iv_dma = iv_dma; - edesc->link_tbl_bytes = link_tbl_bytes; - edesc->link_tbl = (void *)edesc + sizeof(struct aead_edesc) + - desc_bytes; - edesc->link_tbl_dma = dma_map_single(jrdev, edesc->link_tbl, - link_tbl_bytes, DMA_TO_DEVICE); - *contig_ptr = contig; - - link_tbl_index = 0; - if (!(contig & GIV_SRC_CONTIG)) { - sg_to_link_tbl(req->assoc, assoc_nents, - edesc->link_tbl + - link_tbl_index, 0); - link_tbl_index += assoc_nents; - sg_to_link_tbl_one(edesc->link_tbl + link_tbl_index, - iv_dma, ivsize, 0); - link_tbl_index += 1; - sg_to_link_tbl_last(req->src, src_nents, - edesc->link_tbl + - link_tbl_index, 0); - link_tbl_index += src_nents; - } - if (unlikely(req->src != req->dst && !(contig & GIV_DST_CONTIG))) { - sg_to_link_tbl_one(edesc->link_tbl + link_tbl_index, - iv_dma, ivsize, 0); - link_tbl_index += 1; - sg_to_link_tbl_last(req->dst, dst_nents, - edesc->link_tbl + link_tbl_index, 0); - } - - return edesc; -} - -static int aead_givencrypt(struct aead_givcrypt_request *areq) -{ - struct aead_request *req = &areq->areq; - struct aead_edesc *edesc; - struct crypto_aead *aead = crypto_aead_reqtfm(req); struct caam_ctx *ctx = crypto_aead_ctx(aead); struct device *jrdev = ctx->jrdev; - u32 contig; + struct ipsec_esp_edesc *edesc; u32 *desc; - int ret = 0; + dma_addr_t iv_dma; - req->cryptlen += ctx->authsize; + req->cryptlen -= ctx->authsize; /* allocate extended descriptor */ - edesc = aead_giv_edesc_alloc(areq, DESC_JOB_IO_LEN * - CAAM_CMD_SZ, &contig); - + edesc = ipsec_esp_edesc_alloc(req, DESC_AEAD_DECRYPT_TEXT_LEN * + CAAM_CMD_SZ); if (IS_ERR(edesc)) return PTR_ERR(edesc); -#ifdef DEBUG - print_hex_dump(KERN_ERR, "giv src@"xstr(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src), - req->cryptlen, 1); -#endif - - /* Create and submit job descriptor*/ - init_aead_giv_job(ctx->sh_desc_givenc, - ctx->sh_desc_givenc_dma, edesc, req, contig); -#ifdef DEBUG - print_hex_dump(KERN_ERR, "aead jobdesc@"xstr(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc, - desc_bytes(edesc->hw_desc), 1); -#endif - desc = edesc->hw_desc; - ret = caam_jr_enqueue(jrdev, desc, aead_encrypt_done, req); - if (!ret) { - ret = -EINPROGRESS; - } else { - aead_unmap(jrdev, edesc, req); - kfree(edesc); - } - return ret; -} - -/* - * allocate and map the ablkcipher extended descriptor for ablkcipher - */ -static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request - *req, int desc_bytes, - bool *iv_contig_out) -{ - struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); - struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); - struct device *jrdev = ctx->jrdev; - gfp_t flags = (req->base.flags & (CRYPTO_TFM_REQ_MAY_BACKLOG | - CRYPTO_TFM_REQ_MAY_SLEEP)) ? - GFP_KERNEL : GFP_ATOMIC; - int src_nents, dst_nents = 0, link_tbl_bytes; - struct ablkcipher_edesc *edesc; - dma_addr_t iv_dma = 0; - bool iv_contig = false; - int sgc; - int ivsize = crypto_ablkcipher_ivsize(ablkcipher); - int link_tbl_index; - - src_nents = sg_count(req->src, req->nbytes); - - if (unlikely(req->dst != req->src)) - dst_nents = sg_count(req->dst, req->nbytes); - - if (likely(req->src == req->dst)) { - sgc = dma_map_sg(jrdev, req->src, src_nents ? : 1, - DMA_BIDIRECTIONAL); - } else { - sgc = dma_map_sg(jrdev, req->src, src_nents ? : 1, - DMA_TO_DEVICE); - sgc = dma_map_sg(jrdev, req->dst, dst_nents ? : 1, - DMA_FROM_DEVICE); - } - - /* - * Check if iv can be contiguous with source and destination. - * If so, include it. If not, create scatterlist. - */ - iv_dma = dma_map_single(jrdev, req->info, ivsize, DMA_TO_DEVICE); - if (!src_nents && iv_dma + ivsize == sg_dma_address(req->src)) - iv_contig = true; - else - src_nents = src_nents ? : 1; - link_tbl_bytes = ((iv_contig ? 0 : 1) + src_nents + dst_nents) * - sizeof(struct link_tbl_entry); - - /* allocate space for base edesc and hw desc commands, link tables */ - edesc = kmalloc(sizeof(struct ablkcipher_edesc) + desc_bytes + - link_tbl_bytes, GFP_DMA | flags); - if (!edesc) { - dev_err(jrdev, "could not allocate extended descriptor\n"); - return ERR_PTR(-ENOMEM); - } - - edesc->src_nents = src_nents; - edesc->dst_nents = dst_nents; - edesc->link_tbl_bytes = link_tbl_bytes; - edesc->link_tbl = (void *)edesc + sizeof(struct ablkcipher_edesc) + - desc_bytes; - - link_tbl_index = 0; - if (!iv_contig) { - sg_to_link_tbl_one(edesc->link_tbl, iv_dma, ivsize, 0); - sg_to_link_tbl_last(req->src, src_nents, - edesc->link_tbl + 1, 0); - link_tbl_index += 1 + src_nents; - } - - if (unlikely(dst_nents)) { - sg_to_link_tbl_last(req->dst, dst_nents, - edesc->link_tbl + link_tbl_index, 0); - } + /* insert shared descriptor pointer */ + init_job_desc_shared(desc, ctx->shared_desc_phys, + desc_len(ctx->sh_desc), HDR_SHARE_DEFER); - edesc->link_tbl_dma = dma_map_single(jrdev, edesc->link_tbl, - link_tbl_bytes, DMA_TO_DEVICE); - edesc->iv_dma = iv_dma; + iv_dma = dma_map_single(jrdev, req->iv, ivsize, DMA_TO_DEVICE); + /* check dma error */ -#ifdef DEBUG - print_hex_dump(KERN_ERR, "ablkcipher link_tbl@"xstr(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, edesc->link_tbl, - link_tbl_bytes, 1); -#endif + append_load(desc, iv_dma, ivsize, + LDST_CLASS_1_CCB | LDST_SRCDST_BYTE_CONTEXT); - *iv_contig_out = iv_contig; - return edesc; + return ipsec_esp(edesc, req, !OP_ALG_ENCRYPT, ipsec_esp_decrypt_done); } -static int ablkcipher_encrypt(struct ablkcipher_request *req) +static int aead_authenc_givencrypt(struct aead_givcrypt_request *req) { - struct ablkcipher_edesc *edesc; - struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); - struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); + struct aead_request *areq = &req->areq; + struct ipsec_esp_edesc *edesc; + struct crypto_aead *aead = crypto_aead_reqtfm(areq); + struct caam_ctx *ctx = crypto_aead_ctx(aead); struct device *jrdev = ctx->jrdev; - bool iv_contig; + int ivsize = crypto_aead_ivsize(aead); + dma_addr_t iv_dma; u32 *desc; - int ret = 0; + + iv_dma = dma_map_single(jrdev, req->giv, ivsize, DMA_FROM_DEVICE); + + debug("%s: giv %p\n", __func__, req->giv); /* allocate extended descriptor */ - edesc = ablkcipher_edesc_alloc(req, DESC_JOB_IO_LEN * - CAAM_CMD_SZ, &iv_contig); + edesc = ipsec_esp_edesc_alloc(areq, DESC_AEAD_GIVENCRYPT_TEXT_LEN * + CAAM_CMD_SZ); if (IS_ERR(edesc)) return PTR_ERR(edesc); - /* Create and submit job descriptor*/ - init_ablkcipher_job(ctx->sh_desc_enc, - ctx->sh_desc_enc_dma, edesc, req, iv_contig); -#ifdef DEBUG - print_hex_dump(KERN_ERR, "ablkcipher jobdesc@"xstr(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc, - desc_bytes(edesc->hw_desc), 1); -#endif desc = edesc->hw_desc; - ret = caam_jr_enqueue(jrdev, desc, ablkcipher_encrypt_done, req); - if (!ret) { - ret = -EINPROGRESS; - } else { - ablkcipher_unmap(jrdev, edesc, req); - kfree(edesc); - } + /* insert shared descriptor pointer */ + init_job_desc_shared(desc, ctx->shared_desc_phys, + desc_len(ctx->sh_desc), HDR_SHARE_DEFER); - return ret; -} + /* + * LOAD IMM Info FIFO + * to DECO, Last, Padding, Random, Message, 16 bytes + */ + append_load_imm_u32(desc, NFIFOENTRY_DEST_DECO | NFIFOENTRY_LC1 | + NFIFOENTRY_STYPE_PAD | NFIFOENTRY_DTYPE_MSG | + NFIFOENTRY_PTYPE_RND | ivsize, + LDST_SRCDST_WORD_INFO_FIFO); -static int ablkcipher_decrypt(struct ablkcipher_request *req) -{ - struct ablkcipher_edesc *edesc; - struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); - struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); - struct device *jrdev = ctx->jrdev; - bool iv_contig; - u32 *desc; - int ret = 0; + /* + * disable info fifo entries since the above serves as the entry + * this way, the MOVE command won't generate an entry. + * Note that this isn't required in more recent versions of + * SEC as a MOVE that doesn't do info FIFO entries is available. + */ + append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); - /* allocate extended descriptor */ - edesc = ablkcipher_edesc_alloc(req, DESC_JOB_IO_LEN * - CAAM_CMD_SZ, &iv_contig); - if (IS_ERR(edesc)) - return PTR_ERR(edesc); + /* MOVE DECO Alignment -> C1 Context 16 bytes */ + append_move(desc, MOVE_SRC_INFIFO | MOVE_DEST_CLASS1CTX | ivsize); - /* Create and submit job descriptor*/ - init_ablkcipher_job(ctx->sh_desc_dec, - ctx->sh_desc_dec_dma, edesc, req, iv_contig); - desc = edesc->hw_desc; -#ifdef DEBUG - print_hex_dump(KERN_ERR, "ablkcipher jobdesc@"xstr(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc, - desc_bytes(edesc->hw_desc), 1); -#endif + /* re-enable info fifo entries */ + append_cmd(desc, CMD_LOAD | ENABLE_AUTO_INFO_FIFO); - ret = caam_jr_enqueue(jrdev, desc, ablkcipher_decrypt_done, req); - if (!ret) { - ret = -EINPROGRESS; - } else { - ablkcipher_unmap(jrdev, edesc, req); - kfree(edesc); - } + /* MOVE C1 Context -> OFIFO 16 bytes */ + append_move(desc, MOVE_SRC_CLASS1CTX | MOVE_DEST_OUTFIFO | ivsize); - return ret; + append_fifo_store(desc, iv_dma, ivsize, FIFOST_TYPE_MESSAGE_DATA); + + return ipsec_esp(edesc, areq, OP_ALG_ENCRYPT, ipsec_esp_encrypt_done); } -#define template_aead template_u.aead -#define template_ablkcipher template_u.ablkcipher struct caam_alg_template { char name[CRYPTO_MAX_ALG_NAME]; char driver_name[CRYPTO_MAX_ALG_NAME]; unsigned int blocksize; - u32 type; - union { - struct ablkcipher_alg ablkcipher; - struct aead_alg aead; - struct blkcipher_alg blkcipher; - struct cipher_alg cipher; - struct compress_alg compress; - struct rng_alg rng; - } template_u; + struct aead_alg aead; u32 class1_alg_type; u32 class2_alg_type; u32 alg_op; @@ -1809,13 +900,12 @@ static struct caam_alg_template driver_algs[] = { .name = "authenc(hmac(sha1),cbc(aes))", .driver_name = "authenc-hmac-sha1-cbc-aes-caam", .blocksize = AES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = aead_setkey, - .setauthsize = aead_setauthsize, - .encrypt = aead_encrypt, - .decrypt = aead_decrypt, - .givencrypt = aead_givencrypt, + .aead = { + .setkey = aead_authenc_setkey, + .setauthsize = aead_authenc_setauthsize, + .encrypt = aead_authenc_encrypt, + .decrypt = aead_authenc_decrypt, + .givencrypt = aead_authenc_givencrypt, .geniv = "", .ivsize = AES_BLOCK_SIZE, .maxauthsize = SHA1_DIGEST_SIZE, @@ -1828,13 +918,12 @@ static struct caam_alg_template driver_algs[] = { .name = "authenc(hmac(sha256),cbc(aes))", .driver_name = "authenc-hmac-sha256-cbc-aes-caam", .blocksize = AES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = aead_setkey, - .setauthsize = aead_setauthsize, - .encrypt = aead_encrypt, - .decrypt = aead_decrypt, - .givencrypt = aead_givencrypt, + .aead = { + .setkey = aead_authenc_setkey, + .setauthsize = aead_authenc_setauthsize, + .encrypt = aead_authenc_encrypt, + .decrypt = aead_authenc_decrypt, + .givencrypt = aead_authenc_givencrypt, .geniv = "", .ivsize = AES_BLOCK_SIZE, .maxauthsize = SHA256_DIGEST_SIZE, @@ -1848,13 +937,12 @@ static struct caam_alg_template driver_algs[] = { .name = "authenc(hmac(sha512),cbc(aes))", .driver_name = "authenc-hmac-sha512-cbc-aes-caam", .blocksize = AES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = aead_setkey, - .setauthsize = aead_setauthsize, - .encrypt = aead_encrypt, - .decrypt = aead_decrypt, - .givencrypt = aead_givencrypt, + .aead = { + .setkey = aead_authenc_setkey, + .setauthsize = aead_authenc_setauthsize, + .encrypt = aead_authenc_encrypt, + .decrypt = aead_authenc_decrypt, + .givencrypt = aead_authenc_givencrypt, .geniv = "", .ivsize = AES_BLOCK_SIZE, .maxauthsize = SHA512_DIGEST_SIZE, @@ -1868,13 +956,12 @@ static struct caam_alg_template driver_algs[] = { .name = "authenc(hmac(sha1),cbc(des3_ede))", .driver_name = "authenc-hmac-sha1-cbc-des3_ede-caam", .blocksize = DES3_EDE_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = aead_setkey, - .setauthsize = aead_setauthsize, - .encrypt = aead_encrypt, - .decrypt = aead_decrypt, - .givencrypt = aead_givencrypt, + .aead = { + .setkey = aead_authenc_setkey, + .setauthsize = aead_authenc_setauthsize, + .encrypt = aead_authenc_encrypt, + .decrypt = aead_authenc_decrypt, + .givencrypt = aead_authenc_givencrypt, .geniv = "", .ivsize = DES3_EDE_BLOCK_SIZE, .maxauthsize = SHA1_DIGEST_SIZE, @@ -1887,13 +974,12 @@ static struct caam_alg_template driver_algs[] = { .name = "authenc(hmac(sha256),cbc(des3_ede))", .driver_name = "authenc-hmac-sha256-cbc-des3_ede-caam", .blocksize = DES3_EDE_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = aead_setkey, - .setauthsize = aead_setauthsize, - .encrypt = aead_encrypt, - .decrypt = aead_decrypt, - .givencrypt = aead_givencrypt, + .aead = { + .setkey = aead_authenc_setkey, + .setauthsize = aead_authenc_setauthsize, + .encrypt = aead_authenc_encrypt, + .decrypt = aead_authenc_decrypt, + .givencrypt = aead_authenc_givencrypt, .geniv = "", .ivsize = DES3_EDE_BLOCK_SIZE, .maxauthsize = SHA256_DIGEST_SIZE, @@ -1907,13 +993,12 @@ static struct caam_alg_template driver_algs[] = { .name = "authenc(hmac(sha512),cbc(des3_ede))", .driver_name = "authenc-hmac-sha512-cbc-des3_ede-caam", .blocksize = DES3_EDE_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = aead_setkey, - .setauthsize = aead_setauthsize, - .encrypt = aead_encrypt, - .decrypt = aead_decrypt, - .givencrypt = aead_givencrypt, + .aead = { + .setkey = aead_authenc_setkey, + .setauthsize = aead_authenc_setauthsize, + .encrypt = aead_authenc_encrypt, + .decrypt = aead_authenc_decrypt, + .givencrypt = aead_authenc_givencrypt, .geniv = "", .ivsize = DES3_EDE_BLOCK_SIZE, .maxauthsize = SHA512_DIGEST_SIZE, @@ -1927,13 +1012,12 @@ static struct caam_alg_template driver_algs[] = { .name = "authenc(hmac(sha1),cbc(des))", .driver_name = "authenc-hmac-sha1-cbc-des-caam", .blocksize = DES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = aead_setkey, - .setauthsize = aead_setauthsize, - .encrypt = aead_encrypt, - .decrypt = aead_decrypt, - .givencrypt = aead_givencrypt, + .aead = { + .setkey = aead_authenc_setkey, + .setauthsize = aead_authenc_setauthsize, + .encrypt = aead_authenc_encrypt, + .decrypt = aead_authenc_decrypt, + .givencrypt = aead_authenc_givencrypt, .geniv = "", .ivsize = DES_BLOCK_SIZE, .maxauthsize = SHA1_DIGEST_SIZE, @@ -1946,13 +1030,12 @@ static struct caam_alg_template driver_algs[] = { .name = "authenc(hmac(sha256),cbc(des))", .driver_name = "authenc-hmac-sha256-cbc-des-caam", .blocksize = DES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = aead_setkey, - .setauthsize = aead_setauthsize, - .encrypt = aead_encrypt, - .decrypt = aead_decrypt, - .givencrypt = aead_givencrypt, + .aead = { + .setkey = aead_authenc_setkey, + .setauthsize = aead_authenc_setauthsize, + .encrypt = aead_authenc_encrypt, + .decrypt = aead_authenc_decrypt, + .givencrypt = aead_authenc_givencrypt, .geniv = "", .ivsize = DES_BLOCK_SIZE, .maxauthsize = SHA256_DIGEST_SIZE, @@ -1966,13 +1049,12 @@ static struct caam_alg_template driver_algs[] = { .name = "authenc(hmac(sha512),cbc(des))", .driver_name = "authenc-hmac-sha512-cbc-des-caam", .blocksize = DES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = aead_setkey, - .setauthsize = aead_setauthsize, - .encrypt = aead_encrypt, - .decrypt = aead_decrypt, - .givencrypt = aead_givencrypt, + .aead = { + .setkey = aead_authenc_setkey, + .setauthsize = aead_authenc_setauthsize, + .encrypt = aead_authenc_encrypt, + .decrypt = aead_authenc_decrypt, + .givencrypt = aead_authenc_givencrypt, .geniv = "", .ivsize = DES_BLOCK_SIZE, .maxauthsize = SHA512_DIGEST_SIZE, @@ -1982,55 +1064,6 @@ static struct caam_alg_template driver_algs[] = { OP_ALG_AAI_HMAC_PRECOMP, .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, }, - /* ablkcipher descriptor */ - { - .name = "cbc(aes)", - .driver_name = "cbc-aes-caam", - .blocksize = AES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_ABLKCIPHER, - .template_ablkcipher = { - .setkey = ablkcipher_setkey, - .encrypt = ablkcipher_encrypt, - .decrypt = ablkcipher_decrypt, - .geniv = "eseqiv", - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .ivsize = AES_BLOCK_SIZE, - }, - .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, - }, - { - .name = "cbc(des3_ede)", - .driver_name = "cbc-3des-caam", - .blocksize = DES3_EDE_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_ABLKCIPHER, - .template_ablkcipher = { - .setkey = ablkcipher_setkey, - .encrypt = ablkcipher_encrypt, - .decrypt = ablkcipher_decrypt, - .geniv = "eseqiv", - .min_keysize = DES3_EDE_KEY_SIZE, - .max_keysize = DES3_EDE_KEY_SIZE, - .ivsize = DES3_EDE_BLOCK_SIZE, - }, - .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, - }, - { - .name = "cbc(des)", - .driver_name = "cbc-des-caam", - .blocksize = DES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_ABLKCIPHER, - .template_ablkcipher = { - .setkey = ablkcipher_setkey, - .encrypt = ablkcipher_encrypt, - .decrypt = ablkcipher_decrypt, - .geniv = "eseqiv", - .min_keysize = DES_KEY_SIZE, - .max_keysize = DES_KEY_SIZE, - .ivsize = DES_BLOCK_SIZE, - }, - .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, - } }; struct caam_crypto_alg { @@ -2069,19 +1102,16 @@ static void caam_cra_exit(struct crypto_tfm *tfm) { struct caam_ctx *ctx = crypto_tfm_ctx(tfm); - if (ctx->sh_desc_enc_dma && - !dma_mapping_error(ctx->jrdev, ctx->sh_desc_enc_dma)) - dma_unmap_single(ctx->jrdev, ctx->sh_desc_enc_dma, - desc_bytes(ctx->sh_desc_enc), DMA_TO_DEVICE); - if (ctx->sh_desc_dec_dma && - !dma_mapping_error(ctx->jrdev, ctx->sh_desc_dec_dma)) - dma_unmap_single(ctx->jrdev, ctx->sh_desc_dec_dma, - desc_bytes(ctx->sh_desc_dec), DMA_TO_DEVICE); - if (ctx->sh_desc_givenc_dma && - !dma_mapping_error(ctx->jrdev, ctx->sh_desc_givenc_dma)) - dma_unmap_single(ctx->jrdev, ctx->sh_desc_givenc_dma, - desc_bytes(ctx->sh_desc_givenc), + if (!dma_mapping_error(ctx->jrdev, ctx->shared_desc_phys)) + dma_unmap_single(ctx->jrdev, ctx->shared_desc_phys, + desc_bytes(ctx->sh_desc), DMA_TO_DEVICE); + kfree(ctx->sh_desc); + + if (!dma_mapping_error(ctx->jrdev, ctx->key_phys)) + dma_unmap_single(ctx->jrdev, ctx->key_phys, + ctx->split_key_pad_len + ctx->enckeylen, DMA_TO_DEVICE); + kfree(ctx->key); } static void __exit caam_algapi_exit(void) @@ -2145,20 +1175,12 @@ static struct caam_crypto_alg *caam_alg_alloc(struct device *ctrldev, alg->cra_init = caam_cra_init; alg->cra_exit = caam_cra_exit; alg->cra_priority = CAAM_CRA_PRIORITY; + alg->cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC; alg->cra_blocksize = template->blocksize; alg->cra_alignmask = 0; + alg->cra_type = &crypto_aead_type; alg->cra_ctxsize = sizeof(struct caam_ctx); - alg->cra_flags = CRYPTO_ALG_ASYNC | template->type; - switch (template->type) { - case CRYPTO_ALG_TYPE_ABLKCIPHER: - alg->cra_type = &crypto_ablkcipher_type; - alg->cra_ablkcipher = template->template_ablkcipher; - break; - case CRYPTO_ALG_TYPE_AEAD: - alg->cra_type = &crypto_aead_type; - alg->cra_aead = template->template_aead; - break; - } + alg->cra_u.aead = template->aead; t_alg->class1_alg_type = template->class1_alg_type; t_alg->class2_alg_type = template->class2_alg_type; diff --git a/trunk/drivers/crypto/caam/compat.h b/trunk/drivers/crypto/caam/compat.h index d38f2afaa966..950450346f70 100644 --- a/trunk/drivers/crypto/caam/compat.h +++ b/trunk/drivers/crypto/caam/compat.h @@ -31,6 +31,5 @@ #include #include #include -#include #endif /* !defined(CAAM_COMPAT_H) */ diff --git a/trunk/drivers/crypto/caam/ctrl.c b/trunk/drivers/crypto/caam/ctrl.c index fc2d9ed22470..9009713a3c2e 100644 --- a/trunk/drivers/crypto/caam/ctrl.c +++ b/trunk/drivers/crypto/caam/ctrl.c @@ -52,11 +52,9 @@ static int caam_probe(struct platform_device *pdev) struct caam_ctrl __iomem *ctrl; struct caam_full __iomem *topregs; struct caam_drv_private *ctrlpriv; + struct caam_perfmon *perfmon; struct caam_deco **deco; u32 deconum; -#ifdef CONFIG_DEBUG_FS - struct caam_perfmon *perfmon; -#endif ctrlpriv = kzalloc(sizeof(struct caam_drv_private), GFP_KERNEL); if (!ctrlpriv) diff --git a/trunk/drivers/crypto/caam/desc_constr.h b/trunk/drivers/crypto/caam/desc_constr.h index 0991323cf3fd..46915800c26f 100644 --- a/trunk/drivers/crypto/caam/desc_constr.h +++ b/trunk/drivers/crypto/caam/desc_constr.h @@ -9,7 +9,7 @@ #define IMMEDIATE (1 << 23) #define CAAM_CMD_SZ sizeof(u32) #define CAAM_PTR_SZ sizeof(dma_addr_t) -#define CAAM_DESC_BYTES_MAX (CAAM_CMD_SZ * MAX_CAAM_DESCSIZE) +#define CAAM_DESC_BYTES_MAX (CAAM_CMD_SZ * 64) #ifdef DEBUG #define PRINT_POS do { printk(KERN_DEBUG "%02d: %s\n", desc_len(desc),\ @@ -18,9 +18,6 @@ #define PRINT_POS #endif -#define SET_OK_PROP_ERRORS (IMMEDIATE | LDST_CLASS_DECO | \ - LDST_SRCDST_WORD_DECOCTRL | \ - (LDOFF_CHG_SHARE_OK_PROP << LDST_OFFSET_SHIFT)) #define DISABLE_AUTO_INFO_FIFO (IMMEDIATE | LDST_CLASS_DECO | \ LDST_SRCDST_WORD_DECOCTRL | \ (LDOFF_DISABLE_AUTO_NFIFO << LDST_OFFSET_SHIFT)) @@ -206,56 +203,3 @@ static inline void append_##cmd##_imm_##type(u32 *desc, type immediate, \ append_cmd(desc, immediate); \ } APPEND_CMD_RAW_IMM(load, LOAD, u32); - -/* - * Append math command. Only the last part of destination and source need to - * be specified - */ -#define APPEND_MATH(op, desc, dest, src_0, src_1, len) \ -append_cmd(desc, CMD_MATH | MATH_FUN_##op | MATH_DEST_##dest | \ - MATH_SRC0_##src_0 | MATH_SRC1_##src_1 | (u32) (len & MATH_LEN_MASK)); - -#define append_math_add(desc, dest, src0, src1, len) \ - APPEND_MATH(ADD, desc, dest, src0, src1, len) -#define append_math_sub(desc, dest, src0, src1, len) \ - APPEND_MATH(SUB, desc, dest, src0, src1, len) -#define append_math_add_c(desc, dest, src0, src1, len) \ - APPEND_MATH(ADDC, desc, dest, src0, src1, len) -#define append_math_sub_b(desc, dest, src0, src1, len) \ - APPEND_MATH(SUBB, desc, dest, src0, src1, len) -#define append_math_and(desc, dest, src0, src1, len) \ - APPEND_MATH(AND, desc, dest, src0, src1, len) -#define append_math_or(desc, dest, src0, src1, len) \ - APPEND_MATH(OR, desc, dest, src0, src1, len) -#define append_math_xor(desc, dest, src0, src1, len) \ - APPEND_MATH(XOR, desc, dest, src0, src1, len) -#define append_math_lshift(desc, dest, src0, src1, len) \ - APPEND_MATH(LSHIFT, desc, dest, src0, src1, len) -#define append_math_rshift(desc, dest, src0, src1, len) \ - APPEND_MATH(RSHIFT, desc, dest, src0, src1, len) - -/* Exactly one source is IMM. Data is passed in as u32 value */ -#define APPEND_MATH_IMM_u32(op, desc, dest, src_0, src_1, data) \ -do { \ - APPEND_MATH(op, desc, dest, src_0, src_1, CAAM_CMD_SZ); \ - append_cmd(desc, data); \ -} while (0); - -#define append_math_add_imm_u32(desc, dest, src0, src1, data) \ - APPEND_MATH_IMM_u32(ADD, desc, dest, src0, src1, data) -#define append_math_sub_imm_u32(desc, dest, src0, src1, data) \ - APPEND_MATH_IMM_u32(SUB, desc, dest, src0, src1, data) -#define append_math_add_c_imm_u32(desc, dest, src0, src1, data) \ - APPEND_MATH_IMM_u32(ADDC, desc, dest, src0, src1, data) -#define append_math_sub_b_imm_u32(desc, dest, src0, src1, data) \ - APPEND_MATH_IMM_u32(SUBB, desc, dest, src0, src1, data) -#define append_math_and_imm_u32(desc, dest, src0, src1, data) \ - APPEND_MATH_IMM_u32(AND, desc, dest, src0, src1, data) -#define append_math_or_imm_u32(desc, dest, src0, src1, data) \ - APPEND_MATH_IMM_u32(OR, desc, dest, src0, src1, data) -#define append_math_xor_imm_u32(desc, dest, src0, src1, data) \ - APPEND_MATH_IMM_u32(XOR, desc, dest, src0, src1, data) -#define append_math_lshift_imm_u32(desc, dest, src0, src1, data) \ - APPEND_MATH_IMM_u32(LSHIFT, desc, dest, src0, src1, data) -#define append_math_rshift_imm_u32(desc, dest, src0, src1, data) \ - APPEND_MATH_IMM_u32(RSHIFT, desc, dest, src0, src1, data) diff --git a/trunk/drivers/crypto/omap-sham.c b/trunk/drivers/crypto/omap-sham.c index 6399a8f1938a..ba8f1ea84c5e 100644 --- a/trunk/drivers/crypto/omap-sham.c +++ b/trunk/drivers/crypto/omap-sham.c @@ -72,20 +72,17 @@ #define DEFAULT_TIMEOUT_INTERVAL HZ -/* mostly device flags */ -#define FLAGS_BUSY 0 -#define FLAGS_FINAL 1 -#define FLAGS_DMA_ACTIVE 2 -#define FLAGS_OUTPUT_READY 3 -#define FLAGS_INIT 4 -#define FLAGS_CPU 5 -#define FLAGS_DMA_READY 6 -/* context flags */ -#define FLAGS_FINUP 16 -#define FLAGS_SG 17 -#define FLAGS_SHA1 18 -#define FLAGS_HMAC 19 -#define FLAGS_ERROR 20 +#define FLAGS_FINUP 0x0002 +#define FLAGS_FINAL 0x0004 +#define FLAGS_SG 0x0008 +#define FLAGS_SHA1 0x0010 +#define FLAGS_DMA_ACTIVE 0x0020 +#define FLAGS_OUTPUT_READY 0x0040 +#define FLAGS_INIT 0x0100 +#define FLAGS_CPU 0x0200 +#define FLAGS_HMAC 0x0400 +#define FLAGS_ERROR 0x0800 +#define FLAGS_BUSY 0x1000 #define OP_UPDATE 1 #define OP_FINAL 2 @@ -147,6 +144,7 @@ struct omap_sham_dev { int dma; int dma_lch; struct tasklet_struct done_task; + struct tasklet_struct queue_task; unsigned long flags; struct crypto_queue queue; @@ -225,7 +223,7 @@ static void omap_sham_copy_ready_hash(struct ahash_request *req) if (!hash) return; - if (likely(ctx->flags & BIT(FLAGS_SHA1))) { + if (likely(ctx->flags & FLAGS_SHA1)) { /* SHA1 results are in big endian */ for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(u32); i++) hash[i] = be32_to_cpu(in[i]); @@ -240,7 +238,7 @@ static int omap_sham_hw_init(struct omap_sham_dev *dd) { clk_enable(dd->iclk); - if (!test_bit(FLAGS_INIT, &dd->flags)) { + if (!(dd->flags & FLAGS_INIT)) { omap_sham_write_mask(dd, SHA_REG_MASK, SHA_REG_MASK_SOFTRESET, SHA_REG_MASK_SOFTRESET); @@ -248,7 +246,7 @@ static int omap_sham_hw_init(struct omap_sham_dev *dd) SHA_REG_SYSSTATUS_RESETDONE)) return -ETIMEDOUT; - set_bit(FLAGS_INIT, &dd->flags); + dd->flags |= FLAGS_INIT; dd->err = 0; } @@ -271,7 +269,7 @@ static void omap_sham_write_ctrl(struct omap_sham_dev *dd, size_t length, * Setting ALGO_CONST only for the first iteration * and CLOSE_HASH only for the last one. */ - if (ctx->flags & BIT(FLAGS_SHA1)) + if (ctx->flags & FLAGS_SHA1) val |= SHA_REG_CTRL_ALGO; if (!ctx->digcnt) val |= SHA_REG_CTRL_ALGO_CONST; @@ -303,9 +301,7 @@ static int omap_sham_xmit_cpu(struct omap_sham_dev *dd, const u8 *buf, return -ETIMEDOUT; if (final) - set_bit(FLAGS_FINAL, &dd->flags); /* catch last interrupt */ - - set_bit(FLAGS_CPU, &dd->flags); + ctx->flags |= FLAGS_FINAL; /* catch last interrupt */ len32 = DIV_ROUND_UP(length, sizeof(u32)); @@ -338,9 +334,9 @@ static int omap_sham_xmit_dma(struct omap_sham_dev *dd, dma_addr_t dma_addr, ctx->digcnt += length; if (final) - set_bit(FLAGS_FINAL, &dd->flags); /* catch last interrupt */ + ctx->flags |= FLAGS_FINAL; /* catch last interrupt */ - set_bit(FLAGS_DMA_ACTIVE, &dd->flags); + dd->flags |= FLAGS_DMA_ACTIVE; omap_start_dma(dd->dma_lch); @@ -396,7 +392,7 @@ static int omap_sham_xmit_dma_map(struct omap_sham_dev *dd, return -EINVAL; } - ctx->flags &= ~BIT(FLAGS_SG); + ctx->flags &= ~FLAGS_SG; /* next call does not fail... so no unmap in the case of error */ return omap_sham_xmit_dma(dd, ctx->dma_addr, length, final); @@ -410,7 +406,7 @@ static int omap_sham_update_dma_slow(struct omap_sham_dev *dd) omap_sham_append_sg(ctx); - final = (ctx->flags & BIT(FLAGS_FINUP)) && !ctx->total; + final = (ctx->flags & FLAGS_FINUP) && !ctx->total; dev_dbg(dd->dev, "slow: bufcnt: %u, digcnt: %d, final: %d\n", ctx->bufcnt, ctx->digcnt, final); @@ -456,7 +452,7 @@ static int omap_sham_update_dma_start(struct omap_sham_dev *dd) length = min(ctx->total, sg->length); if (sg_is_last(sg)) { - if (!(ctx->flags & BIT(FLAGS_FINUP))) { + if (!(ctx->flags & FLAGS_FINUP)) { /* not last sg must be SHA1_MD5_BLOCK_SIZE aligned */ tail = length & (SHA1_MD5_BLOCK_SIZE - 1); /* without finup() we need one block to close hash */ @@ -471,12 +467,12 @@ static int omap_sham_update_dma_start(struct omap_sham_dev *dd) return -EINVAL; } - ctx->flags |= BIT(FLAGS_SG); + ctx->flags |= FLAGS_SG; ctx->total -= length; ctx->offset = length; /* offset where to start slow */ - final = (ctx->flags & BIT(FLAGS_FINUP)) && !ctx->total; + final = (ctx->flags & FLAGS_FINUP) && !ctx->total; /* next call does not fail... so no unmap in the case of error */ return omap_sham_xmit_dma(dd, sg_dma_address(ctx->sg), length, final); @@ -499,7 +495,7 @@ static int omap_sham_update_dma_stop(struct omap_sham_dev *dd) struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req); omap_stop_dma(dd->dma_lch); - if (ctx->flags & BIT(FLAGS_SG)) { + if (ctx->flags & FLAGS_SG) { dma_unmap_sg(dd->dev, ctx->sg, 1, DMA_TO_DEVICE); if (ctx->sg->length == ctx->offset) { ctx->sg = sg_next(ctx->sg); @@ -541,18 +537,18 @@ static int omap_sham_init(struct ahash_request *req) crypto_ahash_digestsize(tfm)); if (crypto_ahash_digestsize(tfm) == SHA1_DIGEST_SIZE) - ctx->flags |= BIT(FLAGS_SHA1); + ctx->flags |= FLAGS_SHA1; ctx->bufcnt = 0; ctx->digcnt = 0; ctx->buflen = BUFLEN; - if (tctx->flags & BIT(FLAGS_HMAC)) { + if (tctx->flags & FLAGS_HMAC) { struct omap_sham_hmac_ctx *bctx = tctx->base; memcpy(ctx->buffer, bctx->ipad, SHA1_MD5_BLOCK_SIZE); ctx->bufcnt = SHA1_MD5_BLOCK_SIZE; - ctx->flags |= BIT(FLAGS_HMAC); + ctx->flags |= FLAGS_HMAC; } return 0; @@ -566,9 +562,9 @@ static int omap_sham_update_req(struct omap_sham_dev *dd) int err; dev_dbg(dd->dev, "update_req: total: %u, digcnt: %d, finup: %d\n", - ctx->total, ctx->digcnt, (ctx->flags & BIT(FLAGS_FINUP)) != 0); + ctx->total, ctx->digcnt, (ctx->flags & FLAGS_FINUP) != 0); - if (ctx->flags & BIT(FLAGS_CPU)) + if (ctx->flags & FLAGS_CPU) err = omap_sham_update_cpu(dd); else err = omap_sham_update_dma_start(dd); @@ -628,7 +624,7 @@ static int omap_sham_finish(struct ahash_request *req) if (ctx->digcnt) { omap_sham_copy_ready_hash(req); - if (ctx->flags & BIT(FLAGS_HMAC)) + if (ctx->flags & FLAGS_HMAC) err = omap_sham_finish_hmac(req); } @@ -643,23 +639,18 @@ static void omap_sham_finish_req(struct ahash_request *req, int err) struct omap_sham_dev *dd = ctx->dd; if (!err) { - omap_sham_copy_hash(req, 1); - if (test_bit(FLAGS_FINAL, &dd->flags)) + omap_sham_copy_hash(ctx->dd->req, 1); + if (ctx->flags & FLAGS_FINAL) err = omap_sham_finish(req); } else { - ctx->flags |= BIT(FLAGS_ERROR); + ctx->flags |= FLAGS_ERROR; } - /* atomic operation is not needed here */ - dd->flags &= ~(BIT(FLAGS_BUSY) | BIT(FLAGS_FINAL) | BIT(FLAGS_CPU) | - BIT(FLAGS_DMA_READY) | BIT(FLAGS_OUTPUT_READY)); clk_disable(dd->iclk); + dd->flags &= ~FLAGS_BUSY; if (req->base.complete) req->base.complete(&req->base, err); - - /* handle new request */ - tasklet_schedule(&dd->done_task); } static int omap_sham_handle_queue(struct omap_sham_dev *dd, @@ -667,20 +658,21 @@ static int omap_sham_handle_queue(struct omap_sham_dev *dd, { struct crypto_async_request *async_req, *backlog; struct omap_sham_reqctx *ctx; + struct ahash_request *prev_req; unsigned long flags; int err = 0, ret = 0; spin_lock_irqsave(&dd->lock, flags); if (req) ret = ahash_enqueue_request(&dd->queue, req); - if (test_bit(FLAGS_BUSY, &dd->flags)) { + if (dd->flags & FLAGS_BUSY) { spin_unlock_irqrestore(&dd->lock, flags); return ret; } backlog = crypto_get_backlog(&dd->queue); async_req = crypto_dequeue_request(&dd->queue); if (async_req) - set_bit(FLAGS_BUSY, &dd->flags); + dd->flags |= FLAGS_BUSY; spin_unlock_irqrestore(&dd->lock, flags); if (!async_req) @@ -690,12 +682,16 @@ static int omap_sham_handle_queue(struct omap_sham_dev *dd, backlog->complete(backlog, -EINPROGRESS); req = ahash_request_cast(async_req); + + prev_req = dd->req; dd->req = req; + ctx = ahash_request_ctx(req); dev_dbg(dd->dev, "handling new req, op: %lu, nbytes: %d\n", ctx->op, req->nbytes); + err = omap_sham_hw_init(dd); if (err) goto err1; @@ -716,16 +712,18 @@ static int omap_sham_handle_queue(struct omap_sham_dev *dd, if (ctx->op == OP_UPDATE) { err = omap_sham_update_req(dd); - if (err != -EINPROGRESS && (ctx->flags & BIT(FLAGS_FINUP))) + if (err != -EINPROGRESS && (ctx->flags & FLAGS_FINUP)) /* no final() after finup() */ err = omap_sham_final_req(dd); } else if (ctx->op == OP_FINAL) { err = omap_sham_final_req(dd); } err1: - if (err != -EINPROGRESS) + if (err != -EINPROGRESS) { /* done_task will not finish it, so do it here */ omap_sham_finish_req(req, err); + tasklet_schedule(&dd->queue_task); + } dev_dbg(dd->dev, "exit, err: %d\n", err); @@ -754,7 +752,7 @@ static int omap_sham_update(struct ahash_request *req) ctx->sg = req->src; ctx->offset = 0; - if (ctx->flags & BIT(FLAGS_FINUP)) { + if (ctx->flags & FLAGS_FINUP) { if ((ctx->digcnt + ctx->bufcnt + ctx->total) < 9) { /* * OMAP HW accel works only with buffers >= 9 @@ -767,7 +765,7 @@ static int omap_sham_update(struct ahash_request *req) /* * faster to use CPU for short transfers */ - ctx->flags |= BIT(FLAGS_CPU); + ctx->flags |= FLAGS_CPU; } } else if (ctx->bufcnt + ctx->total < ctx->buflen) { omap_sham_append_sg(ctx); @@ -804,9 +802,9 @@ static int omap_sham_final(struct ahash_request *req) { struct omap_sham_reqctx *ctx = ahash_request_ctx(req); - ctx->flags |= BIT(FLAGS_FINUP); + ctx->flags |= FLAGS_FINUP; - if (ctx->flags & BIT(FLAGS_ERROR)) + if (ctx->flags & FLAGS_ERROR) return 0; /* uncompleted hash is not needed */ /* OMAP HW accel works only with buffers >= 9 */ @@ -825,7 +823,7 @@ static int omap_sham_finup(struct ahash_request *req) struct omap_sham_reqctx *ctx = ahash_request_ctx(req); int err1, err2; - ctx->flags |= BIT(FLAGS_FINUP); + ctx->flags |= FLAGS_FINUP; err1 = omap_sham_update(req); if (err1 == -EINPROGRESS || err1 == -EBUSY) @@ -897,7 +895,7 @@ static int omap_sham_cra_init_alg(struct crypto_tfm *tfm, const char *alg_base) if (alg_base) { struct omap_sham_hmac_ctx *bctx = tctx->base; - tctx->flags |= BIT(FLAGS_HMAC); + tctx->flags |= FLAGS_HMAC; bctx->shash = crypto_alloc_shash(alg_base, 0, CRYPTO_ALG_NEED_FALLBACK); if (IS_ERR(bctx->shash)) { @@ -934,7 +932,7 @@ static void omap_sham_cra_exit(struct crypto_tfm *tfm) crypto_free_shash(tctx->fallback); tctx->fallback = NULL; - if (tctx->flags & BIT(FLAGS_HMAC)) { + if (tctx->flags & FLAGS_HMAC) { struct omap_sham_hmac_ctx *bctx = tctx->base; crypto_free_shash(bctx->shash); } @@ -1038,46 +1036,51 @@ static struct ahash_alg algs[] = { static void omap_sham_done_task(unsigned long data) { struct omap_sham_dev *dd = (struct omap_sham_dev *)data; - int err = 0; + struct ahash_request *req = dd->req; + struct omap_sham_reqctx *ctx = ahash_request_ctx(req); + int ready = 0, err = 0; - if (!test_bit(FLAGS_BUSY, &dd->flags)) { - omap_sham_handle_queue(dd, NULL); - return; + if (ctx->flags & FLAGS_OUTPUT_READY) { + ctx->flags &= ~FLAGS_OUTPUT_READY; + ready = 1; } - if (test_bit(FLAGS_CPU, &dd->flags)) { - if (test_and_clear_bit(FLAGS_OUTPUT_READY, &dd->flags)) - goto finish; - } else if (test_bit(FLAGS_DMA_READY, &dd->flags)) { - if (test_and_clear_bit(FLAGS_DMA_ACTIVE, &dd->flags)) { - omap_sham_update_dma_stop(dd); - if (dd->err) { - err = dd->err; - goto finish; - } - } - if (test_and_clear_bit(FLAGS_OUTPUT_READY, &dd->flags)) { - /* hash or semi-hash ready */ - clear_bit(FLAGS_DMA_READY, &dd->flags); + if (dd->flags & FLAGS_DMA_ACTIVE) { + dd->flags &= ~FLAGS_DMA_ACTIVE; + omap_sham_update_dma_stop(dd); + if (!dd->err) err = omap_sham_update_dma_start(dd); - if (err != -EINPROGRESS) - goto finish; - } } - return; + err = dd->err ? : err; -finish: - dev_dbg(dd->dev, "update done: err: %d\n", err); - /* finish curent request */ - omap_sham_finish_req(dd->req, err); + if (err != -EINPROGRESS && (ready || err)) { + dev_dbg(dd->dev, "update done: err: %d\n", err); + /* finish curent request */ + omap_sham_finish_req(req, err); + /* start new request */ + omap_sham_handle_queue(dd, NULL); + } +} + +static void omap_sham_queue_task(unsigned long data) +{ + struct omap_sham_dev *dd = (struct omap_sham_dev *)data; + + omap_sham_handle_queue(dd, NULL); } static irqreturn_t omap_sham_irq(int irq, void *dev_id) { struct omap_sham_dev *dd = dev_id; + struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req); + + if (!ctx) { + dev_err(dd->dev, "unknown interrupt.\n"); + return IRQ_HANDLED; + } - if (unlikely(test_bit(FLAGS_FINAL, &dd->flags))) + if (unlikely(ctx->flags & FLAGS_FINAL)) /* final -> allow device to go to power-saving mode */ omap_sham_write_mask(dd, SHA_REG_CTRL, 0, SHA_REG_CTRL_LENGTH); @@ -1085,12 +1088,8 @@ static irqreturn_t omap_sham_irq(int irq, void *dev_id) SHA_REG_CTRL_OUTPUT_READY); omap_sham_read(dd, SHA_REG_CTRL); - if (!test_bit(FLAGS_BUSY, &dd->flags)) { - dev_warn(dd->dev, "Interrupt when no active requests.\n"); - return IRQ_HANDLED; - } - - set_bit(FLAGS_OUTPUT_READY, &dd->flags); + ctx->flags |= FLAGS_OUTPUT_READY; + dd->err = 0; tasklet_schedule(&dd->done_task); return IRQ_HANDLED; @@ -1103,10 +1102,9 @@ static void omap_sham_dma_callback(int lch, u16 ch_status, void *data) if (ch_status != OMAP_DMA_BLOCK_IRQ) { pr_err("omap-sham DMA error status: 0x%hx\n", ch_status); dd->err = -EIO; - clear_bit(FLAGS_INIT, &dd->flags);/* request to re-initialize */ + dd->flags &= ~FLAGS_INIT; /* request to re-initialize */ } - set_bit(FLAGS_DMA_READY, &dd->flags); tasklet_schedule(&dd->done_task); } @@ -1153,6 +1151,7 @@ static int __devinit omap_sham_probe(struct platform_device *pdev) INIT_LIST_HEAD(&dd->list); spin_lock_init(&dd->lock); tasklet_init(&dd->done_task, omap_sham_done_task, (unsigned long)dd); + tasklet_init(&dd->queue_task, omap_sham_queue_task, (unsigned long)dd); crypto_init_queue(&dd->queue, OMAP_SHAM_QUEUE_LENGTH); dd->irq = -1; @@ -1261,6 +1260,7 @@ static int __devexit omap_sham_remove(struct platform_device *pdev) for (i = 0; i < ARRAY_SIZE(algs); i++) crypto_unregister_ahash(&algs[i]); tasklet_kill(&dd->done_task); + tasklet_kill(&dd->queue_task); iounmap(dd->io_base); clk_put(dd->iclk); omap_sham_dma_cleanup(dd); diff --git a/trunk/drivers/crypto/talitos.c b/trunk/drivers/crypto/talitos.c index 8a0bb417aa11..854e2632f9a6 100644 --- a/trunk/drivers/crypto/talitos.c +++ b/trunk/drivers/crypto/talitos.c @@ -1,7 +1,7 @@ /* * talitos - Freescale Integrated Security Engine (SEC) device driver * - * Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * Copyright (c) 2008-2010 Freescale Semiconductor, Inc. * * Scatterlist Crypto API glue code copied from files with the following: * Copyright (c) 2006-2007 Herbert Xu @@ -282,7 +282,6 @@ static int init_device(struct device *dev) /** * talitos_submit - submits a descriptor to the device for processing * @dev: the SEC device to be used - * @ch: the SEC device channel to be used * @desc: the descriptor to be processed by the device * @callback: whom to call when processing is complete * @context: a handle for use by caller (optional) @@ -291,7 +290,7 @@ static int init_device(struct device *dev) * callback must check err and feedback in descriptor header * for device processing status. */ -static int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc, +static int talitos_submit(struct device *dev, struct talitos_desc *desc, void (*callback)(struct device *dev, struct talitos_desc *desc, void *context, int error), @@ -299,9 +298,15 @@ static int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc, { struct talitos_private *priv = dev_get_drvdata(dev); struct talitos_request *request; - unsigned long flags; + unsigned long flags, ch; int head; + /* select done notification */ + desc->hdr |= DESC_HDR_DONE_NOTIFY; + + /* emulate SEC's round-robin channel fifo polling scheme */ + ch = atomic_inc_return(&priv->last_chan) & (priv->num_channels - 1); + spin_lock_irqsave(&priv->chan[ch].head_lock, flags); if (!atomic_inc_not_zero(&priv->chan[ch].submit_count)) { @@ -701,7 +706,6 @@ static void talitos_unregister_rng(struct device *dev) struct talitos_ctx { struct device *dev; - int ch; __be32 desc_hdr_template; u8 key[TALITOS_MAX_KEY_SIZE]; u8 iv[TALITOS_MAX_IV_LENGTH]; @@ -1113,7 +1117,7 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, map_single_talitos_ptr(dev, &desc->ptr[6], ivsize, ctx->iv, 0, DMA_FROM_DEVICE); - ret = talitos_submit(dev, ctx->ch, desc, callback, areq); + ret = talitos_submit(dev, desc, callback, areq); if (ret != -EINPROGRESS) { ipsec_esp_unmap(dev, edesc, areq); kfree(edesc); @@ -1378,11 +1382,22 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *cipher, const u8 *key, unsigned int keylen) { struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher); + struct ablkcipher_alg *alg = crypto_ablkcipher_alg(cipher); + + if (keylen > TALITOS_MAX_KEY_SIZE) + goto badkey; + + if (keylen < alg->min_keysize || keylen > alg->max_keysize) + goto badkey; memcpy(&ctx->key, key, keylen); ctx->keylen = keylen; return 0; + +badkey: + crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN); + return -EINVAL; } static void common_nonsnoop_unmap(struct device *dev, @@ -1418,6 +1433,7 @@ static void ablkcipher_done(struct device *dev, static int common_nonsnoop(struct talitos_edesc *edesc, struct ablkcipher_request *areq, + u8 *giv, void (*callback) (struct device *dev, struct talitos_desc *desc, void *context, int error)) @@ -1437,7 +1453,7 @@ static int common_nonsnoop(struct talitos_edesc *edesc, /* cipher iv */ ivsize = crypto_ablkcipher_ivsize(cipher); - map_single_talitos_ptr(dev, &desc->ptr[1], ivsize, areq->info, 0, + map_single_talitos_ptr(dev, &desc->ptr[1], ivsize, giv ?: areq->info, 0, DMA_TO_DEVICE); /* cipher key */ @@ -1508,7 +1524,7 @@ static int common_nonsnoop(struct talitos_edesc *edesc, to_talitos_ptr(&desc->ptr[6], 0); desc->ptr[6].j_extent = 0; - ret = talitos_submit(dev, ctx->ch, desc, callback, areq); + ret = talitos_submit(dev, desc, callback, areq); if (ret != -EINPROGRESS) { common_nonsnoop_unmap(dev, edesc, areq); kfree(edesc); @@ -1540,7 +1556,7 @@ static int ablkcipher_encrypt(struct ablkcipher_request *areq) /* set encrypt */ edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_MODE0_ENCRYPT; - return common_nonsnoop(edesc, areq, ablkcipher_done); + return common_nonsnoop(edesc, areq, NULL, ablkcipher_done); } static int ablkcipher_decrypt(struct ablkcipher_request *areq) @@ -1556,7 +1572,7 @@ static int ablkcipher_decrypt(struct ablkcipher_request *areq) edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_DIR_INBOUND; - return common_nonsnoop(edesc, areq, ablkcipher_done); + return common_nonsnoop(edesc, areq, NULL, ablkcipher_done); } static void common_nonsnoop_hash_unmap(struct device *dev, @@ -1687,7 +1703,7 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc, /* last DWORD empty */ desc->ptr[6] = zero_entry; - ret = talitos_submit(dev, ctx->ch, desc, callback, areq); + ret = talitos_submit(dev, desc, callback, areq); if (ret != -EINPROGRESS) { common_nonsnoop_hash_unmap(dev, edesc, areq); kfree(edesc); @@ -2228,7 +2244,6 @@ static int talitos_cra_init(struct crypto_tfm *tfm) struct crypto_alg *alg = tfm->__crt_alg; struct talitos_crypto_alg *talitos_alg; struct talitos_ctx *ctx = crypto_tfm_ctx(tfm); - struct talitos_private *priv; if ((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_AHASH) talitos_alg = container_of(__crypto_ahash_alg(alg), @@ -2241,17 +2256,9 @@ static int talitos_cra_init(struct crypto_tfm *tfm) /* update context with ptr to dev */ ctx->dev = talitos_alg->dev; - /* assign SEC channel to tfm in round-robin fashion */ - priv = dev_get_drvdata(ctx->dev); - ctx->ch = atomic_inc_return(&priv->last_chan) & - (priv->num_channels - 1); - /* copy descriptor header template value */ ctx->desc_hdr_template = talitos_alg->algt.desc_hdr_template; - /* select done notification */ - ctx->desc_hdr_template |= DESC_HDR_DONE_NOTIFY; - return 0; } diff --git a/trunk/drivers/firmware/iscsi_ibft.c b/trunk/drivers/firmware/iscsi_ibft.c index c811cb107904..ce33f4626957 100644 --- a/trunk/drivers/firmware/iscsi_ibft.c +++ b/trunk/drivers/firmware/iscsi_ibft.c @@ -566,11 +566,6 @@ static mode_t __init ibft_check_initiator_for(void *data, int type) return rc; } -static void ibft_kobj_release(void *data) -{ - kfree(data); -} - /* * Helper function for ibft_register_kobjects. */ @@ -600,8 +595,7 @@ static int __init ibft_create_kobject(struct acpi_table_ibft *header, boot_kobj = iscsi_boot_create_initiator(boot_kset, hdr->index, ibft_kobj, ibft_attr_show_initiator, - ibft_check_initiator_for, - ibft_kobj_release); + ibft_check_initiator_for); if (!boot_kobj) { rc = -ENOMEM; goto free_ibft_obj; @@ -616,8 +610,7 @@ static int __init ibft_create_kobject(struct acpi_table_ibft *header, boot_kobj = iscsi_boot_create_ethernet(boot_kset, hdr->index, ibft_kobj, ibft_attr_show_nic, - ibft_check_nic_for, - ibft_kobj_release); + ibft_check_nic_for); if (!boot_kobj) { rc = -ENOMEM; goto free_ibft_obj; @@ -632,8 +625,7 @@ static int __init ibft_create_kobject(struct acpi_table_ibft *header, boot_kobj = iscsi_boot_create_target(boot_kset, hdr->index, ibft_kobj, ibft_attr_show_target, - ibft_check_tgt_for, - ibft_kobj_release); + ibft_check_tgt_for); if (!boot_kobj) { rc = -ENOMEM; goto free_ibft_obj; diff --git a/trunk/drivers/input/gameport/gameport.c b/trunk/drivers/input/gameport/gameport.c index c351aa421f8f..5b8f59d6c3e8 100644 --- a/trunk/drivers/input/gameport/gameport.c +++ b/trunk/drivers/input/gameport/gameport.c @@ -47,7 +47,7 @@ static void gameport_disconnect_port(struct gameport *gameport); #if defined(__i386__) -#include +#include #define DELTA(x,y) ((y)-(x)+((y)<(x)?1193182/HZ:0)) #define GET_TIME(x) do { x = get_time_pit(); } while (0) diff --git a/trunk/drivers/input/joystick/analog.c b/trunk/drivers/input/joystick/analog.c index 9882971827e6..4afe0a3b4884 100644 --- a/trunk/drivers/input/joystick/analog.c +++ b/trunk/drivers/input/joystick/analog.c @@ -136,7 +136,7 @@ struct analog_port { #ifdef __i386__ -#include +#include #define GET_TIME(x) do { if (cpu_has_tsc) rdtscl(x); else x = get_time_pit(); } while (0) #define DELTA(x,y) (cpu_has_tsc ? ((y) - (x)) : ((x) - (y) + ((x) < (y) ? CLOCK_TICK_RATE / HZ : 0))) diff --git a/trunk/drivers/input/misc/pcspkr.c b/trunk/drivers/input/misc/pcspkr.c index 34f4d2e0f50f..f080dd31499b 100644 --- a/trunk/drivers/input/misc/pcspkr.c +++ b/trunk/drivers/input/misc/pcspkr.c @@ -14,7 +14,6 @@ #include #include -#include #include #include #include @@ -26,6 +25,14 @@ MODULE_DESCRIPTION("PC Speaker beeper driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:pcspkr"); +#if defined(CONFIG_MIPS) || defined(CONFIG_X86) +/* Use the global PIT lock ! */ +#include +#else +#include +static DEFINE_RAW_SPINLOCK(i8253_lock); +#endif + static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { unsigned int count = 0; diff --git a/trunk/drivers/iommu/Kconfig b/trunk/drivers/iommu/Kconfig deleted file mode 100644 index b57b3fa492f3..000000000000 --- a/trunk/drivers/iommu/Kconfig +++ /dev/null @@ -1,110 +0,0 @@ -# IOMMU_API always gets selected by whoever wants it. -config IOMMU_API - bool - -menuconfig IOMMU_SUPPORT - bool "IOMMU Hardware Support" - default y - ---help--- - Say Y here if you want to compile device drivers for IO Memory - Management Units into the kernel. These devices usually allow to - remap DMA requests and/or remap interrupts from other devices on the - system. - -if IOMMU_SUPPORT - -# MSM IOMMU support -config MSM_IOMMU - bool "MSM IOMMU Support" - depends on ARCH_MSM8X60 || ARCH_MSM8960 - select IOMMU_API - help - Support for the IOMMUs found on certain Qualcomm SOCs. - These IOMMUs allow virtualization of the address space used by most - cores within the multimedia subsystem. - - If unsure, say N here. - -config IOMMU_PGTABLES_L2 - def_bool y - depends on MSM_IOMMU && MMU && SMP && CPU_DCACHE_DISABLE=n - -# AMD IOMMU support -config AMD_IOMMU - bool "AMD IOMMU support" - select SWIOTLB - select PCI_MSI - select PCI_IOV - select IOMMU_API - depends on X86_64 && PCI && ACPI - ---help--- - With this option you can enable support for AMD IOMMU hardware in - your system. An IOMMU is a hardware component which provides - remapping of DMA memory accesses from devices. With an AMD IOMMU you - can isolate the the DMA memory of different devices and protect the - system from misbehaving device drivers or hardware. - - You can find out if your system has an AMD IOMMU if you look into - your BIOS for an option to enable it or if you have an IVRS ACPI - table. - -config AMD_IOMMU_STATS - bool "Export AMD IOMMU statistics to debugfs" - depends on AMD_IOMMU - select DEBUG_FS - ---help--- - This option enables code in the AMD IOMMU driver to collect various - statistics about whats happening in the driver and exports that - information to userspace via debugfs. - If unsure, say N. - -# Intel IOMMU support -config DMAR - bool "Support for DMA Remapping Devices" - depends on PCI_MSI && ACPI && (X86 || IA64_GENERIC) - select IOMMU_API - help - DMA remapping (DMAR) devices support enables independent address - translations for Direct Memory Access (DMA) from devices. - These DMA remapping devices are reported via ACPI tables - and include PCI device scope covered by these DMA - remapping devices. - -config DMAR_DEFAULT_ON - def_bool y - prompt "Enable DMA Remapping Devices by default" - depends on DMAR - help - Selecting this option will enable a DMAR device at boot time if - one is found. If this option is not selected, DMAR support can - be enabled by passing intel_iommu=on to the kernel. - -config DMAR_BROKEN_GFX_WA - bool "Workaround broken graphics drivers (going away soon)" - depends on DMAR && BROKEN && X86 - ---help--- - Current Graphics drivers tend to use physical address - for DMA and avoid using DMA APIs. Setting this config - option permits the IOMMU driver to set a unity map for - all the OS-visible memory. Hence the driver can continue - to use physical addresses for DMA, at least until this - option is removed in the 2.6.32 kernel. - -config DMAR_FLOPPY_WA - def_bool y - depends on DMAR && X86 - ---help--- - Floppy disk drivers are known to bypass DMA API calls - thereby failing to work when IOMMU is enabled. This - workaround will setup a 1:1 mapping for the first - 16MiB to make floppy (an ISA device) work. - -config INTR_REMAP - bool "Support for Interrupt Remapping (EXPERIMENTAL)" - depends on X86_64 && X86_IO_APIC && PCI_MSI && ACPI && EXPERIMENTAL - ---help--- - Supports Interrupt remapping for IO-APIC and MSI devices. - To use x2apic mode in the CPU's which support x2APIC enhancements or - to support platforms with CPU's having > 8 bit APIC ID, say Y. - -endif # IOMMU_SUPPORT diff --git a/trunk/drivers/iommu/Makefile b/trunk/drivers/iommu/Makefile deleted file mode 100644 index 4d4d77df7cac..000000000000 --- a/trunk/drivers/iommu/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -obj-$(CONFIG_IOMMU_API) += iommu.o -obj-$(CONFIG_MSM_IOMMU) += msm_iommu.o msm_iommu_dev.o -obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o -obj-$(CONFIG_DMAR) += dmar.o iova.o intel-iommu.o -obj-$(CONFIG_INTR_REMAP) += dmar.o intr_remapping.o diff --git a/trunk/drivers/macintosh/nvram.c b/trunk/drivers/macintosh/nvram.c index f0e03e7937e3..a271c8218d82 100644 --- a/trunk/drivers/macintosh/nvram.c +++ b/trunk/drivers/macintosh/nvram.c @@ -21,16 +21,12 @@ static loff_t nvram_llseek(struct file *file, loff_t offset, int origin) { switch (origin) { - case 0: - break; case 1: offset += file->f_pos; break; case 2: offset += NVRAM_SIZE; break; - default: - offset = -1; } if (offset < 0) return -EINVAL; diff --git a/trunk/drivers/md/linear.c b/trunk/drivers/md/linear.c index 6cd2c313e800..abfb59a61ede 100644 --- a/trunk/drivers/md/linear.c +++ b/trunk/drivers/md/linear.c @@ -213,6 +213,12 @@ static int linear_run (mddev_t *mddev) return md_integrity_register(mddev); } +static void free_conf(struct rcu_head *head) +{ + linear_conf_t *conf = container_of(head, linear_conf_t, rcu); + kfree(conf); +} + static int linear_add(mddev_t *mddev, mdk_rdev_t *rdev) { /* Adding a drive to a linear array allows the array to grow. @@ -241,7 +247,7 @@ static int linear_add(mddev_t *mddev, mdk_rdev_t *rdev) md_set_array_sectors(mddev, linear_size(mddev, 0, 0)); set_capacity(mddev->gendisk, mddev->array_sectors); revalidate_disk(mddev->gendisk); - kfree_rcu(oldconf, rcu); + call_rcu(&oldconf->rcu, free_conf); return 0; } diff --git a/trunk/drivers/md/md.c b/trunk/drivers/md/md.c index dfc9425db70b..91e31e260b4a 100644 --- a/trunk/drivers/md/md.c +++ b/trunk/drivers/md/md.c @@ -6394,11 +6394,16 @@ static void md_seq_stop(struct seq_file *seq, void *v) mddev_put(mddev); } +struct mdstat_info { + int event; +}; + static int md_seq_show(struct seq_file *seq, void *v) { mddev_t *mddev = v; sector_t sectors; mdk_rdev_t *rdev; + struct mdstat_info *mi = seq->private; struct bitmap *bitmap; if (v == (void*)1) { @@ -6410,7 +6415,7 @@ static int md_seq_show(struct seq_file *seq, void *v) spin_unlock(&pers_lock); seq_printf(seq, "\n"); - seq->poll_event = atomic_read(&md_event_count); + mi->event = atomic_read(&md_event_count); return 0; } if (v == (void*)2) { @@ -6522,21 +6527,26 @@ static const struct seq_operations md_seq_ops = { static int md_seq_open(struct inode *inode, struct file *file) { - struct seq_file *seq; int error; + struct mdstat_info *mi = kmalloc(sizeof(*mi), GFP_KERNEL); + if (mi == NULL) + return -ENOMEM; error = seq_open(file, &md_seq_ops); if (error) - return error; - - seq = file->private_data; - seq->poll_event = atomic_read(&md_event_count); + kfree(mi); + else { + struct seq_file *p = file->private_data; + p->private = mi; + mi->event = atomic_read(&md_event_count); + } return error; } static unsigned int mdstat_poll(struct file *filp, poll_table *wait) { - struct seq_file *seq = filp->private_data; + struct seq_file *m = filp->private_data; + struct mdstat_info *mi = m->private; int mask; poll_wait(filp, &md_event_waiters, wait); @@ -6544,7 +6554,7 @@ static unsigned int mdstat_poll(struct file *filp, poll_table *wait) /* always allow read */ mask = POLLIN | POLLRDNORM; - if (seq->poll_event != atomic_read(&md_event_count)) + if (mi->event != atomic_read(&md_event_count)) mask |= POLLERR | POLLPRI; return mask; } diff --git a/trunk/drivers/mmc/host/mmci.c b/trunk/drivers/mmc/host/mmci.c index 56e9a4168264..fef7140eb1d0 100644 --- a/trunk/drivers/mmc/host/mmci.c +++ b/trunk/drivers/mmc/host/mmci.c @@ -1184,15 +1184,7 @@ static int __devinit mmci_probe(struct amba_device *dev, } mmc->ops = &mmci_ops; - /* - * The ARM and ST versions of the block have slightly different - * clock divider equations which means that the minimum divider - * differs too. - */ - if (variant->st_clkdiv) - mmc->f_min = DIV_ROUND_UP(host->mclk, 257); - else - mmc->f_min = DIV_ROUND_UP(host->mclk, 512); + mmc->f_min = (host->mclk + 511) / 512; /* * If the platform data supplies a maximum operating * frequency, this takes precedence. Else, we fall back diff --git a/trunk/drivers/mtd/ubi/cdev.c b/trunk/drivers/mtd/ubi/cdev.c index 3320a50ba4f0..191f3bb3c41a 100644 --- a/trunk/drivers/mtd/ubi/cdev.c +++ b/trunk/drivers/mtd/ubi/cdev.c @@ -189,16 +189,12 @@ static loff_t vol_cdev_llseek(struct file *file, loff_t offset, int origin) return new_offset; } -static int vol_cdev_fsync(struct file *file, loff_t start, loff_t end, int datasync) +static int vol_cdev_fsync(struct file *file, int datasync) { struct ubi_volume_desc *desc = file->private_data; struct ubi_device *ubi = desc->vol->ubi; - struct inode *inode = file->f_path.dentry->d_inode; - int err; - mutex_lock(&inode->i_mutex); - err = ubi_sync(ubi->ubi_num); - mutex_unlock(&inode->i_mutex); - return err; + + return ubi_sync(ubi->ubi_num); } diff --git a/trunk/drivers/net/r8169.c b/trunk/drivers/net/r8169.c index 40bcb82d9116..4e2d1448093c 100644 --- a/trunk/drivers/net/r8169.c +++ b/trunk/drivers/net/r8169.c @@ -2160,12 +2160,9 @@ static void rtl8169sb_hw_phy_config(struct rtl8169_private *tp) static void rtl8169scd_hw_phy_config_quirk(struct rtl8169_private *tp) { struct pci_dev *pdev = tp->pci_dev; - u16 vendor_id, device_id; - pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &vendor_id); - pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &device_id); - - if ((vendor_id != PCI_VENDOR_ID_GIGABYTE) || (device_id != 0xe000)) + if ((pdev->subsystem_vendor != PCI_VENDOR_ID_GIGABYTE) || + (pdev->subsystem_device != 0xe000)) return; rtl_writephy(tp, 0x1f, 0x0001); diff --git a/trunk/drivers/of/of_pci.c b/trunk/drivers/of/of_pci.c index 3701b62c1d5e..ec7b060ae952 100644 --- a/trunk/drivers/of/of_pci.c +++ b/trunk/drivers/of/of_pci.c @@ -1,5 +1,4 @@ #include -#include #include #include diff --git a/trunk/drivers/oprofile/oprofile_perf.c b/trunk/drivers/oprofile/oprofile_perf.c index 94796f39bc47..9046f7b2ed79 100644 --- a/trunk/drivers/oprofile/oprofile_perf.c +++ b/trunk/drivers/oprofile/oprofile_perf.c @@ -31,7 +31,7 @@ static int num_counters; /* * Overflow callback for oprofile. */ -static void op_overflow_handler(struct perf_event *event, +static void op_overflow_handler(struct perf_event *event, int unused, struct perf_sample_data *data, struct pt_regs *regs) { int id; @@ -79,7 +79,7 @@ static int op_create_counter(int cpu, int event) pevent = perf_event_create_kernel_counter(&counter_config[event].attr, cpu, NULL, - op_overflow_handler, NULL); + op_overflow_handler); if (IS_ERR(pevent)) return PTR_ERR(pevent); diff --git a/trunk/drivers/pci/Makefile b/trunk/drivers/pci/Makefile index 6fadae3ad134..631f73027608 100644 --- a/trunk/drivers/pci/Makefile +++ b/trunk/drivers/pci/Makefile @@ -29,6 +29,11 @@ obj-$(CONFIG_PCI_MSI) += msi.o # Build the Hypertransport interrupt support obj-$(CONFIG_HT_IRQ) += htirq.o +# Build Intel IOMMU support +obj-$(CONFIG_DMAR) += dmar.o iova.o intel-iommu.o + +obj-$(CONFIG_INTR_REMAP) += dmar.o intr_remapping.o + obj-$(CONFIG_PCI_IOV) += iov.o # diff --git a/trunk/drivers/iommu/dmar.c b/trunk/drivers/pci/dmar.c similarity index 100% rename from trunk/drivers/iommu/dmar.c rename to trunk/drivers/pci/dmar.c diff --git a/trunk/drivers/iommu/intel-iommu.c b/trunk/drivers/pci/intel-iommu.c similarity index 99% rename from trunk/drivers/iommu/intel-iommu.c rename to trunk/drivers/pci/intel-iommu.c index c621c98c99da..f02c34d26d1b 100644 --- a/trunk/drivers/iommu/intel-iommu.c +++ b/trunk/drivers/pci/intel-iommu.c @@ -42,6 +42,7 @@ #include #include #include +#include "pci.h" #define ROOT_SIZE VTD_PAGE_SIZE #define CONTEXT_SIZE VTD_PAGE_SIZE diff --git a/trunk/drivers/iommu/intr_remapping.c b/trunk/drivers/pci/intr_remapping.c similarity index 99% rename from trunk/drivers/iommu/intr_remapping.c rename to trunk/drivers/pci/intr_remapping.c index 1a89d4a2cadf..3607faf28a4d 100644 --- a/trunk/drivers/iommu/intr_remapping.c +++ b/trunk/drivers/pci/intr_remapping.c @@ -13,6 +13,7 @@ #include "intr_remapping.h" #include #include +#include "pci.h" static struct ioapic_scope ir_ioapic[MAX_IO_APICS]; static struct hpet_scope ir_hpet[MAX_HPET_TBS]; diff --git a/trunk/drivers/iommu/intr_remapping.h b/trunk/drivers/pci/intr_remapping.h similarity index 100% rename from trunk/drivers/iommu/intr_remapping.h rename to trunk/drivers/pci/intr_remapping.h diff --git a/trunk/drivers/iommu/iova.c b/trunk/drivers/pci/iova.c similarity index 100% rename from trunk/drivers/iommu/iova.c rename to trunk/drivers/pci/iova.c diff --git a/trunk/drivers/pci/pci.h b/trunk/drivers/pci/pci.h index c8cee764b0de..3a39bf1f1e2c 100644 --- a/trunk/drivers/pci/pci.h +++ b/trunk/drivers/pci/pci.h @@ -186,6 +186,8 @@ pci_match_one_device(const struct pci_device_id *id, const struct pci_dev *dev) return NULL; } +struct pci_dev *pci_find_upstream_pcie_bridge(struct pci_dev *pdev); + /* PCI slot sysfs helper code */ #define to_pci_slot(s) container_of(s, struct pci_slot, kobj) diff --git a/trunk/drivers/regulator/Kconfig b/trunk/drivers/regulator/Kconfig index 118eb213eb3a..d7ed20f293d7 100644 --- a/trunk/drivers/regulator/Kconfig +++ b/trunk/drivers/regulator/Kconfig @@ -235,7 +235,6 @@ config REGULATOR_TPS6105X config REGULATOR_TPS65023 tristate "TI TPS65023 Power regulators" depends on I2C - select REGMAP_I2C help This driver supports TPS65023 voltage regulator chips. TPS65023 provides three step-down converters and two general-purpose LDO voltage regulators. diff --git a/trunk/drivers/regulator/tps65023-regulator.c b/trunk/drivers/regulator/tps65023-regulator.c index 701a5900f83f..fbddc15e1811 100644 --- a/trunk/drivers/regulator/tps65023-regulator.c +++ b/trunk/drivers/regulator/tps65023-regulator.c @@ -25,7 +25,6 @@ #include #include #include -#include /* Register definitions */ #define TPS65023_REG_VERSION 0 @@ -126,35 +125,93 @@ struct tps_pmic { struct i2c_client *client; struct regulator_dev *rdev[TPS65023_NUM_REGULATOR]; const struct tps_info *info[TPS65023_NUM_REGULATOR]; - struct regmap *regmap; + struct mutex io_lock; }; +static inline int tps_65023_read(struct tps_pmic *tps, u8 reg) +{ + return i2c_smbus_read_byte_data(tps->client, reg); +} + +static inline int tps_65023_write(struct tps_pmic *tps, u8 reg, u8 val) +{ + return i2c_smbus_write_byte_data(tps->client, reg, val); +} + static int tps_65023_set_bits(struct tps_pmic *tps, u8 reg, u8 mask) { - return regmap_update_bits(tps->regmap, reg, mask, mask); + int err, data; + + mutex_lock(&tps->io_lock); + + data = tps_65023_read(tps, reg); + if (data < 0) { + dev_err(&tps->client->dev, "Read from reg 0x%x failed\n", reg); + err = data; + goto out; + } + + data |= mask; + err = tps_65023_write(tps, reg, data); + if (err) + dev_err(&tps->client->dev, "Write for reg 0x%x failed\n", reg); + +out: + mutex_unlock(&tps->io_lock); + return err; } static int tps_65023_clear_bits(struct tps_pmic *tps, u8 reg, u8 mask) { - return regmap_update_bits(tps->regmap, reg, mask, 0); + int err, data; + + mutex_lock(&tps->io_lock); + + data = tps_65023_read(tps, reg); + if (data < 0) { + dev_err(&tps->client->dev, "Read from reg 0x%x failed\n", reg); + err = data; + goto out; + } + + data &= ~mask; + + err = tps_65023_write(tps, reg, data); + if (err) + dev_err(&tps->client->dev, "Write for reg 0x%x failed\n", reg); + +out: + mutex_unlock(&tps->io_lock); + return err; + } static int tps_65023_reg_read(struct tps_pmic *tps, u8 reg) { - unsigned int val; - int ret; + int data; - ret = regmap_read(tps->regmap, reg, &val); + mutex_lock(&tps->io_lock); - if (ret != 0) - return ret; - else - return val; + data = tps_65023_read(tps, reg); + if (data < 0) + dev_err(&tps->client->dev, "Read from reg 0x%x failed\n", reg); + + mutex_unlock(&tps->io_lock); + return data; } static int tps_65023_reg_write(struct tps_pmic *tps, u8 reg, u8 val) { - return regmap_write(tps->regmap, reg, val); + int err; + + mutex_lock(&tps->io_lock); + + err = tps_65023_write(tps, reg, val); + if (err < 0) + dev_err(&tps->client->dev, "Write for reg 0x%x failed\n", reg); + + mutex_unlock(&tps->io_lock); + return err; } static int tps65023_dcdc_is_enabled(struct regulator_dev *dev) @@ -406,11 +463,6 @@ static struct regulator_ops tps65023_ldo_ops = { .list_voltage = tps65023_ldo_list_voltage, }; -static struct regmap_config tps65023_regmap_config = { - .reg_bits = 8, - .val_bits = 8, -}; - static int __devinit tps_65023_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -436,13 +488,7 @@ static int __devinit tps_65023_probe(struct i2c_client *client, if (!tps) return -ENOMEM; - tps->regmap = regmap_init_i2c(client, &tps65023_regmap_config); - if (IS_ERR(tps->regmap)) { - error = PTR_ERR(tps->regmap); - dev_err(&client->dev, "Failed to allocate register map: %d\n", - error); - goto fail_alloc; - } + mutex_init(&tps->io_lock); /* common for all regulators */ tps->client = client; @@ -481,8 +527,6 @@ static int __devinit tps_65023_probe(struct i2c_client *client, while (--i >= 0) regulator_unregister(tps->rdev[i]); - regmap_exit(tps->regmap); - fail_alloc: kfree(tps); return error; } @@ -501,7 +545,6 @@ static int __devexit tps_65023_remove(struct i2c_client *client) for (i = 0; i < TPS65023_NUM_REGULATOR; i++) regulator_unregister(tps->rdev[i]); - regmap_exit(tps->regmap); kfree(tps); return 0; diff --git a/trunk/drivers/rtc/Kconfig b/trunk/drivers/rtc/Kconfig index dcb61e23b985..ce2aabf5c550 100644 --- a/trunk/drivers/rtc/Kconfig +++ b/trunk/drivers/rtc/Kconfig @@ -981,11 +981,11 @@ config RTC_DRV_COH901331 config RTC_DRV_STMP - tristate "Freescale STMP3xxx/i.MX23/i.MX28 RTC" - depends on ARCH_MXS + tristate "Freescale STMP3xxx RTC" + depends on ARCH_STMP3XXX help If you say yes here you will get support for the onboard - STMP3xxx/i.MX23/i.MX28 RTC. + STMP3xxx RTC. This driver can also be built as a module. If so, the module will be called rtc-stmp3xxx. diff --git a/trunk/drivers/rtc/class.c b/trunk/drivers/rtc/class.c index 01a7df5317c1..4194e59e14cd 100644 --- a/trunk/drivers/rtc/class.c +++ b/trunk/drivers/rtc/class.c @@ -41,41 +41,20 @@ static void rtc_device_release(struct device *dev) * system's wall clock; restore it on resume(). */ -static struct timespec old_rtc, old_system, old_delta; - +static time_t oldtime; +static struct timespec oldts; static int rtc_suspend(struct device *dev, pm_message_t mesg) { struct rtc_device *rtc = to_rtc_device(dev); struct rtc_time tm; - struct timespec delta, delta_delta; + if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) return 0; - /* snapshot the current RTC and system time at suspend*/ rtc_read_time(rtc, &tm); - getnstimeofday(&old_system); - rtc_tm_to_time(&tm, &old_rtc.tv_sec); - - - /* - * To avoid drift caused by repeated suspend/resumes, - * which each can add ~1 second drift error, - * try to compensate so the difference in system time - * and rtc time stays close to constant. - */ - delta = timespec_sub(old_system, old_rtc); - delta_delta = timespec_sub(delta, old_delta); - if (abs(delta_delta.tv_sec) >= 2) { - /* - * if delta_delta is too large, assume time correction - * has occured and set old_delta to the current delta. - */ - old_delta = delta; - } else { - /* Otherwise try to adjust old_system to compensate */ - old_system = timespec_sub(old_system, delta_delta); - } + ktime_get_ts(&oldts); + rtc_tm_to_time(&tm, &oldtime); return 0; } @@ -84,42 +63,32 @@ static int rtc_resume(struct device *dev) { struct rtc_device *rtc = to_rtc_device(dev); struct rtc_time tm; - struct timespec new_system, new_rtc; - struct timespec sleep_time; + time_t newtime; + struct timespec time; + struct timespec newts; if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) return 0; - /* snapshot the current rtc and system time at resume */ - getnstimeofday(&new_system); + ktime_get_ts(&newts); rtc_read_time(rtc, &tm); if (rtc_valid_tm(&tm) != 0) { pr_debug("%s: bogus resume time\n", dev_name(&rtc->dev)); return 0; } - rtc_tm_to_time(&tm, &new_rtc.tv_sec); - new_rtc.tv_nsec = 0; - - if (new_rtc.tv_sec <= old_rtc.tv_sec) { - if (new_rtc.tv_sec < old_rtc.tv_sec) + rtc_tm_to_time(&tm, &newtime); + if (newtime <= oldtime) { + if (newtime < oldtime) pr_debug("%s: time travel!\n", dev_name(&rtc->dev)); return 0; } + /* calculate the RTC time delta */ + set_normalized_timespec(&time, newtime - oldtime, 0); - /* calculate the RTC time delta (sleep time)*/ - sleep_time = timespec_sub(new_rtc, old_rtc); - - /* - * Since these RTC suspend/resume handlers are not called - * at the very end of suspend or the start of resume, - * some run-time may pass on either sides of the sleep time - * so subtract kernel run-time between rtc_suspend to rtc_resume - * to keep things accurate. - */ - sleep_time = timespec_sub(sleep_time, - timespec_sub(new_system, old_system)); + /* subtract kernel time between rtc_suspend to rtc_resume */ + time = timespec_sub(time, timespec_sub(newts, oldts)); - timekeeping_inject_sleeptime(&sleep_time); + timekeeping_inject_sleeptime(&time); return 0; } diff --git a/trunk/drivers/rtc/rtc-stmp3xxx.c b/trunk/drivers/rtc/rtc-stmp3xxx.c index 7315068daa59..572e9534b591 100644 --- a/trunk/drivers/rtc/rtc-stmp3xxx.c +++ b/trunk/drivers/rtc/rtc-stmp3xxx.c @@ -6,7 +6,6 @@ * * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved. * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. - * Copyright 2011 Wolfram Sang, Pengutronix e.K. */ /* @@ -19,41 +18,21 @@ */ #include #include -#include #include #include #include #include #include -#include - -#define STMP3XXX_RTC_CTRL 0x0 -#define STMP3XXX_RTC_CTRL_SET 0x4 -#define STMP3XXX_RTC_CTRL_CLR 0x8 -#define STMP3XXX_RTC_CTRL_ALARM_IRQ_EN 0x00000001 -#define STMP3XXX_RTC_CTRL_ONEMSEC_IRQ_EN 0x00000002 -#define STMP3XXX_RTC_CTRL_ALARM_IRQ 0x00000004 - -#define STMP3XXX_RTC_STAT 0x10 -#define STMP3XXX_RTC_STAT_STALE_SHIFT 16 -#define STMP3XXX_RTC_STAT_RTC_PRESENT 0x80000000 - -#define STMP3XXX_RTC_SECONDS 0x30 - -#define STMP3XXX_RTC_ALARM 0x40 - -#define STMP3XXX_RTC_PERSISTENT0 0x60 -#define STMP3XXX_RTC_PERSISTENT0_SET 0x64 -#define STMP3XXX_RTC_PERSISTENT0_CLR 0x68 -#define STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN 0x00000002 -#define STMP3XXX_RTC_PERSISTENT0_ALARM_EN 0x00000004 -#define STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE 0x00000080 +#include +#include +#include struct stmp3xxx_rtc_data { struct rtc_device *rtc; + unsigned irq_count; void __iomem *io; - int irq_alarm; + int irq_alarm, irq_1msec; }; static void stmp3xxx_wait_time(struct stmp3xxx_rtc_data *rtc_data) @@ -63,8 +42,8 @@ static void stmp3xxx_wait_time(struct stmp3xxx_rtc_data *rtc_data) * NEW_REGS/STALE_REGS bitfields go. In fact it's 0x1=P0, * 0x2=P1, .., 0x20=P5, 0x40=ALARM, 0x80=SECONDS */ - while (readl(rtc_data->io + STMP3XXX_RTC_STAT) & - (0x80 << STMP3XXX_RTC_STAT_STALE_SHIFT)) + while (__raw_readl(rtc_data->io + HW_RTC_STAT) & + BF(0x80, RTC_STAT_STALE_REGS)) cpu_relax(); } @@ -74,7 +53,7 @@ static int stmp3xxx_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); stmp3xxx_wait_time(rtc_data); - rtc_time_to_tm(readl(rtc_data->io + STMP3XXX_RTC_SECONDS), rtc_tm); + rtc_time_to_tm(__raw_readl(rtc_data->io + HW_RTC_SECONDS), rtc_tm); return 0; } @@ -82,7 +61,7 @@ static int stmp3xxx_rtc_set_mmss(struct device *dev, unsigned long t) { struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); - writel(t, rtc_data->io + STMP3XXX_RTC_SECONDS); + __raw_writel(t, rtc_data->io + HW_RTC_SECONDS); stmp3xxx_wait_time(rtc_data); return 0; } @@ -91,34 +70,47 @@ static int stmp3xxx_rtc_set_mmss(struct device *dev, unsigned long t) static irqreturn_t stmp3xxx_rtc_interrupt(int irq, void *dev_id) { struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev_id); - u32 status = readl(rtc_data->io + STMP3XXX_RTC_CTRL); + u32 status; + u32 events = 0; + + status = __raw_readl(rtc_data->io + HW_RTC_CTRL) & + (BM_RTC_CTRL_ALARM_IRQ | BM_RTC_CTRL_ONEMSEC_IRQ); - if (status & STMP3XXX_RTC_CTRL_ALARM_IRQ) { - writel(STMP3XXX_RTC_CTRL_ALARM_IRQ, - rtc_data->io + STMP3XXX_RTC_CTRL_CLR); - rtc_update_irq(rtc_data->rtc, 1, RTC_AF | RTC_IRQF); - return IRQ_HANDLED; + if (status & BM_RTC_CTRL_ALARM_IRQ) { + stmp3xxx_clearl(BM_RTC_CTRL_ALARM_IRQ, + rtc_data->io + HW_RTC_CTRL); + events |= RTC_AF | RTC_IRQF; } - return IRQ_NONE; + if (status & BM_RTC_CTRL_ONEMSEC_IRQ) { + stmp3xxx_clearl(BM_RTC_CTRL_ONEMSEC_IRQ, + rtc_data->io + HW_RTC_CTRL); + if (++rtc_data->irq_count % 1000 == 0) { + events |= RTC_UF | RTC_IRQF; + rtc_data->irq_count = 0; + } + } + + if (events) + rtc_update_irq(rtc_data->rtc, 1, events); + + return IRQ_HANDLED; } static int stmp3xxx_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); + void __iomem *p = rtc_data->io + HW_RTC_PERSISTENT0, + *ctl = rtc_data->io + HW_RTC_CTRL; if (enabled) { - writel(STMP3XXX_RTC_PERSISTENT0_ALARM_EN | - STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN, - rtc_data->io + STMP3XXX_RTC_PERSISTENT0_SET); - writel(STMP3XXX_RTC_CTRL_ALARM_IRQ_EN, - rtc_data->io + STMP3XXX_RTC_CTRL_SET); + stmp3xxx_setl(BM_RTC_PERSISTENT0_ALARM_EN | + BM_RTC_PERSISTENT0_ALARM_WAKE_EN, p); + stmp3xxx_setl(BM_RTC_CTRL_ALARM_IRQ_EN, ctl); } else { - writel(STMP3XXX_RTC_PERSISTENT0_ALARM_EN | - STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN, - rtc_data->io + STMP3XXX_RTC_PERSISTENT0_CLR); - writel(STMP3XXX_RTC_CTRL_ALARM_IRQ_EN, - rtc_data->io + STMP3XXX_RTC_CTRL_CLR); + stmp3xxx_clearl(BM_RTC_PERSISTENT0_ALARM_EN | + BM_RTC_PERSISTENT0_ALARM_WAKE_EN, p); + stmp3xxx_clearl(BM_RTC_CTRL_ALARM_IRQ_EN, ctl); } return 0; } @@ -127,7 +119,7 @@ static int stmp3xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) { struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); - rtc_time_to_tm(readl(rtc_data->io + STMP3XXX_RTC_ALARM), &alm->time); + rtc_time_to_tm(__raw_readl(rtc_data->io + HW_RTC_ALARM), &alm->time); return 0; } @@ -137,10 +129,7 @@ static int stmp3xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); rtc_tm_to_time(&alm->time, &t); - writel(t, rtc_data->io + STMP3XXX_RTC_ALARM); - - stmp3xxx_alarm_irq_enable(dev, alm->enabled); - + __raw_writel(t, rtc_data->io + HW_RTC_ALARM); return 0; } @@ -160,11 +149,11 @@ static int stmp3xxx_rtc_remove(struct platform_device *pdev) if (!rtc_data) return 0; - writel(STMP3XXX_RTC_CTRL_ALARM_IRQ_EN, - rtc_data->io + STMP3XXX_RTC_CTRL_CLR); + stmp3xxx_clearl(BM_RTC_CTRL_ONEMSEC_IRQ_EN | BM_RTC_CTRL_ALARM_IRQ_EN, + rtc_data->io + HW_RTC_CTRL); free_irq(rtc_data->irq_alarm, &pdev->dev); + free_irq(rtc_data->irq_1msec, &pdev->dev); rtc_device_unregister(rtc_data->rtc); - platform_set_drvdata(pdev, NULL); iounmap(rtc_data->io); kfree(rtc_data); @@ -196,26 +185,20 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev) } rtc_data->irq_alarm = platform_get_irq(pdev, 0); + rtc_data->irq_1msec = platform_get_irq(pdev, 1); - if (!(readl(STMP3XXX_RTC_STAT + rtc_data->io) & - STMP3XXX_RTC_STAT_RTC_PRESENT)) { + if (!(__raw_readl(HW_RTC_STAT + rtc_data->io) & + BM_RTC_STAT_RTC_PRESENT)) { dev_err(&pdev->dev, "no device onboard\n"); err = -ENODEV; goto out_remap; } - platform_set_drvdata(pdev, rtc_data); - - mxs_reset_block(rtc_data->io); - writel(STMP3XXX_RTC_PERSISTENT0_ALARM_EN | - STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN | - STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE, - rtc_data->io + STMP3XXX_RTC_PERSISTENT0_CLR); - - writel(STMP3XXX_RTC_CTRL_ONEMSEC_IRQ_EN | - STMP3XXX_RTC_CTRL_ALARM_IRQ_EN, - rtc_data->io + STMP3XXX_RTC_CTRL_CLR); - + stmp3xxx_reset_block(rtc_data->io, true); + stmp3xxx_clearl(BM_RTC_PERSISTENT0_ALARM_EN | + BM_RTC_PERSISTENT0_ALARM_WAKE_EN | + BM_RTC_PERSISTENT0_ALARM_WAKE, + rtc_data->io + HW_RTC_PERSISTENT0); rtc_data->rtc = rtc_device_register(pdev->name, &pdev->dev, &stmp3xxx_rtc_ops, THIS_MODULE); if (IS_ERR(rtc_data->rtc)) { @@ -223,20 +206,33 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev) goto out_remap; } - err = request_irq(rtc_data->irq_alarm, stmp3xxx_rtc_interrupt, 0, - "RTC alarm", &pdev->dev); + rtc_data->irq_count = 0; + err = request_irq(rtc_data->irq_alarm, stmp3xxx_rtc_interrupt, + IRQF_DISABLED, "RTC alarm", &pdev->dev); if (err) { dev_err(&pdev->dev, "Cannot claim IRQ%d\n", rtc_data->irq_alarm); goto out_irq_alarm; } + err = request_irq(rtc_data->irq_1msec, stmp3xxx_rtc_interrupt, + IRQF_DISABLED, "RTC tick", &pdev->dev); + if (err) { + dev_err(&pdev->dev, "Cannot claim IRQ%d\n", + rtc_data->irq_1msec); + goto out_irq1; + } + + platform_set_drvdata(pdev, rtc_data); return 0; +out_irq1: + free_irq(rtc_data->irq_alarm, &pdev->dev); out_irq_alarm: + stmp3xxx_clearl(BM_RTC_CTRL_ONEMSEC_IRQ_EN | BM_RTC_CTRL_ALARM_IRQ_EN, + rtc_data->io + HW_RTC_CTRL); rtc_device_unregister(rtc_data->rtc); out_remap: - platform_set_drvdata(pdev, NULL); iounmap(rtc_data->io); out_free: kfree(rtc_data); @@ -253,11 +249,11 @@ static int stmp3xxx_rtc_resume(struct platform_device *dev) { struct stmp3xxx_rtc_data *rtc_data = platform_get_drvdata(dev); - mxs_reset_block(rtc_data->io); - writel(STMP3XXX_RTC_PERSISTENT0_ALARM_EN | - STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN | - STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE, - rtc_data->io + STMP3XXX_RTC_PERSISTENT0_CLR); + stmp3xxx_reset_block(rtc_data->io, true); + stmp3xxx_clearl(BM_RTC_PERSISTENT0_ALARM_EN | + BM_RTC_PERSISTENT0_ALARM_WAKE_EN | + BM_RTC_PERSISTENT0_ALARM_WAKE, + rtc_data->io + HW_RTC_PERSISTENT0); return 0; } #else @@ -290,6 +286,5 @@ module_init(stmp3xxx_rtc_init); module_exit(stmp3xxx_rtc_exit); MODULE_DESCRIPTION("STMP3xxx RTC Driver"); -MODULE_AUTHOR("dmitry pervushin and " - "Wolfram Sang "); +MODULE_AUTHOR("dmitry pervushin "); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/rtc/rtc-vt8500.c b/trunk/drivers/rtc/rtc-vt8500.c index f93f412423c6..efd6066b5cd2 100644 --- a/trunk/drivers/rtc/rtc-vt8500.c +++ b/trunk/drivers/rtc/rtc-vt8500.c @@ -74,8 +74,6 @@ #define VT8500_RTC_CR_SM_SEC (1 << 3) /* 0: 1Hz/60, 1: 1Hz */ #define VT8500_RTC_CR_CALIB (1 << 4) /* Enable calibration */ -#define VT8500_RTC_IS_ALARM (1 << 0) /* Alarm interrupt status */ - struct vt8500_rtc { void __iomem *regbase; struct resource *res; @@ -98,7 +96,7 @@ static irqreturn_t vt8500_rtc_irq(int irq, void *dev_id) spin_unlock(&vt8500_rtc->lock); - if (isr & VT8500_RTC_IS_ALARM) + if (isr & 1) events |= RTC_AF | RTC_IRQF; rtc_update_irq(vt8500_rtc->rtc, 1, events); @@ -163,8 +161,8 @@ static int vt8500_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) alrm->time.tm_sec = bcd2bin((alarm & TIME_SEC_MASK)); alrm->enabled = (alarm & ALARM_ENABLE_MASK) ? 1 : 0; - alrm->pending = (isr & VT8500_RTC_IS_ALARM) ? 1 : 0; + alrm->pending = (isr & 1) ? 1 : 0; return rtc_valid_tm(&alrm->time); } diff --git a/trunk/drivers/s390/block/dasd.c b/trunk/drivers/s390/block/dasd.c index 432444af7ee4..86b6f1cc1b10 100644 --- a/trunk/drivers/s390/block/dasd.c +++ b/trunk/drivers/s390/block/dasd.c @@ -22,8 +22,6 @@ #include #include #include -#include -#include #include #include @@ -47,7 +45,6 @@ * SECTION: exported variables of dasd.c */ debug_info_t *dasd_debug_area; -static struct dentry *dasd_debugfs_root_entry; struct dasd_discipline *dasd_diag_discipline_pointer; void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *); @@ -74,8 +71,6 @@ static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *); static void dasd_device_timeout(unsigned long); static void dasd_block_timeout(unsigned long); static void __dasd_process_erp(struct dasd_device *, struct dasd_ccw_req *); -static void dasd_profile_init(struct dasd_profile *, struct dentry *); -static void dasd_profile_exit(struct dasd_profile *); /* * SECTION: Operations on the device structure. @@ -126,7 +121,7 @@ struct dasd_device *dasd_alloc_device(void) device->state = DASD_STATE_NEW; device->target = DASD_STATE_NEW; mutex_init(&device->state_mutex); - spin_lock_init(&device->profile.lock); + return device; } @@ -164,7 +159,6 @@ struct dasd_block *dasd_alloc_block(void) init_timer(&block->timer); block->timer.function = dasd_block_timeout; block->timer.data = (unsigned long) block; - spin_lock_init(&block->profile.lock); return block; } @@ -228,44 +222,19 @@ static int dasd_state_known_to_new(struct dasd_device *device) return 0; } -static struct dentry *dasd_debugfs_setup(const char *name, - struct dentry *base_dentry) -{ - struct dentry *pde; - - if (!base_dentry) - return NULL; - pde = debugfs_create_dir(name, base_dentry); - if (!pde || IS_ERR(pde)) - return NULL; - return pde; -} - /* * Request the irq line for the device. */ static int dasd_state_known_to_basic(struct dasd_device *device) { - struct dasd_block *block = device->block; int rc; /* Allocate and register gendisk structure. */ - if (block) { - rc = dasd_gendisk_alloc(block); + if (device->block) { + rc = dasd_gendisk_alloc(device->block); if (rc) return rc; - block->debugfs_dentry = - dasd_debugfs_setup(block->gdp->disk_name, - dasd_debugfs_root_entry); - dasd_profile_init(&block->profile, block->debugfs_dentry); - if (dasd_global_profile_level == DASD_PROFILE_ON) - dasd_profile_on(&device->block->profile); - } - device->debugfs_dentry = - dasd_debugfs_setup(dev_name(&device->cdev->dev), - dasd_debugfs_root_entry); - dasd_profile_init(&device->profile, device->debugfs_dentry); - + } /* register 'device' debug area, used for all DBF_DEV_XXX calls */ device->debug_area = debug_register(dev_name(&device->cdev->dev), 4, 1, 8 * sizeof(long)); @@ -284,9 +253,6 @@ static int dasd_state_basic_to_known(struct dasd_device *device) { int rc; if (device->block) { - dasd_profile_exit(&device->block->profile); - if (device->block->debugfs_dentry) - debugfs_remove(device->block->debugfs_dentry); dasd_gendisk_free(device->block); dasd_block_clear_timer(device->block); } @@ -294,9 +260,6 @@ static int dasd_state_basic_to_known(struct dasd_device *device) if (rc) return rc; dasd_device_clear_timer(device); - dasd_profile_exit(&device->profile); - if (device->debugfs_dentry) - debugfs_remove(device->debugfs_dentry); DBF_DEV_EVENT(DBF_EMERG, device, "%p debug area deleted", device); if (device->debug_area != NULL) { @@ -646,13 +609,21 @@ void dasd_enable_device(struct dasd_device *device) /* * SECTION: device operation (interrupt handler, start i/o, term i/o ...) */ +#ifdef CONFIG_DASD_PROFILE -unsigned int dasd_global_profile_level = DASD_PROFILE_OFF; +struct dasd_profile_info_t dasd_global_profile; +unsigned int dasd_profile_level = DASD_PROFILE_OFF; -#ifdef CONFIG_DASD_PROFILE -struct dasd_profile_info dasd_global_profile_data; -static struct dentry *dasd_global_profile_dentry; -static struct dentry *dasd_debugfs_global_entry; +/* + * Increments counter in global and local profiling structures. + */ +#define dasd_profile_counter(value, counter, block) \ +{ \ + int index; \ + for (index = 0; index < 31 && value >> (2+index); index++); \ + dasd_global_profile.counter[index]++; \ + block->profile.counter[index]++; \ +} /* * Add profiling information for cqr before execution. @@ -663,121 +634,30 @@ static void dasd_profile_start(struct dasd_block *block, { struct list_head *l; unsigned int counter; - struct dasd_device *device; + + if (dasd_profile_level != DASD_PROFILE_ON) + return; /* count the length of the chanq for statistics */ counter = 0; - if (dasd_global_profile_level || block->profile.data) - list_for_each(l, &block->ccw_queue) - if (++counter >= 31) - break; - - if (dasd_global_profile_level) { - dasd_global_profile_data.dasd_io_nr_req[counter]++; - if (rq_data_dir(req) == READ) - dasd_global_profile_data.dasd_read_nr_req[counter]++; - } - - spin_lock(&block->profile.lock); - if (block->profile.data) - block->profile.data->dasd_io_nr_req[counter]++; - if (rq_data_dir(req) == READ) - block->profile.data->dasd_read_nr_req[counter]++; - spin_unlock(&block->profile.lock); - - /* - * We count the request for the start device, even though it may run on - * some other device due to error recovery. This way we make sure that - * we count each request only once. - */ - device = cqr->startdev; - if (device->profile.data) { - counter = 1; /* request is not yet queued on the start device */ - list_for_each(l, &device->ccw_queue) - if (++counter >= 31) - break; - } - spin_lock(&device->profile.lock); - if (device->profile.data) { - device->profile.data->dasd_io_nr_req[counter]++; - if (rq_data_dir(req) == READ) - device->profile.data->dasd_read_nr_req[counter]++; - } - spin_unlock(&device->profile.lock); + list_for_each(l, &block->ccw_queue) + if (++counter >= 31) + break; + dasd_global_profile.dasd_io_nr_req[counter]++; + block->profile.dasd_io_nr_req[counter]++; } /* * Add profiling information for cqr after execution. */ - -#define dasd_profile_counter(value, index) \ -{ \ - for (index = 0; index < 31 && value >> (2+index); index++) \ - ; \ -} - -static void dasd_profile_end_add_data(struct dasd_profile_info *data, - int is_alias, - int is_tpm, - int is_read, - long sectors, - int sectors_ind, - int tottime_ind, - int tottimeps_ind, - int strtime_ind, - int irqtime_ind, - int irqtimeps_ind, - int endtime_ind) -{ - /* in case of an overflow, reset the whole profile */ - if (data->dasd_io_reqs == UINT_MAX) { - memset(data, 0, sizeof(*data)); - getnstimeofday(&data->starttod); - } - data->dasd_io_reqs++; - data->dasd_io_sects += sectors; - if (is_alias) - data->dasd_io_alias++; - if (is_tpm) - data->dasd_io_tpm++; - - data->dasd_io_secs[sectors_ind]++; - data->dasd_io_times[tottime_ind]++; - data->dasd_io_timps[tottimeps_ind]++; - data->dasd_io_time1[strtime_ind]++; - data->dasd_io_time2[irqtime_ind]++; - data->dasd_io_time2ps[irqtimeps_ind]++; - data->dasd_io_time3[endtime_ind]++; - - if (is_read) { - data->dasd_read_reqs++; - data->dasd_read_sects += sectors; - if (is_alias) - data->dasd_read_alias++; - if (is_tpm) - data->dasd_read_tpm++; - data->dasd_read_secs[sectors_ind]++; - data->dasd_read_times[tottime_ind]++; - data->dasd_read_time1[strtime_ind]++; - data->dasd_read_time2[irqtime_ind]++; - data->dasd_read_time3[endtime_ind]++; - } -} - static void dasd_profile_end(struct dasd_block *block, struct dasd_ccw_req *cqr, struct request *req) { long strtime, irqtime, endtime, tottime; /* in microseconds */ long tottimeps, sectors; - struct dasd_device *device; - int sectors_ind, tottime_ind, tottimeps_ind, strtime_ind; - int irqtime_ind, irqtimeps_ind, endtime_ind; - device = cqr->startdev; - if (!(dasd_global_profile_level || - block->profile.data || - device->profile.data)) + if (dasd_profile_level != DASD_PROFILE_ON) return; sectors = blk_rq_sectors(req); @@ -792,392 +672,29 @@ static void dasd_profile_end(struct dasd_block *block, tottime = ((cqr->endclk - cqr->buildclk) >> 12); tottimeps = tottime / sectors; - dasd_profile_counter(sectors, sectors_ind); - dasd_profile_counter(tottime, tottime_ind); - dasd_profile_counter(tottimeps, tottimeps_ind); - dasd_profile_counter(strtime, strtime_ind); - dasd_profile_counter(irqtime, irqtime_ind); - dasd_profile_counter(irqtime / sectors, irqtimeps_ind); - dasd_profile_counter(endtime, endtime_ind); - - if (dasd_global_profile_level) { - dasd_profile_end_add_data(&dasd_global_profile_data, - cqr->startdev != block->base, - cqr->cpmode == 1, - rq_data_dir(req) == READ, - sectors, sectors_ind, tottime_ind, - tottimeps_ind, strtime_ind, - irqtime_ind, irqtimeps_ind, - endtime_ind); - } - - spin_lock(&block->profile.lock); - if (block->profile.data) - dasd_profile_end_add_data(block->profile.data, - cqr->startdev != block->base, - cqr->cpmode == 1, - rq_data_dir(req) == READ, - sectors, sectors_ind, tottime_ind, - tottimeps_ind, strtime_ind, - irqtime_ind, irqtimeps_ind, - endtime_ind); - spin_unlock(&block->profile.lock); - - spin_lock(&device->profile.lock); - if (device->profile.data) - dasd_profile_end_add_data(device->profile.data, - cqr->startdev != block->base, - cqr->cpmode == 1, - rq_data_dir(req) == READ, - sectors, sectors_ind, tottime_ind, - tottimeps_ind, strtime_ind, - irqtime_ind, irqtimeps_ind, - endtime_ind); - spin_unlock(&device->profile.lock); -} - -void dasd_profile_reset(struct dasd_profile *profile) -{ - struct dasd_profile_info *data; - - spin_lock_bh(&profile->lock); - data = profile->data; - if (!data) { - spin_unlock_bh(&profile->lock); - return; - } - memset(data, 0, sizeof(*data)); - getnstimeofday(&data->starttod); - spin_unlock_bh(&profile->lock); -} - -void dasd_global_profile_reset(void) -{ - memset(&dasd_global_profile_data, 0, sizeof(dasd_global_profile_data)); - getnstimeofday(&dasd_global_profile_data.starttod); -} - -int dasd_profile_on(struct dasd_profile *profile) -{ - struct dasd_profile_info *data; - - data = kzalloc(sizeof(*data), GFP_KERNEL); - if (!data) - return -ENOMEM; - spin_lock_bh(&profile->lock); - if (profile->data) { - spin_unlock_bh(&profile->lock); - kfree(data); - return 0; - } - getnstimeofday(&data->starttod); - profile->data = data; - spin_unlock_bh(&profile->lock); - return 0; -} - -void dasd_profile_off(struct dasd_profile *profile) -{ - spin_lock_bh(&profile->lock); - kfree(profile->data); - profile->data = NULL; - spin_unlock_bh(&profile->lock); -} - -char *dasd_get_user_string(const char __user *user_buf, size_t user_len) -{ - char *buffer; - - buffer = kmalloc(user_len + 1, GFP_KERNEL); - if (buffer == NULL) - return ERR_PTR(-ENOMEM); - if (copy_from_user(buffer, user_buf, user_len) != 0) { - kfree(buffer); - return ERR_PTR(-EFAULT); - } - /* got the string, now strip linefeed. */ - if (buffer[user_len - 1] == '\n') - buffer[user_len - 1] = 0; - else - buffer[user_len] = 0; - return buffer; + if (!dasd_global_profile.dasd_io_reqs) + memset(&dasd_global_profile, 0, + sizeof(struct dasd_profile_info_t)); + dasd_global_profile.dasd_io_reqs++; + dasd_global_profile.dasd_io_sects += sectors; + + if (!block->profile.dasd_io_reqs) + memset(&block->profile, 0, + sizeof(struct dasd_profile_info_t)); + block->profile.dasd_io_reqs++; + block->profile.dasd_io_sects += sectors; + + dasd_profile_counter(sectors, dasd_io_secs, block); + dasd_profile_counter(tottime, dasd_io_times, block); + dasd_profile_counter(tottimeps, dasd_io_timps, block); + dasd_profile_counter(strtime, dasd_io_time1, block); + dasd_profile_counter(irqtime, dasd_io_time2, block); + dasd_profile_counter(irqtime / sectors, dasd_io_time2ps, block); + dasd_profile_counter(endtime, dasd_io_time3, block); } - -static ssize_t dasd_stats_write(struct file *file, - const char __user *user_buf, - size_t user_len, loff_t *pos) -{ - char *buffer, *str; - int rc; - struct seq_file *m = (struct seq_file *)file->private_data; - struct dasd_profile *prof = m->private; - - if (user_len > 65536) - user_len = 65536; - buffer = dasd_get_user_string(user_buf, user_len); - if (IS_ERR(buffer)) - return PTR_ERR(buffer); - - str = skip_spaces(buffer); - rc = user_len; - if (strncmp(str, "reset", 5) == 0) { - dasd_profile_reset(prof); - } else if (strncmp(str, "on", 2) == 0) { - rc = dasd_profile_on(prof); - if (!rc) - rc = user_len; - } else if (strncmp(str, "off", 3) == 0) { - dasd_profile_off(prof); - } else - rc = -EINVAL; - kfree(buffer); - return rc; -} - -static void dasd_stats_array(struct seq_file *m, unsigned int *array) -{ - int i; - - for (i = 0; i < 32; i++) - seq_printf(m, "%u ", array[i]); - seq_putc(m, '\n'); -} - -static void dasd_stats_seq_print(struct seq_file *m, - struct dasd_profile_info *data) -{ - seq_printf(m, "start_time %ld.%09ld\n", - data->starttod.tv_sec, data->starttod.tv_nsec); - seq_printf(m, "total_requests %u\n", data->dasd_io_reqs); - seq_printf(m, "total_sectors %u\n", data->dasd_io_sects); - seq_printf(m, "total_pav %u\n", data->dasd_io_alias); - seq_printf(m, "total_hpf %u\n", data->dasd_io_tpm); - seq_printf(m, "histogram_sectors "); - dasd_stats_array(m, data->dasd_io_secs); - seq_printf(m, "histogram_io_times "); - dasd_stats_array(m, data->dasd_io_times); - seq_printf(m, "histogram_io_times_weighted "); - dasd_stats_array(m, data->dasd_io_timps); - seq_printf(m, "histogram_time_build_to_ssch "); - dasd_stats_array(m, data->dasd_io_time1); - seq_printf(m, "histogram_time_ssch_to_irq "); - dasd_stats_array(m, data->dasd_io_time2); - seq_printf(m, "histogram_time_ssch_to_irq_weighted "); - dasd_stats_array(m, data->dasd_io_time2ps); - seq_printf(m, "histogram_time_irq_to_end "); - dasd_stats_array(m, data->dasd_io_time3); - seq_printf(m, "histogram_ccw_queue_length "); - dasd_stats_array(m, data->dasd_io_nr_req); - seq_printf(m, "total_read_requests %u\n", data->dasd_read_reqs); - seq_printf(m, "total_read_sectors %u\n", data->dasd_read_sects); - seq_printf(m, "total_read_pav %u\n", data->dasd_read_alias); - seq_printf(m, "total_read_hpf %u\n", data->dasd_read_tpm); - seq_printf(m, "histogram_read_sectors "); - dasd_stats_array(m, data->dasd_read_secs); - seq_printf(m, "histogram_read_times "); - dasd_stats_array(m, data->dasd_read_times); - seq_printf(m, "histogram_read_time_build_to_ssch "); - dasd_stats_array(m, data->dasd_read_time1); - seq_printf(m, "histogram_read_time_ssch_to_irq "); - dasd_stats_array(m, data->dasd_read_time2); - seq_printf(m, "histogram_read_time_irq_to_end "); - dasd_stats_array(m, data->dasd_read_time3); - seq_printf(m, "histogram_read_ccw_queue_length "); - dasd_stats_array(m, data->dasd_read_nr_req); -} - -static int dasd_stats_show(struct seq_file *m, void *v) -{ - struct dasd_profile *profile; - struct dasd_profile_info *data; - - profile = m->private; - spin_lock_bh(&profile->lock); - data = profile->data; - if (!data) { - spin_unlock_bh(&profile->lock); - seq_printf(m, "disabled\n"); - return 0; - } - dasd_stats_seq_print(m, data); - spin_unlock_bh(&profile->lock); - return 0; -} - -static int dasd_stats_open(struct inode *inode, struct file *file) -{ - struct dasd_profile *profile = inode->i_private; - return single_open(file, dasd_stats_show, profile); -} - -static const struct file_operations dasd_stats_raw_fops = { - .owner = THIS_MODULE, - .open = dasd_stats_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .write = dasd_stats_write, -}; - -static ssize_t dasd_stats_global_write(struct file *file, - const char __user *user_buf, - size_t user_len, loff_t *pos) -{ - char *buffer, *str; - ssize_t rc; - - if (user_len > 65536) - user_len = 65536; - buffer = dasd_get_user_string(user_buf, user_len); - if (IS_ERR(buffer)) - return PTR_ERR(buffer); - str = skip_spaces(buffer); - rc = user_len; - if (strncmp(str, "reset", 5) == 0) { - dasd_global_profile_reset(); - } else if (strncmp(str, "on", 2) == 0) { - dasd_global_profile_reset(); - dasd_global_profile_level = DASD_PROFILE_GLOBAL_ONLY; - } else if (strncmp(str, "off", 3) == 0) { - dasd_global_profile_level = DASD_PROFILE_OFF; - } else - rc = -EINVAL; - kfree(buffer); - return rc; -} - -static int dasd_stats_global_show(struct seq_file *m, void *v) -{ - if (!dasd_global_profile_level) { - seq_printf(m, "disabled\n"); - return 0; - } - dasd_stats_seq_print(m, &dasd_global_profile_data); - return 0; -} - -static int dasd_stats_global_open(struct inode *inode, struct file *file) -{ - return single_open(file, dasd_stats_global_show, NULL); -} - -static const struct file_operations dasd_stats_global_fops = { - .owner = THIS_MODULE, - .open = dasd_stats_global_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .write = dasd_stats_global_write, -}; - -static void dasd_profile_init(struct dasd_profile *profile, - struct dentry *base_dentry) -{ - mode_t mode; - struct dentry *pde; - - if (!base_dentry) - return; - profile->dentry = NULL; - profile->data = NULL; - mode = (S_IRUSR | S_IWUSR | S_IFREG); - pde = debugfs_create_file("statistics", mode, base_dentry, - profile, &dasd_stats_raw_fops); - if (pde && !IS_ERR(pde)) - profile->dentry = pde; - return; -} - -static void dasd_profile_exit(struct dasd_profile *profile) -{ - dasd_profile_off(profile); - if (profile->dentry) { - debugfs_remove(profile->dentry); - profile->dentry = NULL; - } -} - -static void dasd_statistics_removeroot(void) -{ - dasd_global_profile_level = DASD_PROFILE_OFF; - if (dasd_global_profile_dentry) { - debugfs_remove(dasd_global_profile_dentry); - dasd_global_profile_dentry = NULL; - } - if (dasd_debugfs_global_entry) - debugfs_remove(dasd_debugfs_global_entry); - if (dasd_debugfs_root_entry) - debugfs_remove(dasd_debugfs_root_entry); -} - -static void dasd_statistics_createroot(void) -{ - mode_t mode; - struct dentry *pde; - - dasd_debugfs_root_entry = NULL; - dasd_debugfs_global_entry = NULL; - dasd_global_profile_dentry = NULL; - pde = debugfs_create_dir("dasd", NULL); - if (!pde || IS_ERR(pde)) - goto error; - dasd_debugfs_root_entry = pde; - pde = debugfs_create_dir("global", dasd_debugfs_root_entry); - if (!pde || IS_ERR(pde)) - goto error; - dasd_debugfs_global_entry = pde; - - mode = (S_IRUSR | S_IWUSR | S_IFREG); - pde = debugfs_create_file("statistics", mode, dasd_debugfs_global_entry, - NULL, &dasd_stats_global_fops); - if (!pde || IS_ERR(pde)) - goto error; - dasd_global_profile_dentry = pde; - return; - -error: - DBF_EVENT(DBF_ERR, "%s", - "Creation of the dasd debugfs interface failed"); - dasd_statistics_removeroot(); - return; -} - #else #define dasd_profile_start(block, cqr, req) do {} while (0) #define dasd_profile_end(block, cqr, req) do {} while (0) - -static void dasd_statistics_createroot(void) -{ - return; -} - -static void dasd_statistics_removeroot(void) -{ - return; -} - -int dasd_stats_generic_show(struct seq_file *m, void *v) -{ - seq_printf(m, "Statistics are not activated in this kernel\n"); - return 0; -} - -static void dasd_profile_init(struct dasd_profile *profile, - struct dentry *base_dentry) -{ - return; -} - -static void dasd_profile_exit(struct dasd_profile *profile) -{ - return; -} - -int dasd_profile_on(struct dasd_profile *profile) -{ - return 0; -} - #endif /* CONFIG_DASD_PROFILE */ /* @@ -2924,7 +2441,6 @@ dasd_exit(void) debug_unregister(dasd_debug_area); dasd_debug_area = NULL; } - dasd_statistics_removeroot(); } /* @@ -3476,8 +2992,6 @@ static int __init dasd_init(void) dasd_diag_discipline_pointer = NULL; - dasd_statistics_createroot(); - rc = dasd_devmap_init(); if (rc) goto failed; diff --git a/trunk/drivers/s390/block/dasd_int.h b/trunk/drivers/s390/block/dasd_int.h index 1dd12bd85a69..d1e4f2c1264c 100644 --- a/trunk/drivers/s390/block/dasd_int.h +++ b/trunk/drivers/s390/block/dasd_int.h @@ -382,41 +382,6 @@ struct dasd_path { __u8 npm; }; -struct dasd_profile_info { - /* legacy part of profile data, as in dasd_profile_info_t */ - unsigned int dasd_io_reqs; /* number of requests processed */ - unsigned int dasd_io_sects; /* number of sectors processed */ - unsigned int dasd_io_secs[32]; /* histogram of request's sizes */ - unsigned int dasd_io_times[32]; /* histogram of requests's times */ - unsigned int dasd_io_timps[32]; /* h. of requests's times per sector */ - unsigned int dasd_io_time1[32]; /* hist. of time from build to start */ - unsigned int dasd_io_time2[32]; /* hist. of time from start to irq */ - unsigned int dasd_io_time2ps[32]; /* hist. of time from start to irq */ - unsigned int dasd_io_time3[32]; /* hist. of time from irq to end */ - unsigned int dasd_io_nr_req[32]; /* hist. of # of requests in chanq */ - - /* new data */ - struct timespec starttod; /* time of start or last reset */ - unsigned int dasd_io_alias; /* requests using an alias */ - unsigned int dasd_io_tpm; /* requests using transport mode */ - unsigned int dasd_read_reqs; /* total number of read requests */ - unsigned int dasd_read_sects; /* total number read sectors */ - unsigned int dasd_read_alias; /* read request using an alias */ - unsigned int dasd_read_tpm; /* read requests in transport mode */ - unsigned int dasd_read_secs[32]; /* histogram of request's sizes */ - unsigned int dasd_read_times[32]; /* histogram of requests's times */ - unsigned int dasd_read_time1[32]; /* hist. time from build to start */ - unsigned int dasd_read_time2[32]; /* hist. of time from start to irq */ - unsigned int dasd_read_time3[32]; /* hist. of time from irq to end */ - unsigned int dasd_read_nr_req[32]; /* hist. of # of requests in chanq */ -}; - -struct dasd_profile { - struct dentry *dentry; - struct dasd_profile_info *data; - spinlock_t lock; -}; - struct dasd_device { /* Block device stuff. */ struct dasd_block *block; @@ -466,9 +431,6 @@ struct dasd_device { /* default expiration time in s */ unsigned long default_expires; - - struct dentry *debugfs_dentry; - struct dasd_profile profile; }; struct dasd_block { @@ -491,8 +453,9 @@ struct dasd_block { struct tasklet_struct tasklet; struct timer_list timer; - struct dentry *debugfs_dentry; - struct dasd_profile profile; +#ifdef CONFIG_DASD_PROFILE + struct dasd_profile_info_t profile; +#endif }; @@ -626,13 +589,12 @@ dasd_check_blocksize(int bsize) } /* externals in dasd.c */ -#define DASD_PROFILE_OFF 0 -#define DASD_PROFILE_ON 1 -#define DASD_PROFILE_GLOBAL_ONLY 2 +#define DASD_PROFILE_ON 1 +#define DASD_PROFILE_OFF 0 extern debug_info_t *dasd_debug_area; -extern struct dasd_profile_info dasd_global_profile_data; -extern unsigned int dasd_global_profile_level; +extern struct dasd_profile_info_t dasd_global_profile; +extern unsigned int dasd_profile_level; extern const struct block_device_operations dasd_device_operations; extern struct kmem_cache *dasd_page_cache; @@ -700,11 +662,6 @@ void dasd_device_remove_stop_bits(struct dasd_device *, int); int dasd_device_is_ro(struct dasd_device *); -void dasd_profile_reset(struct dasd_profile *); -int dasd_profile_on(struct dasd_profile *); -void dasd_profile_off(struct dasd_profile *); -void dasd_global_profile_reset(void); -char *dasd_get_user_string(const char __user *, size_t); /* externals in dasd_devmap.c */ extern int dasd_max_devindex; diff --git a/trunk/drivers/s390/block/dasd_ioctl.c b/trunk/drivers/s390/block/dasd_ioctl.c index eb4e034378cd..72261e4c516d 100644 --- a/trunk/drivers/s390/block/dasd_ioctl.c +++ b/trunk/drivers/s390/block/dasd_ioctl.c @@ -239,7 +239,7 @@ dasd_ioctl_format(struct block_device *bdev, void __user *argp) */ static int dasd_ioctl_reset_profile(struct dasd_block *block) { - dasd_profile_reset(&block->profile); + memset(&block->profile, 0, sizeof(struct dasd_profile_info_t)); return 0; } @@ -248,40 +248,10 @@ static int dasd_ioctl_reset_profile(struct dasd_block *block) */ static int dasd_ioctl_read_profile(struct dasd_block *block, void __user *argp) { - struct dasd_profile_info_t *data; - - data = kmalloc(sizeof(*data), GFP_KERNEL); - if (!data) - return -ENOMEM; - - spin_lock_bh(&block->profile.lock); - if (block->profile.data) { - data->dasd_io_reqs = block->profile.data->dasd_io_reqs; - data->dasd_io_sects = block->profile.data->dasd_io_sects; - memcpy(data->dasd_io_secs, block->profile.data->dasd_io_secs, - sizeof(data->dasd_io_secs)); - memcpy(data->dasd_io_times, block->profile.data->dasd_io_times, - sizeof(data->dasd_io_times)); - memcpy(data->dasd_io_timps, block->profile.data->dasd_io_timps, - sizeof(data->dasd_io_timps)); - memcpy(data->dasd_io_time1, block->profile.data->dasd_io_time1, - sizeof(data->dasd_io_time1)); - memcpy(data->dasd_io_time2, block->profile.data->dasd_io_time2, - sizeof(data->dasd_io_time2)); - memcpy(data->dasd_io_time2ps, - block->profile.data->dasd_io_time2ps, - sizeof(data->dasd_io_time2ps)); - memcpy(data->dasd_io_time3, block->profile.data->dasd_io_time3, - sizeof(data->dasd_io_time3)); - memcpy(data->dasd_io_nr_req, - block->profile.data->dasd_io_nr_req, - sizeof(data->dasd_io_nr_req)); - spin_unlock_bh(&block->profile.lock); - } else { - spin_unlock_bh(&block->profile.lock); + if (dasd_profile_level == DASD_PROFILE_OFF) return -EIO; - } - if (copy_to_user(argp, data, sizeof(*data))) + if (copy_to_user(argp, &block->profile, + sizeof(struct dasd_profile_info_t))) return -EFAULT; return 0; } diff --git a/trunk/drivers/s390/block/dasd_proc.c b/trunk/drivers/s390/block/dasd_proc.c index 6c3c5364d082..c4a6a31bd9cd 100644 --- a/trunk/drivers/s390/block/dasd_proc.c +++ b/trunk/drivers/s390/block/dasd_proc.c @@ -32,6 +32,28 @@ static struct proc_dir_entry *dasd_proc_root_entry = NULL; static struct proc_dir_entry *dasd_devices_entry = NULL; static struct proc_dir_entry *dasd_statistics_entry = NULL; +#ifdef CONFIG_DASD_PROFILE +static char * +dasd_get_user_string(const char __user *user_buf, size_t user_len) +{ + char *buffer; + + buffer = kmalloc(user_len + 1, GFP_KERNEL); + if (buffer == NULL) + return ERR_PTR(-ENOMEM); + if (copy_from_user(buffer, user_buf, user_len) != 0) { + kfree(buffer); + return ERR_PTR(-EFAULT); + } + /* got the string, now strip linefeed. */ + if (buffer[user_len - 1] == '\n') + buffer[user_len - 1] = 0; + else + buffer[user_len] = 0; + return buffer; +} +#endif /* CONFIG_DASD_PROFILE */ + static int dasd_devices_show(struct seq_file *m, void *v) { @@ -145,55 +167,6 @@ static const struct file_operations dasd_devices_file_ops = { }; #ifdef CONFIG_DASD_PROFILE -static int dasd_stats_all_block_on(void) -{ - int i, rc; - struct dasd_device *device; - - rc = 0; - for (i = 0; i < dasd_max_devindex; ++i) { - device = dasd_device_from_devindex(i); - if (IS_ERR(device)) - continue; - if (device->block) - rc = dasd_profile_on(&device->block->profile); - dasd_put_device(device); - if (rc) - return rc; - } - return 0; -} - -static void dasd_stats_all_block_off(void) -{ - int i; - struct dasd_device *device; - - for (i = 0; i < dasd_max_devindex; ++i) { - device = dasd_device_from_devindex(i); - if (IS_ERR(device)) - continue; - if (device->block) - dasd_profile_off(&device->block->profile); - dasd_put_device(device); - } -} - -static void dasd_stats_all_block_reset(void) -{ - int i; - struct dasd_device *device; - - for (i = 0; i < dasd_max_devindex; ++i) { - device = dasd_device_from_devindex(i); - if (IS_ERR(device)) - continue; - if (device->block) - dasd_profile_reset(&device->block->profile); - dasd_put_device(device); - } -} - static void dasd_statistics_array(struct seq_file *m, unsigned int *array, int factor) { int i; @@ -210,18 +183,18 @@ static void dasd_statistics_array(struct seq_file *m, unsigned int *array, int f static int dasd_stats_proc_show(struct seq_file *m, void *v) { #ifdef CONFIG_DASD_PROFILE - struct dasd_profile_info *prof; + struct dasd_profile_info_t *prof; int factor; /* check for active profiling */ - if (!dasd_global_profile_level) { + if (dasd_profile_level == DASD_PROFILE_OFF) { seq_printf(m, "Statistics are off - they might be " "switched on using 'echo set on > " "/proc/dasd/statistics'\n"); return 0; } - prof = &dasd_global_profile_data; + prof = &dasd_global_profile; /* prevent counter 'overflow' on output */ for (factor = 1; (prof->dasd_io_reqs / factor) > 9999999; factor *= 10); @@ -272,7 +245,6 @@ static ssize_t dasd_stats_proc_write(struct file *file, { #ifdef CONFIG_DASD_PROFILE char *buffer, *str; - int rc; if (user_len > 65536) user_len = 65536; @@ -287,40 +259,32 @@ static ssize_t dasd_stats_proc_write(struct file *file, str = skip_spaces(str + 4); if (strcmp(str, "on") == 0) { /* switch on statistics profiling */ - rc = dasd_stats_all_block_on(); - if (rc) { - dasd_stats_all_block_off(); - goto out_error; - } - dasd_global_profile_reset(); - dasd_global_profile_level = DASD_PROFILE_ON; + dasd_profile_level = DASD_PROFILE_ON; pr_info("The statistics feature has been switched " "on\n"); } else if (strcmp(str, "off") == 0) { /* switch off and reset statistics profiling */ - dasd_global_profile_level = DASD_PROFILE_OFF; - dasd_global_profile_reset(); - dasd_stats_all_block_off(); + memset(&dasd_global_profile, + 0, sizeof (struct dasd_profile_info_t)); + dasd_profile_level = DASD_PROFILE_OFF; pr_info("The statistics feature has been switched " "off\n"); } else - goto out_parse_error; + goto out_error; } else if (strncmp(str, "reset", 5) == 0) { /* reset the statistics */ - dasd_global_profile_reset(); - dasd_stats_all_block_reset(); + memset(&dasd_global_profile, 0, + sizeof (struct dasd_profile_info_t)); pr_info("The statistics have been reset\n"); } else - goto out_parse_error; + goto out_error; kfree(buffer); return user_len; -out_parse_error: - rc = -EINVAL; +out_error: pr_warning("%s is not a supported value for /proc/dasd/statistics\n", str); -out_error: kfree(buffer); - return rc; + return -EINVAL; #else pr_warning("/proc/dasd/statistics: is not activated in this kernel\n"); return user_len; diff --git a/trunk/drivers/s390/char/Kconfig b/trunk/drivers/s390/char/Kconfig index 2c9a776bd63c..a4f117d9fdc6 100644 --- a/trunk/drivers/s390/char/Kconfig +++ b/trunk/drivers/s390/char/Kconfig @@ -116,6 +116,9 @@ config S390_TAPE called tape390 and include all selected interfaces and hardware drivers. +comment "S/390 tape interface support" + depends on S390_TAPE + comment "S/390 tape hardware support" depends on S390_TAPE diff --git a/trunk/drivers/s390/cio/qdio_thinint.c b/trunk/drivers/s390/cio/qdio_thinint.c index 68be6e157126..5c4e741d8221 100644 --- a/trunk/drivers/s390/cio/qdio_thinint.c +++ b/trunk/drivers/s390/cio/qdio_thinint.c @@ -95,11 +95,9 @@ void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr) } } -static inline u32 clear_shared_ind(void) +static inline u32 shared_ind_set(void) { - if (!atomic_read(&q_indicators[TIQDIO_SHARED_IND].count)) - return 0; - return xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 0); + return q_indicators[TIQDIO_SHARED_IND].ind; } /** @@ -109,7 +107,7 @@ static inline u32 clear_shared_ind(void) */ static void tiqdio_thinint_handler(void *alsi, void *data) { - u32 si_used = clear_shared_ind(); + u32 si_used = shared_ind_set(); struct qdio_q *q; last_ai_time = S390_lowcore.int_clock; @@ -152,6 +150,13 @@ static void tiqdio_thinint_handler(void *alsi, void *data) qperf_inc(q, adapter_int); } rcu_read_unlock(); + + /* + * If the shared indicator was used clear it now after all queues + * were processed. + */ + if (si_used && shared_ind_set()) + xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 0); } static int set_subchannel_ind(struct qdio_irq *irq_ptr, int reset) diff --git a/trunk/drivers/s390/crypto/ap_bus.c b/trunk/drivers/s390/crypto/ap_bus.c index f8134a44cefa..16e4a25596e7 100644 --- a/trunk/drivers/s390/crypto/ap_bus.c +++ b/trunk/drivers/s390/crypto/ap_bus.c @@ -6,7 +6,6 @@ * Martin Schwidefsky * Ralph Wuerthner * Felix Beck - * Holger Dengler * * Adjunct processor bus. * @@ -223,52 +222,47 @@ ap_queue_interruption_control(ap_qid_t qid, void *ind) } #endif -#ifdef CONFIG_64BIT -static inline struct ap_queue_status -__ap_query_functions(ap_qid_t qid, unsigned int *functions) +static inline struct ap_queue_status __ap_4096_commands_available(ap_qid_t qid, + int *support) { register unsigned long reg0 asm ("0") = 0UL | qid | (1UL << 23); - register struct ap_queue_status reg1 asm ("1") = AP_QUEUE_STATUS_INVALID; - register unsigned long reg2 asm ("2"); + register struct ap_queue_status reg1 asm ("1"); + register unsigned long reg2 asm ("2") = 0UL; asm volatile( ".long 0xb2af0000\n" - "0:\n" - EX_TABLE(0b, 0b) - : "+d" (reg0), "+d" (reg1), "=d" (reg2) + "0: la %1,0\n" + "1:\n" + EX_TABLE(0b, 1b) + : "+d" (reg0), "=d" (reg1), "=d" (reg2) : : "cc"); - *functions = (unsigned int)(reg2 >> 32); + if (reg2 & 0x6000000000000000ULL) + *support = 1; + else + *support = 0; + return reg1; } -#endif /** - * ap_query_functions(): Query supported functions. + * ap_4096_commands_availablen(): Check for availability of 4096 bit RSA + * support. * @qid: The AP queue number - * @functions: Pointer to functions field. * - * Returns - * 0 on success. - * -ENODEV if queue not valid. - * -EBUSY if device busy. - * -EINVAL if query function is not supported + * Returns 1 if 4096 bit RSA keys are support fo the AP, returns 0 if not. */ -static int ap_query_functions(ap_qid_t qid, unsigned int *functions) +int ap_4096_commands_available(ap_qid_t qid) { -#ifdef CONFIG_64BIT struct ap_queue_status status; - int i; - status = __ap_query_functions(qid, functions); + int i, support = 0; + status = __ap_4096_commands_available(qid, &support); for (i = 0; i < AP_MAX_RESET; i++) { - if (ap_queue_status_invalid_test(&status)) - return -ENODEV; - switch (status.response_code) { case AP_RESPONSE_NORMAL: - return 0; + return support; case AP_RESPONSE_RESET_IN_PROGRESS: case AP_RESPONSE_BUSY: break; @@ -276,7 +270,7 @@ static int ap_query_functions(ap_qid_t qid, unsigned int *functions) case AP_RESPONSE_DECONFIGURED: case AP_RESPONSE_CHECKSTOPPED: case AP_RESPONSE_INVALID_ADDRESS: - return -ENODEV; + return 0; case AP_RESPONSE_OTHERWISE_CHANGED: break; default: @@ -284,31 +278,10 @@ static int ap_query_functions(ap_qid_t qid, unsigned int *functions) } if (i < AP_MAX_RESET - 1) { udelay(5); - status = __ap_query_functions(qid, functions); + status = __ap_4096_commands_available(qid, &support); } } - return -EBUSY; -#else - return -EINVAL; -#endif -} - -/** - * ap_4096_commands_availablen(): Check for availability of 4096 bit RSA - * support. - * @qid: The AP queue number - * - * Returns 1 if 4096 bit RSA keys are support fo the AP, returns 0 if not. - */ -int ap_4096_commands_available(ap_qid_t qid) -{ - unsigned int functions; - - if (ap_query_functions(qid, &functions)) - return 0; - - return test_ap_facility(functions, 1) && - test_ap_facility(functions, 2); + return support; } EXPORT_SYMBOL(ap_4096_commands_available); @@ -1162,7 +1135,6 @@ static void ap_scan_bus(struct work_struct *unused) struct device *dev; ap_qid_t qid; int queue_depth, device_type; - unsigned int device_functions; int rc, i; if (ap_select_domain() != 0) @@ -1211,30 +1183,14 @@ static void ap_scan_bus(struct work_struct *unused) INIT_LIST_HEAD(&ap_dev->list); setup_timer(&ap_dev->timeout, ap_request_timeout, (unsigned long) ap_dev); - switch (device_type) { - case 0: + if (device_type == 0) { if (ap_probe_device_type(ap_dev)) { kfree(ap_dev); continue; } - break; - case 10: - if (ap_query_functions(qid, &device_functions)) { - kfree(ap_dev); - continue; - } - if (test_ap_facility(device_functions, 3)) - ap_dev->device_type = AP_DEVICE_TYPE_CEX3C; - else if (test_ap_facility(device_functions, 4)) - ap_dev->device_type = AP_DEVICE_TYPE_CEX3A; - else { - kfree(ap_dev); - continue; - } - break; - default: - ap_dev->device_type = device_type; } + else + ap_dev->device_type = device_type; ap_dev->device.bus = &ap_bus_type; ap_dev->device.parent = ap_root_device; diff --git a/trunk/drivers/s390/crypto/ap_bus.h b/trunk/drivers/s390/crypto/ap_bus.h index d960a6309eec..08b9738285b4 100644 --- a/trunk/drivers/s390/crypto/ap_bus.h +++ b/trunk/drivers/s390/crypto/ap_bus.h @@ -6,7 +6,6 @@ * Martin Schwidefsky * Ralph Wuerthner * Felix Beck - * Holger Dengler * * Adjunct processor bus header file. * @@ -73,26 +72,7 @@ struct ap_queue_status { unsigned int int_enabled : 1; unsigned int response_code : 8; unsigned int pad2 : 16; -} __packed; - -#define AP_QUEUE_STATUS_INVALID \ - { 1, 1, 1, 0xF, 1, 0xFF, 0xFFFF } - -static inline -int ap_queue_status_invalid_test(struct ap_queue_status *status) -{ - struct ap_queue_status invalid = AP_QUEUE_STATUS_INVALID; - return !(memcmp(status, &invalid, sizeof(struct ap_queue_status))); -} - -#define MAX_AP_FACILITY 31 - -static inline int test_ap_facility(unsigned int function, unsigned int nr) -{ - if (nr > MAX_AP_FACILITY) - return 0; - return function & (unsigned int)(0x80000000 >> nr); -} +}; #define AP_RESPONSE_NORMAL 0x00 #define AP_RESPONSE_Q_NOT_AVAIL 0x01 diff --git a/trunk/drivers/scsi/aha152x.c b/trunk/drivers/scsi/aha152x.c index f17c92cf808b..c5169f01c1cd 100644 --- a/trunk/drivers/scsi/aha152x.c +++ b/trunk/drivers/scsi/aha152x.c @@ -422,19 +422,10 @@ MODULE_PARM_DESC(aha152x1, "parameters for second controller"); #ifdef __ISAPNP__ static struct isapnp_device_id id_table[] __devinitdata = { - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1502), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1505), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1510), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1515), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1520), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x2015), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1522), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x2215), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1530), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x3015), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1532), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x3215), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x6360), 0 }, + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('A','D','P'), ISAPNP_FUNCTION(0x1505), 0 }, + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('A','D','P'), ISAPNP_FUNCTION(0x1530), 0 }, { ISAPNP_DEVICE_SINGLE_END, } }; MODULE_DEVICE_TABLE(isapnp, id_table); diff --git a/trunk/drivers/scsi/atari_NCR5380.c b/trunk/drivers/scsi/atari_NCR5380.c index 2db79b469d9e..ea439f93ed81 100644 --- a/trunk/drivers/scsi/atari_NCR5380.c +++ b/trunk/drivers/scsi/atari_NCR5380.c @@ -892,11 +892,6 @@ static int __init NCR5380_init(struct Scsi_Host *instance, int flags) return 0; } -static void NCR5380_exit(struct Scsi_Host *instance) -{ - /* Empty, as we didn't schedule any delayed work */ -} - /* * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd, * void (*done)(Scsi_Cmnd *)) @@ -919,6 +914,7 @@ static int NCR5380_queue_command_lck(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) { SETUP_HOSTDATA(cmd->device->host); Scsi_Cmnd *tmp; + int oldto; unsigned long flags; #if (NDEBUG & NDEBUG_NO_WRITE) diff --git a/trunk/drivers/scsi/atari_scsi.c b/trunk/drivers/scsi/atari_scsi.c index 04a154f87e3e..3e8658e2f154 100644 --- a/trunk/drivers/scsi/atari_scsi.c +++ b/trunk/drivers/scsi/atari_scsi.c @@ -730,7 +730,6 @@ int atari_scsi_release(struct Scsi_Host *sh) free_irq(IRQ_TT_MFP_SCSI, sh); if (atari_dma_buffer) atari_stram_free(atari_dma_buffer); - NCR5380_exit(sh); return 1; } diff --git a/trunk/drivers/scsi/be2iscsi/be_main.c b/trunk/drivers/scsi/be2iscsi/be_main.c index 0a9bdfa3d939..94b9a07845d5 100644 --- a/trunk/drivers/scsi/be2iscsi/be_main.c +++ b/trunk/drivers/scsi/be2iscsi/be_main.c @@ -215,62 +215,73 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc) static ssize_t beiscsi_show_boot_tgt_info(void *data, int type, char *buf) { struct beiscsi_hba *phba = data; - struct mgmt_session_info *boot_sess = &phba->boot_sess; - struct mgmt_conn_info *boot_conn = &boot_sess->conn_list[0]; char *str = buf; int rc; switch (type) { case ISCSI_BOOT_TGT_NAME: rc = sprintf(buf, "%.*s\n", - (int)strlen(boot_sess->target_name), - (char *)&boot_sess->target_name); + (int)strlen(phba->boot_sess.target_name), + (char *)&phba->boot_sess.target_name); break; case ISCSI_BOOT_TGT_IP_ADDR: - if (boot_conn->dest_ipaddr.ip_type == 0x1) + if (phba->boot_sess.conn_list[0].dest_ipaddr.ip_type == 0x1) rc = sprintf(buf, "%pI4\n", - (char *)&boot_conn->dest_ipaddr.ip_address); + (char *)&phba->boot_sess.conn_list[0]. + dest_ipaddr.ip_address); else rc = sprintf(str, "%pI6\n", - (char *)&boot_conn->dest_ipaddr.ip_address); + (char *)&phba->boot_sess.conn_list[0]. + dest_ipaddr.ip_address); break; case ISCSI_BOOT_TGT_PORT: - rc = sprintf(str, "%d\n", boot_conn->dest_port); + rc = sprintf(str, "%d\n", phba->boot_sess.conn_list[0]. + dest_port); break; case ISCSI_BOOT_TGT_CHAP_NAME: rc = sprintf(str, "%.*s\n", - boot_conn->negotiated_login_options.auth_data.chap. - target_chap_name_length, - (char *)&boot_conn->negotiated_login_options. - auth_data.chap.target_chap_name); + phba->boot_sess.conn_list[0]. + negotiated_login_options.auth_data.chap. + target_chap_name_length, + (char *)&phba->boot_sess.conn_list[0]. + negotiated_login_options.auth_data.chap. + target_chap_name); break; case ISCSI_BOOT_TGT_CHAP_SECRET: rc = sprintf(str, "%.*s\n", - boot_conn->negotiated_login_options.auth_data.chap. - target_secret_length, - (char *)&boot_conn->negotiated_login_options. - auth_data.chap.target_secret); + phba->boot_sess.conn_list[0]. + negotiated_login_options.auth_data.chap. + target_secret_length, + (char *)&phba->boot_sess.conn_list[0]. + negotiated_login_options.auth_data.chap. + target_secret); + break; case ISCSI_BOOT_TGT_REV_CHAP_NAME: rc = sprintf(str, "%.*s\n", - boot_conn->negotiated_login_options.auth_data.chap. - intr_chap_name_length, - (char *)&boot_conn->negotiated_login_options. - auth_data.chap.intr_chap_name); + phba->boot_sess.conn_list[0]. + negotiated_login_options.auth_data.chap. + intr_chap_name_length, + (char *)&phba->boot_sess.conn_list[0]. + negotiated_login_options.auth_data.chap. + intr_chap_name); + break; case ISCSI_BOOT_TGT_REV_CHAP_SECRET: - rc = sprintf(str, "%.*s\n", - boot_conn->negotiated_login_options.auth_data.chap. - intr_secret_length, - (char *)&boot_conn->negotiated_login_options. - auth_data.chap.intr_secret); + rc = sprintf(str, "%.*s\n", + phba->boot_sess.conn_list[0]. + negotiated_login_options.auth_data.chap. + intr_secret_length, + (char *)&phba->boot_sess.conn_list[0]. + negotiated_login_options.auth_data.chap. + intr_secret); break; case ISCSI_BOOT_TGT_FLAGS: - rc = sprintf(str, "2\n"); + rc = sprintf(str, "2\n"); break; case ISCSI_BOOT_TGT_NIC_ASSOC: - rc = sprintf(str, "0\n"); + rc = sprintf(str, "0\n"); break; default: rc = -ENOSYS; @@ -304,10 +315,10 @@ static ssize_t beiscsi_show_boot_eth_info(void *data, int type, char *buf) switch (type) { case ISCSI_BOOT_ETH_FLAGS: - rc = sprintf(str, "2\n"); + rc = sprintf(str, "2\n"); break; case ISCSI_BOOT_ETH_INDEX: - rc = sprintf(str, "0\n"); + rc = sprintf(str, "0\n"); break; case ISCSI_BOOT_ETH_MAC: rc = beiscsi_get_macaddr(buf, phba); @@ -380,6 +391,40 @@ static mode_t beiscsi_eth_get_attr_visibility(void *data, int type) return rc; } +static int beiscsi_setup_boot_info(struct beiscsi_hba *phba) +{ + struct iscsi_boot_kobj *boot_kobj; + + phba->boot_kset = iscsi_boot_create_host_kset(phba->shost->host_no); + if (!phba->boot_kset) + return -ENOMEM; + + /* get boot info using mgmt cmd */ + boot_kobj = iscsi_boot_create_target(phba->boot_kset, 0, phba, + beiscsi_show_boot_tgt_info, + beiscsi_tgt_get_attr_visibility); + if (!boot_kobj) + goto free_kset; + + boot_kobj = iscsi_boot_create_initiator(phba->boot_kset, 0, phba, + beiscsi_show_boot_ini_info, + beiscsi_ini_get_attr_visibility); + if (!boot_kobj) + goto free_kset; + + boot_kobj = iscsi_boot_create_ethernet(phba->boot_kset, 0, phba, + beiscsi_show_boot_eth_info, + beiscsi_eth_get_attr_visibility); + if (!boot_kobj) + goto free_kset; + return 0; + +free_kset: + if (phba->boot_kset) + iscsi_boot_destroy_kset(phba->boot_kset); + return -ENOMEM; +} + /*------------------- PCI Driver operations and data ----------------- */ static DEFINE_PCI_DEVICE_TABLE(beiscsi_pci_id_table) = { { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID1) }, @@ -438,6 +483,14 @@ static struct beiscsi_hba *beiscsi_hba_alloc(struct pci_dev *pcidev) if (iscsi_host_add(shost, &phba->pcidev->dev)) goto free_devices; + if (beiscsi_setup_boot_info(phba)) + /* + * log error but continue, because we may not be using + * iscsi boot. + */ + shost_printk(KERN_ERR, phba->shost, "Could not set up " + "iSCSI boot info."); + return phba; free_devices: @@ -3458,7 +3511,6 @@ static int beiscsi_get_boot_info(struct beiscsi_hba *phba) unsigned int tag, wrb_num; unsigned short status, extd_status; struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q; - int ret = -ENOMEM; tag = beiscsi_get_boot_target(phba); if (!tag) { @@ -3483,7 +3535,8 @@ static int beiscsi_get_boot_info(struct beiscsi_hba *phba) boot_resp = embedded_payload(wrb); if (boot_resp->boot_session_handle < 0) { - shost_printk(KERN_INFO, phba->shost, "No Boot Session.\n"); + printk(KERN_ERR "No Boot Session for this pci_func," + "session Hndl = %d\n", boot_resp->boot_session_handle); return -ENXIO; } @@ -3521,70 +3574,14 @@ static int beiscsi_get_boot_info(struct beiscsi_hba *phba) wrb = queue_get_wrb(mccq, wrb_num); free_mcc_tag(&phba->ctrl, tag); session_resp = nonemb_cmd.va ; - memcpy(&phba->boot_sess, &session_resp->session_info, sizeof(struct mgmt_session_info)); - ret = 0; - -boot_freemem: pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, nonemb_cmd.va, nonemb_cmd.dma); - return ret; -} - -static void beiscsi_boot_release(void *data) -{ - struct beiscsi_hba *phba = data; - - scsi_host_put(phba->shost); -} - -static int beiscsi_setup_boot_info(struct beiscsi_hba *phba) -{ - struct iscsi_boot_kobj *boot_kobj; - - /* get boot info using mgmt cmd */ - if (beiscsi_get_boot_info(phba)) - /* Try to see if we can carry on without this */ - return 0; - - phba->boot_kset = iscsi_boot_create_host_kset(phba->shost->host_no); - if (!phba->boot_kset) - return -ENOMEM; - - /* get a ref because the show function will ref the phba */ - if (!scsi_host_get(phba->shost)) - goto free_kset; - boot_kobj = iscsi_boot_create_target(phba->boot_kset, 0, phba, - beiscsi_show_boot_tgt_info, - beiscsi_tgt_get_attr_visibility, - beiscsi_boot_release); - if (!boot_kobj) - goto put_shost; - - if (!scsi_host_get(phba->shost)) - goto free_kset; - boot_kobj = iscsi_boot_create_initiator(phba->boot_kset, 0, phba, - beiscsi_show_boot_ini_info, - beiscsi_ini_get_attr_visibility, - beiscsi_boot_release); - if (!boot_kobj) - goto put_shost; - - if (!scsi_host_get(phba->shost)) - goto free_kset; - boot_kobj = iscsi_boot_create_ethernet(phba->boot_kset, 0, phba, - beiscsi_show_boot_eth_info, - beiscsi_eth_get_attr_visibility, - beiscsi_boot_release); - if (!boot_kobj) - goto put_shost; return 0; - -put_shost: - scsi_host_put(phba->shost); -free_kset: - iscsi_boot_destroy_kset(phba->boot_kset); +boot_freemem: + pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, + nonemb_cmd.va, nonemb_cmd.dma); return -ENOMEM; } @@ -3966,10 +3963,11 @@ static int beiscsi_iotask(struct iscsi_task *task, struct scatterlist *sg, } memcpy(&io_task->cmd_bhs->iscsi_data_pdu. dw[offsetof(struct amap_pdu_data_out, lun) / 32], - &io_task->cmd_bhs->iscsi_hdr.lun, sizeof(struct scsi_lun)); + io_task->cmd_bhs->iscsi_hdr.lun, sizeof(struct scsi_lun)); AMAP_SET_BITS(struct amap_iscsi_wrb, lun, pwrb, - cpu_to_be16(*(unsigned short *)&io_task->cmd_bhs->iscsi_hdr.lun)); + cpu_to_be16((unsigned short)io_task->cmd_bhs->iscsi_hdr. + lun[0])); AMAP_SET_BITS(struct amap_iscsi_wrb, r2t_exp_dtl, pwrb, xferlen); AMAP_SET_BITS(struct amap_iscsi_wrb, wrb_idx, pwrb, io_task->pwrb_handle->wrb_index); @@ -4152,7 +4150,8 @@ static void beiscsi_remove(struct pci_dev *pcidev) phba->ctrl.mbox_mem_alloced.size, phba->ctrl.mbox_mem_alloced.va, phba->ctrl.mbox_mem_alloced.dma); - iscsi_boot_destroy_kset(phba->boot_kset); + if (phba->boot_kset) + iscsi_boot_destroy_kset(phba->boot_kset); iscsi_host_remove(phba->shost); pci_dev_put(phba->pcidev); iscsi_host_free(phba->shost); @@ -4311,15 +4310,11 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev, goto free_blkenbld; } hwi_enable_intr(phba); - - if (beiscsi_setup_boot_info(phba)) - /* - * log error but continue, because we may not be using - * iscsi boot. - */ - shost_printk(KERN_ERR, phba->shost, "Could not set up " - "iSCSI boot info."); - + ret = beiscsi_get_boot_info(phba); + if (ret < 0) { + shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-" + "No Boot Devices !!!!!\n"); + } SE_DEBUG(DBG_LVL_8, "\n\n\n SUCCESS - DRIVER LOADED\n\n\n"); return 0; diff --git a/trunk/drivers/scsi/bfa/Makefile b/trunk/drivers/scsi/bfa/Makefile index 475cf925d5e8..4ce6f4942327 100644 --- a/trunk/drivers/scsi/bfa/Makefile +++ b/trunk/drivers/scsi/bfa/Makefile @@ -1,6 +1,6 @@ obj-$(CONFIG_SCSI_BFA_FC) := bfa.o -bfa-y := bfad.o bfad_im.o bfad_attr.o bfad_debugfs.o bfad_bsg.o +bfa-y := bfad.o bfad_im.o bfad_attr.o bfad_debugfs.o bfa-y += bfa_ioc.o bfa_ioc_cb.o bfa_ioc_ct.o bfa_hw_cb.o bfa_hw_ct.o bfa-y += bfa_fcs.o bfa_fcs_lport.o bfa_fcs_rport.o bfa_fcs_fcpim.o bfa_fcbuild.o bfa-y += bfa_port.o bfa_fcpim.o bfa_core.o bfa_svc.o diff --git a/trunk/drivers/scsi/bfa/bfa.h b/trunk/drivers/scsi/bfa/bfa.h index 3b0af1102bf4..7be6b5a8114b 100644 --- a/trunk/drivers/scsi/bfa/bfa.h +++ b/trunk/drivers/scsi/bfa/bfa.h @@ -27,6 +27,7 @@ struct bfa_s; typedef void (*bfa_isr_func_t) (struct bfa_s *bfa, struct bfi_msg_s *m); +typedef void (*bfa_cb_cbfn_t) (void *cbarg, bfa_boolean_t complete); /* * Interrupt message handlers @@ -53,8 +54,7 @@ void bfa_isr_unhandled(struct bfa_s *bfa, struct bfi_msg_s *m); ((void *)((struct bfi_msg_s *)((__bfa)->iocfc.req_cq_ba[__reqq].kva) \ + bfa_reqq_pi((__bfa), (__reqq))))) -#define bfa_reqq_produce(__bfa, __reqq, __mh) do { \ - (__mh).mtag.h2i.qid = (__bfa)->iocfc.hw_qid[__reqq];\ +#define bfa_reqq_produce(__bfa, __reqq) do { \ (__bfa)->iocfc.req_cq_pi[__reqq]++; \ (__bfa)->iocfc.req_cq_pi[__reqq] &= \ ((__bfa)->iocfc.cfg.drvcfg.num_reqq_elems - 1); \ @@ -75,6 +75,16 @@ void bfa_isr_unhandled(struct bfa_s *bfa, struct bfi_msg_s *m); (__index) &= ((__size) - 1); \ } while (0) +/* + * Queue element to wait for room in request queue. FIFO order is + * maintained when fullfilling requests. + */ +struct bfa_reqq_wait_s { + struct list_head qe; + void (*qresume) (void *cbarg); + void *cbarg; +}; + /* * Circular queue usage assignments */ @@ -118,6 +128,18 @@ bfa_reqq_winit(struct bfa_reqq_wait_s *wqe, void (*qresume) (void *cbarg), #define bfa_reqq_wcancel(__wqe) list_del(&(__wqe)->qe) + +/* + * Generic BFA callback element. + */ +struct bfa_cb_qe_s { + struct list_head qe; + bfa_cb_cbfn_t cbfn; + bfa_boolean_t once; + u32 rsvd; + void *cbarg; +}; + #define bfa_cb_queue(__bfa, __hcb_qe, __cbfn, __cbarg) do { \ (__hcb_qe)->cbfn = (__cbfn); \ (__hcb_qe)->cbarg = (__cbarg); \ @@ -150,14 +172,44 @@ struct bfa_pciid_s { extern char bfa_version[]; +/* + * BFA memory resources + */ +enum bfa_mem_type { + BFA_MEM_TYPE_KVA = 1, /* Kernel Virtual Memory *(non-dma-able) */ + BFA_MEM_TYPE_DMA = 2, /* DMA-able memory */ + BFA_MEM_TYPE_MAX = BFA_MEM_TYPE_DMA, +}; + +struct bfa_mem_elem_s { + enum bfa_mem_type mem_type; /* see enum bfa_mem_type */ + u32 mem_len; /* Total Length in Bytes */ + u8 *kva; /* kernel virtual address */ + u64 dma; /* dma address if DMA memory */ + u8 *kva_curp; /* kva allocation cursor */ + u64 dma_curp; /* dma allocation cursor */ +}; + +struct bfa_meminfo_s { + struct bfa_mem_elem_s meminfo[BFA_MEM_TYPE_MAX]; +}; +#define bfa_meminfo_kva(_m) \ + ((_m)->meminfo[BFA_MEM_TYPE_KVA - 1].kva_curp) +#define bfa_meminfo_dma_virt(_m) \ + ((_m)->meminfo[BFA_MEM_TYPE_DMA - 1].kva_curp) +#define bfa_meminfo_dma_phys(_m) \ + ((_m)->meminfo[BFA_MEM_TYPE_DMA - 1].dma_curp) + struct bfa_iocfc_regs_s { void __iomem *intr_status; void __iomem *intr_mask; void __iomem *cpe_q_pi[BFI_IOC_MAX_CQS]; void __iomem *cpe_q_ci[BFI_IOC_MAX_CQS]; + void __iomem *cpe_q_depth[BFI_IOC_MAX_CQS]; void __iomem *cpe_q_ctrl[BFI_IOC_MAX_CQS]; void __iomem *rme_q_ci[BFI_IOC_MAX_CQS]; void __iomem *rme_q_pi[BFI_IOC_MAX_CQS]; + void __iomem *rme_q_depth[BFI_IOC_MAX_CQS]; void __iomem *rme_q_ctrl[BFI_IOC_MAX_CQS]; }; @@ -179,55 +231,25 @@ struct bfa_hwif_s { void (*hw_reqq_ack)(struct bfa_s *bfa, int reqq); void (*hw_rspq_ack)(struct bfa_s *bfa, int rspq); void (*hw_msix_init)(struct bfa_s *bfa, int nvecs); - void (*hw_msix_ctrl_install)(struct bfa_s *bfa); - void (*hw_msix_queue_install)(struct bfa_s *bfa); + void (*hw_msix_install)(struct bfa_s *bfa); void (*hw_msix_uninstall)(struct bfa_s *bfa); void (*hw_isr_mode_set)(struct bfa_s *bfa, bfa_boolean_t msix); void (*hw_msix_getvecs)(struct bfa_s *bfa, u32 *vecmap, u32 *nvecs, u32 *maxvec); void (*hw_msix_get_rme_range) (struct bfa_s *bfa, u32 *start, u32 *end); - int cpe_vec_q0; - int rme_vec_q0; }; typedef void (*bfa_cb_iocfc_t) (void *cbarg, enum bfa_status status); -struct bfa_faa_cbfn_s { - bfa_cb_iocfc_t faa_cbfn; - void *faa_cbarg; -}; - -#define BFA_FAA_ENABLED 1 -#define BFA_FAA_DISABLED 2 - -/* - * FAA attributes - */ -struct bfa_faa_attr_s { - wwn_t faa; - u8 faa_state; - u8 pwwn_source; - u8 rsvd[6]; -}; - -struct bfa_faa_args_s { - struct bfa_faa_attr_s *faa_attr; - struct bfa_faa_cbfn_s faa_cb; - u8 faa_state; - bfa_boolean_t busy; -}; - struct bfa_iocfc_s { struct bfa_s *bfa; struct bfa_iocfc_cfg_s cfg; int action; u32 req_cq_pi[BFI_IOC_MAX_CQS]; u32 rsp_cq_ci[BFI_IOC_MAX_CQS]; - u8 hw_qid[BFI_IOC_MAX_CQS]; struct bfa_cb_qe_s init_hcb_qe; struct bfa_cb_qe_s stop_hcb_qe; struct bfa_cb_qe_s dis_hcb_qe; - struct bfa_cb_qe_s en_hcb_qe; struct bfa_cb_qe_s stats_hcb_qe; bfa_boolean_t cfgdone; @@ -235,6 +257,7 @@ struct bfa_iocfc_s { struct bfi_iocfc_cfg_s *cfginfo; struct bfa_dma_s cfgrsp_dma; struct bfi_iocfc_cfgrsp_s *cfgrsp; + struct bfi_iocfc_cfg_reply_s *cfg_reply; struct bfa_dma_s req_cq_ba[BFI_IOC_MAX_CQS]; struct bfa_dma_s req_cq_shadow_ci[BFI_IOC_MAX_CQS]; struct bfa_dma_s rsp_cq_ba[BFI_IOC_MAX_CQS]; @@ -244,42 +267,18 @@ struct bfa_iocfc_s { bfa_cb_iocfc_t updateq_cbfn; /* bios callback function */ void *updateq_cbarg; /* bios callback arg */ u32 intr_mask; - struct bfa_faa_args_s faa_args; - struct bfa_mem_dma_s ioc_dma; - struct bfa_mem_dma_s iocfc_dma; - struct bfa_mem_dma_s reqq_dma[BFI_IOC_MAX_CQS]; - struct bfa_mem_dma_s rspq_dma[BFI_IOC_MAX_CQS]; - struct bfa_mem_kva_s kva_seg; }; -#define BFA_MEM_IOC_DMA(_bfa) (&((_bfa)->iocfc.ioc_dma)) -#define BFA_MEM_IOCFC_DMA(_bfa) (&((_bfa)->iocfc.iocfc_dma)) -#define BFA_MEM_REQQ_DMA(_bfa, _qno) (&((_bfa)->iocfc.reqq_dma[(_qno)])) -#define BFA_MEM_RSPQ_DMA(_bfa, _qno) (&((_bfa)->iocfc.rspq_dma[(_qno)])) -#define BFA_MEM_IOCFC_KVA(_bfa) (&((_bfa)->iocfc.kva_seg)) - -#define bfa_fn_lpu(__bfa) \ - bfi_fn_lpu(bfa_ioc_pcifn(&(__bfa)->ioc), bfa_ioc_portid(&(__bfa)->ioc)) +#define bfa_lpuid(__bfa) \ + bfa_ioc_portid(&(__bfa)->ioc) #define bfa_msix_init(__bfa, __nvecs) \ ((__bfa)->iocfc.hwif.hw_msix_init(__bfa, __nvecs)) -#define bfa_msix_ctrl_install(__bfa) \ - ((__bfa)->iocfc.hwif.hw_msix_ctrl_install(__bfa)) -#define bfa_msix_queue_install(__bfa) \ - ((__bfa)->iocfc.hwif.hw_msix_queue_install(__bfa)) +#define bfa_msix_install(__bfa) \ + ((__bfa)->iocfc.hwif.hw_msix_install(__bfa)) #define bfa_msix_uninstall(__bfa) \ ((__bfa)->iocfc.hwif.hw_msix_uninstall(__bfa)) -#define bfa_isr_rspq_ack(__bfa, __queue) do { \ - if ((__bfa)->iocfc.hwif.hw_rspq_ack) \ - (__bfa)->iocfc.hwif.hw_rspq_ack(__bfa, __queue); \ -} while (0) -#define bfa_isr_reqq_ack(__bfa, __queue) do { \ - if ((__bfa)->iocfc.hwif.hw_reqq_ack) \ - (__bfa)->iocfc.hwif.hw_reqq_ack(__bfa, __queue); \ -} while (0) -#define bfa_isr_mode_set(__bfa, __msix) do { \ - if ((__bfa)->iocfc.hwif.hw_isr_mode_set) \ - (__bfa)->iocfc.hwif.hw_isr_mode_set(__bfa, __msix); \ -} while (0) +#define bfa_isr_mode_set(__bfa, __msix) \ + ((__bfa)->iocfc.hwif.hw_isr_mode_set(__bfa, __msix)) #define bfa_msix_getvecs(__bfa, __vecmap, __nvecs, __maxvec) \ ((__bfa)->iocfc.hwif.hw_msix_getvecs(__bfa, __vecmap, \ __nvecs, __maxvec)) @@ -291,17 +290,17 @@ struct bfa_iocfc_s { /* * FC specific IOC functions. */ -void bfa_iocfc_meminfo(struct bfa_iocfc_cfg_s *cfg, - struct bfa_meminfo_s *meminfo, - struct bfa_s *bfa); +void bfa_iocfc_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len, + u32 *dm_len); void bfa_iocfc_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, + struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev); void bfa_iocfc_init(struct bfa_s *bfa); void bfa_iocfc_start(struct bfa_s *bfa); void bfa_iocfc_stop(struct bfa_s *bfa); void bfa_iocfc_isr(void *bfa, struct bfi_mbmsg_s *msg); -void bfa_iocfc_set_snsbase(struct bfa_s *bfa, int seg_no, u64 snsbase_pa); +void bfa_iocfc_set_snsbase(struct bfa_s *bfa, u64 snsbase_pa); bfa_boolean_t bfa_iocfc_is_operational(struct bfa_s *bfa); void bfa_iocfc_reset_queues(struct bfa_s *bfa); @@ -311,10 +310,10 @@ void bfa_msix_rspq(struct bfa_s *bfa, int vec); void bfa_msix_lpu_err(struct bfa_s *bfa, int vec); void bfa_hwcb_reginit(struct bfa_s *bfa); +void bfa_hwcb_reqq_ack(struct bfa_s *bfa, int rspq); void bfa_hwcb_rspq_ack(struct bfa_s *bfa, int rspq); void bfa_hwcb_msix_init(struct bfa_s *bfa, int nvecs); -void bfa_hwcb_msix_ctrl_install(struct bfa_s *bfa); -void bfa_hwcb_msix_queue_install(struct bfa_s *bfa); +void bfa_hwcb_msix_install(struct bfa_s *bfa); void bfa_hwcb_msix_uninstall(struct bfa_s *bfa); void bfa_hwcb_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix); void bfa_hwcb_msix_getvecs(struct bfa_s *bfa, u32 *vecmap, u32 *nvecs, @@ -322,12 +321,10 @@ void bfa_hwcb_msix_getvecs(struct bfa_s *bfa, u32 *vecmap, u32 *nvecs, void bfa_hwcb_msix_get_rme_range(struct bfa_s *bfa, u32 *start, u32 *end); void bfa_hwct_reginit(struct bfa_s *bfa); -void bfa_hwct2_reginit(struct bfa_s *bfa); void bfa_hwct_reqq_ack(struct bfa_s *bfa, int rspq); void bfa_hwct_rspq_ack(struct bfa_s *bfa, int rspq); void bfa_hwct_msix_init(struct bfa_s *bfa, int nvecs); -void bfa_hwct_msix_ctrl_install(struct bfa_s *bfa); -void bfa_hwct_msix_queue_install(struct bfa_s *bfa); +void bfa_hwct_msix_install(struct bfa_s *bfa); void bfa_hwct_msix_uninstall(struct bfa_s *bfa); void bfa_hwct_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix); void bfa_hwct_msix_getvecs(struct bfa_s *bfa, u32 *vecmap, u32 *nvecs, @@ -380,8 +377,7 @@ void bfa_get_pciids(struct bfa_pciid_s **pciids, int *npciids); void bfa_cfg_get_default(struct bfa_iocfc_cfg_s *cfg); void bfa_cfg_get_min(struct bfa_iocfc_cfg_s *cfg); void bfa_cfg_get_meminfo(struct bfa_iocfc_cfg_s *cfg, - struct bfa_meminfo_s *meminfo, - struct bfa_s *bfa); + struct bfa_meminfo_s *meminfo); void bfa_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev); diff --git a/trunk/drivers/scsi/bfa/bfa_core.c b/trunk/drivers/scsi/bfa/bfa_core.c index c38e589105a5..91838c51fb76 100644 --- a/trunk/drivers/scsi/bfa/bfa_core.c +++ b/trunk/drivers/scsi/bfa/bfa_core.c @@ -17,7 +17,7 @@ #include "bfad_drv.h" #include "bfa_modules.h" -#include "bfi_reg.h" +#include "bfi_ctreg.h" BFA_TRC_FILE(HAL, CORE); @@ -25,14 +25,13 @@ BFA_TRC_FILE(HAL, CORE); * BFA module list terminated by NULL */ static struct bfa_module_s *hal_mods[] = { - &hal_mod_fcdiag, &hal_mod_sgpg, &hal_mod_fcport, &hal_mod_fcxp, &hal_mod_lps, &hal_mod_uf, &hal_mod_rport, - &hal_mod_fcp, + &hal_mod_fcpim, NULL }; @@ -42,7 +41,7 @@ static struct bfa_module_s *hal_mods[] = { static bfa_isr_func_t bfa_isrs[BFI_MC_MAX] = { bfa_isr_unhandled, /* NONE */ bfa_isr_unhandled, /* BFI_MC_IOC */ - bfa_fcdiag_intr, /* BFI_MC_DIAG */ + bfa_isr_unhandled, /* BFI_MC_DIAG */ bfa_isr_unhandled, /* BFI_MC_FLASH */ bfa_isr_unhandled, /* BFI_MC_CEE */ bfa_fcport_isr, /* BFI_MC_FCPORT */ @@ -52,7 +51,7 @@ static bfa_isr_func_t bfa_isrs[BFI_MC_MAX] = { bfa_fcxp_isr, /* BFI_MC_FCXP */ bfa_lps_isr, /* BFI_MC_LPS */ bfa_rport_isr, /* BFI_MC_RPORT */ - bfa_itn_isr, /* BFI_MC_ITN */ + bfa_itnim_isr, /* BFI_MC_ITNIM */ bfa_isr_unhandled, /* BFI_MC_IOIM_READ */ bfa_isr_unhandled, /* BFI_MC_IOIM_WRITE */ bfa_isr_unhandled, /* BFI_MC_IOIM_IO */ @@ -90,78 +89,23 @@ static bfa_ioc_mbox_mcfunc_t bfa_mbox_isrs[BFI_MC_MAX] = { static void -bfa_com_port_attach(struct bfa_s *bfa) +bfa_com_port_attach(struct bfa_s *bfa, struct bfa_meminfo_s *mi) { struct bfa_port_s *port = &bfa->modules.port; - struct bfa_mem_dma_s *port_dma = BFA_MEM_PORT_DMA(bfa); + u32 dm_len; + u8 *dm_kva; + u64 dm_pa; - bfa_port_attach(port, &bfa->ioc, bfa, bfa->trcmod); - bfa_port_mem_claim(port, port_dma->kva_curp, port_dma->dma_curp); -} - -/* - * ablk module attach - */ -static void -bfa_com_ablk_attach(struct bfa_s *bfa) -{ - struct bfa_ablk_s *ablk = &bfa->modules.ablk; - struct bfa_mem_dma_s *ablk_dma = BFA_MEM_ABLK_DMA(bfa); - - bfa_ablk_attach(ablk, &bfa->ioc); - bfa_ablk_memclaim(ablk, ablk_dma->kva_curp, ablk_dma->dma_curp); -} - -static void -bfa_com_cee_attach(struct bfa_s *bfa) -{ - struct bfa_cee_s *cee = &bfa->modules.cee; - struct bfa_mem_dma_s *cee_dma = BFA_MEM_CEE_DMA(bfa); - - cee->trcmod = bfa->trcmod; - bfa_cee_attach(cee, &bfa->ioc, bfa); - bfa_cee_mem_claim(cee, cee_dma->kva_curp, cee_dma->dma_curp); -} - -static void -bfa_com_sfp_attach(struct bfa_s *bfa) -{ - struct bfa_sfp_s *sfp = BFA_SFP_MOD(bfa); - struct bfa_mem_dma_s *sfp_dma = BFA_MEM_SFP_DMA(bfa); - - bfa_sfp_attach(sfp, &bfa->ioc, bfa, bfa->trcmod); - bfa_sfp_memclaim(sfp, sfp_dma->kva_curp, sfp_dma->dma_curp); -} - -static void -bfa_com_flash_attach(struct bfa_s *bfa, bfa_boolean_t mincfg) -{ - struct bfa_flash_s *flash = BFA_FLASH(bfa); - struct bfa_mem_dma_s *flash_dma = BFA_MEM_FLASH_DMA(bfa); - - bfa_flash_attach(flash, &bfa->ioc, bfa, bfa->trcmod, mincfg); - bfa_flash_memclaim(flash, flash_dma->kva_curp, - flash_dma->dma_curp, mincfg); -} - -static void -bfa_com_diag_attach(struct bfa_s *bfa) -{ - struct bfa_diag_s *diag = BFA_DIAG_MOD(bfa); - struct bfa_mem_dma_s *diag_dma = BFA_MEM_DIAG_DMA(bfa); + dm_len = bfa_port_meminfo(); + dm_kva = bfa_meminfo_dma_virt(mi); + dm_pa = bfa_meminfo_dma_phys(mi); - bfa_diag_attach(diag, &bfa->ioc, bfa, bfa_fcport_beacon, bfa->trcmod); - bfa_diag_memclaim(diag, diag_dma->kva_curp, diag_dma->dma_curp); -} - -static void -bfa_com_phy_attach(struct bfa_s *bfa, bfa_boolean_t mincfg) -{ - struct bfa_phy_s *phy = BFA_PHY(bfa); - struct bfa_mem_dma_s *phy_dma = BFA_MEM_PHY_DMA(bfa); + memset(port, 0, sizeof(struct bfa_port_s)); + bfa_port_attach(port, &bfa->ioc, bfa, bfa->trcmod); + bfa_port_mem_claim(port, dm_kva, dm_pa); - bfa_phy_attach(phy, &bfa->ioc, bfa, bfa->trcmod, mincfg); - bfa_phy_memclaim(phy, phy_dma->kva_curp, phy_dma->dma_curp, mincfg); + bfa_meminfo_dma_virt(mi) = dm_kva + dm_len; + bfa_meminfo_dma_phys(mi) = dm_pa + dm_len; } /* @@ -178,7 +122,6 @@ enum { BFA_IOCFC_ACT_INIT = 1, BFA_IOCFC_ACT_STOP = 2, BFA_IOCFC_ACT_DISABLE = 3, - BFA_IOCFC_ACT_ENABLE = 4, }; #define DEF_CFG_NUM_FABRICS 1 @@ -230,92 +173,10 @@ bfa_reqq_resume(struct bfa_s *bfa, int qid) } } -static inline void -bfa_isr_rspq(struct bfa_s *bfa, int qid) -{ - struct bfi_msg_s *m; - u32 pi, ci; - struct list_head *waitq; - - bfa_isr_rspq_ack(bfa, qid); - - ci = bfa_rspq_ci(bfa, qid); - pi = bfa_rspq_pi(bfa, qid); - - while (ci != pi) { - m = bfa_rspq_elem(bfa, qid, ci); - WARN_ON(m->mhdr.msg_class >= BFI_MC_MAX); - - bfa_isrs[m->mhdr.msg_class] (bfa, m); - CQ_INCR(ci, bfa->iocfc.cfg.drvcfg.num_rspq_elems); - } - - /* - * update CI - */ - bfa_rspq_ci(bfa, qid) = pi; - writel(pi, bfa->iocfc.bfa_regs.rme_q_ci[qid]); - mmiowb(); - - /* - * Resume any pending requests in the corresponding reqq. - */ - waitq = bfa_reqq(bfa, qid); - if (!list_empty(waitq)) - bfa_reqq_resume(bfa, qid); -} - -static inline void -bfa_isr_reqq(struct bfa_s *bfa, int qid) -{ - struct list_head *waitq; - - bfa_isr_reqq_ack(bfa, qid); - - /* - * Resume any pending requests in the corresponding reqq. - */ - waitq = bfa_reqq(bfa, qid); - if (!list_empty(waitq)) - bfa_reqq_resume(bfa, qid); -} - void bfa_msix_all(struct bfa_s *bfa, int vec) { - u32 intr, qintr; - int queue; - - intr = readl(bfa->iocfc.bfa_regs.intr_status); - if (!intr) - return; - - /* - * RME completion queue interrupt - */ - qintr = intr & __HFN_INT_RME_MASK; - if (qintr && bfa->queue_process) { - for (queue = 0; queue < BFI_IOC_MAX_CQS; queue++) - bfa_isr_rspq(bfa, queue); - } - - intr &= ~qintr; - if (!intr) - return; - - /* - * CPE completion queue interrupt - */ - qintr = intr & __HFN_INT_CPE_MASK; - if (qintr && bfa->queue_process) { - for (queue = 0; queue < BFI_IOC_MAX_CQS; queue++) - bfa_isr_reqq(bfa, queue); - } - intr &= ~qintr; - if (!intr) - return; - - bfa_msix_lpu_err(bfa, intr); + bfa_intx(bfa); } bfa_boolean_t @@ -328,19 +189,16 @@ bfa_intx(struct bfa_s *bfa) if (!intr) return BFA_FALSE; - qintr = intr & (__HFN_INT_RME_MASK | __HFN_INT_CPE_MASK); - if (qintr) - writel(qintr, bfa->iocfc.bfa_regs.intr_status); - /* * RME completion queue interrupt */ qintr = intr & __HFN_INT_RME_MASK; - if (qintr && bfa->queue_process) { - for (queue = 0; queue < BFI_IOC_MAX_CQS; queue++) - bfa_isr_rspq(bfa, queue); - } + writel(qintr, bfa->iocfc.bfa_regs.intr_status); + for (queue = 0; queue < BFI_IOC_MAX_CQS_ASIC; queue++) { + if (intr & (__HFN_INT_RME_Q0 << queue)) + bfa_msix_rspq(bfa, queue & (BFI_IOC_MAX_CQS - 1)); + } intr &= ~qintr; if (!intr) return BFA_TRUE; @@ -349,9 +207,11 @@ bfa_intx(struct bfa_s *bfa) * CPE completion queue interrupt */ qintr = intr & __HFN_INT_CPE_MASK; - if (qintr && bfa->queue_process) { - for (queue = 0; queue < BFI_IOC_MAX_CQS; queue++) - bfa_isr_reqq(bfa, queue); + writel(qintr, bfa->iocfc.bfa_regs.intr_status); + + for (queue = 0; queue < BFI_IOC_MAX_CQS_ASIC; queue++) { + if (intr & (__HFN_INT_CPE_Q0 << queue)) + bfa_msix_reqq(bfa, queue & (BFI_IOC_MAX_CQS - 1)); } intr &= ~qintr; if (!intr) @@ -365,25 +225,32 @@ bfa_intx(struct bfa_s *bfa) void bfa_isr_enable(struct bfa_s *bfa) { - u32 umsk; + u32 intr_unmask; int pci_func = bfa_ioc_pcifn(&bfa->ioc); bfa_trc(bfa, pci_func); - bfa_msix_ctrl_install(bfa); - - if (bfa_asic_id_ct2(bfa->ioc.pcidev.device_id)) { - umsk = __HFN_INT_ERR_MASK_CT2; - umsk |= pci_func == 0 ? - __HFN_INT_FN0_MASK_CT2 : __HFN_INT_FN1_MASK_CT2; - } else { - umsk = __HFN_INT_ERR_MASK; - umsk |= pci_func == 0 ? __HFN_INT_FN0_MASK : __HFN_INT_FN1_MASK; - } - - writel(umsk, bfa->iocfc.bfa_regs.intr_status); - writel(~umsk, bfa->iocfc.bfa_regs.intr_mask); - bfa->iocfc.intr_mask = ~umsk; + bfa_msix_install(bfa); + intr_unmask = (__HFN_INT_ERR_EMC | __HFN_INT_ERR_LPU0 | + __HFN_INT_ERR_LPU1 | __HFN_INT_ERR_PSS | + __HFN_INT_LL_HALT); + + if (pci_func == 0) + intr_unmask |= (__HFN_INT_CPE_Q0 | __HFN_INT_CPE_Q1 | + __HFN_INT_CPE_Q2 | __HFN_INT_CPE_Q3 | + __HFN_INT_RME_Q0 | __HFN_INT_RME_Q1 | + __HFN_INT_RME_Q2 | __HFN_INT_RME_Q3 | + __HFN_INT_MBOX_LPU0); + else + intr_unmask |= (__HFN_INT_CPE_Q4 | __HFN_INT_CPE_Q5 | + __HFN_INT_CPE_Q6 | __HFN_INT_CPE_Q7 | + __HFN_INT_RME_Q4 | __HFN_INT_RME_Q5 | + __HFN_INT_RME_Q6 | __HFN_INT_RME_Q7 | + __HFN_INT_MBOX_LPU1); + + writel(intr_unmask, bfa->iocfc.bfa_regs.intr_status); + writel(~intr_unmask, bfa->iocfc.bfa_regs.intr_mask); + bfa->iocfc.intr_mask = ~intr_unmask; bfa_isr_mode_set(bfa, bfa->msix.nvecs != 0); } @@ -396,9 +263,20 @@ bfa_isr_disable(struct bfa_s *bfa) } void -bfa_msix_reqq(struct bfa_s *bfa, int vec) +bfa_msix_reqq(struct bfa_s *bfa, int qid) { - bfa_isr_reqq(bfa, vec - bfa->iocfc.hwif.cpe_vec_q0); + struct list_head *waitq; + + qid &= (BFI_IOC_MAX_CQS - 1); + + bfa->iocfc.hwif.hw_reqq_ack(bfa, qid); + + /* + * Resume any pending requests in the corresponding reqq. + */ + waitq = bfa_reqq(bfa, qid); + if (!list_empty(waitq)) + bfa_reqq_resume(bfa, qid); } void @@ -412,37 +290,57 @@ bfa_isr_unhandled(struct bfa_s *bfa, struct bfi_msg_s *m) } void -bfa_msix_rspq(struct bfa_s *bfa, int vec) +bfa_msix_rspq(struct bfa_s *bfa, int qid) { - bfa_isr_rspq(bfa, vec - bfa->iocfc.hwif.rme_vec_q0); + struct bfi_msg_s *m; + u32 pi, ci; + struct list_head *waitq; + + qid &= (BFI_IOC_MAX_CQS - 1); + + bfa->iocfc.hwif.hw_rspq_ack(bfa, qid); + + ci = bfa_rspq_ci(bfa, qid); + pi = bfa_rspq_pi(bfa, qid); + + if (bfa->rme_process) { + while (ci != pi) { + m = bfa_rspq_elem(bfa, qid, ci); + bfa_isrs[m->mhdr.msg_class] (bfa, m); + CQ_INCR(ci, bfa->iocfc.cfg.drvcfg.num_rspq_elems); + } + } + + /* + * update CI + */ + bfa_rspq_ci(bfa, qid) = pi; + writel(pi, bfa->iocfc.bfa_regs.rme_q_ci[qid]); + mmiowb(); + + /* + * Resume any pending requests in the corresponding reqq. + */ + waitq = bfa_reqq(bfa, qid); + if (!list_empty(waitq)) + bfa_reqq_resume(bfa, qid); } void bfa_msix_lpu_err(struct bfa_s *bfa, int vec) { u32 intr, curr_value; - bfa_boolean_t lpu_isr, halt_isr, pss_isr; intr = readl(bfa->iocfc.bfa_regs.intr_status); - if (bfa_asic_id_ct2(bfa->ioc.pcidev.device_id)) { - halt_isr = intr & __HFN_INT_CPQ_HALT_CT2; - pss_isr = intr & __HFN_INT_ERR_PSS_CT2; - lpu_isr = intr & (__HFN_INT_MBOX_LPU0_CT2 | - __HFN_INT_MBOX_LPU1_CT2); - intr &= __HFN_INT_ERR_MASK_CT2; - } else { - halt_isr = intr & __HFN_INT_LL_HALT; - pss_isr = intr & __HFN_INT_ERR_PSS; - lpu_isr = intr & (__HFN_INT_MBOX_LPU0 | __HFN_INT_MBOX_LPU1); - intr &= __HFN_INT_ERR_MASK; - } - - if (lpu_isr) + if (intr & (__HFN_INT_MBOX_LPU0 | __HFN_INT_MBOX_LPU1)) bfa_ioc_mbox_isr(&bfa->ioc); + intr &= (__HFN_INT_ERR_EMC | __HFN_INT_ERR_LPU0 | + __HFN_INT_ERR_LPU1 | __HFN_INT_ERR_PSS | __HFN_INT_LL_HALT); + if (intr) { - if (halt_isr) { + if (intr & __HFN_INT_LL_HALT) { /* * If LL_HALT bit is set then FW Init Halt LL Port * Register needs to be cleared as well so Interrupt @@ -453,7 +351,7 @@ bfa_msix_lpu_err(struct bfa_s *bfa, int vec) writel(curr_value, bfa->ioc.ioc_regs.ll_halt); } - if (pss_isr) { + if (intr & __HFN_INT_ERR_PSS) { /* * ERR_PSS bit needs to be cleared as well in case * interrups are shared so driver's interrupt handler is @@ -461,6 +359,7 @@ bfa_msix_lpu_err(struct bfa_s *bfa, int vec) */ curr_value = readl( bfa->ioc.ioc_regs.pss_err_status_reg); + curr_value &= __PSS_ERR_STATUS_SET; writel(curr_value, bfa->ioc.ioc_regs.pss_err_status_reg); } @@ -478,6 +377,41 @@ bfa_msix_lpu_err(struct bfa_s *bfa, int vec) * BFA IOC private functions */ +static void +bfa_iocfc_cqs_sz(struct bfa_iocfc_cfg_s *cfg, u32 *dm_len) +{ + int i, per_reqq_sz, per_rspq_sz; + + per_reqq_sz = BFA_ROUNDUP((cfg->drvcfg.num_reqq_elems * BFI_LMSG_SZ), + BFA_DMA_ALIGN_SZ); + per_rspq_sz = BFA_ROUNDUP((cfg->drvcfg.num_rspq_elems * BFI_LMSG_SZ), + BFA_DMA_ALIGN_SZ); + + /* + * Calculate CQ size + */ + for (i = 0; i < cfg->fwcfg.num_cqs; i++) { + *dm_len = *dm_len + per_reqq_sz; + *dm_len = *dm_len + per_rspq_sz; + } + + /* + * Calculate Shadow CI/PI size + */ + for (i = 0; i < cfg->fwcfg.num_cqs; i++) + *dm_len += (2 * BFA_CACHELINE_SZ); +} + +static void +bfa_iocfc_fw_cfg_sz(struct bfa_iocfc_cfg_s *cfg, u32 *dm_len) +{ + *dm_len += + BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfg_s), BFA_CACHELINE_SZ); + *dm_len += + BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfgrsp_s), + BFA_CACHELINE_SZ); +} + /* * Use the Mailbox interface to send BFI_IOCFC_H2I_CFG_REQ */ @@ -499,13 +433,8 @@ bfa_iocfc_send_cfg(void *bfa_arg) /* * initialize IOC configuration info */ - cfg_info->single_msix_vec = 0; - if (bfa->msix.nvecs == 1) - cfg_info->single_msix_vec = 1; cfg_info->endian_sig = BFI_IOC_ENDIAN_SIG; cfg_info->num_cqs = cfg->fwcfg.num_cqs; - cfg_info->num_ioim_reqs = cpu_to_be16(cfg->fwcfg.num_ioim_reqs); - cfg_info->num_fwtio_reqs = cpu_to_be16(cfg->fwcfg.num_fwtio_reqs); bfa_dma_be_addr_set(cfg_info->cfgrsp_addr, iocfc->cfgrsp_dma.pa); /* @@ -540,7 +469,7 @@ bfa_iocfc_send_cfg(void *bfa_arg) * dma map IOC configuration itself */ bfi_h2i_set(cfg_req.mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_CFG_REQ, - bfa_fn_lpu(bfa)); + bfa_lpuid(bfa)); bfa_dma_be_addr_set(cfg_req.ioc_cfg_dma_addr, iocfc->cfg_info.pa); bfa_ioc_mbox_send(&bfa->ioc, &cfg_req, @@ -562,40 +491,26 @@ bfa_iocfc_init_mem(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, /* * Initialize chip specific handlers. */ - if (bfa_asic_id_ctc(bfa_ioc_devid(&bfa->ioc))) { + if (bfa_asic_id_ct(bfa_ioc_devid(&bfa->ioc))) { iocfc->hwif.hw_reginit = bfa_hwct_reginit; iocfc->hwif.hw_reqq_ack = bfa_hwct_reqq_ack; iocfc->hwif.hw_rspq_ack = bfa_hwct_rspq_ack; iocfc->hwif.hw_msix_init = bfa_hwct_msix_init; - iocfc->hwif.hw_msix_ctrl_install = bfa_hwct_msix_ctrl_install; - iocfc->hwif.hw_msix_queue_install = bfa_hwct_msix_queue_install; + iocfc->hwif.hw_msix_install = bfa_hwct_msix_install; iocfc->hwif.hw_msix_uninstall = bfa_hwct_msix_uninstall; iocfc->hwif.hw_isr_mode_set = bfa_hwct_isr_mode_set; iocfc->hwif.hw_msix_getvecs = bfa_hwct_msix_getvecs; iocfc->hwif.hw_msix_get_rme_range = bfa_hwct_msix_get_rme_range; - iocfc->hwif.rme_vec_q0 = BFI_MSIX_RME_QMIN_CT; - iocfc->hwif.cpe_vec_q0 = BFI_MSIX_CPE_QMIN_CT; } else { iocfc->hwif.hw_reginit = bfa_hwcb_reginit; - iocfc->hwif.hw_reqq_ack = NULL; - iocfc->hwif.hw_rspq_ack = NULL; + iocfc->hwif.hw_reqq_ack = bfa_hwcb_reqq_ack; + iocfc->hwif.hw_rspq_ack = bfa_hwcb_rspq_ack; iocfc->hwif.hw_msix_init = bfa_hwcb_msix_init; - iocfc->hwif.hw_msix_ctrl_install = bfa_hwcb_msix_ctrl_install; - iocfc->hwif.hw_msix_queue_install = bfa_hwcb_msix_queue_install; + iocfc->hwif.hw_msix_install = bfa_hwcb_msix_install; iocfc->hwif.hw_msix_uninstall = bfa_hwcb_msix_uninstall; iocfc->hwif.hw_isr_mode_set = bfa_hwcb_isr_mode_set; iocfc->hwif.hw_msix_getvecs = bfa_hwcb_msix_getvecs; iocfc->hwif.hw_msix_get_rme_range = bfa_hwcb_msix_get_rme_range; - iocfc->hwif.rme_vec_q0 = BFI_MSIX_RME_QMIN_CB + - bfa_ioc_pcifn(&bfa->ioc) * BFI_IOC_MAX_CQS; - iocfc->hwif.cpe_vec_q0 = BFI_MSIX_CPE_QMIN_CB + - bfa_ioc_pcifn(&bfa->ioc) * BFI_IOC_MAX_CQS; - } - - if (bfa_asic_id_ct2(bfa_ioc_devid(&bfa->ioc))) { - iocfc->hwif.hw_reginit = bfa_hwct2_reginit; - iocfc->hwif.hw_isr_mode_set = NULL; - iocfc->hwif.hw_rspq_ack = NULL; } iocfc->hwif.hw_reginit(bfa); @@ -603,42 +518,48 @@ bfa_iocfc_init_mem(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, } static void -bfa_iocfc_mem_claim(struct bfa_s *bfa, struct bfa_iocfc_cfg_s *cfg) +bfa_iocfc_mem_claim(struct bfa_s *bfa, struct bfa_iocfc_cfg_s *cfg, + struct bfa_meminfo_s *meminfo) { - u8 *dm_kva = NULL; - u64 dm_pa = 0; - int i, per_reqq_sz, per_rspq_sz, dbgsz; + u8 *dm_kva; + u64 dm_pa; + int i, per_reqq_sz, per_rspq_sz; struct bfa_iocfc_s *iocfc = &bfa->iocfc; - struct bfa_mem_dma_s *ioc_dma = BFA_MEM_IOC_DMA(bfa); - struct bfa_mem_dma_s *iocfc_dma = BFA_MEM_IOCFC_DMA(bfa); - struct bfa_mem_dma_s *reqq_dma, *rspq_dma; + int dbgsz; + + dm_kva = bfa_meminfo_dma_virt(meminfo); + dm_pa = bfa_meminfo_dma_phys(meminfo); - /* First allocate dma memory for IOC */ - bfa_ioc_mem_claim(&bfa->ioc, bfa_mem_dma_virt(ioc_dma), - bfa_mem_dma_phys(ioc_dma)); + /* + * First allocate dma memory for IOC. + */ + bfa_ioc_mem_claim(&bfa->ioc, dm_kva, dm_pa); + dm_kva += BFA_ROUNDUP(sizeof(struct bfi_ioc_attr_s), BFA_DMA_ALIGN_SZ); + dm_pa += BFA_ROUNDUP(sizeof(struct bfi_ioc_attr_s), BFA_DMA_ALIGN_SZ); - /* Claim DMA-able memory for the request/response queues */ + /* + * Claim DMA-able memory for the request/response queues and for shadow + * ci/pi registers + */ per_reqq_sz = BFA_ROUNDUP((cfg->drvcfg.num_reqq_elems * BFI_LMSG_SZ), - BFA_DMA_ALIGN_SZ); + BFA_DMA_ALIGN_SZ); per_rspq_sz = BFA_ROUNDUP((cfg->drvcfg.num_rspq_elems * BFI_LMSG_SZ), - BFA_DMA_ALIGN_SZ); + BFA_DMA_ALIGN_SZ); for (i = 0; i < cfg->fwcfg.num_cqs; i++) { - reqq_dma = BFA_MEM_REQQ_DMA(bfa, i); - iocfc->req_cq_ba[i].kva = bfa_mem_dma_virt(reqq_dma); - iocfc->req_cq_ba[i].pa = bfa_mem_dma_phys(reqq_dma); - memset(iocfc->req_cq_ba[i].kva, 0, per_reqq_sz); - - rspq_dma = BFA_MEM_RSPQ_DMA(bfa, i); - iocfc->rsp_cq_ba[i].kva = bfa_mem_dma_virt(rspq_dma); - iocfc->rsp_cq_ba[i].pa = bfa_mem_dma_phys(rspq_dma); - memset(iocfc->rsp_cq_ba[i].kva, 0, per_rspq_sz); + iocfc->req_cq_ba[i].kva = dm_kva; + iocfc->req_cq_ba[i].pa = dm_pa; + memset(dm_kva, 0, per_reqq_sz); + dm_kva += per_reqq_sz; + dm_pa += per_reqq_sz; + + iocfc->rsp_cq_ba[i].kva = dm_kva; + iocfc->rsp_cq_ba[i].pa = dm_pa; + memset(dm_kva, 0, per_rspq_sz); + dm_kva += per_rspq_sz; + dm_pa += per_rspq_sz; } - /* Claim IOCFC dma memory - for shadow CI/PI */ - dm_kva = bfa_mem_dma_virt(iocfc_dma); - dm_pa = bfa_mem_dma_phys(iocfc_dma); - for (i = 0; i < cfg->fwcfg.num_cqs; i++) { iocfc->req_cq_shadow_ci[i].kva = dm_kva; iocfc->req_cq_shadow_ci[i].pa = dm_pa; @@ -651,27 +572,36 @@ bfa_iocfc_mem_claim(struct bfa_s *bfa, struct bfa_iocfc_cfg_s *cfg) dm_pa += BFA_CACHELINE_SZ; } - /* Claim IOCFC dma memory - for the config info page */ + /* + * Claim DMA-able memory for the config info page + */ bfa->iocfc.cfg_info.kva = dm_kva; bfa->iocfc.cfg_info.pa = dm_pa; bfa->iocfc.cfginfo = (struct bfi_iocfc_cfg_s *) dm_kva; dm_kva += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfg_s), BFA_CACHELINE_SZ); dm_pa += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfg_s), BFA_CACHELINE_SZ); - /* Claim IOCFC dma memory - for the config response */ + /* + * Claim DMA-able memory for the config response + */ bfa->iocfc.cfgrsp_dma.kva = dm_kva; bfa->iocfc.cfgrsp_dma.pa = dm_pa; bfa->iocfc.cfgrsp = (struct bfi_iocfc_cfgrsp_s *) dm_kva; - dm_kva += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfgrsp_s), - BFA_CACHELINE_SZ); + + dm_kva += + BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfgrsp_s), + BFA_CACHELINE_SZ); dm_pa += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfgrsp_s), - BFA_CACHELINE_SZ); + BFA_CACHELINE_SZ); + + + bfa_meminfo_dma_virt(meminfo) = dm_kva; + bfa_meminfo_dma_phys(meminfo) = dm_pa; - /* Claim IOCFC kva memory */ dbgsz = (bfa_auto_recover) ? BFA_DBG_FWTRC_LEN : 0; if (dbgsz > 0) { - bfa_ioc_debug_memclaim(&bfa->ioc, bfa_mem_kva_curp(iocfc)); - bfa_mem_kva_curp(iocfc) += dbgsz; + bfa_ioc_debug_memclaim(&bfa->ioc, bfa_meminfo_kva(meminfo)); + bfa_meminfo_kva(meminfo) += dbgsz; } } @@ -683,9 +613,7 @@ bfa_iocfc_start_submod(struct bfa_s *bfa) { int i; - bfa->queue_process = BFA_TRUE; - for (i = 0; i < BFI_IOC_MAX_CQS; i++) - bfa_isr_rspq_ack(bfa, i); + bfa->rme_process = BFA_TRUE; for (i = 0; hal_mods[i]; i++) hal_mods[i]->start(bfa); @@ -731,16 +659,6 @@ bfa_iocfc_stop_cb(void *bfa_arg, bfa_boolean_t compl) bfa->iocfc.action = BFA_IOCFC_ACT_NONE; } -static void -bfa_iocfc_enable_cb(void *bfa_arg, bfa_boolean_t compl) -{ - struct bfa_s *bfa = bfa_arg; - struct bfad_s *bfad = bfa->bfad; - - if (compl) - complete(&bfad->enable_comp); -} - static void bfa_iocfc_disable_cb(void *bfa_arg, bfa_boolean_t compl) { @@ -751,37 +669,6 @@ bfa_iocfc_disable_cb(void *bfa_arg, bfa_boolean_t compl) complete(&bfad->disable_comp); } -/** - * configure queue registers from firmware response - */ -static void -bfa_iocfc_qreg(struct bfa_s *bfa, struct bfi_iocfc_qreg_s *qreg) -{ - int i; - struct bfa_iocfc_regs_s *r = &bfa->iocfc.bfa_regs; - void __iomem *kva = bfa_ioc_bar0(&bfa->ioc); - - for (i = 0; i < BFI_IOC_MAX_CQS; i++) { - bfa->iocfc.hw_qid[i] = qreg->hw_qid[i]; - r->cpe_q_ci[i] = kva + be32_to_cpu(qreg->cpe_q_ci_off[i]); - r->cpe_q_pi[i] = kva + be32_to_cpu(qreg->cpe_q_pi_off[i]); - r->cpe_q_ctrl[i] = kva + be32_to_cpu(qreg->cpe_qctl_off[i]); - r->rme_q_ci[i] = kva + be32_to_cpu(qreg->rme_q_ci_off[i]); - r->rme_q_pi[i] = kva + be32_to_cpu(qreg->rme_q_pi_off[i]); - r->rme_q_ctrl[i] = kva + be32_to_cpu(qreg->rme_qctl_off[i]); - } -} - -static void -bfa_iocfc_res_recfg(struct bfa_s *bfa, struct bfa_iocfc_fwcfg_s *fwcfg) -{ - bfa_fcxp_res_recfg(bfa, fwcfg->num_fcxp_reqs); - bfa_uf_res_recfg(bfa, fwcfg->num_uf_bufs); - bfa_rport_res_recfg(bfa, fwcfg->num_rports); - bfa_fcp_res_recfg(bfa, fwcfg->num_ioim_reqs); - bfa_tskim_res_recfg(bfa, fwcfg->num_tskim_reqs); -} - /* * Update BFA configuration from firmware configuration. */ @@ -794,7 +681,6 @@ bfa_iocfc_cfgrsp(struct bfa_s *bfa) fwcfg->num_cqs = fwcfg->num_cqs; fwcfg->num_ioim_reqs = be16_to_cpu(fwcfg->num_ioim_reqs); - fwcfg->num_fwtio_reqs = be16_to_cpu(fwcfg->num_fwtio_reqs); fwcfg->num_tskim_reqs = be16_to_cpu(fwcfg->num_tskim_reqs); fwcfg->num_fcxp_reqs = be16_to_cpu(fwcfg->num_fcxp_reqs); fwcfg->num_uf_bufs = be16_to_cpu(fwcfg->num_uf_bufs); @@ -802,21 +688,6 @@ bfa_iocfc_cfgrsp(struct bfa_s *bfa) iocfc->cfgdone = BFA_TRUE; - /* - * configure queue register offsets as learnt from firmware - */ - bfa_iocfc_qreg(bfa, &cfgrsp->qreg); - - /* - * Re-configure resources as learnt from Firmware - */ - bfa_iocfc_res_recfg(bfa, fwcfg); - - /* - * Install MSIX queue handlers - */ - bfa_msix_queue_install(bfa); - /* * Configuration is complete - initialize/start submodules */ @@ -824,12 +695,8 @@ bfa_iocfc_cfgrsp(struct bfa_s *bfa) if (iocfc->action == BFA_IOCFC_ACT_INIT) bfa_cb_queue(bfa, &iocfc->init_hcb_qe, bfa_iocfc_init_cb, bfa); - else { - if (bfa->iocfc.action == BFA_IOCFC_ACT_ENABLE) - bfa_cb_queue(bfa, &bfa->iocfc.en_hcb_qe, - bfa_iocfc_enable_cb, bfa); + else bfa_iocfc_start_submod(bfa); - } } void bfa_iocfc_reset_queues(struct bfa_s *bfa) @@ -844,181 +711,6 @@ bfa_iocfc_reset_queues(struct bfa_s *bfa) } } -/* Fabric Assigned Address specific functions */ - -/* - * Check whether IOC is ready before sending command down - */ -static bfa_status_t -bfa_faa_validate_request(struct bfa_s *bfa) -{ - enum bfa_ioc_type_e ioc_type = bfa_get_type(bfa); - u32 card_type = bfa->ioc.attr->card_type; - - if (bfa_ioc_is_operational(&bfa->ioc)) { - if ((ioc_type != BFA_IOC_TYPE_FC) || bfa_mfg_is_mezz(card_type)) - return BFA_STATUS_FEATURE_NOT_SUPPORTED; - } else { - if (!bfa_ioc_is_acq_addr(&bfa->ioc)) - return BFA_STATUS_IOC_NON_OP; - } - - return BFA_STATUS_OK; -} - -bfa_status_t -bfa_faa_enable(struct bfa_s *bfa, bfa_cb_iocfc_t cbfn, void *cbarg) -{ - struct bfi_faa_en_dis_s faa_enable_req; - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - bfa_status_t status; - - iocfc->faa_args.faa_cb.faa_cbfn = cbfn; - iocfc->faa_args.faa_cb.faa_cbarg = cbarg; - - status = bfa_faa_validate_request(bfa); - if (status != BFA_STATUS_OK) - return status; - - if (iocfc->faa_args.busy == BFA_TRUE) - return BFA_STATUS_DEVBUSY; - - if (iocfc->faa_args.faa_state == BFA_FAA_ENABLED) - return BFA_STATUS_FAA_ENABLED; - - if (bfa_fcport_is_trunk_enabled(bfa)) - return BFA_STATUS_ERROR_TRUNK_ENABLED; - - bfa_fcport_cfg_faa(bfa, BFA_FAA_ENABLED); - iocfc->faa_args.busy = BFA_TRUE; - - memset(&faa_enable_req, 0, sizeof(struct bfi_faa_en_dis_s)); - bfi_h2i_set(faa_enable_req.mh, BFI_MC_IOCFC, - BFI_IOCFC_H2I_FAA_ENABLE_REQ, bfa_fn_lpu(bfa)); - - bfa_ioc_mbox_send(&bfa->ioc, &faa_enable_req, - sizeof(struct bfi_faa_en_dis_s)); - - return BFA_STATUS_OK; -} - -bfa_status_t -bfa_faa_disable(struct bfa_s *bfa, bfa_cb_iocfc_t cbfn, - void *cbarg) -{ - struct bfi_faa_en_dis_s faa_disable_req; - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - bfa_status_t status; - - iocfc->faa_args.faa_cb.faa_cbfn = cbfn; - iocfc->faa_args.faa_cb.faa_cbarg = cbarg; - - status = bfa_faa_validate_request(bfa); - if (status != BFA_STATUS_OK) - return status; - - if (iocfc->faa_args.busy == BFA_TRUE) - return BFA_STATUS_DEVBUSY; - - if (iocfc->faa_args.faa_state == BFA_FAA_DISABLED) - return BFA_STATUS_FAA_DISABLED; - - bfa_fcport_cfg_faa(bfa, BFA_FAA_DISABLED); - iocfc->faa_args.busy = BFA_TRUE; - - memset(&faa_disable_req, 0, sizeof(struct bfi_faa_en_dis_s)); - bfi_h2i_set(faa_disable_req.mh, BFI_MC_IOCFC, - BFI_IOCFC_H2I_FAA_DISABLE_REQ, bfa_fn_lpu(bfa)); - - bfa_ioc_mbox_send(&bfa->ioc, &faa_disable_req, - sizeof(struct bfi_faa_en_dis_s)); - - return BFA_STATUS_OK; -} - -bfa_status_t -bfa_faa_query(struct bfa_s *bfa, struct bfa_faa_attr_s *attr, - bfa_cb_iocfc_t cbfn, void *cbarg) -{ - struct bfi_faa_query_s faa_attr_req; - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - bfa_status_t status; - - iocfc->faa_args.faa_attr = attr; - iocfc->faa_args.faa_cb.faa_cbfn = cbfn; - iocfc->faa_args.faa_cb.faa_cbarg = cbarg; - - status = bfa_faa_validate_request(bfa); - if (status != BFA_STATUS_OK) - return status; - - if (iocfc->faa_args.busy == BFA_TRUE) - return BFA_STATUS_DEVBUSY; - - iocfc->faa_args.busy = BFA_TRUE; - memset(&faa_attr_req, 0, sizeof(struct bfi_faa_query_s)); - bfi_h2i_set(faa_attr_req.mh, BFI_MC_IOCFC, - BFI_IOCFC_H2I_FAA_QUERY_REQ, bfa_fn_lpu(bfa)); - - bfa_ioc_mbox_send(&bfa->ioc, &faa_attr_req, - sizeof(struct bfi_faa_query_s)); - - return BFA_STATUS_OK; -} - -/* - * FAA enable response - */ -static void -bfa_faa_enable_reply(struct bfa_iocfc_s *iocfc, - struct bfi_faa_en_dis_rsp_s *rsp) -{ - void *cbarg = iocfc->faa_args.faa_cb.faa_cbarg; - bfa_status_t status = rsp->status; - - WARN_ON(!iocfc->faa_args.faa_cb.faa_cbfn); - - iocfc->faa_args.faa_cb.faa_cbfn(cbarg, status); - iocfc->faa_args.busy = BFA_FALSE; -} - -/* - * FAA disable response - */ -static void -bfa_faa_disable_reply(struct bfa_iocfc_s *iocfc, - struct bfi_faa_en_dis_rsp_s *rsp) -{ - void *cbarg = iocfc->faa_args.faa_cb.faa_cbarg; - bfa_status_t status = rsp->status; - - WARN_ON(!iocfc->faa_args.faa_cb.faa_cbfn); - - iocfc->faa_args.faa_cb.faa_cbfn(cbarg, status); - iocfc->faa_args.busy = BFA_FALSE; -} - -/* - * FAA query response - */ -static void -bfa_faa_query_reply(struct bfa_iocfc_s *iocfc, - bfi_faa_query_rsp_t *rsp) -{ - void *cbarg = iocfc->faa_args.faa_cb.faa_cbarg; - - if (iocfc->faa_args.faa_attr) { - iocfc->faa_args.faa_attr->faa = rsp->faa; - iocfc->faa_args.faa_attr->faa_state = rsp->faa_status; - iocfc->faa_args.faa_attr->pwwn_source = rsp->addr_source; - } - - WARN_ON(!iocfc->faa_args.faa_cb.faa_cbfn); - - iocfc->faa_args.faa_cb.faa_cbfn(cbarg, BFA_STATUS_OK); - iocfc->faa_args.busy = BFA_FALSE; -} - /* * IOC enable request is complete */ @@ -1027,20 +719,11 @@ bfa_iocfc_enable_cbfn(void *bfa_arg, enum bfa_status status) { struct bfa_s *bfa = bfa_arg; - if (status == BFA_STATUS_FAA_ACQ_ADDR) { - bfa_cb_queue(bfa, &bfa->iocfc.init_hcb_qe, - bfa_iocfc_init_cb, bfa); - return; - } - if (status != BFA_STATUS_OK) { bfa_isr_disable(bfa); if (bfa->iocfc.action == BFA_IOCFC_ACT_INIT) bfa_cb_queue(bfa, &bfa->iocfc.init_hcb_qe, bfa_iocfc_init_cb, bfa); - else if (bfa->iocfc.action == BFA_IOCFC_ACT_ENABLE) - bfa_cb_queue(bfa, &bfa->iocfc.en_hcb_qe, - bfa_iocfc_enable_cb, bfa); return; } @@ -1076,7 +759,7 @@ bfa_iocfc_hbfail_cbfn(void *bfa_arg) { struct bfa_s *bfa = bfa_arg; - bfa->queue_process = BFA_FALSE; + bfa->rme_process = BFA_FALSE; bfa_isr_disable(bfa); bfa_iocfc_disable_submod(bfa); @@ -1103,47 +786,15 @@ bfa_iocfc_reset_cbfn(void *bfa_arg) * Query IOC memory requirement information. */ void -bfa_iocfc_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo, - struct bfa_s *bfa) +bfa_iocfc_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len, + u32 *dm_len) { - int q, per_reqq_sz, per_rspq_sz; - struct bfa_mem_dma_s *ioc_dma = BFA_MEM_IOC_DMA(bfa); - struct bfa_mem_dma_s *iocfc_dma = BFA_MEM_IOCFC_DMA(bfa); - struct bfa_mem_kva_s *iocfc_kva = BFA_MEM_IOCFC_KVA(bfa); - u32 dm_len = 0; - - /* dma memory setup for IOC */ - bfa_mem_dma_setup(meminfo, ioc_dma, - BFA_ROUNDUP(sizeof(struct bfi_ioc_attr_s), BFA_DMA_ALIGN_SZ)); - - /* dma memory setup for REQ/RSP queues */ - per_reqq_sz = BFA_ROUNDUP((cfg->drvcfg.num_reqq_elems * BFI_LMSG_SZ), - BFA_DMA_ALIGN_SZ); - per_rspq_sz = BFA_ROUNDUP((cfg->drvcfg.num_rspq_elems * BFI_LMSG_SZ), - BFA_DMA_ALIGN_SZ); - - for (q = 0; q < cfg->fwcfg.num_cqs; q++) { - bfa_mem_dma_setup(meminfo, BFA_MEM_REQQ_DMA(bfa, q), - per_reqq_sz); - bfa_mem_dma_setup(meminfo, BFA_MEM_RSPQ_DMA(bfa, q), - per_rspq_sz); - } - - /* IOCFC dma memory - calculate Shadow CI/PI size */ - for (q = 0; q < cfg->fwcfg.num_cqs; q++) - dm_len += (2 * BFA_CACHELINE_SZ); - - /* IOCFC dma memory - calculate config info / rsp size */ - dm_len += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfg_s), BFA_CACHELINE_SZ); - dm_len += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfgrsp_s), - BFA_CACHELINE_SZ); + /* dma memory for IOC */ + *dm_len += BFA_ROUNDUP(sizeof(struct bfi_ioc_attr_s), BFA_DMA_ALIGN_SZ); - /* dma memory setup for IOCFC */ - bfa_mem_dma_setup(meminfo, iocfc_dma, dm_len); - - /* kva memory setup for IOCFC */ - bfa_mem_kva_setup(meminfo, iocfc_kva, - ((bfa_auto_recover) ? BFA_DBG_FWTRC_LEN : 0)); + bfa_iocfc_fw_cfg_sz(cfg, dm_len); + bfa_iocfc_cqs_sz(cfg, dm_len); + *km_len += (bfa_auto_recover) ? BFA_DBG_FWTRC_LEN : 0; } /* @@ -1151,7 +802,7 @@ bfa_iocfc_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo, */ void bfa_iocfc_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_pcidev_s *pcidev) + struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) { int i; struct bfa_ioc_s *ioc = &bfa->ioc; @@ -1164,11 +815,17 @@ bfa_iocfc_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, ioc->trcmod = bfa->trcmod; bfa_ioc_attach(&bfa->ioc, bfa, &bfa_iocfc_cbfn, &bfa->timer_mod); - bfa_ioc_pci_init(&bfa->ioc, pcidev, BFI_PCIFN_CLASS_FC); + /* + * Set FC mode for BFA_PCI_DEVICE_ID_CT_FC. + */ + if (pcidev->device_id == BFA_PCI_DEVICE_ID_CT_FC) + bfa_ioc_set_fcmode(&bfa->ioc); + + bfa_ioc_pci_init(&bfa->ioc, pcidev, BFI_MC_IOCFC); bfa_ioc_mbox_register(&bfa->ioc, bfa_mbox_isrs); bfa_iocfc_init_mem(bfa, bfad, cfg, pcidev); - bfa_iocfc_mem_claim(bfa, cfg); + bfa_iocfc_mem_claim(bfa, cfg, meminfo); INIT_LIST_HEAD(&bfa->timer_mod.timer_q); INIT_LIST_HEAD(&bfa->comp_q); @@ -1206,7 +863,7 @@ bfa_iocfc_stop(struct bfa_s *bfa) { bfa->iocfc.action = BFA_IOCFC_ACT_STOP; - bfa->queue_process = BFA_FALSE; + bfa->rme_process = BFA_FALSE; bfa_ioc_disable(&bfa->ioc); } @@ -1222,22 +879,12 @@ bfa_iocfc_isr(void *bfaarg, struct bfi_mbmsg_s *m) switch (msg->mh.msg_id) { case BFI_IOCFC_I2H_CFG_REPLY: + iocfc->cfg_reply = &msg->cfg_reply; bfa_iocfc_cfgrsp(bfa); break; case BFI_IOCFC_I2H_UPDATEQ_RSP: iocfc->updateq_cbfn(iocfc->updateq_cbarg, BFA_STATUS_OK); break; - case BFI_IOCFC_I2H_FAA_ENABLE_RSP: - bfa_faa_enable_reply(iocfc, - (struct bfi_faa_en_dis_rsp_s *)msg); - break; - case BFI_IOCFC_I2H_FAA_DISABLE_RSP: - bfa_faa_disable_reply(iocfc, - (struct bfi_faa_en_dis_rsp_s *)msg); - break; - case BFI_IOCFC_I2H_FAA_QUERY_RSP: - bfa_faa_query_reply(iocfc, (bfi_faa_query_rsp_t *)msg); - break; default: WARN_ON(1); } @@ -1279,7 +926,7 @@ bfa_iocfc_israttr_set(struct bfa_s *bfa, struct bfa_iocfc_intr_attr_s *attr) return BFA_STATUS_DEVBUSY; bfi_h2i_set(m->mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_SET_INTR_REQ, - bfa_fn_lpu(bfa)); + bfa_lpuid(bfa)); m->coalesce = iocfc->cfginfo->intr_attr.coalesce; m->delay = iocfc->cfginfo->intr_attr.delay; m->latency = iocfc->cfginfo->intr_attr.latency; @@ -1287,17 +934,17 @@ bfa_iocfc_israttr_set(struct bfa_s *bfa, struct bfa_iocfc_intr_attr_s *attr) bfa_trc(bfa, attr->delay); bfa_trc(bfa, attr->latency); - bfa_reqq_produce(bfa, BFA_REQQ_IOC, m->mh); + bfa_reqq_produce(bfa, BFA_REQQ_IOC); return BFA_STATUS_OK; } void -bfa_iocfc_set_snsbase(struct bfa_s *bfa, int seg_no, u64 snsbase_pa) +bfa_iocfc_set_snsbase(struct bfa_s *bfa, u64 snsbase_pa) { struct bfa_iocfc_s *iocfc = &bfa->iocfc; iocfc->cfginfo->sense_buf_len = (BFI_IOIM_SNSLEN - 1); - bfa_dma_be_addr_set(iocfc->cfginfo->ioim_snsbase[seg_no], snsbase_pa); + bfa_dma_be_addr_set(iocfc->cfginfo->ioim_snsbase, snsbase_pa); } /* * Enable IOC after it is disabled. @@ -1307,7 +954,6 @@ bfa_iocfc_enable(struct bfa_s *bfa) { bfa_plog_str(bfa->plog, BFA_PL_MID_HAL, BFA_PL_EID_MISC, 0, "IOC Enable"); - bfa->iocfc.action = BFA_IOCFC_ACT_ENABLE; bfa_ioc_enable(&bfa->ioc); } @@ -1318,7 +964,7 @@ bfa_iocfc_disable(struct bfa_s *bfa) "IOC Disable"); bfa->iocfc.action = BFA_IOCFC_ACT_DISABLE; - bfa->queue_process = BFA_FALSE; + bfa->rme_process = BFA_FALSE; bfa_ioc_disable(&bfa->ioc); } @@ -1387,49 +1033,33 @@ bfa_iocfc_get_pbc_vports(struct bfa_s *bfa, struct bfi_pbc_vport_s *pbc_vport) * starting address for each block and provide the same * structure as input parameter to bfa_attach() call. * - * @param[in] bfa - pointer to the bfa structure, used while fetching the - * dma, kva memory information of the bfa sub-modules. - * * @return void * * Special Considerations: @note */ void -bfa_cfg_get_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo, - struct bfa_s *bfa) +bfa_cfg_get_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo) { int i; - struct bfa_mem_dma_s *port_dma = BFA_MEM_PORT_DMA(bfa); - struct bfa_mem_dma_s *ablk_dma = BFA_MEM_ABLK_DMA(bfa); - struct bfa_mem_dma_s *cee_dma = BFA_MEM_CEE_DMA(bfa); - struct bfa_mem_dma_s *sfp_dma = BFA_MEM_SFP_DMA(bfa); - struct bfa_mem_dma_s *flash_dma = BFA_MEM_FLASH_DMA(bfa); - struct bfa_mem_dma_s *diag_dma = BFA_MEM_DIAG_DMA(bfa); - struct bfa_mem_dma_s *phy_dma = BFA_MEM_PHY_DMA(bfa); + u32 km_len = 0, dm_len = 0; WARN_ON((cfg == NULL) || (meminfo == NULL)); memset((void *)meminfo, 0, sizeof(struct bfa_meminfo_s)); + meminfo->meminfo[BFA_MEM_TYPE_KVA - 1].mem_type = + BFA_MEM_TYPE_KVA; + meminfo->meminfo[BFA_MEM_TYPE_DMA - 1].mem_type = + BFA_MEM_TYPE_DMA; - /* Initialize the DMA & KVA meminfo queues */ - INIT_LIST_HEAD(&meminfo->dma_info.qe); - INIT_LIST_HEAD(&meminfo->kva_info.qe); - - bfa_iocfc_meminfo(cfg, meminfo, bfa); + bfa_iocfc_meminfo(cfg, &km_len, &dm_len); for (i = 0; hal_mods[i]; i++) - hal_mods[i]->meminfo(cfg, meminfo, bfa); - - /* dma info setup */ - bfa_mem_dma_setup(meminfo, port_dma, bfa_port_meminfo()); - bfa_mem_dma_setup(meminfo, ablk_dma, bfa_ablk_meminfo()); - bfa_mem_dma_setup(meminfo, cee_dma, bfa_cee_meminfo()); - bfa_mem_dma_setup(meminfo, sfp_dma, bfa_sfp_meminfo()); - bfa_mem_dma_setup(meminfo, flash_dma, - bfa_flash_meminfo(cfg->drvcfg.min_cfg)); - bfa_mem_dma_setup(meminfo, diag_dma, bfa_diag_meminfo()); - bfa_mem_dma_setup(meminfo, phy_dma, - bfa_phy_meminfo(cfg->drvcfg.min_cfg)); + hal_mods[i]->meminfo(cfg, &km_len, &dm_len); + + dm_len += bfa_port_meminfo(); + + meminfo->meminfo[BFA_MEM_TYPE_KVA - 1].mem_len = km_len; + meminfo->meminfo[BFA_MEM_TYPE_DMA - 1].mem_len = dm_len; } /* @@ -1462,46 +1092,28 @@ void bfa_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) { - int i; - struct bfa_mem_dma_s *dma_info, *dma_elem; - struct bfa_mem_kva_s *kva_info, *kva_elem; - struct list_head *dm_qe, *km_qe; + int i; + struct bfa_mem_elem_s *melem; bfa->fcs = BFA_FALSE; WARN_ON((cfg == NULL) || (meminfo == NULL)); - /* Initialize memory pointers for iterative allocation */ - dma_info = &meminfo->dma_info; - dma_info->kva_curp = dma_info->kva; - dma_info->dma_curp = dma_info->dma; - - kva_info = &meminfo->kva_info; - kva_info->kva_curp = kva_info->kva; - - list_for_each(dm_qe, &dma_info->qe) { - dma_elem = (struct bfa_mem_dma_s *) dm_qe; - dma_elem->kva_curp = dma_elem->kva; - dma_elem->dma_curp = dma_elem->dma; - } - - list_for_each(km_qe, &kva_info->qe) { - kva_elem = (struct bfa_mem_kva_s *) km_qe; - kva_elem->kva_curp = kva_elem->kva; + /* + * initialize all memory pointers for iterative allocation + */ + for (i = 0; i < BFA_MEM_TYPE_MAX; i++) { + melem = meminfo->meminfo + i; + melem->kva_curp = melem->kva; + melem->dma_curp = melem->dma; } - bfa_iocfc_attach(bfa, bfad, cfg, pcidev); + bfa_iocfc_attach(bfa, bfad, cfg, meminfo, pcidev); for (i = 0; hal_mods[i]; i++) - hal_mods[i]->attach(bfa, bfad, cfg, pcidev); - - bfa_com_port_attach(bfa); - bfa_com_ablk_attach(bfa); - bfa_com_cee_attach(bfa); - bfa_com_sfp_attach(bfa); - bfa_com_flash_attach(bfa, cfg->drvcfg.min_cfg); - bfa_com_diag_attach(bfa); - bfa_com_phy_attach(bfa, cfg->drvcfg.min_cfg); + hal_mods[i]->attach(bfa, bfad, cfg, meminfo, pcidev); + + bfa_com_port_attach(bfa, meminfo); } /* @@ -1603,7 +1215,6 @@ bfa_cfg_get_default(struct bfa_iocfc_cfg_s *cfg) cfg->fwcfg.num_fcxp_reqs = DEF_CFG_NUM_FCXP_REQS; cfg->fwcfg.num_uf_bufs = DEF_CFG_NUM_UF_BUFS; cfg->fwcfg.num_cqs = DEF_CFG_NUM_CQS; - cfg->fwcfg.num_fwtio_reqs = 0; cfg->drvcfg.num_reqq_elems = DEF_CFG_NUM_REQQ_ELEMS; cfg->drvcfg.num_rspq_elems = DEF_CFG_NUM_RSPQ_ELEMS; @@ -1625,7 +1236,6 @@ bfa_cfg_get_min(struct bfa_iocfc_cfg_s *cfg) cfg->fwcfg.num_fcxp_reqs = BFA_FCXP_MIN; cfg->fwcfg.num_uf_bufs = BFA_UF_MIN; cfg->fwcfg.num_rports = BFA_RPORT_MIN; - cfg->fwcfg.num_fwtio_reqs = 0; cfg->drvcfg.num_sgpgs = BFA_SGPG_MIN; cfg->drvcfg.num_reqq_elems = BFA_REQQ_NELEMS_MIN; diff --git a/trunk/drivers/scsi/bfa/bfa_defs.h b/trunk/drivers/scsi/bfa/bfa_defs.h index ed8d31b0188b..d85f93aea465 100644 --- a/trunk/drivers/scsi/bfa/bfa_defs.h +++ b/trunk/drivers/scsi/bfa/bfa_defs.h @@ -40,12 +40,7 @@ enum { BFA_MFG_TYPE_ASTRA = 807, /* Astra mezz card */ BFA_MFG_TYPE_LIGHTNING_P0 = 902, /* Lightning mezz card - old */ BFA_MFG_TYPE_LIGHTNING = 1741, /* Lightning mezz card */ - BFA_MFG_TYPE_PROWLER_F = 1560, /* Prowler FC only cards */ - BFA_MFG_TYPE_PROWLER_N = 1410, /* Prowler NIC only cards */ - BFA_MFG_TYPE_PROWLER_C = 1710, /* Prowler CNA only cards */ - BFA_MFG_TYPE_PROWLER_D = 1860, /* Prowler Dual cards */ - BFA_MFG_TYPE_CHINOOK = 1867, /* Chinook cards */ - BFA_MFG_TYPE_INVALID = 0, /* Invalid card type */ + BFA_MFG_TYPE_INVALID = 0, /* Invalid card type */ }; #pragma pack(1) @@ -58,8 +53,7 @@ enum { (type) == BFA_MFG_TYPE_WANCHESE || \ (type) == BFA_MFG_TYPE_ASTRA || \ (type) == BFA_MFG_TYPE_LIGHTNING_P0 || \ - (type) == BFA_MFG_TYPE_LIGHTNING || \ - (type) == BFA_MFG_TYPE_CHINOOK)) + (type) == BFA_MFG_TYPE_LIGHTNING)) /* * Check if the card having old wwn/mac handling @@ -130,53 +124,30 @@ enum bfa_status { BFA_STATUS_ETIMER = 5, /* Timer expired - Retry, if persists, * contact support */ BFA_STATUS_EPROTOCOL = 6, /* Protocol error */ - BFA_STATUS_SFP_UNSUPP = 10, /* Unsupported SFP - Replace SFP */ - BFA_STATUS_UNKNOWN_VFID = 11, /* VF_ID not found */ - BFA_STATUS_DATACORRUPTED = 12, /* Diag returned data corrupted */ BFA_STATUS_DEVBUSY = 13, /* Device busy - Retry operation */ - BFA_STATUS_HDMA_FAILED = 16, /* Host dma failed contact support */ - BFA_STATUS_FLASH_BAD_LEN = 17, /* Flash bad length */ BFA_STATUS_UNKNOWN_LWWN = 18, /* LPORT PWWN not found */ BFA_STATUS_UNKNOWN_RWWN = 19, /* RPORT PWWN not found */ BFA_STATUS_VPORT_EXISTS = 21, /* VPORT already exists */ BFA_STATUS_VPORT_MAX = 22, /* Reached max VPORT supported limit */ BFA_STATUS_UNSUPP_SPEED = 23, /* Invalid Speed Check speed setting */ BFA_STATUS_INVLD_DFSZ = 24, /* Invalid Max data field size */ - BFA_STATUS_CMD_NOTSUPP = 26, /* Command/API not supported */ BFA_STATUS_FABRIC_RJT = 29, /* Reject from attached fabric */ - BFA_STATUS_PORT_OFFLINE = 34, /* Port is not online */ BFA_STATUS_VPORT_WWN_BP = 46, /* WWN is same as base port's WWN */ - BFA_STATUS_PORT_NOT_DISABLED = 47, /* Port not disabled disable port */ BFA_STATUS_NO_FCPIM_NEXUS = 52, /* No FCP Nexus exists with the rport */ BFA_STATUS_IOC_FAILURE = 56, /* IOC failure - Retry, if persists * contact support */ BFA_STATUS_INVALID_WWN = 57, /* Invalid WWN */ - BFA_STATUS_ADAPTER_ENABLED = 60, /* Adapter is not disabled */ - BFA_STATUS_IOC_NON_OP = 61, /* IOC is not operational */ - BFA_STATUS_VERSION_FAIL = 70, /* Application/Driver version mismatch */ BFA_STATUS_DIAG_BUSY = 71, /* diag busy */ - BFA_STATUS_BEACON_ON = 72, /* Port Beacon already on */ BFA_STATUS_ENOFSAVE = 78, /* No saved firmware trace */ BFA_STATUS_IOC_DISABLED = 82, /* IOC is already disabled */ - BFA_STATUS_NO_SFP_DEV = 89, /* No SFP device check or replace SFP */ - BFA_STATUS_MEMTEST_FAILED = 90, /* Memory test failed contact support */ - BFA_STATUS_LEDTEST_OP = 109, /* LED test is operating */ BFA_STATUS_INVALID_MAC = 134, /* Invalid MAC address */ BFA_STATUS_PBC = 154, /* Operation not allowed for pre-boot * configuration */ - BFA_STATUS_SFP_NOT_READY = 159, /* SFP info is not ready. Retry */ BFA_STATUS_TRUNK_ENABLED = 164, /* Trunk is already enabled on * this adapter */ BFA_STATUS_TRUNK_DISABLED = 165, /* Trunking is disabled on * the adapter */ BFA_STATUS_IOPROFILE_OFF = 175, /* IO profile OFF */ - BFA_STATUS_PHY_NOT_PRESENT = 183, /* PHY module not present */ - BFA_STATUS_FEATURE_NOT_SUPPORTED = 192, /* Feature not supported */ - BFA_STATUS_FAA_ENABLED = 197, /* FAA is already enabled */ - BFA_STATUS_FAA_DISABLED = 198, /* FAA is already disabled */ - BFA_STATUS_FAA_ACQUIRED = 199, /* FAA is already acquired */ - BFA_STATUS_FAA_ACQ_ADDR = 200, /* Acquiring addr */ - BFA_STATUS_ERROR_TRUNK_ENABLED = 203, /* Trunk enabled on adapter */ BFA_STATUS_MAX_VAL /* Unknown error code */ }; #define bfa_status_t enum bfa_status @@ -294,8 +265,6 @@ enum bfa_ioc_state { BFA_IOC_DISABLED = 10, /* IOC is disabled */ BFA_IOC_FWMISMATCH = 11, /* IOC f/w different from drivers */ BFA_IOC_ENABLING = 12, /* IOC is being enabled */ - BFA_IOC_HWFAIL = 13, /* PCI mapping doesn't exist */ - BFA_IOC_ACQ_ADDR = 14, /* Acquiring addr from fabric */ }; /* @@ -325,7 +294,6 @@ struct bfa_ioc_drv_stats_s { u32 enable_reqs; u32 disable_replies; u32 enable_replies; - u32 rsvd; }; /* @@ -352,10 +320,7 @@ struct bfa_ioc_attr_s { struct bfa_ioc_driver_attr_s driver_attr; /* driver attr */ struct bfa_ioc_pci_attr_s pci_attr; u8 port_id; /* port number */ - u8 port_mode; /* bfa_mode_s */ - u8 cap_bm; /* capability */ - u8 port_mode_cfg; /* bfa_mode_s */ - u8 rsvd[4]; /* 64bit align */ + u8 rsvd[7]; /* 64bit align */ }; /* @@ -372,21 +337,6 @@ struct bfa_ioc_attr_s { #define BFA_MFG_SUPPLIER_PARTNUM_SIZE 20 #define BFA_MFG_SUPPLIER_SERIALNUM_SIZE 20 #define BFA_MFG_SUPPLIER_REVISION_SIZE 4 -/* - * Initial capability definition - */ -#define BFA_MFG_IC_FC 0x01 -#define BFA_MFG_IC_ETH 0x02 - -/* - * Adapter capability mask definition - */ -#define BFA_CM_HBA 0x01 -#define BFA_CM_CNA 0x02 -#define BFA_CM_NIC 0x04 -#define BFA_CM_FC16G 0x08 -#define BFA_CM_SRIOV 0x10 -#define BFA_CM_MEZZ 0x20 #pragma pack(1) @@ -394,39 +344,31 @@ struct bfa_ioc_attr_s { * All numerical fields are in big-endian format. */ struct bfa_mfg_block_s { - u8 version; /*!< manufacturing block version */ - u8 mfg_sig[3]; /*!< characters 'M', 'F', 'G' */ - u16 mfgsize; /*!< mfg block size */ - u16 u16_chksum; /*!< old u16 checksum */ - char brcd_serialnum[STRSZ(BFA_MFG_SERIALNUM_SIZE)]; - char brcd_partnum[STRSZ(BFA_MFG_PARTNUM_SIZE)]; - u8 mfg_day; /*!< manufacturing day */ - u8 mfg_month; /*!< manufacturing month */ - u16 mfg_year; /*!< manufacturing year */ - wwn_t mfg_wwn; /*!< wwn base for this adapter */ - u8 num_wwn; /*!< number of wwns assigned */ - u8 mfg_speeds; /*!< speeds allowed for this adapter */ - u8 rsv[2]; - char supplier_id[STRSZ(BFA_MFG_SUPPLIER_ID_SIZE)]; - char supplier_partnum[STRSZ(BFA_MFG_SUPPLIER_PARTNUM_SIZE)]; - char supplier_serialnum[STRSZ(BFA_MFG_SUPPLIER_SERIALNUM_SIZE)]; - char supplier_revision[STRSZ(BFA_MFG_SUPPLIER_REVISION_SIZE)]; - mac_t mfg_mac; /*!< base mac address */ - u8 num_mac; /*!< number of mac addresses */ - u8 rsv2; - u32 card_type; /*!< card type */ - char cap_nic; /*!< capability nic */ - char cap_cna; /*!< capability cna */ - char cap_hba; /*!< capability hba */ - char cap_fc16g; /*!< capability fc 16g */ - char cap_sriov; /*!< capability sriov */ - char cap_mezz; /*!< capability mezz */ - u8 rsv3; - u8 mfg_nports; /*!< number of ports */ - char media[8]; /*!< xfi/xaui */ - char initial_mode[8]; /*!< initial mode: hba/cna/nic */ - u8 rsv4[84]; - u8 md5_chksum[BFA_MFG_CHKSUM_SIZE]; /*!< md5 checksum */ + u8 version; /* manufacturing block version */ + u8 mfg_sig[3]; /* characters 'M', 'F', 'G' */ + u16 mfgsize; /* mfg block size */ + u16 u16_chksum; /* old u16 checksum */ + char brcd_serialnum[STRSZ(BFA_MFG_SERIALNUM_SIZE)]; + char brcd_partnum[STRSZ(BFA_MFG_PARTNUM_SIZE)]; + u8 mfg_day; /* manufacturing day */ + u8 mfg_month; /* manufacturing month */ + u16 mfg_year; /* manufacturing year */ + wwn_t mfg_wwn; /* wwn base for this adapter */ + u8 num_wwn; /* number of wwns assigned */ + u8 mfg_speeds; /* speeds allowed for this adapter */ + u8 rsv[2]; + char supplier_id[STRSZ(BFA_MFG_SUPPLIER_ID_SIZE)]; + char supplier_partnum[STRSZ(BFA_MFG_SUPPLIER_PARTNUM_SIZE)]; + char + supplier_serialnum[STRSZ(BFA_MFG_SUPPLIER_SERIALNUM_SIZE)]; + char + supplier_revision[STRSZ(BFA_MFG_SUPPLIER_REVISION_SIZE)]; + mac_t mfg_mac; /* mac address */ + u8 num_mac; /* number of mac addresses */ + u8 rsv2; + u32 mfg_type; /* card type */ + u8 rsv3[108]; + u8 md5_chksum[BFA_MFG_CHKSUM_SIZE]; /* md5 checksum */ }; #pragma pack() @@ -444,27 +386,17 @@ enum { BFA_PCI_DEVICE_ID_FC_8G1P = 0x17, BFA_PCI_DEVICE_ID_CT = 0x14, BFA_PCI_DEVICE_ID_CT_FC = 0x21, - BFA_PCI_DEVICE_ID_CT2 = 0x22, }; -#define bfa_asic_id_cb(__d) \ - ((__d) == BFA_PCI_DEVICE_ID_FC_8G2P || \ - (__d) == BFA_PCI_DEVICE_ID_FC_8G1P) -#define bfa_asic_id_ct(__d) \ - ((__d) == BFA_PCI_DEVICE_ID_CT || \ - (__d) == BFA_PCI_DEVICE_ID_CT_FC) -#define bfa_asic_id_ct2(__d) ((__d) == BFA_PCI_DEVICE_ID_CT2) -#define bfa_asic_id_ctc(__d) \ - (bfa_asic_id_ct(__d) || bfa_asic_id_ct2(__d)) +#define bfa_asic_id_ct(devid) \ + ((devid) == BFA_PCI_DEVICE_ID_CT || \ + (devid) == BFA_PCI_DEVICE_ID_CT_FC) /* * PCI sub-system device and vendor ID information */ enum { BFA_PCI_FCOE_SSDEVICE_ID = 0x14, - BFA_PCI_CT2_SSID_FCoE = 0x22, - BFA_PCI_CT2_SSID_ETH = 0x23, - BFA_PCI_CT2_SSID_FC = 0x24, }; /* @@ -484,7 +416,9 @@ enum bfa_port_speed { BFA_PORT_SPEED_8GBPS = 8, BFA_PORT_SPEED_10GBPS = 10, BFA_PORT_SPEED_16GBPS = 16, - BFA_PORT_SPEED_AUTO = 0xf, + BFA_PORT_SPEED_AUTO = + (BFA_PORT_SPEED_1GBPS | BFA_PORT_SPEED_2GBPS | + BFA_PORT_SPEED_4GBPS | BFA_PORT_SPEED_8GBPS), }; #define bfa_port_speed_t enum bfa_port_speed @@ -529,453 +463,4 @@ struct bfa_boot_pbc_s { struct bfa_boot_bootlun_s pblun[BFA_PREBOOT_BOOTLUN_MAX]; }; -/* - * ASIC block configuration related structures - */ -#define BFA_ABLK_MAX_PORTS 2 -#define BFA_ABLK_MAX_PFS 16 -#define BFA_ABLK_MAX 2 - -#pragma pack(1) -enum bfa_mode_s { - BFA_MODE_HBA = 1, - BFA_MODE_CNA = 2, - BFA_MODE_NIC = 3 -}; - -struct bfa_adapter_cfg_mode_s { - u16 max_pf; - u16 max_vf; - enum bfa_mode_s mode; -}; - -struct bfa_ablk_cfg_pf_s { - u16 pers; - u8 port_id; - u8 optrom; - u8 valid; - u8 sriov; - u8 max_vfs; - u8 rsvd[1]; - u16 num_qpairs; - u16 num_vectors; - u32 bw; -}; - -struct bfa_ablk_cfg_port_s { - u8 mode; - u8 type; - u8 max_pfs; - u8 rsvd[5]; -}; - -struct bfa_ablk_cfg_inst_s { - u8 nports; - u8 max_pfs; - u8 rsvd[6]; - struct bfa_ablk_cfg_pf_s pf_cfg[BFA_ABLK_MAX_PFS]; - struct bfa_ablk_cfg_port_s port_cfg[BFA_ABLK_MAX_PORTS]; -}; - -struct bfa_ablk_cfg_s { - struct bfa_ablk_cfg_inst_s inst[BFA_ABLK_MAX]; -}; - - -/* - * SFP module specific - */ -#define SFP_DIAGMON_SIZE 10 /* num bytes of diag monitor data */ - -enum bfa_defs_sfp_media_e { - BFA_SFP_MEDIA_UNKNOWN = 0x00, - BFA_SFP_MEDIA_CU = 0x01, - BFA_SFP_MEDIA_LW = 0x02, - BFA_SFP_MEDIA_SW = 0x03, - BFA_SFP_MEDIA_EL = 0x04, - BFA_SFP_MEDIA_UNSUPPORT = 0x05, -}; - -/* - * values for xmtr_tech above - */ -enum { - SFP_XMTR_TECH_CU = (1 << 0), /* copper FC-BaseT */ - SFP_XMTR_TECH_CP = (1 << 1), /* copper passive */ - SFP_XMTR_TECH_CA = (1 << 2), /* copper active */ - SFP_XMTR_TECH_LL = (1 << 3), /* longwave laser */ - SFP_XMTR_TECH_SL = (1 << 4), /* shortwave laser w/ OFC */ - SFP_XMTR_TECH_SN = (1 << 5), /* shortwave laser w/o OFC */ - SFP_XMTR_TECH_EL_INTRA = (1 << 6), /* elec intra-enclosure */ - SFP_XMTR_TECH_EL_INTER = (1 << 7), /* elec inter-enclosure */ - SFP_XMTR_TECH_LC = (1 << 8), /* longwave laser */ - SFP_XMTR_TECH_SA = (1 << 9) -}; - -/* - * Serial ID: Data Fields -- Address A0h - * Basic ID field total 64 bytes - */ -struct sfp_srlid_base_s { - u8 id; /* 00: Identifier */ - u8 extid; /* 01: Extended Identifier */ - u8 connector; /* 02: Connector */ - u8 xcvr[8]; /* 03-10: Transceiver */ - u8 encoding; /* 11: Encoding */ - u8 br_norm; /* 12: BR, Nominal */ - u8 rate_id; /* 13: Rate Identifier */ - u8 len_km; /* 14: Length single mode km */ - u8 len_100m; /* 15: Length single mode 100m */ - u8 len_om2; /* 16: Length om2 fiber 10m */ - u8 len_om1; /* 17: Length om1 fiber 10m */ - u8 len_cu; /* 18: Length copper 1m */ - u8 len_om3; /* 19: Length om3 fiber 10m */ - u8 vendor_name[16];/* 20-35 */ - u8 unalloc1; - u8 vendor_oui[3]; /* 37-39 */ - u8 vendor_pn[16]; /* 40-55 */ - u8 vendor_rev[4]; /* 56-59 */ - u8 wavelen[2]; /* 60-61 */ - u8 unalloc2; - u8 cc_base; /* 63: check code for base id field */ -}; - -/* - * Serial ID: Data Fields -- Address A0h - * Extended id field total 32 bytes - */ -struct sfp_srlid_ext_s { - u8 options[2]; - u8 br_max; - u8 br_min; - u8 vendor_sn[16]; - u8 date_code[8]; - u8 diag_mon_type; /* 92: Diagnostic Monitoring type */ - u8 en_options; - u8 sff_8472; - u8 cc_ext; -}; - -/* - * Diagnostic: Data Fields -- Address A2h - * Diagnostic and control/status base field total 96 bytes - */ -struct sfp_diag_base_s { - /* - * Alarm and warning Thresholds 40 bytes - */ - u8 temp_high_alarm[2]; /* 00-01 */ - u8 temp_low_alarm[2]; /* 02-03 */ - u8 temp_high_warning[2]; /* 04-05 */ - u8 temp_low_warning[2]; /* 06-07 */ - - u8 volt_high_alarm[2]; /* 08-09 */ - u8 volt_low_alarm[2]; /* 10-11 */ - u8 volt_high_warning[2]; /* 12-13 */ - u8 volt_low_warning[2]; /* 14-15 */ - - u8 bias_high_alarm[2]; /* 16-17 */ - u8 bias_low_alarm[2]; /* 18-19 */ - u8 bias_high_warning[2]; /* 20-21 */ - u8 bias_low_warning[2]; /* 22-23 */ - - u8 tx_pwr_high_alarm[2]; /* 24-25 */ - u8 tx_pwr_low_alarm[2]; /* 26-27 */ - u8 tx_pwr_high_warning[2]; /* 28-29 */ - u8 tx_pwr_low_warning[2]; /* 30-31 */ - - u8 rx_pwr_high_alarm[2]; /* 32-33 */ - u8 rx_pwr_low_alarm[2]; /* 34-35 */ - u8 rx_pwr_high_warning[2]; /* 36-37 */ - u8 rx_pwr_low_warning[2]; /* 38-39 */ - - u8 unallocate_1[16]; - - /* - * ext_cal_const[36] - */ - u8 rx_pwr[20]; - u8 tx_i[4]; - u8 tx_pwr[4]; - u8 temp[4]; - u8 volt[4]; - u8 unallocate_2[3]; - u8 cc_dmi; -}; - -/* - * Diagnostic: Data Fields -- Address A2h - * Diagnostic and control/status extended field total 24 bytes - */ -struct sfp_diag_ext_s { - u8 diag[SFP_DIAGMON_SIZE]; - u8 unalloc1[4]; - u8 status_ctl; - u8 rsvd; - u8 alarm_flags[2]; - u8 unalloc2[2]; - u8 warning_flags[2]; - u8 ext_status_ctl[2]; -}; - -struct sfp_mem_s { - struct sfp_srlid_base_s srlid_base; - struct sfp_srlid_ext_s srlid_ext; - struct sfp_diag_base_s diag_base; - struct sfp_diag_ext_s diag_ext; -}; - -/* - * transceiver codes (SFF-8472 Rev 10.2 Table 3.5) - */ -union sfp_xcvr_e10g_code_u { - u8 b; - struct { -#ifdef __BIGENDIAN - u8 e10g_unall:1; /* 10G Ethernet compliance */ - u8 e10g_lrm:1; - u8 e10g_lr:1; - u8 e10g_sr:1; - u8 ib_sx:1; /* Infiniband compliance */ - u8 ib_lx:1; - u8 ib_cu_a:1; - u8 ib_cu_p:1; -#else - u8 ib_cu_p:1; - u8 ib_cu_a:1; - u8 ib_lx:1; - u8 ib_sx:1; /* Infiniband compliance */ - u8 e10g_sr:1; - u8 e10g_lr:1; - u8 e10g_lrm:1; - u8 e10g_unall:1; /* 10G Ethernet compliance */ -#endif - } r; -}; - -union sfp_xcvr_so1_code_u { - u8 b; - struct { - u8 escon:2; /* ESCON compliance code */ - u8 oc192_reach:1; /* SONET compliance code */ - u8 so_reach:2; - u8 oc48_reach:3; - } r; -}; - -union sfp_xcvr_so2_code_u { - u8 b; - struct { - u8 reserved:1; - u8 oc12_reach:3; /* OC12 reach */ - u8 reserved1:1; - u8 oc3_reach:3; /* OC3 reach */ - } r; -}; - -union sfp_xcvr_eth_code_u { - u8 b; - struct { - u8 base_px:1; - u8 base_bx10:1; - u8 e100base_fx:1; - u8 e100base_lx:1; - u8 e1000base_t:1; - u8 e1000base_cx:1; - u8 e1000base_lx:1; - u8 e1000base_sx:1; - } r; -}; - -struct sfp_xcvr_fc1_code_s { - u8 link_len:5; /* FC link length */ - u8 xmtr_tech2:3; - u8 xmtr_tech1:7; /* FC transmitter technology */ - u8 reserved1:1; -}; - -union sfp_xcvr_fc2_code_u { - u8 b; - struct { - u8 tw_media:1; /* twin axial pair (tw) */ - u8 tp_media:1; /* shielded twisted pair (sp) */ - u8 mi_media:1; /* miniature coax (mi) */ - u8 tv_media:1; /* video coax (tv) */ - u8 m6_media:1; /* multimode, 62.5m (m6) */ - u8 m5_media:1; /* multimode, 50m (m5) */ - u8 reserved:1; - u8 sm_media:1; /* single mode (sm) */ - } r; -}; - -union sfp_xcvr_fc3_code_u { - u8 b; - struct { -#ifdef __BIGENDIAN - u8 rsv4:1; - u8 mb800:1; /* 800 Mbytes/sec */ - u8 mb1600:1; /* 1600 Mbytes/sec */ - u8 mb400:1; /* 400 Mbytes/sec */ - u8 rsv2:1; - u8 mb200:1; /* 200 Mbytes/sec */ - u8 rsv1:1; - u8 mb100:1; /* 100 Mbytes/sec */ -#else - u8 mb100:1; /* 100 Mbytes/sec */ - u8 rsv1:1; - u8 mb200:1; /* 200 Mbytes/sec */ - u8 rsv2:1; - u8 mb400:1; /* 400 Mbytes/sec */ - u8 mb1600:1; /* 1600 Mbytes/sec */ - u8 mb800:1; /* 800 Mbytes/sec */ - u8 rsv4:1; -#endif - } r; -}; - -struct sfp_xcvr_s { - union sfp_xcvr_e10g_code_u e10g; - union sfp_xcvr_so1_code_u so1; - union sfp_xcvr_so2_code_u so2; - union sfp_xcvr_eth_code_u eth; - struct sfp_xcvr_fc1_code_s fc1; - union sfp_xcvr_fc2_code_u fc2; - union sfp_xcvr_fc3_code_u fc3; -}; - -/* - * Flash module specific - */ -#define BFA_FLASH_PART_ENTRY_SIZE 32 /* partition entry size */ -#define BFA_FLASH_PART_MAX 32 /* maximal # of partitions */ - -enum bfa_flash_part_type { - BFA_FLASH_PART_OPTROM = 1, /* option rom partition */ - BFA_FLASH_PART_FWIMG = 2, /* firmware image partition */ - BFA_FLASH_PART_FWCFG = 3, /* firmware tuneable config */ - BFA_FLASH_PART_DRV = 4, /* IOC driver config */ - BFA_FLASH_PART_BOOT = 5, /* boot config */ - BFA_FLASH_PART_ASIC = 6, /* asic bootstrap configuration */ - BFA_FLASH_PART_MFG = 7, /* manufacturing block partition */ - BFA_FLASH_PART_OPTROM2 = 8, /* 2nd option rom partition */ - BFA_FLASH_PART_VPD = 9, /* vpd data of OEM info */ - BFA_FLASH_PART_PBC = 10, /* pre-boot config */ - BFA_FLASH_PART_BOOTOVL = 11, /* boot overlay partition */ - BFA_FLASH_PART_LOG = 12, /* firmware log partition */ - BFA_FLASH_PART_PXECFG = 13, /* pxe boot config partition */ - BFA_FLASH_PART_PXEOVL = 14, /* pxe boot overlay partition */ - BFA_FLASH_PART_PORTCFG = 15, /* port cfg partition */ - BFA_FLASH_PART_ASICBK = 16, /* asic backup partition */ -}; - -/* - * flash partition attributes - */ -struct bfa_flash_part_attr_s { - u32 part_type; /* partition type */ - u32 part_instance; /* partition instance */ - u32 part_off; /* partition offset */ - u32 part_size; /* partition size */ - u32 part_len; /* partition content length */ - u32 part_status; /* partition status */ - char rsv[BFA_FLASH_PART_ENTRY_SIZE - 24]; -}; - -/* - * flash attributes - */ -struct bfa_flash_attr_s { - u32 status; /* flash overall status */ - u32 npart; /* num of partitions */ - struct bfa_flash_part_attr_s part[BFA_FLASH_PART_MAX]; -}; - -/* - * DIAG module specific - */ -#define LB_PATTERN_DEFAULT 0xB5B5B5B5 -#define QTEST_CNT_DEFAULT 10 -#define QTEST_PAT_DEFAULT LB_PATTERN_DEFAULT - -struct bfa_diag_memtest_s { - u8 algo; - u8 rsvd[7]; -}; - -struct bfa_diag_memtest_result { - u32 status; - u32 addr; - u32 exp; /* expect value read from reg */ - u32 act; /* actually value read */ - u32 err_status; /* error status reg */ - u32 err_status1; /* extra error info reg */ - u32 err_addr; /* error address reg */ - u8 algo; - u8 rsv[3]; -}; - -struct bfa_diag_loopback_result_s { - u32 numtxmfrm; /* no. of transmit frame */ - u32 numosffrm; /* no. of outstanding frame */ - u32 numrcvfrm; /* no. of received good frame */ - u32 badfrminf; /* mis-match info */ - u32 badfrmnum; /* mis-match fram number */ - u8 status; /* loopback test result */ - u8 rsvd[3]; -}; - -struct bfa_diag_ledtest_s { - u32 cmd; /* bfa_led_op_t */ - u32 color; /* bfa_led_color_t */ - u16 freq; /* no. of blinks every 10 secs */ - u8 led; /* bitmap of LEDs to be tested */ - u8 rsvd[5]; -}; - -struct bfa_diag_loopback_s { - u32 loopcnt; - u32 pattern; - u8 lb_mode; /* bfa_port_opmode_t */ - u8 speed; /* bfa_port_speed_t */ - u8 rsvd[2]; -}; - -/* - * PHY module specific - */ -enum bfa_phy_status_e { - BFA_PHY_STATUS_GOOD = 0, /* phy is good */ - BFA_PHY_STATUS_NOT_PRESENT = 1, /* phy does not exist */ - BFA_PHY_STATUS_BAD = 2, /* phy is bad */ -}; - -/* - * phy attributes for phy query - */ -struct bfa_phy_attr_s { - u32 status; /* phy present/absent status */ - u32 length; /* firmware length */ - u32 fw_ver; /* firmware version */ - u32 an_status; /* AN status */ - u32 pma_pmd_status; /* PMA/PMD link status */ - u32 pma_pmd_signal; /* PMA/PMD signal detect */ - u32 pcs_status; /* PCS link status */ -}; - -/* - * phy stats - */ -struct bfa_phy_stats_s { - u32 status; /* phy stats status */ - u32 link_breaks; /* Num of link breaks after linkup */ - u32 pma_pmd_fault; /* NPMA/PMD fault */ - u32 pcs_fault; /* PCS fault */ - u32 speed_neg; /* Num of speed negotiation */ - u32 tx_eq_training; /* Num of TX EQ training */ - u32 tx_eq_timeout; /* Num of TX EQ timeout */ - u32 crc_error; /* Num of CRC errors */ -}; - -#pragma pack() - #endif /* __BFA_DEFS_H__ */ diff --git a/trunk/drivers/scsi/bfa/bfa_defs_fcs.h b/trunk/drivers/scsi/bfa/bfa_defs_fcs.h index 3bbc583f65cf..191d34a58b9c 100644 --- a/trunk/drivers/scsi/bfa/bfa_defs_fcs.h +++ b/trunk/drivers/scsi/bfa/bfa_defs_fcs.h @@ -90,14 +90,12 @@ enum bfa_lport_role { * FCS port configuration. */ struct bfa_lport_cfg_s { - wwn_t pwwn; /* port wwn */ - wwn_t nwwn; /* node wwn */ - struct bfa_lport_symname_s sym_name; /* vm port symbolic name */ - enum bfa_lport_role roles; /* FCS port roles */ - u32 rsvd; - bfa_boolean_t preboot_vp; /* vport created from PBC */ - u8 tag[16]; /* opaque tag from application */ - u8 padding[4]; + wwn_t pwwn; /* port wwn */ + wwn_t nwwn; /* node wwn */ + struct bfa_lport_symname_s sym_name; /* vm port symbolic name */ + bfa_boolean_t preboot_vp; /* vport created from PBC */ + enum bfa_lport_role roles; /* FCS port roles */ + u8 tag[16]; /* opaque tag from application */ }; /* @@ -251,13 +249,12 @@ enum bfa_vport_state { BFA_FCS_VPORT_FDISC_SEND = 2, BFA_FCS_VPORT_FDISC = 3, BFA_FCS_VPORT_FDISC_RETRY = 4, - BFA_FCS_VPORT_FDISC_RSP_WAIT = 5, - BFA_FCS_VPORT_ONLINE = 6, - BFA_FCS_VPORT_DELETING = 7, - BFA_FCS_VPORT_CLEANUP = 8, - BFA_FCS_VPORT_LOGO_SEND = 9, - BFA_FCS_VPORT_LOGO = 10, - BFA_FCS_VPORT_ERROR = 11, + BFA_FCS_VPORT_ONLINE = 5, + BFA_FCS_VPORT_DELETING = 6, + BFA_FCS_VPORT_CLEANUP = 6, + BFA_FCS_VPORT_LOGO_SEND = 7, + BFA_FCS_VPORT_LOGO = 8, + BFA_FCS_VPORT_ERROR = 9, BFA_FCS_VPORT_MAX_STATE, }; diff --git a/trunk/drivers/scsi/bfa/bfa_defs_svc.h b/trunk/drivers/scsi/bfa/bfa_defs_svc.h index 0b97525803fb..207f598877c7 100644 --- a/trunk/drivers/scsi/bfa/bfa_defs_svc.h +++ b/trunk/drivers/scsi/bfa/bfa_defs_svc.h @@ -47,12 +47,13 @@ struct bfa_iocfc_fwcfg_s { u16 num_rports; /* number of remote ports */ u16 num_ioim_reqs; /* number of IO reqs */ u16 num_tskim_reqs; /* task management requests */ - u16 num_fwtio_reqs; /* number of TM IO reqs in FW */ + u16 num_iotm_reqs; /* number of TM IO reqs */ + u16 num_tsktm_reqs; /* TM task management requests*/ u16 num_fcxp_reqs; /* unassisted FC exchanges */ u16 num_uf_bufs; /* unsolicited recv buffers */ u8 num_cqs; u8 fw_tick_res; /* FW clock resolution in ms */ - u8 rsvd[2]; + u8 rsvd[4]; }; #pragma pack() @@ -65,12 +66,8 @@ struct bfa_iocfc_drvcfg_s { u16 ioc_recover; /* IOC recovery mode */ u16 min_cfg; /* minimum configuration */ u16 path_tov; /* device path timeout */ - u16 num_tio_reqs; /*!< number of TM IO reqs */ - u8 port_mode; - u8 rsvd_a; bfa_boolean_t delay_comp; /* delay completion of failed inflight IOs */ - u16 num_ttsk_reqs; /* TM task management requests */ u32 rsvd; }; @@ -85,7 +82,7 @@ struct bfa_iocfc_cfg_s { /* * IOC firmware IO stats */ -struct bfa_fw_ioim_stats_s { +struct bfa_fw_io_stats_s { u32 host_abort; /* IO aborted by host driver*/ u32 host_cleanup; /* IO clean up by host driver */ @@ -155,54 +152,6 @@ struct bfa_fw_ioim_stats_s { */ }; -struct bfa_fw_tio_stats_s { - u32 tio_conf_proc; /* TIO CONF processed */ - u32 tio_conf_drop; /* TIO CONF dropped */ - u32 tio_cleanup_req; /* TIO cleanup requested */ - u32 tio_cleanup_comp; /* TIO cleanup completed */ - u32 tio_abort_rsp; /* TIO abort response */ - u32 tio_abort_rsp_comp; /* TIO abort rsp completed */ - u32 tio_abts_req; /* TIO ABTS requested */ - u32 tio_abts_ack; /* TIO ABTS ack-ed */ - u32 tio_abts_ack_nocomp; /* TIO ABTS ack-ed but not completed */ - u32 tio_abts_tmo; /* TIO ABTS timeout */ - u32 tio_snsdata_dma; /* TIO sense data DMA */ - u32 tio_rxwchan_wait; /* TIO waiting for RX wait channel */ - u32 tio_rxwchan_avail; /* TIO RX wait channel available */ - u32 tio_hit_bls; /* TIO IOH BLS event */ - u32 tio_uf_recv; /* TIO received UF */ - u32 tio_rd_invalid_sm; /* TIO read reqst in wrong state machine */ - u32 tio_wr_invalid_sm;/* TIO write reqst in wrong state machine */ - - u32 ds_rxwchan_wait; /* DS waiting for RX wait channel */ - u32 ds_rxwchan_avail; /* DS RX wait channel available */ - u32 ds_unaligned_rd; /* DS unaligned read */ - u32 ds_rdcomp_invalid_sm; /* DS read completed in wrong state machine */ - u32 ds_wrcomp_invalid_sm; /* DS write completed in wrong state machine */ - u32 ds_flush_req; /* DS flush requested */ - u32 ds_flush_comp; /* DS flush completed */ - u32 ds_xfrdy_exp; /* DS XFER_RDY expired */ - u32 ds_seq_cnt_err; /* DS seq cnt error */ - u32 ds_seq_len_err; /* DS seq len error */ - u32 ds_data_oor; /* DS data out of order */ - u32 ds_hit_bls; /* DS hit BLS */ - u32 ds_edtov_timer_exp; /* DS edtov expired */ - u32 ds_cpu_owned; /* DS cpu owned */ - u32 ds_hit_class2; /* DS hit class2 */ - u32 ds_length_err; /* DS length error */ - u32 ds_ro_ooo_err; /* DS relative offset out-of-order error */ - u32 ds_rectov_timer_exp; /* DS rectov expired */ - u32 ds_unexp_fr_err; /* DS unexp frame error */ -}; - -/* - * IOC firmware IO stats - */ -struct bfa_fw_io_stats_s { - struct bfa_fw_ioim_stats_s ioim_stats; - struct bfa_fw_tio_stats_s tio_stats; -}; - /* * IOC port firmware stats */ @@ -256,7 +205,6 @@ struct bfa_fw_port_lksm_stats_s { u32 nos_tx; /* No. of times NOS tx started */ u32 hwsm_lrr_rx; /* No. of times LRR rx-ed by HWSM */ u32 hwsm_lr_rx; /* No. of times LR rx-ed by HWSM */ - u32 bbsc_lr; /* LKSM LR tx for credit recovery */ }; struct bfa_fw_port_snsm_stats_s { @@ -318,8 +266,8 @@ struct bfa_fw_fcoe_stats_s { * IOC firmware FCoE port stats */ struct bfa_fw_fcoe_port_stats_s { - struct bfa_fw_fcoe_stats_s fcoe_stats; - struct bfa_fw_fip_stats_s fip_stats; + struct bfa_fw_fcoe_stats_s fcoe_stats; + struct bfa_fw_fip_stats_s fip_stats; }; /* @@ -688,7 +636,6 @@ enum bfa_port_states { BFA_PORT_ST_FWMISMATCH = 12, BFA_PORT_ST_PREBOOT_DISABLED = 13, BFA_PORT_ST_TOGGLING_QWAIT = 14, - BFA_PORT_ST_ACQ_ADDR = 15, BFA_PORT_ST_MAX_STATE, }; @@ -801,10 +748,6 @@ struct bfa_port_cfg_s { u8 tx_bbcredit; /* transmit buffer credits */ u8 ratelimit; /* ratelimit enabled or not */ u8 trl_def_speed; /* ratelimit default speed */ - u8 bb_scn; /* BB_SCN value from FLOGI Exchg */ - u8 bb_scn_state; /* Config state of BB_SCN */ - u8 faa_state; /* FAA enabled/disabled */ - u8 rsvd[1]; u16 path_tov; /* device path timeout */ u16 q_depth; /* SCSI Queue depth */ }; @@ -840,7 +783,7 @@ struct bfa_port_attr_s { enum bfa_port_topology topology; /* current topology */ bfa_boolean_t beacon; /* current beacon status */ bfa_boolean_t link_e2e_beacon; /* link beacon is on */ - bfa_boolean_t bbsc_op_status; /* fc credit recovery oper state */ + bfa_boolean_t plog_enabled; /* portlog is enabled */ /* * Dynamic field - info from FCS @@ -849,10 +792,12 @@ struct bfa_port_attr_s { enum bfa_port_type port_type; /* current topology */ u32 loopback; /* external loopback */ u32 authfail; /* auth fail state */ + bfa_boolean_t io_profile; /* get it from fcpim mod */ + u8 pad[4]; /* for 64-bit alignement */ /* FCoE specific */ u16 fcoe_vlan; - u8 rsvd1[2]; + u8 rsvd1[6]; }; /* @@ -1042,19 +987,6 @@ struct bfa_itnim_ioprofile_s { struct bfa_itnim_latency_s io_latency; }; -/* - * vHBA port attribute values. - */ -struct bfa_vhba_attr_s { - wwn_t nwwn; /* node wwn */ - wwn_t pwwn; /* port wwn */ - u32 pid; /* port ID */ - bfa_boolean_t io_profile; /* get it from fcpim mod */ - bfa_boolean_t plog_enabled; /* portlog is enabled */ - u16 path_tov; - u8 rsvd[2]; -}; - /* * FC physical port statistics. */ @@ -1088,9 +1020,6 @@ struct bfa_port_fc_stats_s { u64 bad_os_count; /* Invalid ordered sets */ u64 err_enc_out; /* Encoding err nonframe_8b10b */ u64 err_enc; /* Encoding err frame_8b10b */ - u64 bbsc_frames_lost; /* Credit Recovery-Frames Lost */ - u64 bbsc_credits_lost; /* Credit Recovery-Credits Lost */ - u64 bbsc_link_resets; /* Credit Recovery-Link Resets */ }; /* @@ -1149,83 +1078,4 @@ union bfa_port_stats_u { struct bfa_port_eth_stats_s eth; }; -struct bfa_port_cfg_mode_s { - u16 max_pf; - u16 max_vf; - enum bfa_mode_s mode; -}; - -#pragma pack(1) - -#define BFA_CEE_LLDP_MAX_STRING_LEN (128) -#define BFA_CEE_DCBX_MAX_PRIORITY (8) -#define BFA_CEE_DCBX_MAX_PGID (8) - -struct bfa_cee_lldp_str_s { - u8 sub_type; - u8 len; - u8 rsvd[2]; - u8 value[BFA_CEE_LLDP_MAX_STRING_LEN]; -}; - -struct bfa_cee_lldp_cfg_s { - struct bfa_cee_lldp_str_s chassis_id; - struct bfa_cee_lldp_str_s port_id; - struct bfa_cee_lldp_str_s port_desc; - struct bfa_cee_lldp_str_s sys_name; - struct bfa_cee_lldp_str_s sys_desc; - struct bfa_cee_lldp_str_s mgmt_addr; - u16 time_to_live; - u16 enabled_system_cap; -}; - -/* CEE/DCBX parameters */ -struct bfa_cee_dcbx_cfg_s { - u8 pgid[BFA_CEE_DCBX_MAX_PRIORITY]; - u8 pg_percentage[BFA_CEE_DCBX_MAX_PGID]; - u8 pfc_primap; /* bitmap of priorties with PFC enabled */ - u8 fcoe_primap; /* bitmap of priorities used for FcoE traffic */ - u8 iscsi_primap; /* bitmap of priorities used for iSCSI traffic */ - u8 dcbx_version; /* operating version:CEE or preCEE */ - u8 lls_fcoe; /* FCoE Logical Link Status */ - u8 lls_lan; /* LAN Logical Link Status */ - u8 rsvd[2]; -}; - -/* CEE Query */ -struct bfa_cee_attr_s { - u8 cee_status; - u8 error_reason; - struct bfa_cee_lldp_cfg_s lldp_remote; - struct bfa_cee_dcbx_cfg_s dcbx_remote; - mac_t src_mac; - u8 link_speed; - u8 nw_priority; - u8 filler[2]; -}; - -/* LLDP/DCBX/CEE Statistics */ -struct bfa_cee_stats_s { - u32 lldp_tx_frames; /* LLDP Tx Frames */ - u32 lldp_rx_frames; /* LLDP Rx Frames */ - u32 lldp_rx_frames_invalid; /* LLDP Rx Frames invalid */ - u32 lldp_rx_frames_new; /* LLDP Rx Frames new */ - u32 lldp_tlvs_unrecognized; /* LLDP Rx unrecog. TLVs */ - u32 lldp_rx_shutdown_tlvs; /* LLDP Rx shutdown TLVs */ - u32 lldp_info_aged_out; /* LLDP remote info aged */ - u32 dcbx_phylink_ups; /* DCBX phy link ups */ - u32 dcbx_phylink_downs; /* DCBX phy link downs */ - u32 dcbx_rx_tlvs; /* DCBX Rx TLVs */ - u32 dcbx_rx_tlvs_invalid; /* DCBX Rx TLVs invalid */ - u32 dcbx_control_tlv_error; /* DCBX control TLV errors */ - u32 dcbx_feature_tlv_error; /* DCBX feature TLV errors */ - u32 dcbx_cee_cfg_new; /* DCBX new CEE cfg rcvd */ - u32 cee_status_down; /* DCB status down */ - u32 cee_status_up; /* DCB status up */ - u32 cee_hw_cfg_changed; /* DCB hw cfg changed */ - u32 cee_rx_invalid_cfg; /* DCB invalid cfg */ -}; - -#pragma pack() - #endif /* __BFA_DEFS_SVC_H__ */ diff --git a/trunk/drivers/scsi/bfa/bfa_fc.h b/trunk/drivers/scsi/bfa/bfa_fc.h index 8d0b88f67a38..bf0067e0fd0d 100644 --- a/trunk/drivers/scsi/bfa/bfa_fc.h +++ b/trunk/drivers/scsi/bfa/bfa_fc.h @@ -1021,7 +1021,7 @@ struct fc_symname_s { #define FC_ED_TOV 2 #define FC_REC_TOV (FC_ED_TOV + 1) #define FC_RA_TOV 10 -#define FC_ELS_TOV ((2 * FC_RA_TOV) + 1) +#define FC_ELS_TOV (2 * FC_RA_TOV) #define FC_FCCT_TOV (3 * FC_RA_TOV) /* @@ -1048,6 +1048,15 @@ struct fc_vft_s { u32 res_c:24; }; +/* + * FCP + */ +enum { + FCP_RJT = 0x01000000, /* SRR reject */ + FCP_SRR_ACCEPT = 0x02000000, /* SRR accept */ + FCP_SRR = 0x14000000, /* Sequence Retransmission Request */ +}; + /* * FCP_CMND definitions */ diff --git a/trunk/drivers/scsi/bfa/bfa_fcbuild.c b/trunk/drivers/scsi/bfa/bfa_fcbuild.c index 17b59b8b5644..b7e253451654 100644 --- a/trunk/drivers/scsi/bfa/bfa_fcbuild.c +++ b/trunk/drivers/scsi/bfa/bfa_fcbuild.c @@ -94,6 +94,7 @@ fcbuild_init(void) */ plogi_tmpl.csp.verhi = FC_PH_VER_PH_3; plogi_tmpl.csp.verlo = FC_PH_VER_4_3; + plogi_tmpl.csp.bbcred = cpu_to_be16(0x0004); plogi_tmpl.csp.ciro = 0x1; plogi_tmpl.csp.cisc = 0x0; plogi_tmpl.csp.altbbcred = 0x0; @@ -155,22 +156,6 @@ fc_gs_fchdr_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u32 ox_id) */ } -static void -fc_gsresp_fchdr_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id) -{ - memset(fchs, 0, sizeof(struct fchs_s)); - - fchs->routing = FC_RTG_FC4_DEV_DATA; - fchs->cat_info = FC_CAT_SOLICIT_CTRL; - fchs->type = FC_TYPE_SERVICES; - fchs->f_ctl = - bfa_hton3b(FCTL_EC_RESP | FCTL_SEQ_INI | FCTL_LS_EXCH | - FCTL_END_SEQ | FCTL_SI_XFER); - fchs->d_id = d_id; - fchs->s_id = s_id; - fchs->ox_id = ox_id; -} - void fc_els_req_build(struct fchs_s *fchs, u32 d_id, u32 s_id, __be16 ox_id) { @@ -222,7 +207,7 @@ fc_bls_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id, __be16 ox_id) static u16 fc_plogi_x_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id, __be16 ox_id, wwn_t port_name, wwn_t node_name, - u16 pdu_size, u16 bb_cr, u8 els_code) + u16 pdu_size, u8 els_code) { struct fc_logi_s *plogi = (struct fc_logi_s *) (pld); @@ -235,7 +220,6 @@ fc_plogi_x_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id, fc_els_rsp_build(fchs, d_id, s_id, ox_id); plogi->csp.rxsz = plogi->class3.rxsz = cpu_to_be16(pdu_size); - plogi->csp.bbcred = cpu_to_be16(bb_cr); memcpy(&plogi->port_name, &port_name, sizeof(wwn_t)); memcpy(&plogi->node_name, &node_name, sizeof(wwn_t)); @@ -284,17 +268,15 @@ fc_flogi_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id, u16 fc_flogi_acc_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id, __be16 ox_id, wwn_t port_name, wwn_t node_name, - u16 pdu_size, u16 local_bb_credits, u8 bb_scn) + u16 pdu_size, u16 local_bb_credits) { u32 d_id = 0; - u16 bbscn_rxsz = (bb_scn << 12) | pdu_size; memcpy(flogi, &plogi_tmpl, sizeof(struct fc_logi_s)); fc_els_rsp_build(fchs, d_id, s_id, ox_id); flogi->els_cmd.els_code = FC_ELS_ACC; - flogi->class3.rxsz = cpu_to_be16(pdu_size); - flogi->csp.rxsz = cpu_to_be16(bbscn_rxsz); /* bb_scn/rxsz */ + flogi->csp.rxsz = flogi->class3.rxsz = cpu_to_be16(pdu_size); flogi->port_name = port_name; flogi->node_name = node_name; @@ -324,19 +306,19 @@ fc_fdisc_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id, u16 fc_plogi_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id, u16 ox_id, wwn_t port_name, wwn_t node_name, - u16 pdu_size, u16 bb_cr) + u16 pdu_size) { return fc_plogi_x_build(fchs, pld, d_id, s_id, ox_id, port_name, - node_name, pdu_size, bb_cr, FC_ELS_PLOGI); + node_name, pdu_size, FC_ELS_PLOGI); } u16 fc_plogi_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id, u16 ox_id, wwn_t port_name, wwn_t node_name, - u16 pdu_size, u16 bb_cr) + u16 pdu_size) { return fc_plogi_x_build(fchs, pld, d_id, s_id, ox_id, port_name, - node_name, pdu_size, bb_cr, FC_ELS_ACC); + node_name, pdu_size, FC_ELS_ACC); } enum fc_parse_status @@ -1113,21 +1095,6 @@ fc_ct_rsp_parse(struct ct_hdr_s *cthdr) return FC_PARSE_OK; } -u16 -fc_gs_rjt_build(struct fchs_s *fchs, struct ct_hdr_s *cthdr, - u32 d_id, u32 s_id, u16 ox_id, u8 reason_code, - u8 reason_code_expl) -{ - fc_gsresp_fchdr_build(fchs, d_id, s_id, ox_id); - - cthdr->cmd_rsp_code = cpu_to_be16(CT_RSP_REJECT); - cthdr->rev_id = CT_GS3_REVISION; - - cthdr->reason_code = reason_code; - cthdr->exp_code = reason_code_expl; - return sizeof(struct ct_hdr_s); -} - u16 fc_scr_build(struct fchs_s *fchs, struct fc_scr_s *scr, u8 set_br_reg, u32 s_id, u16 ox_id) diff --git a/trunk/drivers/scsi/bfa/bfa_fcbuild.h b/trunk/drivers/scsi/bfa/bfa_fcbuild.h index 42cd9d4da697..ece51ec7620b 100644 --- a/trunk/drivers/scsi/bfa/bfa_fcbuild.h +++ b/trunk/drivers/scsi/bfa/bfa_fcbuild.h @@ -66,9 +66,6 @@ fc_rpsc_operspeed_to_bfa_speed(enum fc_rpsc_op_speed speed) case RPSC_OP_SPEED_8G: return BFA_PORT_SPEED_8GBPS; - case RPSC_OP_SPEED_16G: - return BFA_PORT_SPEED_16GBPS; - case RPSC_OP_SPEED_10G: return BFA_PORT_SPEED_10GBPS; @@ -97,9 +94,6 @@ fc_bfa_speed_to_rpsc_operspeed(enum bfa_port_speed op_speed) case BFA_PORT_SPEED_8GBPS: return RPSC_OP_SPEED_8G; - case BFA_PORT_SPEED_16GBPS: - return RPSC_OP_SPEED_16G; - case BFA_PORT_SPEED_10GBPS: return RPSC_OP_SPEED_10G; @@ -147,11 +141,11 @@ u16 fc_flogi_acc_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id, __be16 ox_id, wwn_t port_name, wwn_t node_name, u16 pdu_size, - u16 local_bb_credits, u8 bb_scn); + u16 local_bb_credits); u16 fc_plogi_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id, u16 ox_id, wwn_t port_name, - wwn_t node_name, u16 pdu_size, u16 bb_cr); + wwn_t node_name, u16 pdu_size); enum fc_parse_status fc_plogi_parse(struct fchs_s *fchs); @@ -183,17 +177,13 @@ u16 fc_gidpn_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 fc_gpnid_build(struct fchs_s *fchs, void *pld, u32 s_id, u16 ox_id, u32 port_id); -u16 fc_gs_rjt_build(struct fchs_s *fchs, struct ct_hdr_s *cthdr, - u32 d_id, u32 s_id, u16 ox_id, - u8 reason_code, u8 reason_code_expl); - u16 fc_scr_build(struct fchs_s *fchs, struct fc_scr_s *scr, u8 set_br_reg, u32 s_id, u16 ox_id); u16 fc_plogi_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id, u16 ox_id, wwn_t port_name, wwn_t node_name, - u16 pdu_size, u16 bb_cr); + u16 pdu_size); u16 fc_adisc_build(struct fchs_s *fchs, struct fc_adisc_s *adisc, u32 d_id, u32 s_id, __be16 ox_id, wwn_t port_name, diff --git a/trunk/drivers/scsi/bfa/bfa_fcpim.c b/trunk/drivers/scsi/bfa/bfa_fcpim.c index a4e7951c6063..c0353cdca929 100644 --- a/trunk/drivers/scsi/bfa/bfa_fcpim.c +++ b/trunk/drivers/scsi/bfa/bfa_fcpim.c @@ -19,6 +19,7 @@ #include "bfa_modules.h" BFA_TRC_FILE(HAL, FCPIM); +BFA_MODULE(fcpim); /* * BFA ITNIM Related definitions @@ -286,16 +287,24 @@ static void bfa_tskim_sm_hcb(struct bfa_tskim_s *tskim, * Compute and return memory needed by FCP(im) module. */ static void -bfa_fcpim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len) +bfa_fcpim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len, + u32 *dm_len) { - bfa_itnim_meminfo(cfg, km_len); + bfa_itnim_meminfo(cfg, km_len, dm_len); /* * IO memory */ + if (cfg->fwcfg.num_ioim_reqs < BFA_IOIM_MIN) + cfg->fwcfg.num_ioim_reqs = BFA_IOIM_MIN; + else if (cfg->fwcfg.num_ioim_reqs > BFA_IOIM_MAX) + cfg->fwcfg.num_ioim_reqs = BFA_IOIM_MAX; + *km_len += cfg->fwcfg.num_ioim_reqs * (sizeof(struct bfa_ioim_s) + sizeof(struct bfa_ioim_sp_s)); + *dm_len += cfg->fwcfg.num_ioim_reqs * BFI_IOIM_SNSLEN; + /* * task management command memory */ @@ -306,41 +315,52 @@ bfa_fcpim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len) static void -bfa_fcpim_attach(struct bfa_fcp_mod_s *fcp, void *bfad, - struct bfa_iocfc_cfg_s *cfg, struct bfa_pcidev_s *pcidev) +bfa_fcpim_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, + struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) { - struct bfa_fcpim_s *fcpim = &fcp->fcpim; - struct bfa_s *bfa = fcp->bfa; + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); bfa_trc(bfa, cfg->drvcfg.path_tov); bfa_trc(bfa, cfg->fwcfg.num_rports); bfa_trc(bfa, cfg->fwcfg.num_ioim_reqs); bfa_trc(bfa, cfg->fwcfg.num_tskim_reqs); - fcpim->fcp = fcp; fcpim->bfa = bfa; fcpim->num_itnims = cfg->fwcfg.num_rports; + fcpim->num_ioim_reqs = cfg->fwcfg.num_ioim_reqs; fcpim->num_tskim_reqs = cfg->fwcfg.num_tskim_reqs; fcpim->path_tov = cfg->drvcfg.path_tov; fcpim->delay_comp = cfg->drvcfg.delay_comp; fcpim->profile_comp = NULL; fcpim->profile_start = NULL; - bfa_itnim_attach(fcpim); - bfa_tskim_attach(fcpim); - bfa_ioim_attach(fcpim); + bfa_itnim_attach(fcpim, meminfo); + bfa_tskim_attach(fcpim, meminfo); + bfa_ioim_attach(fcpim, meminfo); +} + +static void +bfa_fcpim_detach(struct bfa_s *bfa) +{ +} + +static void +bfa_fcpim_start(struct bfa_s *bfa) +{ } static void -bfa_fcpim_iocdisable(struct bfa_fcp_mod_s *fcp) +bfa_fcpim_stop(struct bfa_s *bfa) { - struct bfa_fcpim_s *fcpim = &fcp->fcpim; +} + +static void +bfa_fcpim_iocdisable(struct bfa_s *bfa) +{ + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); struct bfa_itnim_s *itnim; struct list_head *qe, *qen; - /* Enqueue unused ioim resources to free_q */ - list_splice_tail_init(&fcpim->tskim_unused_q, &fcpim->tskim_free_q); - list_for_each_safe(qe, qen, &fcpim->itnim_q) { itnim = (struct bfa_itnim_s *) qe; bfa_itnim_iocdisable(itnim); @@ -350,7 +370,7 @@ bfa_fcpim_iocdisable(struct bfa_fcp_mod_s *fcp) void bfa_fcpim_path_tov_set(struct bfa_s *bfa, u16 path_tov) { - struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); fcpim->path_tov = path_tov * 1000; if (fcpim->path_tov > BFA_FCPIM_PATHTOV_MAX) @@ -360,87 +380,15 @@ bfa_fcpim_path_tov_set(struct bfa_s *bfa, u16 path_tov) u16 bfa_fcpim_path_tov_get(struct bfa_s *bfa) { - struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); return fcpim->path_tov / 1000; } -#define bfa_fcpim_add_iostats(__l, __r, __stats) \ - (__l->__stats += __r->__stats) - -void -bfa_fcpim_add_stats(struct bfa_itnim_iostats_s *lstats, - struct bfa_itnim_iostats_s *rstats) -{ - bfa_fcpim_add_iostats(lstats, rstats, total_ios); - bfa_fcpim_add_iostats(lstats, rstats, qresumes); - bfa_fcpim_add_iostats(lstats, rstats, no_iotags); - bfa_fcpim_add_iostats(lstats, rstats, io_aborts); - bfa_fcpim_add_iostats(lstats, rstats, no_tskims); - bfa_fcpim_add_iostats(lstats, rstats, iocomp_ok); - bfa_fcpim_add_iostats(lstats, rstats, iocomp_underrun); - bfa_fcpim_add_iostats(lstats, rstats, iocomp_overrun); - bfa_fcpim_add_iostats(lstats, rstats, iocomp_aborted); - bfa_fcpim_add_iostats(lstats, rstats, iocomp_timedout); - bfa_fcpim_add_iostats(lstats, rstats, iocom_nexus_abort); - bfa_fcpim_add_iostats(lstats, rstats, iocom_proto_err); - bfa_fcpim_add_iostats(lstats, rstats, iocom_dif_err); - bfa_fcpim_add_iostats(lstats, rstats, iocom_sqer_needed); - bfa_fcpim_add_iostats(lstats, rstats, iocom_res_free); - bfa_fcpim_add_iostats(lstats, rstats, iocom_hostabrts); - bfa_fcpim_add_iostats(lstats, rstats, iocom_utags); - bfa_fcpim_add_iostats(lstats, rstats, io_cleanups); - bfa_fcpim_add_iostats(lstats, rstats, io_tmaborts); - bfa_fcpim_add_iostats(lstats, rstats, onlines); - bfa_fcpim_add_iostats(lstats, rstats, offlines); - bfa_fcpim_add_iostats(lstats, rstats, creates); - bfa_fcpim_add_iostats(lstats, rstats, deletes); - bfa_fcpim_add_iostats(lstats, rstats, create_comps); - bfa_fcpim_add_iostats(lstats, rstats, delete_comps); - bfa_fcpim_add_iostats(lstats, rstats, sler_events); - bfa_fcpim_add_iostats(lstats, rstats, fw_create); - bfa_fcpim_add_iostats(lstats, rstats, fw_delete); - bfa_fcpim_add_iostats(lstats, rstats, ioc_disabled); - bfa_fcpim_add_iostats(lstats, rstats, cleanup_comps); - bfa_fcpim_add_iostats(lstats, rstats, tm_cmnds); - bfa_fcpim_add_iostats(lstats, rstats, tm_fw_rsps); - bfa_fcpim_add_iostats(lstats, rstats, tm_success); - bfa_fcpim_add_iostats(lstats, rstats, tm_failures); - bfa_fcpim_add_iostats(lstats, rstats, tm_io_comps); - bfa_fcpim_add_iostats(lstats, rstats, tm_qresumes); - bfa_fcpim_add_iostats(lstats, rstats, tm_iocdowns); - bfa_fcpim_add_iostats(lstats, rstats, tm_cleanups); - bfa_fcpim_add_iostats(lstats, rstats, tm_cleanup_comps); - bfa_fcpim_add_iostats(lstats, rstats, io_comps); - bfa_fcpim_add_iostats(lstats, rstats, input_reqs); - bfa_fcpim_add_iostats(lstats, rstats, output_reqs); - bfa_fcpim_add_iostats(lstats, rstats, rd_throughput); - bfa_fcpim_add_iostats(lstats, rstats, wr_throughput); -} - -bfa_status_t -bfa_fcpim_port_iostats(struct bfa_s *bfa, - struct bfa_itnim_iostats_s *stats, u8 lp_tag) -{ - struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); - struct list_head *qe, *qen; - struct bfa_itnim_s *itnim; - - /* accumulate IO stats from itnim */ - memset(stats, 0, sizeof(struct bfa_itnim_iostats_s)); - list_for_each_safe(qe, qen, &fcpim->itnim_q) { - itnim = (struct bfa_itnim_s *) qe; - if (itnim->rport->rport_info.lp_tag != lp_tag) - continue; - bfa_fcpim_add_stats(stats, &(itnim->stats)); - } - return BFA_STATUS_OK; -} - u16 bfa_fcpim_qdepth_get(struct bfa_s *bfa) { - struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); return fcpim->q_depth; } @@ -1042,7 +990,8 @@ bfa_itnim_tskdone(struct bfa_itnim_s *itnim) } void -bfa_itnim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len) +bfa_itnim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len, + u32 *dm_len) { /* * ITN memory @@ -1051,16 +1000,15 @@ bfa_itnim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len) } void -bfa_itnim_attach(struct bfa_fcpim_s *fcpim) +bfa_itnim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo) { struct bfa_s *bfa = fcpim->bfa; - struct bfa_fcp_mod_s *fcp = fcpim->fcp; struct bfa_itnim_s *itnim; int i, j; INIT_LIST_HEAD(&fcpim->itnim_q); - itnim = (struct bfa_itnim_s *) bfa_mem_kva_curp(fcp); + itnim = (struct bfa_itnim_s *) bfa_meminfo_kva(minfo); fcpim->itnim_arr = itnim; for (i = 0; i < fcpim->num_itnims; i++, itnim++) { @@ -1082,7 +1030,7 @@ bfa_itnim_attach(struct bfa_fcpim_s *fcpim) bfa_sm_set_state(itnim, bfa_itnim_sm_uninit); } - bfa_mem_kva_curp(fcp) = (u8 *) itnim; + bfa_meminfo_kva(minfo) = (u8 *) itnim; } void @@ -1095,7 +1043,7 @@ bfa_itnim_iocdisable(struct bfa_itnim_s *itnim) static bfa_boolean_t bfa_itnim_send_fwcreate(struct bfa_itnim_s *itnim) { - struct bfi_itn_create_req_s *m; + struct bfi_itnim_create_req_s *m; itnim->msg_no++; @@ -1108,8 +1056,8 @@ bfa_itnim_send_fwcreate(struct bfa_itnim_s *itnim) return BFA_FALSE; } - bfi_h2i_set(m->mh, BFI_MC_ITN, BFI_ITN_H2I_CREATE_REQ, - bfa_fn_lpu(itnim->bfa)); + bfi_h2i_set(m->mh, BFI_MC_ITNIM, BFI_ITNIM_H2I_CREATE_REQ, + bfa_lpuid(itnim->bfa)); m->fw_handle = itnim->rport->fw_handle; m->class = FC_CLASS_3; m->seq_rec = itnim->seq_rec; @@ -1119,14 +1067,14 @@ bfa_itnim_send_fwcreate(struct bfa_itnim_s *itnim) /* * queue I/O message to firmware */ - bfa_reqq_produce(itnim->bfa, itnim->reqq, m->mh); + bfa_reqq_produce(itnim->bfa, itnim->reqq); return BFA_TRUE; } static bfa_boolean_t bfa_itnim_send_fwdelete(struct bfa_itnim_s *itnim) { - struct bfi_itn_delete_req_s *m; + struct bfi_itnim_delete_req_s *m; /* * check for room in queue to send request now @@ -1137,15 +1085,15 @@ bfa_itnim_send_fwdelete(struct bfa_itnim_s *itnim) return BFA_FALSE; } - bfi_h2i_set(m->mh, BFI_MC_ITN, BFI_ITN_H2I_DELETE_REQ, - bfa_fn_lpu(itnim->bfa)); + bfi_h2i_set(m->mh, BFI_MC_ITNIM, BFI_ITNIM_H2I_DELETE_REQ, + bfa_lpuid(itnim->bfa)); m->fw_handle = itnim->rport->fw_handle; bfa_stats(itnim, fw_delete); /* * queue I/O message to firmware */ - bfa_reqq_produce(itnim->bfa, itnim->reqq, m->mh); + bfa_reqq_produce(itnim->bfa, itnim->reqq); return BFA_TRUE; } @@ -1276,7 +1224,7 @@ bfa_itnim_iotov_delete(struct bfa_itnim_s *itnim) static void bfa_itnim_update_del_itn_stats(struct bfa_itnim_s *itnim) { - struct bfa_fcpim_s *fcpim = BFA_FCPIM(itnim->bfa); + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(itnim->bfa); fcpim->del_itn_stats.del_itn_iocomp_aborted += itnim->stats.iocomp_aborted; fcpim->del_itn_stats.del_itn_iocomp_timedout += @@ -1302,8 +1250,8 @@ bfa_itnim_update_del_itn_stats(struct bfa_itnim_s *itnim) void bfa_itnim_isr(struct bfa_s *bfa, struct bfi_msg_s *m) { - struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); - union bfi_itn_i2h_msg_u msg; + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); + union bfi_itnim_i2h_msg_u msg; struct bfa_itnim_s *itnim; bfa_trc(bfa, m->mhdr.msg_id); @@ -1311,7 +1259,7 @@ bfa_itnim_isr(struct bfa_s *bfa, struct bfi_msg_s *m) msg.msg = m; switch (m->mhdr.msg_id) { - case BFI_ITN_I2H_CREATE_RSP: + case BFI_ITNIM_I2H_CREATE_RSP: itnim = BFA_ITNIM_FROM_TAG(fcpim, msg.create_rsp->bfa_handle); WARN_ON(msg.create_rsp->status != BFA_STATUS_OK); @@ -1319,7 +1267,7 @@ bfa_itnim_isr(struct bfa_s *bfa, struct bfi_msg_s *m) bfa_sm_send_event(itnim, BFA_ITNIM_SM_FWRSP); break; - case BFI_ITN_I2H_DELETE_RSP: + case BFI_ITNIM_I2H_DELETE_RSP: itnim = BFA_ITNIM_FROM_TAG(fcpim, msg.delete_rsp->bfa_handle); WARN_ON(msg.delete_rsp->status != BFA_STATUS_OK); @@ -1327,7 +1275,7 @@ bfa_itnim_isr(struct bfa_s *bfa, struct bfi_msg_s *m) bfa_sm_send_event(itnim, BFA_ITNIM_SM_FWRSP); break; - case BFI_ITN_I2H_SLER_EVENT: + case BFI_ITNIM_I2H_SLER_EVENT: itnim = BFA_ITNIM_FROM_TAG(fcpim, msg.sler_event->bfa_handle); bfa_stats(itnim, sler_events); @@ -1347,11 +1295,9 @@ bfa_itnim_isr(struct bfa_s *bfa, struct bfi_msg_s *m) struct bfa_itnim_s * bfa_itnim_create(struct bfa_s *bfa, struct bfa_rport_s *rport, void *ditn) { - struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); struct bfa_itnim_s *itnim; - bfa_itn_create(bfa, rport, bfa_itnim_isr); - itnim = BFA_ITNIM_FROM_TAG(fcpim, rport->rport_tag); WARN_ON(itnim->rport != rport); @@ -2045,8 +1991,7 @@ __bfa_cb_ioim_comp(void *cbarg, bfa_boolean_t complete) if ((m->scsi_status == SCSI_STATUS_CHECK_CONDITION) && m->sns_len) { sns_len = m->sns_len; - snsinfo = BFA_SNSINFO_FROM_TAG(ioim->fcpim->fcp, - ioim->iotag); + snsinfo = ioim->iosp->snsinfo; } /* @@ -2244,12 +2189,12 @@ bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim) */ switch (m->cmnd.iodir) { case FCP_IODIR_READ: - bfi_h2i_set(m->mh, BFI_MC_IOIM_READ, 0, bfa_fn_lpu(ioim->bfa)); + bfi_h2i_set(m->mh, BFI_MC_IOIM_READ, 0, bfa_lpuid(ioim->bfa)); bfa_stats(itnim, input_reqs); ioim->itnim->stats.rd_throughput += fcp_dl; break; case FCP_IODIR_WRITE: - bfi_h2i_set(m->mh, BFI_MC_IOIM_WRITE, 0, bfa_fn_lpu(ioim->bfa)); + bfi_h2i_set(m->mh, BFI_MC_IOIM_WRITE, 0, bfa_lpuid(ioim->bfa)); bfa_stats(itnim, output_reqs); ioim->itnim->stats.wr_throughput += fcp_dl; break; @@ -2257,16 +2202,16 @@ bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim) bfa_stats(itnim, input_reqs); bfa_stats(itnim, output_reqs); default: - bfi_h2i_set(m->mh, BFI_MC_IOIM_IO, 0, bfa_fn_lpu(ioim->bfa)); + bfi_h2i_set(m->mh, BFI_MC_IOIM_IO, 0, bfa_lpuid(ioim->bfa)); } if (itnim->seq_rec || (scsi_bufflen(cmnd) & (sizeof(u32) - 1))) - bfi_h2i_set(m->mh, BFI_MC_IOIM_IO, 0, bfa_fn_lpu(ioim->bfa)); + bfi_h2i_set(m->mh, BFI_MC_IOIM_IO, 0, bfa_lpuid(ioim->bfa)); /* * queue I/O message to firmware */ - bfa_reqq_produce(ioim->bfa, ioim->reqq, m->mh); + bfa_reqq_produce(ioim->bfa, ioim->reqq); return BFA_TRUE; } @@ -2324,14 +2269,14 @@ bfa_ioim_send_abort(struct bfa_ioim_s *ioim) else msgop = BFI_IOIM_H2I_IOCLEANUP_REQ; - bfi_h2i_set(m->mh, BFI_MC_IOIM, msgop, bfa_fn_lpu(ioim->bfa)); + bfi_h2i_set(m->mh, BFI_MC_IOIM, msgop, bfa_lpuid(ioim->bfa)); m->io_tag = cpu_to_be16(ioim->iotag); m->abort_tag = ++ioim->abort_tag; /* * queue I/O message to firmware */ - bfa_reqq_produce(ioim->bfa, ioim->reqq, m->mh); + bfa_reqq_produce(ioim->bfa, ioim->reqq); return BFA_TRUE; } @@ -2415,32 +2360,46 @@ bfa_ioim_delayed_comp(struct bfa_ioim_s *ioim, bfa_boolean_t iotov) * Memory allocation and initialization. */ void -bfa_ioim_attach(struct bfa_fcpim_s *fcpim) +bfa_ioim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo) { struct bfa_ioim_s *ioim; - struct bfa_fcp_mod_s *fcp = fcpim->fcp; struct bfa_ioim_sp_s *iosp; u16 i; + u8 *snsinfo; + u32 snsbufsz; /* * claim memory first */ - ioim = (struct bfa_ioim_s *) bfa_mem_kva_curp(fcp); + ioim = (struct bfa_ioim_s *) bfa_meminfo_kva(minfo); fcpim->ioim_arr = ioim; - bfa_mem_kva_curp(fcp) = (u8 *) (ioim + fcpim->fcp->num_ioim_reqs); + bfa_meminfo_kva(minfo) = (u8 *) (ioim + fcpim->num_ioim_reqs); - iosp = (struct bfa_ioim_sp_s *) bfa_mem_kva_curp(fcp); + iosp = (struct bfa_ioim_sp_s *) bfa_meminfo_kva(minfo); fcpim->ioim_sp_arr = iosp; - bfa_mem_kva_curp(fcp) = (u8 *) (iosp + fcpim->fcp->num_ioim_reqs); + bfa_meminfo_kva(minfo) = (u8 *) (iosp + fcpim->num_ioim_reqs); + + /* + * Claim DMA memory for per IO sense data. + */ + snsbufsz = fcpim->num_ioim_reqs * BFI_IOIM_SNSLEN; + fcpim->snsbase.pa = bfa_meminfo_dma_phys(minfo); + bfa_meminfo_dma_phys(minfo) += snsbufsz; + + fcpim->snsbase.kva = bfa_meminfo_dma_virt(minfo); + bfa_meminfo_dma_virt(minfo) += snsbufsz; + snsinfo = fcpim->snsbase.kva; + bfa_iocfc_set_snsbase(fcpim->bfa, fcpim->snsbase.pa); /* * Initialize ioim free queues */ + INIT_LIST_HEAD(&fcpim->ioim_free_q); INIT_LIST_HEAD(&fcpim->ioim_resfree_q); INIT_LIST_HEAD(&fcpim->ioim_comp_q); - for (i = 0; i < fcpim->fcp->num_ioim_reqs; - i++, ioim++, iosp++) { + for (i = 0; i < fcpim->num_ioim_reqs; + i++, ioim++, iosp++, snsinfo += BFI_IOIM_SNSLEN) { /* * initialize IOIM */ @@ -2449,19 +2408,22 @@ bfa_ioim_attach(struct bfa_fcpim_s *fcpim) ioim->bfa = fcpim->bfa; ioim->fcpim = fcpim; ioim->iosp = iosp; + iosp->snsinfo = snsinfo; INIT_LIST_HEAD(&ioim->sgpg_q); bfa_reqq_winit(&ioim->iosp->reqq_wait, bfa_ioim_qresume, ioim); bfa_sgpg_winit(&ioim->iosp->sgpg_wqe, bfa_ioim_sgpg_alloced, ioim); bfa_sm_set_state(ioim, bfa_ioim_sm_uninit); + + list_add_tail(&ioim->qe, &fcpim->ioim_free_q); } } void bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *m) { - struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); struct bfi_ioim_rsp_s *rsp = (struct bfi_ioim_rsp_s *) m; struct bfa_ioim_s *ioim; u16 iotag; @@ -2545,7 +2507,7 @@ bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *m) void bfa_ioim_good_comp_isr(struct bfa_s *bfa, struct bfi_msg_s *m) { - struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); struct bfi_ioim_rsp_s *rsp = (struct bfi_ioim_rsp_s *) m; struct bfa_ioim_s *ioim; u16 iotag; @@ -2611,21 +2573,18 @@ struct bfa_ioim_s * bfa_ioim_alloc(struct bfa_s *bfa, struct bfad_ioim_s *dio, struct bfa_itnim_s *itnim, u16 nsges) { - struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); struct bfa_ioim_s *ioim; - struct bfa_iotag_s *iotag = NULL; /* * alocate IOIM resource */ - bfa_q_deq(&fcpim->fcp->iotag_ioim_free_q, &iotag); - if (!iotag) { + bfa_q_deq(&fcpim->ioim_free_q, &ioim); + if (!ioim) { bfa_stats(itnim, no_iotags); return NULL; } - ioim = BFA_IOIM_FROM_TAG(fcpim, iotag->tag); - ioim->dio = dio; ioim->itnim = itnim; ioim->nsges = nsges; @@ -2642,8 +2601,7 @@ bfa_ioim_alloc(struct bfa_s *bfa, struct bfad_ioim_s *dio, void bfa_ioim_free(struct bfa_ioim_s *ioim) { - struct bfa_fcpim_s *fcpim = ioim->fcpim; - struct bfa_iotag_s *iotag; + struct bfa_fcpim_mod_s *fcpim = ioim->fcpim; if (ioim->nsgpgs > 0) bfa_sgpg_mfree(ioim->bfa, &ioim->sgpg_q, ioim->nsgpgs); @@ -2652,17 +2610,8 @@ bfa_ioim_free(struct bfa_ioim_s *ioim) fcpim->ios_active--; ioim->iotag &= BFA_IOIM_IOTAG_MASK; - - WARN_ON(!(ioim->iotag < - (fcpim->fcp->num_ioim_reqs + fcpim->fcp->num_fwtio_reqs))); - iotag = BFA_IOTAG_FROM_TAG(fcpim->fcp, ioim->iotag); - - if (ioim->iotag < fcpim->fcp->num_ioim_reqs) - list_add_tail(&iotag->qe, &fcpim->fcp->iotag_ioim_free_q); - else - list_add_tail(&iotag->qe, &fcpim->fcp->iotag_tio_free_q); - list_del(&ioim->qe); + list_add_tail(&ioim->qe, &fcpim->ioim_free_q); } void @@ -3072,7 +3021,7 @@ bfa_tskim_send(struct bfa_tskim_s *tskim) * build i/o request message next */ bfi_h2i_set(m->mh, BFI_MC_TSKIM, BFI_TSKIM_H2I_TM_REQ, - bfa_fn_lpu(tskim->bfa)); + bfa_lpuid(tskim->bfa)); m->tsk_tag = cpu_to_be16(tskim->tsk_tag); m->itn_fhdl = tskim->itnim->rport->fw_handle; @@ -3083,7 +3032,7 @@ bfa_tskim_send(struct bfa_tskim_s *tskim) /* * queue I/O message to firmware */ - bfa_reqq_produce(tskim->bfa, itnim->reqq, m->mh); + bfa_reqq_produce(tskim->bfa, itnim->reqq); return BFA_TRUE; } @@ -3107,14 +3056,14 @@ bfa_tskim_send_abort(struct bfa_tskim_s *tskim) * build i/o request message next */ bfi_h2i_set(m->mh, BFI_MC_TSKIM, BFI_TSKIM_H2I_ABORT_REQ, - bfa_fn_lpu(tskim->bfa)); + bfa_lpuid(tskim->bfa)); m->tsk_tag = cpu_to_be16(tskim->tsk_tag); /* * queue I/O message to firmware */ - bfa_reqq_produce(tskim->bfa, itnim->reqq, m->mh); + bfa_reqq_produce(tskim->bfa, itnim->reqq); return BFA_TRUE; } @@ -3180,16 +3129,14 @@ bfa_tskim_cleanup(struct bfa_tskim_s *tskim) * Memory allocation and initialization. */ void -bfa_tskim_attach(struct bfa_fcpim_s *fcpim) +bfa_tskim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo) { struct bfa_tskim_s *tskim; - struct bfa_fcp_mod_s *fcp = fcpim->fcp; u16 i; INIT_LIST_HEAD(&fcpim->tskim_free_q); - INIT_LIST_HEAD(&fcpim->tskim_unused_q); - tskim = (struct bfa_tskim_s *) bfa_mem_kva_curp(fcp); + tskim = (struct bfa_tskim_s *) bfa_meminfo_kva(minfo); fcpim->tskim_arr = tskim; for (i = 0; i < fcpim->num_tskim_reqs; i++, tskim++) { @@ -3208,13 +3155,13 @@ bfa_tskim_attach(struct bfa_fcpim_s *fcpim) list_add_tail(&tskim->qe, &fcpim->tskim_free_q); } - bfa_mem_kva_curp(fcp) = (u8 *) tskim; + bfa_meminfo_kva(minfo) = (u8 *) tskim; } void bfa_tskim_isr(struct bfa_s *bfa, struct bfi_msg_s *m) { - struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); struct bfi_tskim_rsp_s *rsp = (struct bfi_tskim_rsp_s *) m; struct bfa_tskim_s *tskim; u16 tsk_tag = be16_to_cpu(rsp->tsk_tag); @@ -3241,7 +3188,7 @@ bfa_tskim_isr(struct bfa_s *bfa, struct bfi_msg_s *m) struct bfa_tskim_s * bfa_tskim_alloc(struct bfa_s *bfa, struct bfad_tskim_s *dtsk) { - struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); struct bfa_tskim_s *tskim; bfa_q_deq(&fcpim->tskim_free_q, &tskim); @@ -3286,214 +3233,3 @@ bfa_tskim_start(struct bfa_tskim_s *tskim, struct bfa_itnim_s *itnim, list_add_tail(&tskim->qe, &itnim->tsk_q); bfa_sm_send_event(tskim, BFA_TSKIM_SM_START); } - -void -bfa_tskim_res_recfg(struct bfa_s *bfa, u16 num_tskim_fw) -{ - struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); - struct list_head *qe; - int i; - - for (i = 0; i < (fcpim->num_tskim_reqs - num_tskim_fw); i++) { - bfa_q_deq_tail(&fcpim->tskim_free_q, &qe); - list_add_tail(qe, &fcpim->tskim_unused_q); - } -} - -/* BFA FCP module - parent module for fcpim */ - -BFA_MODULE(fcp); - -static void -bfa_fcp_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *minfo, - struct bfa_s *bfa) -{ - struct bfa_fcp_mod_s *fcp = BFA_FCP_MOD(bfa); - struct bfa_mem_kva_s *fcp_kva = BFA_MEM_FCP_KVA(bfa); - struct bfa_mem_dma_s *seg_ptr; - u16 nsegs, idx, per_seg_ios, num_io_req; - u32 km_len = 0; - - /* - * ZERO for num_ioim_reqs and num_fwtio_reqs is allowed config value. - * So if the values are non zero, adjust them appropriately. - */ - if (cfg->fwcfg.num_ioim_reqs && - cfg->fwcfg.num_ioim_reqs < BFA_IOIM_MIN) - cfg->fwcfg.num_ioim_reqs = BFA_IOIM_MIN; - else if (cfg->fwcfg.num_ioim_reqs > BFA_IOIM_MAX) - cfg->fwcfg.num_ioim_reqs = BFA_IOIM_MAX; - - if (cfg->fwcfg.num_fwtio_reqs > BFA_FWTIO_MAX) - cfg->fwcfg.num_fwtio_reqs = BFA_FWTIO_MAX; - - num_io_req = (cfg->fwcfg.num_ioim_reqs + cfg->fwcfg.num_fwtio_reqs); - if (num_io_req > BFA_IO_MAX) { - if (cfg->fwcfg.num_ioim_reqs && cfg->fwcfg.num_fwtio_reqs) { - cfg->fwcfg.num_ioim_reqs = BFA_IO_MAX/2; - cfg->fwcfg.num_fwtio_reqs = BFA_IO_MAX/2; - } else if (cfg->fwcfg.num_fwtio_reqs) - cfg->fwcfg.num_fwtio_reqs = BFA_FWTIO_MAX; - else - cfg->fwcfg.num_ioim_reqs = BFA_IOIM_MAX; - } - - bfa_fcpim_meminfo(cfg, &km_len); - - num_io_req = (cfg->fwcfg.num_ioim_reqs + cfg->fwcfg.num_fwtio_reqs); - km_len += num_io_req * sizeof(struct bfa_iotag_s); - km_len += cfg->fwcfg.num_rports * sizeof(struct bfa_itn_s); - - /* dma memory */ - nsegs = BFI_MEM_DMA_NSEGS(num_io_req, BFI_IOIM_SNSLEN); - per_seg_ios = BFI_MEM_NREQS_SEG(BFI_IOIM_SNSLEN); - - bfa_mem_dma_seg_iter(fcp, seg_ptr, nsegs, idx) { - if (num_io_req >= per_seg_ios) { - num_io_req -= per_seg_ios; - bfa_mem_dma_setup(minfo, seg_ptr, - per_seg_ios * BFI_IOIM_SNSLEN); - } else - bfa_mem_dma_setup(minfo, seg_ptr, - num_io_req * BFI_IOIM_SNSLEN); - } - - /* kva memory */ - bfa_mem_kva_setup(minfo, fcp_kva, km_len); -} - -static void -bfa_fcp_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_pcidev_s *pcidev) -{ - struct bfa_fcp_mod_s *fcp = BFA_FCP_MOD(bfa); - struct bfa_mem_dma_s *seg_ptr; - u16 idx, nsegs, num_io_req; - - fcp->num_ioim_reqs = cfg->fwcfg.num_ioim_reqs; - fcp->num_fwtio_reqs = cfg->fwcfg.num_fwtio_reqs; - fcp->num_itns = cfg->fwcfg.num_rports; - fcp->bfa = bfa; - - /* - * Setup the pool of snsbase addr's, that is passed to fw as - * part of bfi_iocfc_cfg_s. - */ - num_io_req = (cfg->fwcfg.num_ioim_reqs + cfg->fwcfg.num_fwtio_reqs); - nsegs = BFI_MEM_DMA_NSEGS(num_io_req, BFI_IOIM_SNSLEN); - - bfa_mem_dma_seg_iter(fcp, seg_ptr, nsegs, idx) { - - if (!bfa_mem_dma_virt(seg_ptr)) - break; - - fcp->snsbase[idx].pa = bfa_mem_dma_phys(seg_ptr); - fcp->snsbase[idx].kva = bfa_mem_dma_virt(seg_ptr); - bfa_iocfc_set_snsbase(bfa, idx, fcp->snsbase[idx].pa); - } - - bfa_fcpim_attach(fcp, bfad, cfg, pcidev); - - bfa_iotag_attach(fcp); - - fcp->itn_arr = (struct bfa_itn_s *) bfa_mem_kva_curp(fcp); - bfa_mem_kva_curp(fcp) = (u8 *)fcp->itn_arr + - (fcp->num_itns * sizeof(struct bfa_itn_s)); - memset(fcp->itn_arr, 0, - (fcp->num_itns * sizeof(struct bfa_itn_s))); -} - -static void -bfa_fcp_detach(struct bfa_s *bfa) -{ -} - -static void -bfa_fcp_start(struct bfa_s *bfa) -{ -} - -static void -bfa_fcp_stop(struct bfa_s *bfa) -{ -} - -static void -bfa_fcp_iocdisable(struct bfa_s *bfa) -{ - struct bfa_fcp_mod_s *fcp = BFA_FCP_MOD(bfa); - - /* Enqueue unused ioim resources to free_q */ - list_splice_tail_init(&fcp->iotag_unused_q, &fcp->iotag_ioim_free_q); - - bfa_fcpim_iocdisable(fcp); -} - -void -bfa_fcp_res_recfg(struct bfa_s *bfa, u16 num_ioim_fw) -{ - struct bfa_fcp_mod_s *mod = BFA_FCP_MOD(bfa); - struct list_head *qe; - int i; - - for (i = 0; i < (mod->num_ioim_reqs - num_ioim_fw); i++) { - bfa_q_deq_tail(&mod->iotag_ioim_free_q, &qe); - list_add_tail(qe, &mod->iotag_unused_q); - } -} - -void -bfa_itn_create(struct bfa_s *bfa, struct bfa_rport_s *rport, - void (*isr)(struct bfa_s *bfa, struct bfi_msg_s *m)) -{ - struct bfa_fcp_mod_s *fcp = BFA_FCP_MOD(bfa); - struct bfa_itn_s *itn; - - itn = BFA_ITN_FROM_TAG(fcp, rport->rport_tag); - itn->isr = isr; -} - -/* - * Itn interrupt processing. - */ -void -bfa_itn_isr(struct bfa_s *bfa, struct bfi_msg_s *m) -{ - struct bfa_fcp_mod_s *fcp = BFA_FCP_MOD(bfa); - union bfi_itn_i2h_msg_u msg; - struct bfa_itn_s *itn; - - msg.msg = m; - itn = BFA_ITN_FROM_TAG(fcp, msg.create_rsp->bfa_handle); - - if (itn->isr) - itn->isr(bfa, m); - else - WARN_ON(1); -} - -void -bfa_iotag_attach(struct bfa_fcp_mod_s *fcp) -{ - struct bfa_iotag_s *iotag; - u16 num_io_req, i; - - iotag = (struct bfa_iotag_s *) bfa_mem_kva_curp(fcp); - fcp->iotag_arr = iotag; - - INIT_LIST_HEAD(&fcp->iotag_ioim_free_q); - INIT_LIST_HEAD(&fcp->iotag_tio_free_q); - INIT_LIST_HEAD(&fcp->iotag_unused_q); - - num_io_req = fcp->num_ioim_reqs + fcp->num_fwtio_reqs; - for (i = 0; i < num_io_req; i++, iotag++) { - memset(iotag, 0, sizeof(struct bfa_iotag_s)); - iotag->tag = i; - if (i < fcp->num_ioim_reqs) - list_add_tail(&iotag->qe, &fcp->iotag_ioim_free_q); - else - list_add_tail(&iotag->qe, &fcp->iotag_tio_free_q); - } - - bfa_mem_kva_curp(fcp) = (u8 *) iotag; -} diff --git a/trunk/drivers/scsi/bfa/bfa_fcpim.h b/trunk/drivers/scsi/bfa/bfa_fcpim.h index 57b695ad4ee5..1e38dade8423 100644 --- a/trunk/drivers/scsi/bfa/bfa_fcpim.h +++ b/trunk/drivers/scsi/bfa/bfa_fcpim.h @@ -24,34 +24,6 @@ #include "bfa_defs_svc.h" #include "bfa_cs.h" -/* FCP module related definitions */ -#define BFA_IO_MAX BFI_IO_MAX -#define BFA_FWTIO_MAX 2000 - -struct bfa_fcp_mod_s; -struct bfa_iotag_s { - struct list_head qe; /* queue element */ - u16 tag; /* FW IO tag */ -}; - -struct bfa_itn_s { - bfa_isr_func_t isr; -}; - -void bfa_itn_create(struct bfa_s *bfa, struct bfa_rport_s *rport, - void (*isr)(struct bfa_s *bfa, struct bfi_msg_s *m)); -void bfa_itn_isr(struct bfa_s *bfa, struct bfi_msg_s *m); -void bfa_iotag_attach(struct bfa_fcp_mod_s *fcp); -void bfa_fcp_res_recfg(struct bfa_s *bfa, u16 num_ioim_fw); - -#define BFA_FCP_MOD(_hal) (&(_hal)->modules.fcp_mod) -#define BFA_MEM_FCP_KVA(__bfa) (&(BFA_FCP_MOD(__bfa)->kva_seg)) -#define BFA_IOTAG_FROM_TAG(_fcp, _tag) \ - (&(_fcp)->iotag_arr[(_tag & BFA_IOIM_IOTAG_MASK)]) -#define BFA_ITN_FROM_TAG(_fcp, _tag) \ - ((_fcp)->itn_arr + ((_tag) & ((_fcp)->num_itns - 1))) -#define BFA_SNSINFO_FROM_TAG(_fcp, _tag) \ - bfa_mem_get_dmabuf_kva(_fcp, _tag, BFI_IOIM_SNSLEN) #define BFA_ITNIM_MIN 32 #define BFA_ITNIM_MAX 1024 @@ -103,24 +75,25 @@ struct bfad_tskim_s; typedef void (*bfa_fcpim_profile_t) (struct bfa_ioim_s *ioim); -struct bfa_fcpim_s { +struct bfa_fcpim_mod_s { struct bfa_s *bfa; - struct bfa_fcp_mod_s *fcp; struct bfa_itnim_s *itnim_arr; struct bfa_ioim_s *ioim_arr; struct bfa_ioim_sp_s *ioim_sp_arr; struct bfa_tskim_s *tskim_arr; + struct bfa_dma_s snsbase; int num_itnims; + int num_ioim_reqs; int num_tskim_reqs; u32 path_tov; u16 q_depth; u8 reqq; /* Request queue to be used */ u8 rsvd; struct list_head itnim_q; /* queue of active itnim */ + struct list_head ioim_free_q; /* free IO resources */ struct list_head ioim_resfree_q; /* IOs waiting for f/w */ struct list_head ioim_comp_q; /* IO global comp Q */ struct list_head tskim_free_q; - struct list_head tskim_unused_q; /* Unused tskim Q */ u32 ios_active; /* current active IOs */ u32 delay_comp; struct bfa_fcpim_del_itn_stats_s del_itn_stats; @@ -131,25 +104,6 @@ struct bfa_fcpim_s { bfa_fcpim_profile_t profile_start; }; -/* Max FCP dma segs required */ -#define BFA_FCP_DMA_SEGS BFI_IOIM_SNSBUF_SEGS - -struct bfa_fcp_mod_s { - struct bfa_s *bfa; - struct list_head iotag_ioim_free_q; /* free IO resources */ - struct list_head iotag_tio_free_q; /* free IO resources */ - struct list_head iotag_unused_q; /* unused IO resources*/ - struct bfa_iotag_s *iotag_arr; - struct bfa_itn_s *itn_arr; - int num_ioim_reqs; - int num_fwtio_reqs; - int num_itns; - struct bfa_dma_s snsbase[BFA_FCP_DMA_SEGS]; - struct bfa_fcpim_s fcpim; - struct bfa_mem_dma_s dma_seg[BFA_FCP_DMA_SEGS]; - struct bfa_mem_kva_s kva_seg; -}; - /* * BFA IO (initiator mode) */ @@ -157,7 +111,7 @@ struct bfa_ioim_s { struct list_head qe; /* queue elememt */ bfa_sm_t sm; /* BFA ioim state machine */ struct bfa_s *bfa; /* BFA module */ - struct bfa_fcpim_s *fcpim; /* parent fcpim module */ + struct bfa_fcpim_mod_s *fcpim; /* parent fcpim module */ struct bfa_itnim_s *itnim; /* i-t-n nexus for this IO */ struct bfad_ioim_s *dio; /* driver IO handle */ u16 iotag; /* FWI IO tag */ @@ -175,6 +129,7 @@ struct bfa_ioim_s { struct bfa_ioim_sp_s { struct bfi_msg_s comp_rspmsg; /* IO comp f/w response */ + u8 *snsinfo; /* sense info for this IO */ struct bfa_sgpg_wqe_s sgpg_wqe; /* waitq elem for sgpg */ struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */ bfa_boolean_t abort_explicit; /* aborted by OS */ @@ -188,7 +143,7 @@ struct bfa_tskim_s { struct list_head qe; bfa_sm_t sm; struct bfa_s *bfa; /* BFA module */ - struct bfa_fcpim_s *fcpim; /* parent fcpim module */ + struct bfa_fcpim_mod_s *fcpim; /* parent fcpim module */ struct bfa_itnim_s *itnim; /* i-t-n nexus for this IO */ struct bfad_tskim_s *dtsk; /* driver task mgmt cmnd */ bfa_boolean_t notify; /* notify itnim on TM comp */ @@ -227,13 +182,13 @@ struct bfa_itnim_s { struct bfa_wc_s wc; /* waiting counter */ struct bfa_timer_s timer; /* pending IO TOV */ struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */ - struct bfa_fcpim_s *fcpim; /* fcpim module */ + struct bfa_fcpim_mod_s *fcpim; /* fcpim module */ struct bfa_itnim_iostats_s stats; struct bfa_itnim_ioprofile_s ioprofile; }; #define bfa_itnim_is_online(_itnim) ((_itnim)->is_online) -#define BFA_FCPIM(_hal) (&(_hal)->modules.fcp_mod.fcpim) +#define BFA_FCPIM_MOD(_hal) (&(_hal)->modules.fcpim_mod) #define BFA_IOIM_TAG_2_ID(_iotag) ((_iotag) & BFA_IOIM_IOTAG_MASK) #define BFA_IOIM_FROM_TAG(_fcpim, _iotag) \ (&fcpim->ioim_arr[(_iotag & BFA_IOIM_IOTAG_MASK)]) @@ -241,9 +196,9 @@ struct bfa_itnim_s { (&fcpim->tskim_arr[_tmtag & (fcpim->num_tskim_reqs - 1)]) #define bfa_io_profile_start_time(_bfa) \ - ((_bfa)->modules.fcp_mod.fcpim.io_profile_start_time) + (_bfa->modules.fcpim_mod.io_profile_start_time) #define bfa_fcpim_get_io_profile(_bfa) \ - ((_bfa)->modules.fcp_mod.fcpim.io_profile) + (_bfa->modules.fcpim_mod.io_profile) #define bfa_ioim_update_iotag(__ioim) do { \ uint16_t k = (__ioim)->iotag >> BFA_IOIM_RETRY_TAG_OFFSET; \ k++; (__ioim)->iotag &= BFA_IOIM_IOTAG_MASK; \ @@ -262,7 +217,8 @@ bfa_ioim_maxretry_reached(struct bfa_ioim_s *ioim) /* * function prototypes */ -void bfa_ioim_attach(struct bfa_fcpim_s *fcpim); +void bfa_ioim_attach(struct bfa_fcpim_mod_s *fcpim, + struct bfa_meminfo_s *minfo); void bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); void bfa_ioim_good_comp_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); @@ -272,15 +228,18 @@ void bfa_ioim_cleanup_tm(struct bfa_ioim_s *ioim, void bfa_ioim_iocdisable(struct bfa_ioim_s *ioim); void bfa_ioim_tov(struct bfa_ioim_s *ioim); -void bfa_tskim_attach(struct bfa_fcpim_s *fcpim); +void bfa_tskim_attach(struct bfa_fcpim_mod_s *fcpim, + struct bfa_meminfo_s *minfo); void bfa_tskim_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); void bfa_tskim_iodone(struct bfa_tskim_s *tskim); void bfa_tskim_iocdisable(struct bfa_tskim_s *tskim); void bfa_tskim_cleanup(struct bfa_tskim_s *tskim); -void bfa_tskim_res_recfg(struct bfa_s *bfa, u16 num_tskim_fw); -void bfa_itnim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len); -void bfa_itnim_attach(struct bfa_fcpim_s *fcpim); +void bfa_itnim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len, + u32 *dm_len); +void bfa_itnim_attach(struct bfa_fcpim_mod_s *fcpim, + struct bfa_meminfo_s *minfo); +void bfa_itnim_detach(struct bfa_fcpim_mod_s *fcpim); void bfa_itnim_iocdisable(struct bfa_itnim_s *itnim); void bfa_itnim_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); void bfa_itnim_iodone(struct bfa_itnim_s *itnim); @@ -293,17 +252,13 @@ bfa_boolean_t bfa_itnim_hold_io(struct bfa_itnim_s *itnim); void bfa_fcpim_path_tov_set(struct bfa_s *bfa, u16 path_tov); u16 bfa_fcpim_path_tov_get(struct bfa_s *bfa); u16 bfa_fcpim_qdepth_get(struct bfa_s *bfa); -bfa_status_t bfa_fcpim_port_iostats(struct bfa_s *bfa, - struct bfa_itnim_iostats_s *stats, u8 lp_tag); -void bfa_fcpim_add_stats(struct bfa_itnim_iostats_s *fcpim_stats, - struct bfa_itnim_iostats_s *itnim_stats); #define bfa_fcpim_ioredirect_enabled(__bfa) \ - (((struct bfa_fcpim_s *)(BFA_FCPIM(__bfa)))->ioredirect) + (((struct bfa_fcpim_mod_s *)(BFA_FCPIM_MOD(__bfa)))->ioredirect) #define bfa_fcpim_get_next_reqq(__bfa, __qid) \ { \ - struct bfa_fcpim_s *__fcpim = BFA_FCPIM(__bfa); \ + struct bfa_fcpim_mod_s *__fcpim = BFA_FCPIM_MOD(__bfa); \ __fcpim->reqq++; \ __fcpim->reqq &= (BFI_IOC_MAX_CQS - 1); \ *(__qid) = __fcpim->reqq; \ diff --git a/trunk/drivers/scsi/bfa/bfa_fcs.c b/trunk/drivers/scsi/bfa/bfa_fcs.c index a9b22bc48bc3..9b43ca4b6778 100644 --- a/trunk/drivers/scsi/bfa/bfa_fcs.c +++ b/trunk/drivers/scsi/bfa/bfa_fcs.c @@ -92,49 +92,25 @@ bfa_fcs_attach(struct bfa_fcs_s *fcs, struct bfa_s *bfa, struct bfad_s *bfad, void bfa_fcs_init(struct bfa_fcs_s *fcs) { - int i; + int i, npbc_vports; struct bfa_fcs_mod_s *mod; + struct bfi_pbc_vport_s pbc_vports[BFI_PBC_MAX_VPORTS]; for (i = 0; i < sizeof(fcs_modules) / sizeof(fcs_modules[0]); i++) { mod = &fcs_modules[i]; if (mod->modinit) mod->modinit(fcs); } -} - -/* - * FCS update cfg - reset the pwwn/nwwn of fabric base logical port - * with values learned during bfa_init firmware GETATTR REQ. - */ -void -bfa_fcs_update_cfg(struct bfa_fcs_s *fcs) -{ - struct bfa_fcs_fabric_s *fabric = &fcs->fabric; - struct bfa_lport_cfg_s *port_cfg = &fabric->bport.port_cfg; - struct bfa_ioc_s *ioc = &fabric->fcs->bfa->ioc; - - port_cfg->nwwn = ioc->attr->nwwn; - port_cfg->pwwn = ioc->attr->pwwn; -} - -/* - * fcs pbc vport initialization - */ -void -bfa_fcs_pbc_vport_init(struct bfa_fcs_s *fcs) -{ - int i, npbc_vports; - struct bfi_pbc_vport_s pbc_vports[BFI_PBC_MAX_VPORTS]; - /* Initialize pbc vports */ if (!fcs->min_cfg) { npbc_vports = - bfa_iocfc_get_pbc_vports(fcs->bfa, pbc_vports); + bfa_iocfc_get_pbc_vports(fcs->bfa, pbc_vports); for (i = 0; i < npbc_vports; i++) bfa_fcb_pbc_vport_create(fcs->bfa->bfad, pbc_vports[i]); } } + /* * brief * FCS driver details initialization. @@ -192,14 +168,11 @@ bfa_fcs_exit(struct bfa_fcs_s *fcs) #define BFA_FCS_FABRIC_CLEANUP_DELAY (10000) /* Milliseconds */ #define bfa_fcs_fabric_set_opertype(__fabric) do { \ - if (bfa_fcport_get_topology((__fabric)->fcs->bfa) \ - == BFA_PORT_TOPOLOGY_P2P) { \ - if (fabric->fab_type == BFA_FCS_FABRIC_SWITCHED) \ + if (bfa_fcport_get_topology((__fabric)->fcs->bfa) \ + == BFA_PORT_TOPOLOGY_P2P) \ (__fabric)->oper_type = BFA_PORT_TYPE_NPORT; \ else \ - (__fabric)->oper_type = BFA_PORT_TYPE_P2P; \ - } else \ - (__fabric)->oper_type = BFA_PORT_TYPE_NLPORT; \ + (__fabric)->oper_type = BFA_PORT_TYPE_NLPORT; \ } while (0) /* @@ -223,9 +196,6 @@ static void bfa_fcs_fabric_flogiacc_comp(void *fcsarg, u32 rsp_len, u32 resid_len, struct fchs_s *rspfchs); -static u8 bfa_fcs_fabric_oper_bbscn(struct bfa_fcs_fabric_s *fabric); -static bfa_boolean_t bfa_fcs_fabric_is_bbscn_enabled( - struct bfa_fcs_fabric_s *fabric); static void bfa_fcs_fabric_sm_uninit(struct bfa_fcs_fabric_s *fabric, enum bfa_fcs_fabric_event event); @@ -299,8 +269,8 @@ bfa_fcs_fabric_sm_created(struct bfa_fcs_fabric_s *fabric, break; case BFA_FCS_FABRIC_SM_DELETE: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting); - bfa_fcs_fabric_delete(fabric); + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_uninit); + bfa_wc_down(&fabric->fcs->wc); break; default: @@ -352,8 +322,7 @@ bfa_fcs_fabric_sm_flogi(struct bfa_fcs_fabric_s *fabric, case BFA_FCS_FABRIC_SM_CONT_OP: bfa_fcport_set_tx_bbcredit(fabric->fcs->bfa, - fabric->bb_credit, - bfa_fcs_fabric_oper_bbscn(fabric)); + fabric->bb_credit); fabric->fab_type = BFA_FCS_FABRIC_SWITCHED; if (fabric->auth_reqd && fabric->is_auth) { @@ -381,8 +350,7 @@ bfa_fcs_fabric_sm_flogi(struct bfa_fcs_fabric_s *fabric, case BFA_FCS_FABRIC_SM_NO_FABRIC: fabric->fab_type = BFA_FCS_FABRIC_N2N; bfa_fcport_set_tx_bbcredit(fabric->fcs->bfa, - fabric->bb_credit, - bfa_fcs_fabric_oper_bbscn(fabric)); + fabric->bb_credit); bfa_fcs_fabric_notify_online(fabric); bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_nofabric); break; @@ -550,11 +518,7 @@ bfa_fcs_fabric_sm_nofabric(struct bfa_fcs_fabric_s *fabric, case BFA_FCS_FABRIC_SM_NO_FABRIC: bfa_trc(fabric->fcs, fabric->bb_credit); bfa_fcport_set_tx_bbcredit(fabric->fcs->bfa, - fabric->bb_credit, - bfa_fcs_fabric_oper_bbscn(fabric)); - break; - - case BFA_FCS_FABRIC_SM_RETRY_OP: + fabric->bb_credit); break; default: @@ -800,10 +764,6 @@ bfa_cb_lps_flogi_comp(void *bfad, void *uarg, bfa_status_t status) case BFA_STATUS_FABRIC_RJT: fabric->stats.flogi_rejects++; - if (fabric->lps->lsrjt_rsn == FC_LS_RJT_RSN_LOGICAL_ERROR && - fabric->lps->lsrjt_expl == FC_LS_RJT_EXP_NO_ADDL_INFO) - fabric->fcs->bbscn_flogi_rjt = BFA_TRUE; - bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_RETRY_OP); return; @@ -833,7 +793,6 @@ bfa_cb_lps_flogi_comp(void *bfad, void *uarg, bfa_status_t status) */ fabric->bport.port_topo.pn2n.rem_port_wwn = fabric->lps->pr_pwwn; - fabric->fab_type = BFA_FCS_FABRIC_N2N; bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_NO_FABRIC); } @@ -849,17 +808,13 @@ bfa_fcs_fabric_login(struct bfa_fcs_fabric_s *fabric) { struct bfa_s *bfa = fabric->fcs->bfa; struct bfa_lport_cfg_s *pcfg = &fabric->bport.port_cfg; - u8 alpa = 0, bb_scn = 0; + u8 alpa = 0; if (bfa_fcport_get_topology(bfa) == BFA_PORT_TOPOLOGY_LOOP) alpa = bfa_fcport_get_myalpa(bfa); - if (bfa_fcs_fabric_is_bbscn_enabled(fabric) && - (!fabric->fcs->bbscn_flogi_rjt)) - bb_scn = BFA_FCS_PORT_DEF_BB_SCN; - bfa_lps_flogi(fabric->lps, fabric, alpa, bfa_fcport_get_maxfrsize(bfa), - pcfg->pwwn, pcfg->nwwn, fabric->auth_reqd, bb_scn); + pcfg->pwwn, pcfg->nwwn, fabric->auth_reqd); fabric->stats.flogi_sent++; } @@ -917,40 +872,6 @@ bfa_fcs_fabric_delay(void *cbarg) bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_DELAYED); } -/* - * Computes operating BB_SCN value - */ -static u8 -bfa_fcs_fabric_oper_bbscn(struct bfa_fcs_fabric_s *fabric) -{ - u8 pr_bbscn = fabric->lps->pr_bbscn; - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(fabric->fcs->bfa); - - if (!(fcport->cfg.bb_scn_state && pr_bbscn)) - return 0; - - /* return max of local/remote bb_scn values */ - return ((pr_bbscn > BFA_FCS_PORT_DEF_BB_SCN) ? - pr_bbscn : BFA_FCS_PORT_DEF_BB_SCN); -} - -/* - * Check if BB_SCN can be enabled. - */ -static bfa_boolean_t -bfa_fcs_fabric_is_bbscn_enabled(struct bfa_fcs_fabric_s *fabric) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(fabric->fcs->bfa); - - if (bfa_ioc_get_fcmode(&fabric->fcs->bfa->ioc) && - fcport->cfg.bb_scn_state && - !bfa_fcport_is_qos_enabled(fabric->fcs->bfa) && - !bfa_fcport_is_trunk_enabled(fabric->fcs->bfa)) - return BFA_TRUE; - else - return BFA_FALSE; -} - /* * Delete all vports and wait for vport delete completions. */ @@ -1068,7 +989,6 @@ void bfa_fcs_fabric_link_down(struct bfa_fcs_fabric_s *fabric) { bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); - fabric->fcs->bbscn_flogi_rjt = BFA_FALSE; bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_LINK_DOWN); } @@ -1272,7 +1192,6 @@ bfa_fcs_fabric_process_flogi(struct bfa_fcs_fabric_s *fabric, } fabric->bb_credit = be16_to_cpu(flogi->csp.bbcred); - fabric->lps->pr_bbscn = (be16_to_cpu(flogi->csp.rxsz) >> 12); bport->port_topo.pn2n.rem_port_wwn = flogi->port_name; bport->port_topo.pn2n.reply_oxid = fchs->ox_id; @@ -1305,10 +1224,9 @@ bfa_fcs_fabric_send_flogi_acc(struct bfa_fcs_fabric_s *fabric) n2n_port->reply_oxid, pcfg->pwwn, pcfg->nwwn, bfa_fcport_get_maxfrsize(bfa), - bfa_fcport_get_rx_bbcredit(bfa), - bfa_fcs_fabric_oper_bbscn(fabric)); + bfa_fcport_get_rx_bbcredit(bfa)); - bfa_fcxp_send(fcxp, NULL, fabric->vf_id, fabric->lps->bfa_tag, + bfa_fcxp_send(fcxp, NULL, fabric->vf_id, fabric->lps->lp_tag, BFA_FALSE, FC_CLASS_3, reqlen, &fchs, bfa_fcs_fabric_flogiacc_comp, fabric, FC_MAX_PDUSZ, 0); @@ -1379,45 +1297,6 @@ bfa_fcs_vf_lookup(struct bfa_fcs_s *fcs, u16 vf_id) return NULL; } -/* - * Return the list of local logical ports present in the given VF. - * - * @param[in] vf vf for which logical ports are returned - * @param[out] lpwwn returned logical port wwn list - * @param[in,out] nlports in:size of lpwwn list; - * out:total elements present, - * actual elements returned is limited by the size - */ -void -bfa_fcs_vf_get_ports(bfa_fcs_vf_t *vf, wwn_t lpwwn[], int *nlports) -{ - struct list_head *qe; - struct bfa_fcs_vport_s *vport; - int i = 0; - struct bfa_fcs_s *fcs; - - if (vf == NULL || lpwwn == NULL || *nlports == 0) - return; - - fcs = vf->fcs; - - bfa_trc(fcs, vf->vf_id); - bfa_trc(fcs, (uint32_t) *nlports); - - lpwwn[i++] = vf->bport.port_cfg.pwwn; - - list_for_each(qe, &vf->vport_q) { - if (i >= *nlports) - break; - - vport = (struct bfa_fcs_vport_s *) qe; - lpwwn[i++] = vport->lport.port_cfg.pwwn; - } - - bfa_trc(fcs, i); - *nlports = i; -} - /* * BFA FCS PPORT ( physical port) */ diff --git a/trunk/drivers/scsi/bfa/bfa_fcs.h b/trunk/drivers/scsi/bfa/bfa_fcs.h index a5f1faf335a7..61cdce4bd913 100644 --- a/trunk/drivers/scsi/bfa/bfa_fcs.h +++ b/trunk/drivers/scsi/bfa/bfa_fcs.h @@ -254,9 +254,6 @@ struct bfa_fcs_fabric_s; #define BFA_FCS_PORT_SYMBNAME_OSINFO_SZ 48 #define BFA_FCS_PORT_SYMBNAME_OSPATCH_SZ 16 -/* bb_scn value in 2^bb_scn */ -#define BFA_FCS_PORT_DEF_BB_SCN 3 - /* * Get FC port ID for a logical port. */ @@ -382,7 +379,6 @@ void bfa_fcs_vport_online(struct bfa_fcs_vport_s *vport); void bfa_fcs_vport_offline(struct bfa_fcs_vport_s *vport); void bfa_fcs_vport_delete_comp(struct bfa_fcs_vport_s *vport); void bfa_fcs_vport_fcs_delete(struct bfa_fcs_vport_s *vport); -void bfa_fcs_vport_stop_comp(struct bfa_fcs_vport_s *vport); #define BFA_FCS_RPORT_DEF_DEL_TIMEOUT 90 /* in secs */ #define BFA_FCS_RPORT_MAX_RETRIES (5) @@ -424,7 +420,6 @@ struct bfa_fcs_rport_s { enum fc_cos fc_cos; /* FC classes of service supp */ bfa_boolean_t cisc; /* CISC capable device */ bfa_boolean_t prlo; /* processing prlo or LOGO */ - bfa_boolean_t plogi_pending; /* Rx Plogi Pending */ wwn_t pwwn; /* port wwn of rport */ wwn_t nwwn; /* node wwn of rport */ struct bfa_rport_symname_s psym_name; /* port symbolic name */ @@ -452,8 +447,6 @@ bfa_fcs_rport_get_halrport(struct bfa_fcs_rport_s *rport) /* * bfa fcs rport API functions */ -void bfa_fcs_rport_get_attr(struct bfa_fcs_rport_s *rport, - struct bfa_rport_attr_s *attr); struct bfa_fcs_rport_s *bfa_fcs_rport_lookup(struct bfa_fcs_lport_s *port, wwn_t rpwwn); struct bfa_fcs_rport_s *bfa_fcs_rport_lookup_by_nwwn( @@ -598,21 +591,10 @@ void bfa_fcs_itnim_is_initiator(struct bfa_fcs_itnim_s *itnim); void bfa_fcs_fcpim_uf_recv(struct bfa_fcs_itnim_s *itnim, struct fchs_s *fchs, u16 len); -#define BFA_FCS_FDMI_SUPP_SPEEDS_4G (FDMI_TRANS_SPEED_1G | \ - FDMI_TRANS_SPEED_2G | \ - FDMI_TRANS_SPEED_4G) - -#define BFA_FCS_FDMI_SUPP_SPEEDS_8G (FDMI_TRANS_SPEED_1G | \ - FDMI_TRANS_SPEED_2G | \ - FDMI_TRANS_SPEED_4G | \ - FDMI_TRANS_SPEED_8G) - -#define BFA_FCS_FDMI_SUPP_SPEEDS_16G (FDMI_TRANS_SPEED_2G | \ - FDMI_TRANS_SPEED_4G | \ - FDMI_TRANS_SPEED_8G | \ - FDMI_TRANS_SPEED_16G) - -#define BFA_FCS_FDMI_SUPP_SPEEDS_10G FDMI_TRANS_SPEED_10G +#define BFA_FCS_FDMI_SUPORTED_SPEEDS (FDMI_TRANS_SPEED_1G | \ + FDMI_TRANS_SPEED_2G | \ + FDMI_TRANS_SPEED_4G | \ + FDMI_TRANS_SPEED_8G) /* * HBA Attribute Block : BFA internal representation. Note : Some variable @@ -667,8 +649,6 @@ struct bfa_fcs_s { struct bfa_trc_mod_s *trcmod; /* tracing module */ bfa_boolean_t vf_enabled; /* VF mode is enabled */ bfa_boolean_t fdmi_enabled; /* FDMI is enabled */ - bfa_boolean_t bbscn_enabled; /* Driver Config Parameter */ - bfa_boolean_t bbscn_flogi_rjt;/* FLOGI reject due to BB_SCN */ bfa_boolean_t min_cfg; /* min cfg enabled/disabled */ u16 port_vfid; /* port default VF ID */ struct bfa_fcs_driver_info_s driver_info; @@ -735,8 +715,6 @@ void bfa_fcs_attach(struct bfa_fcs_s *fcs, struct bfa_s *bfa, struct bfad_s *bfad, bfa_boolean_t min_cfg); void bfa_fcs_init(struct bfa_fcs_s *fcs); -void bfa_fcs_pbc_vport_init(struct bfa_fcs_s *fcs); -void bfa_fcs_update_cfg(struct bfa_fcs_s *fcs); void bfa_fcs_driver_info_init(struct bfa_fcs_s *fcs, struct bfa_fcs_driver_info_s *driver_info); void bfa_fcs_exit(struct bfa_fcs_s *fcs); @@ -745,7 +723,6 @@ void bfa_fcs_exit(struct bfa_fcs_s *fcs); * bfa fcs vf public functions */ bfa_fcs_vf_t *bfa_fcs_vf_lookup(struct bfa_fcs_s *fcs, u16 vf_id); -void bfa_fcs_vf_get_ports(bfa_fcs_vf_t *vf, wwn_t vpwwn[], int *nports); /* * fabric protected interface functions diff --git a/trunk/drivers/scsi/bfa/bfa_fcs_fcpim.c b/trunk/drivers/scsi/bfa/bfa_fcs_fcpim.c index 29b4108be269..e7b49f4cb51f 100644 --- a/trunk/drivers/scsi/bfa/bfa_fcs_fcpim.c +++ b/trunk/drivers/scsi/bfa/bfa_fcs_fcpim.c @@ -54,7 +54,6 @@ enum bfa_fcs_itnim_event { BFA_FCS_ITNIM_SM_INITIATOR = 9, /* rport is initiator */ BFA_FCS_ITNIM_SM_DELETE = 10, /* delete event from rport */ BFA_FCS_ITNIM_SM_PRLO = 11, /* delete event from rport */ - BFA_FCS_ITNIM_SM_RSP_NOT_SUPP = 12, /* cmd not supported rsp */ }; static void bfa_fcs_itnim_sm_offline(struct bfa_fcs_itnim_s *itnim, @@ -179,10 +178,6 @@ bfa_fcs_itnim_sm_prli(struct bfa_fcs_itnim_s *itnim, BFA_FCS_RETRY_TIMEOUT); break; - case BFA_FCS_ITNIM_SM_RSP_NOT_SUPP: - bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); - break; - case BFA_FCS_ITNIM_SM_OFFLINE: bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); bfa_fcxp_discard(itnim->fcxp); @@ -452,7 +447,6 @@ bfa_fcs_itnim_prli_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, itnim->rport->scsi_function = BFA_RPORT_INITIATOR; itnim->stats.prli_rsp_acc++; - itnim->stats.initiator++; bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_OK); return; @@ -478,10 +472,6 @@ bfa_fcs_itnim_prli_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, bfa_trc(itnim->fcs, ls_rjt->reason_code_expl); itnim->stats.prli_rsp_rjt++; - if (ls_rjt->reason_code == FC_LS_RJT_RSN_CMD_NOT_SUPP) { - bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_NOT_SUPP); - return; - } bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_ERROR); } } diff --git a/trunk/drivers/scsi/bfa/bfa_fcs_lport.c b/trunk/drivers/scsi/bfa/bfa_fcs_lport.c index f8251a91ba91..1d6be8c14473 100644 --- a/trunk/drivers/scsi/bfa/bfa_fcs_lport.c +++ b/trunk/drivers/scsi/bfa/bfa_fcs_lport.c @@ -74,7 +74,6 @@ enum bfa_fcs_lport_event { BFA_FCS_PORT_SM_OFFLINE = 3, BFA_FCS_PORT_SM_DELETE = 4, BFA_FCS_PORT_SM_DELRPORT = 5, - BFA_FCS_PORT_SM_STOP = 6, }; static void bfa_fcs_lport_sm_uninit(struct bfa_fcs_lport_s *port, @@ -87,8 +86,6 @@ static void bfa_fcs_lport_sm_offline(struct bfa_fcs_lport_s *port, enum bfa_fcs_lport_event event); static void bfa_fcs_lport_sm_deleting(struct bfa_fcs_lport_s *port, enum bfa_fcs_lport_event event); -static void bfa_fcs_lport_sm_stopping(struct bfa_fcs_lport_s *port, - enum bfa_fcs_lport_event event); static void bfa_fcs_lport_sm_uninit( @@ -126,12 +123,6 @@ bfa_fcs_lport_sm_init(struct bfa_fcs_lport_s *port, bfa_fcs_lport_deleted(port); break; - case BFA_FCS_PORT_SM_STOP: - /* If vport - send completion call back */ - if (port->vport) - bfa_fcs_vport_stop_comp(port->vport); - break; - case BFA_FCS_PORT_SM_OFFLINE: break; @@ -157,23 +148,6 @@ bfa_fcs_lport_sm_online( bfa_fcs_lport_offline_actions(port); break; - case BFA_FCS_PORT_SM_STOP: - __port_action[port->fabric->fab_type].offline(port); - - if (port->num_rports == 0) { - bfa_sm_set_state(port, bfa_fcs_lport_sm_init); - /* If vport - send completion call back */ - if (port->vport) - bfa_fcs_vport_stop_comp(port->vport); - } else { - bfa_sm_set_state(port, bfa_fcs_lport_sm_stopping); - list_for_each_safe(qe, qen, &port->rport_q) { - rport = (struct bfa_fcs_rport_s *) qe; - bfa_sm_send_event(rport, RPSM_EVENT_DELETE); - } - } - break; - case BFA_FCS_PORT_SM_DELETE: __port_action[port->fabric->fab_type].offline(port); @@ -215,21 +189,6 @@ bfa_fcs_lport_sm_offline( bfa_fcs_lport_online_actions(port); break; - case BFA_FCS_PORT_SM_STOP: - if (port->num_rports == 0) { - bfa_sm_set_state(port, bfa_fcs_lport_sm_init); - /* If vport - send completion call back */ - if (port->vport) - bfa_fcs_vport_stop_comp(port->vport); - } else { - bfa_sm_set_state(port, bfa_fcs_lport_sm_stopping); - list_for_each_safe(qe, qen, &port->rport_q) { - rport = (struct bfa_fcs_rport_s *) qe; - bfa_sm_send_event(rport, RPSM_EVENT_DELETE); - } - } - break; - case BFA_FCS_PORT_SM_DELETE: if (port->num_rports == 0) { bfa_sm_set_state(port, bfa_fcs_lport_sm_uninit); @@ -252,28 +211,6 @@ bfa_fcs_lport_sm_offline( } } -static void -bfa_fcs_lport_sm_stopping(struct bfa_fcs_lport_s *port, - enum bfa_fcs_lport_event event) -{ - bfa_trc(port->fcs, port->port_cfg.pwwn); - bfa_trc(port->fcs, event); - - switch (event) { - case BFA_FCS_PORT_SM_DELRPORT: - if (port->num_rports == 0) { - bfa_sm_set_state(port, bfa_fcs_lport_sm_init); - /* If vport - send completion call back */ - if (port->vport) - bfa_fcs_vport_stop_comp(port->vport); - } - break; - - default: - bfa_sm_fault(port->fcs, event); - } -} - static void bfa_fcs_lport_sm_deleting( struct bfa_fcs_lport_s *port, @@ -327,40 +264,6 @@ bfa_fcs_lport_send_ls_rjt(struct bfa_fcs_lport_s *port, struct fchs_s *rx_fchs, FC_MAX_PDUSZ, 0); } -/* - * Send a FCCT Reject - */ -static void -bfa_fcs_lport_send_fcgs_rjt(struct bfa_fcs_lport_s *port, - struct fchs_s *rx_fchs, u8 reason_code, u8 reason_code_expl) -{ - struct fchs_s fchs; - struct bfa_fcxp_s *fcxp; - struct bfa_rport_s *bfa_rport = NULL; - int len; - struct ct_hdr_s *rx_cthdr = (struct ct_hdr_s *)(rx_fchs + 1); - struct ct_hdr_s *ct_hdr; - - bfa_trc(port->fcs, rx_fchs->d_id); - bfa_trc(port->fcs, rx_fchs->s_id); - - fcxp = bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) - return; - - ct_hdr = bfa_fcxp_get_reqbuf(fcxp); - ct_hdr->gs_type = rx_cthdr->gs_type; - ct_hdr->gs_sub_type = rx_cthdr->gs_sub_type; - - len = fc_gs_rjt_build(&fchs, ct_hdr, rx_fchs->s_id, - bfa_fcs_lport_get_fcid(port), - rx_fchs->ox_id, reason_code, reason_code_expl); - - bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag, - BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL, - FC_MAX_PDUSZ, 0); -} - /* * Process incoming plogi from a remote port. */ @@ -744,16 +647,6 @@ bfa_fcs_lport_uf_recv(struct bfa_fcs_lport_s *lport, bfa_fcs_lport_abts_acc(lport, fchs); return; } - - if (fchs->type == FC_TYPE_SERVICES) { - /* - * Unhandled FC-GS frames. Send a FC-CT Reject - */ - bfa_fcs_lport_send_fcgs_rjt(lport, fchs, CT_RSN_NOT_SUPP, - CT_NS_EXP_NOADDITIONAL); - return; - } - /* * look for a matching remote port ID */ @@ -942,8 +835,8 @@ bfa_fcs_lport_attach(struct bfa_fcs_lport_s *lport, struct bfa_fcs_s *fcs, lport->fcs = fcs; lport->fabric = bfa_fcs_vf_lookup(fcs, vf_id); lport->vport = vport; - lport->lp_tag = (vport) ? vport->lps->bfa_tag : - lport->fabric->lps->bfa_tag; + lport->lp_tag = (vport) ? vport->lps->lp_tag : + lport->fabric->lps->lp_tag; INIT_LIST_HEAD(&lport->rport_q); lport->num_rports = 0; @@ -1181,8 +1074,6 @@ static void bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_lport_fdmi_s *fdmi, struct bfa_fcs_fdmi_hba_attr_s *hba_attr); static void bfa_fcs_fdmi_get_portattr(struct bfa_fcs_lport_fdmi_s *fdmi, struct bfa_fcs_fdmi_port_attr_s *port_attr); -u32 bfa_fcs_fdmi_convert_speed(enum bfa_port_speed pport_speed); - /* * fcs_fdmi_sm FCS FDMI state machine */ @@ -1781,7 +1672,7 @@ bfa_fcs_lport_fdmi_build_rhba_pyld(struct bfa_fcs_lport_fdmi_s *fdmi, u8 *pyld) memcpy(attr->value, fcs_hba_attr->driver_version, templen); templen = fc_roundup(templen, sizeof(u32)); curr_ptr += sizeof(attr->type) + sizeof(templen) + templen; - len += templen; + len += templen;; count++; attr->len = cpu_to_be16(templen + sizeof(attr->type) + sizeof(templen)); @@ -2269,36 +2160,12 @@ bfa_fcs_fdmi_get_portattr(struct bfa_fcs_lport_fdmi_s *fdmi, /* * Supported Speeds */ - switch (pport_attr.speed_supported) { - case BFA_PORT_SPEED_16GBPS: - port_attr->supp_speed = - cpu_to_be32(BFA_FCS_FDMI_SUPP_SPEEDS_16G); - break; - - case BFA_PORT_SPEED_10GBPS: - port_attr->supp_speed = - cpu_to_be32(BFA_FCS_FDMI_SUPP_SPEEDS_10G); - break; - - case BFA_PORT_SPEED_8GBPS: - port_attr->supp_speed = - cpu_to_be32(BFA_FCS_FDMI_SUPP_SPEEDS_8G); - break; - - case BFA_PORT_SPEED_4GBPS: - port_attr->supp_speed = - cpu_to_be32(BFA_FCS_FDMI_SUPP_SPEEDS_4G); - break; - - default: - bfa_sm_fault(port->fcs, pport_attr.speed_supported); - } + port_attr->supp_speed = cpu_to_be32(BFA_FCS_FDMI_SUPORTED_SPEEDS); /* * Current Speed */ - port_attr->curr_speed = cpu_to_be32( - bfa_fcs_fdmi_convert_speed(pport_attr.speed)); + port_attr->curr_speed = cpu_to_be32(pport_attr.speed); /* * Max PDU Size. @@ -2319,41 +2186,6 @@ bfa_fcs_fdmi_get_portattr(struct bfa_fcs_lport_fdmi_s *fdmi, } -/* - * Convert BFA speed to FDMI format. - */ -u32 -bfa_fcs_fdmi_convert_speed(bfa_port_speed_t pport_speed) -{ - u32 ret; - - switch (pport_speed) { - case BFA_PORT_SPEED_1GBPS: - case BFA_PORT_SPEED_2GBPS: - ret = pport_speed; - break; - - case BFA_PORT_SPEED_4GBPS: - ret = FDMI_TRANS_SPEED_4G; - break; - - case BFA_PORT_SPEED_8GBPS: - ret = FDMI_TRANS_SPEED_8G; - break; - - case BFA_PORT_SPEED_10GBPS: - ret = FDMI_TRANS_SPEED_10G; - break; - - case BFA_PORT_SPEED_16GBPS: - ret = FDMI_TRANS_SPEED_16G; - break; - - default: - ret = FDMI_TRANS_SPEED_UNKNOWN; - } - return ret; -} void bfa_fcs_lport_fdmi_init(struct bfa_fcs_lport_ms_s *ms) @@ -2997,8 +2829,7 @@ bfa_fcs_lport_ms_send_plogi(void *ms_cbarg, struct bfa_fcxp_s *fcxp_alloced) bfa_hton3b(FC_MGMT_SERVER), bfa_fcs_lport_get_fcid(port), 0, port->port_cfg.pwwn, port->port_cfg.nwwn, - bfa_fcport_get_maxfrsize(port->fcs->bfa), - bfa_fcport_get_rx_bbcredit(port->fcs->bfa)); + bfa_fcport_get_maxfrsize(port->fcs->bfa)); bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, FC_CLASS_3, len, &fchs, @@ -3742,7 +3573,7 @@ bfa_fcs_lport_ns_send_plogi(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced) bfa_trc(port->fcs, port->pid); - fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); +fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); if (!fcxp) { port->stats.ns_plogi_alloc_wait++; bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe, @@ -3755,8 +3586,7 @@ bfa_fcs_lport_ns_send_plogi(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced) bfa_hton3b(FC_NAME_SERVER), bfa_fcs_lport_get_fcid(port), 0, port->port_cfg.pwwn, port->port_cfg.nwwn, - bfa_fcport_get_maxfrsize(port->fcs->bfa), - bfa_fcport_get_rx_bbcredit(port->fcs->bfa)); + bfa_fcport_get_maxfrsize(port->fcs->bfa)); bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, FC_CLASS_3, len, &fchs, @@ -4932,8 +4762,8 @@ bfa_fcs_lport_get_rport_max_speed(bfa_fcs_lport_t *port) while (qe != qh) { rport = (struct bfa_fcs_rport_s *) qe; if ((bfa_ntoh3b(rport->pid) > 0xFFF000) || - (bfa_fcs_rport_get_state(rport) == BFA_RPORT_OFFLINE) || - (rport->scsi_function != BFA_RPORT_TARGET)) { + (bfa_fcs_rport_get_state(rport) == + BFA_RPORT_OFFLINE)) { qe = bfa_q_next(qe); continue; } @@ -4946,15 +4776,17 @@ bfa_fcs_lport_get_rport_max_speed(bfa_fcs_lport_t *port) bfa_fcport_get_ratelim_speed(port->fcs->bfa); } - if (rport_speed > max_speed) + if ((rport_speed == BFA_PORT_SPEED_8GBPS) || + (rport_speed > port_speed)) { max_speed = rport_speed; + break; + } else if (rport_speed > max_speed) { + max_speed = rport_speed; + } qe = bfa_q_next(qe); } - if (max_speed > port_speed) - max_speed = port_speed; - bfa_trc(fcs, max_speed); return max_speed; } @@ -5086,7 +4918,6 @@ enum bfa_fcs_vport_event { BFA_FCS_VPORT_SM_DELCOMP = 11, /* lport delete completion */ BFA_FCS_VPORT_SM_RSP_DUP_WWN = 12, /* Dup wnn error*/ BFA_FCS_VPORT_SM_RSP_FAILED = 13, /* non-retryable failure */ - BFA_FCS_VPORT_SM_STOPCOMP = 14, /* vport delete completion */ }; static void bfa_fcs_vport_sm_uninit(struct bfa_fcs_vport_s *vport, @@ -5099,8 +4930,6 @@ static void bfa_fcs_vport_sm_fdisc(struct bfa_fcs_vport_s *vport, enum bfa_fcs_vport_event event); static void bfa_fcs_vport_sm_fdisc_retry(struct bfa_fcs_vport_s *vport, enum bfa_fcs_vport_event event); -static void bfa_fcs_vport_sm_fdisc_rsp_wait(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event); static void bfa_fcs_vport_sm_online(struct bfa_fcs_vport_s *vport, enum bfa_fcs_vport_event event); static void bfa_fcs_vport_sm_deleting(struct bfa_fcs_vport_s *vport, @@ -5111,10 +4940,6 @@ static void bfa_fcs_vport_sm_logo(struct bfa_fcs_vport_s *vport, enum bfa_fcs_vport_event event); static void bfa_fcs_vport_sm_error(struct bfa_fcs_vport_s *vport, enum bfa_fcs_vport_event event); -static void bfa_fcs_vport_sm_stopping(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event); -static void bfa_fcs_vport_sm_logo_for_stop(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event); static struct bfa_sm_table_s vport_sm_table[] = { {BFA_SM(bfa_fcs_vport_sm_uninit), BFA_FCS_VPORT_UNINIT}, @@ -5122,7 +4947,6 @@ static struct bfa_sm_table_s vport_sm_table[] = { {BFA_SM(bfa_fcs_vport_sm_offline), BFA_FCS_VPORT_OFFLINE}, {BFA_SM(bfa_fcs_vport_sm_fdisc), BFA_FCS_VPORT_FDISC}, {BFA_SM(bfa_fcs_vport_sm_fdisc_retry), BFA_FCS_VPORT_FDISC_RETRY}, - {BFA_SM(bfa_fcs_vport_sm_fdisc_rsp_wait), BFA_FCS_VPORT_FDISC_RSP_WAIT}, {BFA_SM(bfa_fcs_vport_sm_online), BFA_FCS_VPORT_ONLINE}, {BFA_SM(bfa_fcs_vport_sm_deleting), BFA_FCS_VPORT_DELETING}, {BFA_SM(bfa_fcs_vport_sm_cleanup), BFA_FCS_VPORT_CLEANUP}, @@ -5218,11 +5042,6 @@ bfa_fcs_vport_sm_offline(struct bfa_fcs_vport_s *vport, bfa_fcs_vport_do_fdisc(vport); break; - case BFA_FCS_VPORT_SM_STOP: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup); - bfa_sm_send_event(&vport->lport, BFA_FCS_PORT_SM_STOP); - break; - case BFA_FCS_VPORT_SM_OFFLINE: /* * This can happen if the vport couldn't be initialzied @@ -5251,7 +5070,9 @@ bfa_fcs_vport_sm_fdisc(struct bfa_fcs_vport_s *vport, switch (event) { case BFA_FCS_VPORT_SM_DELETE: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_fdisc_rsp_wait); + bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup); + bfa_sm_send_event(vport->lps, BFA_LPS_SM_OFFLINE); + bfa_fcs_lport_delete(&vport->lport); break; case BFA_FCS_VPORT_SM_OFFLINE: @@ -5318,41 +5139,6 @@ bfa_fcs_vport_sm_fdisc_retry(struct bfa_fcs_vport_s *vport, } } -/* - * FDISC is in progress and we got a vport delete request - - * this is a wait state while we wait for fdisc response and - * we will transition to the appropriate state - on rsp status. - */ -static void -bfa_fcs_vport_sm_fdisc_rsp_wait(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event) -{ - bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); - bfa_trc(__vport_fcs(vport), event); - - switch (event) { - case BFA_FCS_VPORT_SM_RSP_OK: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_deleting); - bfa_fcs_lport_delete(&vport->lport); - break; - - case BFA_FCS_VPORT_SM_DELETE: - break; - - case BFA_FCS_VPORT_SM_OFFLINE: - case BFA_FCS_VPORT_SM_RSP_ERROR: - case BFA_FCS_VPORT_SM_RSP_FAILED: - case BFA_FCS_VPORT_SM_RSP_DUP_WWN: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup); - bfa_sm_send_event(vport->lps, BFA_LPS_SM_OFFLINE); - bfa_fcs_lport_delete(&vport->lport); - break; - - default: - bfa_sm_fault(__vport_fcs(vport), event); - } -} - /* * Vport is online (FDISC is complete). */ @@ -5369,11 +5155,6 @@ bfa_fcs_vport_sm_online(struct bfa_fcs_vport_s *vport, bfa_fcs_lport_delete(&vport->lport); break; - case BFA_FCS_VPORT_SM_STOP: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_stopping); - bfa_sm_send_event(&vport->lport, BFA_FCS_PORT_SM_STOP); - break; - case BFA_FCS_VPORT_SM_OFFLINE: bfa_sm_set_state(vport, bfa_fcs_vport_sm_offline); bfa_sm_send_event(vport->lps, BFA_LPS_SM_OFFLINE); @@ -5385,32 +5166,6 @@ bfa_fcs_vport_sm_online(struct bfa_fcs_vport_s *vport, } } -/* - * Vport is being stopped - awaiting lport stop completion to send - * LOGO to fabric. - */ -static void -bfa_fcs_vport_sm_stopping(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event) -{ - bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); - bfa_trc(__vport_fcs(vport), event); - - switch (event) { - case BFA_FCS_VPORT_SM_STOPCOMP: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_logo_for_stop); - bfa_fcs_vport_do_logo(vport); - break; - - case BFA_FCS_VPORT_SM_OFFLINE: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup); - break; - - default: - bfa_sm_fault(__vport_fcs(vport), event); - } -} - /* * Vport is being deleted - awaiting lport delete completion to send * LOGO to fabric. @@ -5481,10 +5236,6 @@ bfa_fcs_vport_sm_cleanup(struct bfa_fcs_vport_s *vport, bfa_fcs_vport_free(vport); break; - case BFA_FCS_VPORT_SM_STOPCOMP: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_created); - break; - case BFA_FCS_VPORT_SM_DELETE: break; @@ -5493,34 +5244,6 @@ bfa_fcs_vport_sm_cleanup(struct bfa_fcs_vport_s *vport, } } -/* - * LOGO is sent to fabric. Vport stop is in progress. Lport stop cleanup - * is done. - */ -static void -bfa_fcs_vport_sm_logo_for_stop(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event) -{ - bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); - bfa_trc(__vport_fcs(vport), event); - - switch (event) { - case BFA_FCS_VPORT_SM_OFFLINE: - bfa_sm_send_event(vport->lps, BFA_LPS_SM_OFFLINE); - /* - * !!! fall through !!! - */ - - case BFA_FCS_VPORT_SM_RSP_OK: - case BFA_FCS_VPORT_SM_RSP_ERROR: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_created); - break; - - default: - bfa_sm_fault(__vport_fcs(vport), event); - } -} - /* * LOGO is sent to fabric. Vport delete is in progress. Lport delete cleanup * is done. @@ -5668,10 +5391,7 @@ void bfa_fcs_vport_online(struct bfa_fcs_vport_s *vport) { vport->vport_stats.fab_online++; - if (bfa_fcs_fabric_npiv_capable(__vport_fabric(vport))) - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_ONLINE); - else - vport->vport_stats.fab_no_npiv++; + bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_ONLINE); } /* @@ -5701,15 +5421,6 @@ bfa_fcs_vport_fcs_delete(struct bfa_fcs_vport_s *vport) bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_DELETE); } -/* - * Stop completion callback from associated lport - */ -void -bfa_fcs_vport_stop_comp(struct bfa_fcs_vport_s *vport) -{ - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_STOPCOMP); -} - /* * Delete completion callback from associated lport */ diff --git a/trunk/drivers/scsi/bfa/bfa_fcs_rport.c b/trunk/drivers/scsi/bfa/bfa_fcs_rport.c index 2c514458a6b4..caaee6f06937 100644 --- a/trunk/drivers/scsi/bfa/bfa_fcs_rport.c +++ b/trunk/drivers/scsi/bfa/bfa_fcs_rport.c @@ -262,7 +262,6 @@ bfa_fcs_rport_sm_plogiacc_sending(struct bfa_fcs_rport_s *rport, break; case RPSM_EVENT_PLOGI_RCVD: - case RPSM_EVENT_PLOGI_COMP: case RPSM_EVENT_SCN: /* * Ignore, SCN is possibly online notification. @@ -471,7 +470,6 @@ bfa_fcs_rport_sm_hal_online(struct bfa_fcs_rport_s *rport, break; case RPSM_EVENT_PRLO_RCVD: - case RPSM_EVENT_PLOGI_COMP: break; case RPSM_EVENT_LOGO_RCVD: @@ -486,9 +484,9 @@ bfa_fcs_rport_sm_hal_online(struct bfa_fcs_rport_s *rport, break; case RPSM_EVENT_PLOGI_RCVD: - rport->plogi_pending = BFA_TRUE; - bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_offline); + bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending); bfa_sm_send_event(rport->bfa_rport, BFA_RPORT_SM_OFFLINE); + bfa_fcs_rport_send_plogiacc(rport, NULL); break; case RPSM_EVENT_DELETE: @@ -893,18 +891,6 @@ bfa_fcs_rport_sm_hcb_offline(struct bfa_fcs_rport_s *rport, switch (event) { case RPSM_EVENT_HCB_OFFLINE: - if (bfa_fcs_lport_is_online(rport->port) && - (rport->plogi_pending)) { - rport->plogi_pending = BFA_FALSE; - bfa_sm_set_state(rport, - bfa_fcs_rport_sm_plogiacc_sending); - bfa_fcs_rport_send_plogiacc(rport, NULL); - break; - } - /* - * !! fall through !! - */ - case RPSM_EVENT_ADDRESS_CHANGE: if (bfa_fcs_lport_is_online(rport->port)) { if (bfa_fcs_fabric_is_switched(rport->port->fabric)) { @@ -935,8 +921,6 @@ bfa_fcs_rport_sm_hcb_offline(struct bfa_fcs_rport_s *rport, case RPSM_EVENT_SCN: case RPSM_EVENT_LOGO_RCVD: case RPSM_EVENT_PRLO_RCVD: - case RPSM_EVENT_PLOGI_RCVD: - case RPSM_EVENT_LOGO_IMP: /* * Ignore, already offline. */ @@ -973,18 +957,10 @@ bfa_fcs_rport_sm_hcb_logorcv(struct bfa_fcs_rport_s *rport, */ if (bfa_fcs_lport_is_online(rport->port) && (!BFA_FCS_PID_IS_WKA(rport->pid))) { - if (bfa_fcs_fabric_is_switched(rport->port->fabric)) { - bfa_sm_set_state(rport, - bfa_fcs_rport_sm_nsdisc_sending); - rport->ns_retries = 0; - bfa_fcs_rport_send_nsdisc(rport, NULL); - } else { - /* For N2N Direct Attach, try to re-login */ - bfa_sm_set_state(rport, - bfa_fcs_rport_sm_plogi_sending); - rport->plogi_retries = 0; - bfa_fcs_rport_send_plogi(rport, NULL); - } + bfa_sm_set_state(rport, + bfa_fcs_rport_sm_nsdisc_sending); + rport->ns_retries = 0; + bfa_fcs_rport_send_nsdisc(rport, NULL); } else { /* * if it is not a well known address, reset the @@ -1380,8 +1356,7 @@ bfa_fcs_rport_send_plogi(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced) len = fc_plogi_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rport->pid, bfa_fcs_lport_get_fcid(port), 0, port->port_cfg.pwwn, port->port_cfg.nwwn, - bfa_fcport_get_maxfrsize(port->fcs->bfa), - bfa_fcport_get_rx_bbcredit(port->fcs->bfa)); + bfa_fcport_get_maxfrsize(port->fcs->bfa)); bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, FC_CLASS_3, len, &fchs, bfa_fcs_rport_plogi_response, @@ -1501,8 +1476,7 @@ bfa_fcs_rport_send_plogiacc(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced) rport->pid, bfa_fcs_lport_get_fcid(port), rport->reply_oxid, port->port_cfg.pwwn, port->port_cfg.nwwn, - bfa_fcport_get_maxfrsize(port->fcs->bfa), - bfa_fcport_get_rx_bbcredit(port->fcs->bfa)); + bfa_fcport_get_maxfrsize(port->fcs->bfa)); bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL, FC_MAX_PDUSZ, 0); @@ -2050,11 +2024,6 @@ bfa_fcs_rport_online_action(struct bfa_fcs_rport_s *rport) rport->stats.onlines++; - if ((!rport->pid) || (!rport->pwwn)) { - bfa_trc(rport->fcs, rport->pid); - bfa_sm_fault(rport->fcs, rport->pid); - } - if (bfa_fcs_lport_is_initiator(port)) { bfa_fcs_itnim_rport_online(rport->itnim); if (!BFA_FCS_PID_IS_WKA(rport->pid)) @@ -2078,7 +2047,6 @@ bfa_fcs_rport_offline_action(struct bfa_fcs_rport_s *rport) char rpwwn_buf[BFA_STRING_32]; rport->stats.offlines++; - rport->plogi_pending = BFA_FALSE; wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port)); wwn2str(rpwwn_buf, rport->pwwn); @@ -2152,7 +2120,7 @@ bfa_fcs_rport_update(struct bfa_fcs_rport_s *rport, struct fc_logi_s *plogi) port->fabric->bb_credit = be16_to_cpu(plogi->csp.bbcred); bfa_fcport_set_tx_bbcredit(port->fcs->bfa, - port->fabric->bb_credit, 0); + port->fabric->bb_credit); } } @@ -2265,6 +2233,22 @@ bfa_fcs_rport_plogi_create(struct bfa_fcs_lport_s *port, struct fchs_s *fchs, bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_RCVD); } +static int +wwn_compare(wwn_t wwn1, wwn_t wwn2) +{ + u8 *b1 = (u8 *) &wwn1; + u8 *b2 = (u8 *) &wwn2; + int i; + + for (i = 0; i < sizeof(wwn_t); i++) { + if (b1[i] < b2[i]) + return -1; + if (b1[i] > b2[i]) + return 1; + } + return 0; +} + /* * Called by bport/vport to handle PLOGI received from an existing * remote port. @@ -2282,8 +2266,19 @@ bfa_fcs_rport_plogi(struct bfa_fcs_rport_s *rport, struct fchs_s *rx_fchs, rport->reply_oxid = rx_fchs->ox_id; bfa_trc(rport->fcs, rport->reply_oxid); - rport->pid = rx_fchs->s_id; - bfa_trc(rport->fcs, rport->pid); + /* + * In Switched fabric topology, + * PLOGI to each other. If our pwwn is smaller, ignore it, + * if it is not a well known address. + * If the link topology is N2N, + * this Plogi should be accepted. + */ + if ((wwn_compare(rport->port->port_cfg.pwwn, rport->pwwn) == -1) && + (bfa_fcs_fabric_is_switched(rport->port->fabric)) && + (!BFA_FCS_PID_IS_WKA(rport->pid))) { + bfa_trc(rport->fcs, rport->pid); + return; + } rport->stats.plogi_rcvd++; bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_RCVD); @@ -2536,45 +2531,7 @@ bfa_fcs_rport_prlo(struct bfa_fcs_rport_s *rport, __be16 ox_id) bfa_sm_send_event(rport, RPSM_EVENT_PRLO_RCVD); } -void -bfa_fcs_rport_get_attr(struct bfa_fcs_rport_s *rport, - struct bfa_rport_attr_s *rport_attr) -{ - struct bfa_rport_qos_attr_s qos_attr; - struct bfa_fcs_lport_s *port = rport->port; - bfa_port_speed_t rport_speed = rport->rpf.rpsc_speed; - - memset(rport_attr, 0, sizeof(struct bfa_rport_attr_s)); - memset(&qos_attr, 0, sizeof(struct bfa_rport_qos_attr_s)); - - rport_attr->pid = rport->pid; - rport_attr->pwwn = rport->pwwn; - rport_attr->nwwn = rport->nwwn; - rport_attr->cos_supported = rport->fc_cos; - rport_attr->df_sz = rport->maxfrsize; - rport_attr->state = bfa_fcs_rport_get_state(rport); - rport_attr->fc_cos = rport->fc_cos; - rport_attr->cisc = rport->cisc; - rport_attr->scsi_function = rport->scsi_function; - rport_attr->curr_speed = rport->rpf.rpsc_speed; - rport_attr->assigned_speed = rport->rpf.assigned_speed; - - qos_attr.qos_priority = rport->bfa_rport->qos_attr.qos_priority; - qos_attr.qos_flow_id = - cpu_to_be32(rport->bfa_rport->qos_attr.qos_flow_id); - rport_attr->qos_attr = qos_attr; - - rport_attr->trl_enforced = BFA_FALSE; - if (bfa_fcport_is_ratelim(port->fcs->bfa) && - (rport->scsi_function == BFA_RPORT_TARGET)) { - if (rport_speed == BFA_PORT_SPEED_UNKNOWN) - rport_speed = - bfa_fcport_get_ratelim_speed(rport->fcs->bfa); - - if (rport_speed < bfa_fcs_lport_get_rport_max_speed(port)) - rport_attr->trl_enforced = BFA_TRUE; - } -} + /* * Remote port implementation. diff --git a/trunk/drivers/scsi/bfa/bfa_hw_cb.c b/trunk/drivers/scsi/bfa/bfa_hw_cb.c index e7ffd8205dc7..977e681ec803 100644 --- a/trunk/drivers/scsi/bfa/bfa_hw_cb.c +++ b/trunk/drivers/scsi/bfa/bfa_hw_cb.c @@ -17,14 +17,14 @@ #include "bfad_drv.h" #include "bfa_modules.h" -#include "bfi_reg.h" +#include "bfi_cbreg.h" void bfa_hwcb_reginit(struct bfa_s *bfa) { struct bfa_iocfc_regs_s *bfa_regs = &bfa->iocfc.bfa_regs; void __iomem *kva = bfa_ioc_bar0(&bfa->ioc); - int fn = bfa_ioc_pcifn(&bfa->ioc); + int i, q, fn = bfa_ioc_pcifn(&bfa->ioc); if (fn == 0) { bfa_regs->intr_status = (kva + HOSTFN0_INT_STATUS); @@ -33,6 +33,29 @@ bfa_hwcb_reginit(struct bfa_s *bfa) bfa_regs->intr_status = (kva + HOSTFN1_INT_STATUS); bfa_regs->intr_mask = (kva + HOSTFN1_INT_MSK); } + + for (i = 0; i < BFI_IOC_MAX_CQS; i++) { + /* + * CPE registers + */ + q = CPE_Q_NUM(fn, i); + bfa_regs->cpe_q_pi[i] = (kva + CPE_Q_PI(q)); + bfa_regs->cpe_q_ci[i] = (kva + CPE_Q_CI(q)); + bfa_regs->cpe_q_depth[i] = (kva + CPE_Q_DEPTH(q)); + + /* + * RME registers + */ + q = CPE_Q_NUM(fn, i); + bfa_regs->rme_q_pi[i] = (kva + RME_Q_PI(q)); + bfa_regs->rme_q_ci[i] = (kva + RME_Q_CI(q)); + bfa_regs->rme_q_depth[i] = (kva + RME_Q_DEPTH(q)); + } +} + +void +bfa_hwcb_reqq_ack(struct bfa_s *bfa, int reqq) +{ } static void @@ -42,6 +65,11 @@ bfa_hwcb_reqq_ack_msix(struct bfa_s *bfa, int reqq) bfa->iocfc.bfa_regs.intr_status); } +void +bfa_hwcb_rspq_ack(struct bfa_s *bfa, int rspq) +{ +} + static void bfa_hwcb_rspq_ack_msix(struct bfa_s *bfa, int rspq) { @@ -75,72 +103,44 @@ bfa_hwcb_msix_getvecs(struct bfa_s *bfa, u32 *msix_vecs_bmap, *num_vecs = __HFN_NUMINTS; } -/* - * Dummy interrupt handler for handling spurious interrupts. - */ -static void -bfa_hwcb_msix_dummy(struct bfa_s *bfa, int vec) -{ -} - /* * No special setup required for crossbow -- vector assignments are implicit. */ void bfa_hwcb_msix_init(struct bfa_s *bfa, int nvecs) -{ - WARN_ON((nvecs != 1) && (nvecs != __HFN_NUMINTS)); - - bfa->msix.nvecs = nvecs; - bfa_hwcb_msix_uninstall(bfa); -} - -void -bfa_hwcb_msix_ctrl_install(struct bfa_s *bfa) { int i; - if (bfa->msix.nvecs == 0) - return; + WARN_ON((nvecs != 1) && (nvecs != __HFN_NUMINTS)); - if (bfa->msix.nvecs == 1) { - for (i = BFI_MSIX_CPE_QMIN_CB; i < BFI_MSIX_CB_MAX; i++) + bfa->msix.nvecs = nvecs; + if (nvecs == 1) { + for (i = 0; i < BFA_MSIX_CB_MAX; i++) bfa->msix.handler[i] = bfa_msix_all; return; } - for (i = BFI_MSIX_RME_QMAX_CB+1; i < BFI_MSIX_CB_MAX; i++) + for (i = BFA_MSIX_CPE_Q0; i <= BFA_MSIX_CPE_Q7; i++) + bfa->msix.handler[i] = bfa_msix_reqq; + + for (i = BFA_MSIX_RME_Q0; i <= BFA_MSIX_RME_Q7; i++) + bfa->msix.handler[i] = bfa_msix_rspq; + + for (; i < BFA_MSIX_CB_MAX; i++) bfa->msix.handler[i] = bfa_msix_lpu_err; } +/* + * Crossbow -- dummy, interrupts are masked + */ void -bfa_hwcb_msix_queue_install(struct bfa_s *bfa) +bfa_hwcb_msix_install(struct bfa_s *bfa) { - int i; - - if (bfa->msix.nvecs == 0) - return; - - if (bfa->msix.nvecs == 1) { - for (i = BFI_MSIX_CPE_QMIN_CB; i <= BFI_MSIX_RME_QMAX_CB; i++) - bfa->msix.handler[i] = bfa_msix_all; - return; - } - - for (i = BFI_MSIX_CPE_QMIN_CB; i <= BFI_MSIX_CPE_QMAX_CB; i++) - bfa->msix.handler[i] = bfa_msix_reqq; - - for (i = BFI_MSIX_RME_QMIN_CB; i <= BFI_MSIX_RME_QMAX_CB; i++) - bfa->msix.handler[i] = bfa_msix_rspq; } void bfa_hwcb_msix_uninstall(struct bfa_s *bfa) { - int i; - - for (i = 0; i < BFI_MSIX_CB_MAX; i++) - bfa->msix.handler[i] = bfa_hwcb_msix_dummy; } /* @@ -156,6 +156,6 @@ bfa_hwcb_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix) void bfa_hwcb_msix_get_rme_range(struct bfa_s *bfa, u32 *start, u32 *end) { - *start = BFI_MSIX_RME_QMIN_CB; - *end = BFI_MSIX_RME_QMAX_CB; + *start = BFA_MSIX_RME_Q0; + *end = BFA_MSIX_RME_Q7; } diff --git a/trunk/drivers/scsi/bfa/bfa_hw_ct.c b/trunk/drivers/scsi/bfa/bfa_hw_ct.c index 989bbce9b296..21018d98a07b 100644 --- a/trunk/drivers/scsi/bfa/bfa_hw_ct.c +++ b/trunk/drivers/scsi/bfa/bfa_hw_ct.c @@ -17,10 +17,29 @@ #include "bfad_drv.h" #include "bfa_modules.h" -#include "bfi_reg.h" +#include "bfi_ctreg.h" BFA_TRC_FILE(HAL, IOCFC_CT); +static u32 __ct_msix_err_vec_reg[] = { + HOST_MSIX_ERR_INDEX_FN0, + HOST_MSIX_ERR_INDEX_FN1, + HOST_MSIX_ERR_INDEX_FN2, + HOST_MSIX_ERR_INDEX_FN3, +}; + +static void +bfa_hwct_msix_lpu_err_set(struct bfa_s *bfa, bfa_boolean_t msix, int vec) +{ + int fn = bfa_ioc_pcifn(&bfa->ioc); + void __iomem *kva = bfa_ioc_bar0(&bfa->ioc); + + if (msix) + writel(vec, kva + __ct_msix_err_vec_reg[fn]); + else + writel(0, kva + __ct_msix_err_vec_reg[fn]); +} + /* * Dummy interrupt handler for handling spurious interrupt during chip-reinit. */ @@ -34,7 +53,7 @@ bfa_hwct_reginit(struct bfa_s *bfa) { struct bfa_iocfc_regs_s *bfa_regs = &bfa->iocfc.bfa_regs; void __iomem *kva = bfa_ioc_bar0(&bfa->ioc); - int fn = bfa_ioc_pcifn(&bfa->ioc); + int i, q, fn = bfa_ioc_pcifn(&bfa->ioc); if (fn == 0) { bfa_regs->intr_status = (kva + HOSTFN0_INT_STATUS); @@ -43,16 +62,26 @@ bfa_hwct_reginit(struct bfa_s *bfa) bfa_regs->intr_status = (kva + HOSTFN1_INT_STATUS); bfa_regs->intr_mask = (kva + HOSTFN1_INT_MSK); } -} - -void -bfa_hwct2_reginit(struct bfa_s *bfa) -{ - struct bfa_iocfc_regs_s *bfa_regs = &bfa->iocfc.bfa_regs; - void __iomem *kva = bfa_ioc_bar0(&bfa->ioc); - bfa_regs->intr_status = (kva + CT2_HOSTFN_INT_STATUS); - bfa_regs->intr_mask = (kva + CT2_HOSTFN_INTR_MASK); + for (i = 0; i < BFI_IOC_MAX_CQS; i++) { + /* + * CPE registers + */ + q = CPE_Q_NUM(fn, i); + bfa_regs->cpe_q_pi[i] = (kva + CPE_PI_PTR_Q(q << 5)); + bfa_regs->cpe_q_ci[i] = (kva + CPE_CI_PTR_Q(q << 5)); + bfa_regs->cpe_q_depth[i] = (kva + CPE_DEPTH_Q(q << 5)); + bfa_regs->cpe_q_ctrl[i] = (kva + CPE_QCTRL_Q(q << 5)); + + /* + * RME registers + */ + q = CPE_Q_NUM(fn, i); + bfa_regs->rme_q_pi[i] = (kva + RME_PI_PTR_Q(q << 5)); + bfa_regs->rme_q_ci[i] = (kva + RME_CI_PTR_Q(q << 5)); + bfa_regs->rme_q_depth[i] = (kva + RME_DEPTH_Q(q << 5)); + bfa_regs->rme_q_ctrl[i] = (kva + RME_QCTRL_Q(q << 5)); + } } void @@ -77,9 +106,9 @@ void bfa_hwct_msix_getvecs(struct bfa_s *bfa, u32 *msix_vecs_bmap, u32 *num_vecs, u32 *max_vec_bit) { - *msix_vecs_bmap = (1 << BFI_MSIX_CT_MAX) - 1; - *max_vec_bit = (1 << (BFI_MSIX_CT_MAX - 1)); - *num_vecs = BFI_MSIX_CT_MAX; + *msix_vecs_bmap = (1 << BFA_MSIX_CT_MAX) - 1; + *max_vec_bit = (1 << (BFA_MSIX_CT_MAX - 1)); + *num_vecs = BFA_MSIX_CT_MAX; } /* @@ -88,7 +117,7 @@ bfa_hwct_msix_getvecs(struct bfa_s *bfa, u32 *msix_vecs_bmap, void bfa_hwct_msix_init(struct bfa_s *bfa, int nvecs) { - WARN_ON((nvecs != 1) && (nvecs != BFI_MSIX_CT_MAX)); + WARN_ON((nvecs != 1) && (nvecs != BFA_MSIX_CT_MAX)); bfa_trc(bfa, nvecs); bfa->msix.nvecs = nvecs; @@ -96,19 +125,7 @@ bfa_hwct_msix_init(struct bfa_s *bfa, int nvecs) } void -bfa_hwct_msix_ctrl_install(struct bfa_s *bfa) -{ - if (bfa->msix.nvecs == 0) - return; - - if (bfa->msix.nvecs == 1) - bfa->msix.handler[BFI_MSIX_LPU_ERR_CT] = bfa_msix_all; - else - bfa->msix.handler[BFI_MSIX_LPU_ERR_CT] = bfa_msix_lpu_err; -} - -void -bfa_hwct_msix_queue_install(struct bfa_s *bfa) +bfa_hwct_msix_install(struct bfa_s *bfa) { int i; @@ -116,16 +133,19 @@ bfa_hwct_msix_queue_install(struct bfa_s *bfa) return; if (bfa->msix.nvecs == 1) { - for (i = BFI_MSIX_CPE_QMIN_CT; i < BFI_MSIX_CT_MAX; i++) + for (i = 0; i < BFA_MSIX_CT_MAX; i++) bfa->msix.handler[i] = bfa_msix_all; return; } - for (i = BFI_MSIX_CPE_QMIN_CT; i <= BFI_MSIX_CPE_QMAX_CT; i++) + for (i = BFA_MSIX_CPE_Q0; i <= BFA_MSIX_CPE_Q3; i++) bfa->msix.handler[i] = bfa_msix_reqq; - for (i = BFI_MSIX_RME_QMIN_CT; i <= BFI_MSIX_RME_QMAX_CT; i++) + for (; i <= BFA_MSIX_RME_Q3; i++) bfa->msix.handler[i] = bfa_msix_rspq; + + WARN_ON(i != BFA_MSIX_LPU_ERR); + bfa->msix.handler[BFA_MSIX_LPU_ERR] = bfa_msix_lpu_err; } void @@ -133,7 +153,7 @@ bfa_hwct_msix_uninstall(struct bfa_s *bfa) { int i; - for (i = 0; i < BFI_MSIX_CT_MAX; i++) + for (i = 0; i < BFA_MSIX_CT_MAX; i++) bfa->msix.handler[i] = bfa_hwct_msix_dummy; } @@ -144,12 +164,13 @@ void bfa_hwct_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix) { bfa_trc(bfa, 0); + bfa_hwct_msix_lpu_err_set(bfa, msix, BFA_MSIX_LPU_ERR); bfa_ioc_isr_mode_set(&bfa->ioc, msix); } void bfa_hwct_msix_get_rme_range(struct bfa_s *bfa, u32 *start, u32 *end) { - *start = BFI_MSIX_RME_QMIN_CT; - *end = BFI_MSIX_RME_QMAX_CT; + *start = BFA_MSIX_RME_Q0; + *end = BFA_MSIX_RME_Q3; } diff --git a/trunk/drivers/scsi/bfa/bfa_ioc.c b/trunk/drivers/scsi/bfa/bfa_ioc.c index d6c2bf3865d2..6c7e0339dda4 100644 --- a/trunk/drivers/scsi/bfa/bfa_ioc.c +++ b/trunk/drivers/scsi/bfa/bfa_ioc.c @@ -17,7 +17,7 @@ #include "bfad_drv.h" #include "bfa_ioc.h" -#include "bfi_reg.h" +#include "bfi_ctreg.h" #include "bfa_defs.h" #include "bfa_defs_svc.h" @@ -29,8 +29,8 @@ BFA_TRC_FILE(CNA, IOC); #define BFA_IOC_TOV 3000 /* msecs */ #define BFA_IOC_HWSEM_TOV 500 /* msecs */ #define BFA_IOC_HB_TOV 500 /* msecs */ +#define BFA_IOC_HWINIT_MAX 5 #define BFA_IOC_TOV_RECOVER BFA_IOC_HB_TOV -#define BFA_IOC_POLL_TOV BFA_TIMER_FREQ #define bfa_ioc_timer_start(__ioc) \ bfa_timer_begin((__ioc)->timer_mod, &(__ioc)->ioc_timer, \ @@ -79,17 +79,14 @@ bfa_boolean_t bfa_auto_recover = BFA_TRUE; static void bfa_ioc_hw_sem_get(struct bfa_ioc_s *ioc); static void bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force); static void bfa_ioc_timeout(void *ioc); -static void bfa_ioc_poll_fwinit(struct bfa_ioc_s *ioc); static void bfa_ioc_send_enable(struct bfa_ioc_s *ioc); static void bfa_ioc_send_disable(struct bfa_ioc_s *ioc); static void bfa_ioc_send_getattr(struct bfa_ioc_s *ioc); static void bfa_ioc_hb_monitor(struct bfa_ioc_s *ioc); static void bfa_ioc_mbox_poll(struct bfa_ioc_s *ioc); -static void bfa_ioc_mbox_flush(struct bfa_ioc_s *ioc); +static void bfa_ioc_mbox_hbfail(struct bfa_ioc_s *ioc); static void bfa_ioc_recover(struct bfa_ioc_s *ioc); static void bfa_ioc_check_attr_wwns(struct bfa_ioc_s *ioc); -static void bfa_ioc_event_notify(struct bfa_ioc_s *ioc , - enum bfa_ioc_event_e event); static void bfa_ioc_disable_comp(struct bfa_ioc_s *ioc); static void bfa_ioc_lpu_stop(struct bfa_ioc_s *ioc); static void bfa_ioc_debug_save_ftrc(struct bfa_ioc_s *ioc); @@ -108,12 +105,11 @@ enum ioc_event { IOC_E_ENABLED = 5, /* f/w enabled */ IOC_E_FWRSP_GETATTR = 6, /* IOC get attribute response */ IOC_E_DISABLED = 7, /* f/w disabled */ - IOC_E_PFFAILED = 8, /* failure notice by iocpf sm */ - IOC_E_HBFAIL = 9, /* heartbeat failure */ - IOC_E_HWERROR = 10, /* hardware error interrupt */ - IOC_E_TIMEOUT = 11, /* timeout */ - IOC_E_HWFAILED = 12, /* PCI mapping failure notice */ - IOC_E_FWRSP_ACQ_ADDR = 13, /* Acquiring address */ + IOC_E_INITFAILED = 8, /* failure notice by iocpf sm */ + IOC_E_PFFAILED = 9, /* failure notice by iocpf sm */ + IOC_E_HBFAIL = 10, /* heartbeat failure */ + IOC_E_HWERROR = 11, /* hardware error interrupt */ + IOC_E_TIMEOUT = 12, /* timeout */ }; bfa_fsm_state_decl(bfa_ioc, uninit, struct bfa_ioc_s, enum ioc_event); @@ -125,8 +121,6 @@ bfa_fsm_state_decl(bfa_ioc, fail_retry, struct bfa_ioc_s, enum ioc_event); bfa_fsm_state_decl(bfa_ioc, fail, struct bfa_ioc_s, enum ioc_event); bfa_fsm_state_decl(bfa_ioc, disabling, struct bfa_ioc_s, enum ioc_event); bfa_fsm_state_decl(bfa_ioc, disabled, struct bfa_ioc_s, enum ioc_event); -bfa_fsm_state_decl(bfa_ioc, hwfail, struct bfa_ioc_s, enum ioc_event); -bfa_fsm_state_decl(bfa_ioc, acq_addr, struct bfa_ioc_s, enum ioc_event); static struct bfa_sm_table_s ioc_sm_table[] = { {BFA_SM(bfa_ioc_sm_uninit), BFA_IOC_UNINIT}, @@ -138,8 +132,6 @@ static struct bfa_sm_table_s ioc_sm_table[] = { {BFA_SM(bfa_ioc_sm_fail), BFA_IOC_FAIL}, {BFA_SM(bfa_ioc_sm_disabling), BFA_IOC_DISABLING}, {BFA_SM(bfa_ioc_sm_disabled), BFA_IOC_DISABLED}, - {BFA_SM(bfa_ioc_sm_hwfail), BFA_IOC_HWFAIL}, - {BFA_SM(bfa_ioc_sm_acq_addr), BFA_IOC_ACQ_ADDR}, }; /* @@ -151,9 +143,9 @@ static struct bfa_sm_table_s ioc_sm_table[] = { bfa_iocpf_timeout, (__ioc), BFA_IOC_TOV) #define bfa_iocpf_timer_stop(__ioc) bfa_timer_stop(&(__ioc)->ioc_timer) -#define bfa_iocpf_poll_timer_start(__ioc) \ +#define bfa_iocpf_recovery_timer_start(__ioc) \ bfa_timer_begin((__ioc)->timer_mod, &(__ioc)->ioc_timer, \ - bfa_iocpf_poll_timeout, (__ioc), BFA_IOC_POLL_TOV) + bfa_iocpf_timeout, (__ioc), BFA_IOC_TOV_RECOVER) #define bfa_sem_timer_start(__ioc) \ bfa_timer_begin((__ioc)->timer_mod, &(__ioc)->sem_timer, \ @@ -165,7 +157,6 @@ static struct bfa_sm_table_s ioc_sm_table[] = { */ static void bfa_iocpf_timeout(void *ioc_arg); static void bfa_iocpf_sem_timeout(void *ioc_arg); -static void bfa_iocpf_poll_timeout(void *ioc_arg); /* * IOCPF state machine events @@ -182,7 +173,6 @@ enum iocpf_event { IOCPF_E_GETATTRFAIL = 9, /* init fail notice by ioc sm */ IOCPF_E_SEMLOCKED = 10, /* h/w semaphore is locked */ IOCPF_E_TIMEOUT = 11, /* f/w response timeout */ - IOCPF_E_SEM_ERROR = 12, /* h/w sem mapping error */ }; /* @@ -324,16 +314,11 @@ bfa_ioc_sm_enabling(struct bfa_ioc_s *ioc, enum ioc_event event) /* !!! fall through !!! */ case IOC_E_HWERROR: ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE); - bfa_fsm_set_state(ioc, bfa_ioc_sm_fail); + bfa_fsm_set_state(ioc, bfa_ioc_sm_fail_retry); if (event != IOC_E_PFFAILED) bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_INITFAIL); break; - case IOC_E_HWFAILED: - ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE); - bfa_fsm_set_state(ioc, bfa_ioc_sm_hwfail); - break; - case IOC_E_DISABLE: bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling); break; @@ -371,23 +356,17 @@ bfa_ioc_sm_getattr(struct bfa_ioc_s *ioc, enum ioc_event event) case IOC_E_FWRSP_GETATTR: bfa_ioc_timer_stop(ioc); bfa_ioc_check_attr_wwns(ioc); - bfa_ioc_hb_monitor(ioc); bfa_fsm_set_state(ioc, bfa_ioc_sm_op); break; - case IOC_E_FWRSP_ACQ_ADDR: - bfa_ioc_timer_stop(ioc); - bfa_ioc_hb_monitor(ioc); - bfa_fsm_set_state(ioc, bfa_ioc_sm_acq_addr); break; - case IOC_E_PFFAILED: case IOC_E_HWERROR: bfa_ioc_timer_stop(ioc); /* !!! fall through !!! */ case IOC_E_TIMEOUT: ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE); - bfa_fsm_set_state(ioc, bfa_ioc_sm_fail); + bfa_fsm_set_state(ioc, bfa_ioc_sm_fail_retry); if (event != IOC_E_PFFAILED) bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_GETATTRFAIL); break; @@ -405,50 +384,6 @@ bfa_ioc_sm_getattr(struct bfa_ioc_s *ioc, enum ioc_event event) } } -/* - * Acquiring address from fabric (entry function) - */ -static void -bfa_ioc_sm_acq_addr_entry(struct bfa_ioc_s *ioc) -{ -} - -/* - * Acquiring address from the fabric - */ -static void -bfa_ioc_sm_acq_addr(struct bfa_ioc_s *ioc, enum ioc_event event) -{ - bfa_trc(ioc, event); - - switch (event) { - case IOC_E_FWRSP_GETATTR: - bfa_ioc_check_attr_wwns(ioc); - bfa_fsm_set_state(ioc, bfa_ioc_sm_op); - break; - - case IOC_E_PFFAILED: - case IOC_E_HWERROR: - bfa_hb_timer_stop(ioc); - case IOC_E_HBFAIL: - ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE); - bfa_fsm_set_state(ioc, bfa_ioc_sm_fail); - if (event != IOC_E_PFFAILED) - bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_GETATTRFAIL); - break; - - case IOC_E_DISABLE: - bfa_hb_timer_stop(ioc); - bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling); - break; - - case IOC_E_ENABLE: - break; - - default: - bfa_sm_fault(ioc, event); - } -} static void bfa_ioc_sm_op_entry(struct bfa_ioc_s *ioc) @@ -456,7 +391,7 @@ bfa_ioc_sm_op_entry(struct bfa_ioc_s *ioc) struct bfad_s *bfad = (struct bfad_s *)ioc->bfa->bfad; ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_OK); - bfa_ioc_event_notify(ioc, BFA_IOC_E_ENABLED); + bfa_ioc_hb_monitor(ioc); BFA_LOG(KERN_INFO, bfad, bfa_log_level, "IOC enabled\n"); } @@ -479,13 +414,13 @@ bfa_ioc_sm_op(struct bfa_ioc_s *ioc, enum ioc_event event) bfa_hb_timer_stop(ioc); /* !!! fall through !!! */ case IOC_E_HBFAIL: + bfa_ioc_fail_notify(ioc); + if (ioc->iocpf.auto_recover) bfa_fsm_set_state(ioc, bfa_ioc_sm_fail_retry); else bfa_fsm_set_state(ioc, bfa_ioc_sm_fail); - bfa_ioc_fail_notify(ioc); - if (event != IOC_E_PFFAILED) bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_FAIL); break; @@ -526,11 +461,6 @@ bfa_ioc_sm_disabling(struct bfa_ioc_s *ioc, enum ioc_event event) bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_FAIL); break; - case IOC_E_HWFAILED: - bfa_fsm_set_state(ioc, bfa_ioc_sm_hwfail); - bfa_ioc_disable_comp(ioc); - break; - default: bfa_sm_fault(ioc, event); } @@ -595,14 +525,12 @@ bfa_ioc_sm_fail_retry(struct bfa_ioc_s *ioc, enum ioc_event event) * Initialization retry failed. */ ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE); - bfa_fsm_set_state(ioc, bfa_ioc_sm_fail); if (event != IOC_E_PFFAILED) bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_INITFAIL); break; - case IOC_E_HWFAILED: - ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE); - bfa_fsm_set_state(ioc, bfa_ioc_sm_hwfail); + case IOC_E_INITFAILED: + bfa_fsm_set_state(ioc, bfa_ioc_sm_fail); break; case IOC_E_ENABLE: @@ -662,35 +590,6 @@ bfa_ioc_sm_fail(struct bfa_ioc_s *ioc, enum ioc_event event) } } -static void -bfa_ioc_sm_hwfail_entry(struct bfa_ioc_s *ioc) -{ - bfa_trc(ioc, 0); -} - -static void -bfa_ioc_sm_hwfail(struct bfa_ioc_s *ioc, enum ioc_event event) -{ - bfa_trc(ioc, event); - - switch (event) { - case IOC_E_ENABLE: - ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE); - break; - - case IOC_E_DISABLE: - ioc->cbfn->disable_cbfn(ioc->bfa); - break; - - case IOC_E_DETACH: - bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit); - break; - - default: - bfa_sm_fault(ioc, event); - } -} - /* * IOCPF State Machine */ @@ -701,7 +600,7 @@ bfa_ioc_sm_hwfail(struct bfa_ioc_s *ioc, enum ioc_event event) static void bfa_iocpf_sm_reset_entry(struct bfa_iocpf_s *iocpf) { - iocpf->fw_mismatch_notified = BFA_FALSE; + iocpf->retry_count = 0; iocpf->auto_recover = bfa_auto_recover; } @@ -734,28 +633,6 @@ bfa_iocpf_sm_reset(struct bfa_iocpf_s *iocpf, enum iocpf_event event) static void bfa_iocpf_sm_fwcheck_entry(struct bfa_iocpf_s *iocpf) { - struct bfi_ioc_image_hdr_s fwhdr; - u32 fwstate = readl(iocpf->ioc->ioc_regs.ioc_fwstate); - - /* h/w sem init */ - if (fwstate == BFI_IOC_UNINIT) - goto sem_get; - - bfa_ioc_fwver_get(iocpf->ioc, &fwhdr); - - if (swab32(fwhdr.exec) == BFI_FWBOOT_TYPE_NORMAL) - goto sem_get; - - bfa_trc(iocpf->ioc, fwstate); - bfa_trc(iocpf->ioc, fwhdr.exec); - writel(BFI_IOC_UNINIT, iocpf->ioc->ioc_regs.ioc_fwstate); - - /* - * Try to lock and then unlock the semaphore. - */ - readl(iocpf->ioc->ioc_regs.ioc_sem_reg); - writel(1, iocpf->ioc->ioc_regs.ioc_sem_reg); -sem_get: bfa_ioc_hw_sem_get(iocpf->ioc); } @@ -773,6 +650,7 @@ bfa_iocpf_sm_fwcheck(struct bfa_iocpf_s *iocpf, enum iocpf_event event) case IOCPF_E_SEMLOCKED: if (bfa_ioc_firmware_lock(ioc)) { if (bfa_ioc_sync_start(ioc)) { + iocpf->retry_count = 0; bfa_ioc_sync_join(ioc); bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit); } else { @@ -786,11 +664,6 @@ bfa_iocpf_sm_fwcheck(struct bfa_iocpf_s *iocpf, enum iocpf_event event) } break; - case IOCPF_E_SEM_ERROR: - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail); - bfa_fsm_send_event(ioc, IOC_E_HWFAILED); - break; - case IOCPF_E_DISABLE: bfa_sem_timer_stop(ioc); bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset); @@ -816,10 +689,10 @@ bfa_iocpf_sm_mismatch_entry(struct bfa_iocpf_s *iocpf) /* * Call only the first time sm enters fwmismatch state. */ - if (iocpf->fw_mismatch_notified == BFA_FALSE) + if (iocpf->retry_count == 0) bfa_ioc_pf_fwmismatch(iocpf->ioc); - iocpf->fw_mismatch_notified = BFA_TRUE; + iocpf->retry_count++; bfa_iocpf_timer_start(iocpf->ioc); } @@ -884,11 +757,6 @@ bfa_iocpf_sm_semwait(struct bfa_iocpf_s *iocpf, enum iocpf_event event) } break; - case IOCPF_E_SEM_ERROR: - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail); - bfa_fsm_send_event(ioc, IOC_E_HWFAILED); - break; - case IOCPF_E_DISABLE: bfa_sem_timer_stop(ioc); bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync); @@ -902,7 +770,7 @@ bfa_iocpf_sm_semwait(struct bfa_iocpf_s *iocpf, enum iocpf_event event) static void bfa_iocpf_sm_hwinit_entry(struct bfa_iocpf_s *iocpf) { - iocpf->poll_time = 0; + bfa_iocpf_timer_start(iocpf->ioc); bfa_ioc_hwinit(iocpf->ioc, BFA_FALSE); } @@ -919,12 +787,20 @@ bfa_iocpf_sm_hwinit(struct bfa_iocpf_s *iocpf, enum iocpf_event event) switch (event) { case IOCPF_E_FWREADY: + bfa_iocpf_timer_stop(ioc); bfa_fsm_set_state(iocpf, bfa_iocpf_sm_enabling); break; + case IOCPF_E_INITFAIL: + bfa_iocpf_timer_stop(ioc); + /* + * !!! fall through !!! + */ + case IOCPF_E_TIMEOUT: writel(1, ioc->ioc_regs.ioc_sem_reg); - bfa_fsm_send_event(ioc, IOC_E_PFFAILED); + if (event == IOCPF_E_TIMEOUT) + bfa_fsm_send_event(ioc, IOC_E_PFFAILED); bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail_sync); break; @@ -944,10 +820,6 @@ static void bfa_iocpf_sm_enabling_entry(struct bfa_iocpf_s *iocpf) { bfa_iocpf_timer_start(iocpf->ioc); - /* - * Enable Interrupts before sending fw IOC ENABLE cmd. - */ - iocpf->ioc->cbfn->reset_cbfn(iocpf->ioc->bfa); bfa_ioc_send_enable(iocpf->ioc); } @@ -988,6 +860,10 @@ bfa_iocpf_sm_enabling(struct bfa_iocpf_s *iocpf, enum iocpf_event event) bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling); break; + case IOCPF_E_FWREADY: + bfa_ioc_send_enable(ioc); + break; + default: bfa_sm_fault(ioc, event); } @@ -1019,6 +895,16 @@ bfa_iocpf_sm_ready(struct bfa_iocpf_s *iocpf, enum iocpf_event event) bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail_sync); break; + case IOCPF_E_FWREADY: + if (bfa_ioc_is_operational(ioc)) { + bfa_fsm_send_event(ioc, IOC_E_PFFAILED); + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail_sync); + } else { + bfa_fsm_send_event(ioc, IOC_E_PFFAILED); + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail_sync); + } + break; + default: bfa_sm_fault(ioc, event); } @@ -1043,6 +929,7 @@ bfa_iocpf_sm_disabling(struct bfa_iocpf_s *iocpf, enum iocpf_event event) switch (event) { case IOCPF_E_FWRSP_DISABLE: + case IOCPF_E_FWREADY: bfa_iocpf_timer_stop(ioc); bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync); break; @@ -1089,11 +976,6 @@ bfa_iocpf_sm_disabling_sync(struct bfa_iocpf_s *iocpf, enum iocpf_event event) bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled); break; - case IOCPF_E_SEM_ERROR: - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail); - bfa_fsm_send_event(ioc, IOC_E_HWFAILED); - break; - case IOCPF_E_FAIL: break; @@ -1108,7 +990,6 @@ bfa_iocpf_sm_disabling_sync(struct bfa_iocpf_s *iocpf, enum iocpf_event event) static void bfa_iocpf_sm_disabled_entry(struct bfa_iocpf_s *iocpf) { - bfa_ioc_mbox_flush(iocpf->ioc); bfa_fsm_send_event(iocpf->ioc, IOC_E_DISABLED); } @@ -1121,6 +1002,7 @@ bfa_iocpf_sm_disabled(struct bfa_iocpf_s *iocpf, enum iocpf_event event) switch (event) { case IOCPF_E_ENABLE: + iocpf->retry_count = 0; bfa_fsm_set_state(iocpf, bfa_iocpf_sm_semwait); break; @@ -1137,7 +1019,6 @@ bfa_iocpf_sm_disabled(struct bfa_iocpf_s *iocpf, enum iocpf_event event) static void bfa_iocpf_sm_initfail_sync_entry(struct bfa_iocpf_s *iocpf) { - bfa_ioc_debug_save_ftrc(iocpf->ioc); bfa_ioc_hw_sem_get(iocpf->ioc); } @@ -1154,15 +1035,20 @@ bfa_iocpf_sm_initfail_sync(struct bfa_iocpf_s *iocpf, enum iocpf_event event) switch (event) { case IOCPF_E_SEMLOCKED: bfa_ioc_notify_fail(ioc); - bfa_ioc_sync_leave(ioc); - writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate); - writel(1, ioc->ioc_regs.ioc_sem_reg); - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail); - break; - - case IOCPF_E_SEM_ERROR: - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail); - bfa_fsm_send_event(ioc, IOC_E_HWFAILED); + bfa_ioc_sync_ack(ioc); + iocpf->retry_count++; + if (iocpf->retry_count >= BFA_IOC_HWINIT_MAX) { + bfa_ioc_sync_leave(ioc); + writel(1, ioc->ioc_regs.ioc_sem_reg); + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail); + } else { + if (bfa_ioc_sync_complete(ioc)) + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit); + else { + writel(1, ioc->ioc_regs.ioc_sem_reg); + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_semwait); + } + } break; case IOCPF_E_DISABLE: @@ -1187,7 +1073,7 @@ bfa_iocpf_sm_initfail_sync(struct bfa_iocpf_s *iocpf, enum iocpf_event event) static void bfa_iocpf_sm_initfail_entry(struct bfa_iocpf_s *iocpf) { - bfa_trc(iocpf->ioc, 0); + bfa_fsm_send_event(iocpf->ioc, IOC_E_INITFAILED); } /* @@ -1226,7 +1112,7 @@ bfa_iocpf_sm_fail_sync_entry(struct bfa_iocpf_s *iocpf) /* * Flush any queued up mailbox requests. */ - bfa_ioc_mbox_flush(iocpf->ioc); + bfa_ioc_mbox_hbfail(iocpf->ioc); bfa_ioc_hw_sem_get(iocpf->ioc); } @@ -1240,11 +1126,11 @@ bfa_iocpf_sm_fail_sync(struct bfa_iocpf_s *iocpf, enum iocpf_event event) switch (event) { case IOCPF_E_SEMLOCKED: + iocpf->retry_count = 0; bfa_ioc_sync_ack(ioc); bfa_ioc_notify_fail(ioc); if (!iocpf->auto_recover) { bfa_ioc_sync_leave(ioc); - writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate); writel(1, ioc->ioc_regs.ioc_sem_reg); bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail); } else { @@ -1257,11 +1143,6 @@ bfa_iocpf_sm_fail_sync(struct bfa_iocpf_s *iocpf, enum iocpf_event event) } break; - case IOCPF_E_SEM_ERROR: - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail); - bfa_fsm_send_event(ioc, IOC_E_HWFAILED); - break; - case IOCPF_E_DISABLE: bfa_sem_timer_stop(ioc); bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync); @@ -1278,7 +1159,6 @@ bfa_iocpf_sm_fail_sync(struct bfa_iocpf_s *iocpf, enum iocpf_event event) static void bfa_iocpf_sm_fail_entry(struct bfa_iocpf_s *iocpf) { - bfa_trc(iocpf->ioc, 0); } /* @@ -1305,26 +1185,21 @@ bfa_iocpf_sm_fail(struct bfa_iocpf_s *iocpf, enum iocpf_event event) * BFA IOC private functions */ -/* - * Notify common modules registered for notification. - */ -static void -bfa_ioc_event_notify(struct bfa_ioc_s *ioc, enum bfa_ioc_event_e event) -{ - struct bfa_ioc_notify_s *notify; - struct list_head *qe; - - list_for_each(qe, &ioc->notify_q) { - notify = (struct bfa_ioc_notify_s *)qe; - notify->cbfn(notify->cbarg, event); - } -} - static void bfa_ioc_disable_comp(struct bfa_ioc_s *ioc) { + struct list_head *qe; + struct bfa_ioc_hbfail_notify_s *notify; + ioc->cbfn->disable_cbfn(ioc->bfa); - bfa_ioc_event_notify(ioc, BFA_IOC_E_DISABLED); + + /* + * Notify common modules registered for notification. + */ + list_for_each(qe, &ioc->hb_notify_q) { + notify = (struct bfa_ioc_hbfail_notify_s *) qe; + notify->cbfn(notify->cbarg); + } } bfa_boolean_t @@ -1336,15 +1211,16 @@ bfa_ioc_sem_get(void __iomem *sem_reg) r32 = readl(sem_reg); - while ((r32 & 1) && (cnt < BFA_SEM_SPINCNT)) { + while (r32 && (cnt < BFA_SEM_SPINCNT)) { cnt++; udelay(2); r32 = readl(sem_reg); } - if (!(r32 & 1)) + if (r32 == 0) return BFA_TRUE; + WARN_ON(cnt >= BFA_SEM_SPINCNT); return BFA_FALSE; } @@ -1358,12 +1234,7 @@ bfa_ioc_hw_sem_get(struct bfa_ioc_s *ioc) * will return 1. Semaphore is released by writing 1 to the register */ r32 = readl(ioc->ioc_regs.ioc_sem_reg); - if (r32 == ~0) { - WARN_ON(r32 == ~0); - bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_SEM_ERROR); - return; - } - if (!(r32 & 1)) { + if (r32 == 0) { bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_SEMLOCKED); return; } @@ -1472,7 +1343,7 @@ bfa_ioc_fwver_cmp(struct bfa_ioc_s *ioc, struct bfi_ioc_image_hdr_s *fwhdr) int i; drv_fwhdr = (struct bfi_ioc_image_hdr_s *) - bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc), 0); + bfa_cb_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), 0); for (i = 0; i < BFI_IOC_MD5SUM_SZ; i++) { if (fwhdr->md5sum[i] != drv_fwhdr->md5sum[i]) { @@ -1498,7 +1369,7 @@ bfa_ioc_fwver_valid(struct bfa_ioc_s *ioc, u32 boot_env) bfa_ioc_fwver_get(ioc, &fwhdr); drv_fwhdr = (struct bfi_ioc_image_hdr_s *) - bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc), 0); + bfa_cb_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), 0); if (fwhdr.signature != drv_fwhdr->signature) { bfa_trc(ioc, fwhdr.signature); @@ -1506,8 +1377,8 @@ bfa_ioc_fwver_valid(struct bfa_ioc_s *ioc, u32 boot_env) return BFA_FALSE; } - if (swab32(fwhdr.bootenv) != boot_env) { - bfa_trc(ioc, fwhdr.bootenv); + if (swab32(fwhdr.param) != boot_env) { + bfa_trc(ioc, fwhdr.param); bfa_trc(ioc, boot_env); return BFA_FALSE; } @@ -1543,8 +1414,8 @@ bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force) bfa_trc(ioc, ioc_fwstate); - boot_type = BFI_FWBOOT_TYPE_NORMAL; - boot_env = BFI_FWBOOT_ENV_OS; + boot_type = BFI_BOOT_TYPE_NORMAL; + boot_env = BFI_BOOT_LOADER_OS; /* * check if firmware is valid @@ -1554,7 +1425,6 @@ bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force) if (!fwvalid) { bfa_ioc_boot(ioc, boot_type, boot_env); - bfa_ioc_poll_fwinit(ioc); return; } @@ -1563,7 +1433,7 @@ bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force) * just wait for an initialization completion interrupt. */ if (ioc_fwstate == BFI_IOC_INITING) { - bfa_ioc_poll_fwinit(ioc); + ioc->cbfn->reset_cbfn(ioc->bfa); return; } @@ -1582,6 +1452,7 @@ bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force) * be flushed. Otherwise MSI-X interrupts are not delivered. */ bfa_ioc_msgflush(ioc); + ioc->cbfn->reset_cbfn(ioc->bfa); bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_FWREADY); return; } @@ -1590,7 +1461,6 @@ bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force) * Initialize the h/w for any other states. */ bfa_ioc_boot(ioc, boot_type, boot_env); - bfa_ioc_poll_fwinit(ioc); } static void @@ -1638,7 +1508,7 @@ bfa_ioc_send_enable(struct bfa_ioc_s *ioc) bfi_h2i_set(enable_req.mh, BFI_MC_IOC, BFI_IOC_H2I_ENABLE_REQ, bfa_ioc_portid(ioc)); - enable_req.clscode = cpu_to_be16(ioc->clscode); + enable_req.ioc_class = ioc->ioc_mc; do_gettimeofday(&tv); enable_req.tv_sec = be32_to_cpu(tv.tv_sec); bfa_ioc_mbox_send(ioc, &enable_req, sizeof(struct bfi_ioc_ctrl_req_s)); @@ -1702,26 +1572,25 @@ bfa_ioc_download_fw(struct bfa_ioc_s *ioc, u32 boot_type, u32 loff = 0; u32 chunkno = 0; u32 i; - u32 asicmode; /* * Initialize LMEM first before code download */ bfa_ioc_lmem_init(ioc); - bfa_trc(ioc, bfa_cb_image_get_size(bfa_ioc_asic_gen(ioc))); - fwimg = bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc), chunkno); + bfa_trc(ioc, bfa_cb_image_get_size(BFA_IOC_FWIMG_TYPE(ioc))); + fwimg = bfa_cb_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), chunkno); pgnum = PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, loff); pgoff = PSS_SMEM_PGOFF(loff); writel(pgnum, ioc->ioc_regs.host_page_num_fn); - for (i = 0; i < bfa_cb_image_get_size(bfa_ioc_asic_gen(ioc)); i++) { + for (i = 0; i < bfa_cb_image_get_size(BFA_IOC_FWIMG_TYPE(ioc)); i++) { if (BFA_IOC_FLASH_CHUNK_NO(i) != chunkno) { chunkno = BFA_IOC_FLASH_CHUNK_NO(i); - fwimg = bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc), + fwimg = bfa_cb_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), BFA_IOC_FLASH_CHUNK_ADDR(chunkno)); } @@ -1747,15 +1616,11 @@ bfa_ioc_download_fw(struct bfa_ioc_s *ioc, u32 boot_type, ioc->ioc_regs.host_page_num_fn); /* - * Set boot type and device mode at the end. - */ - asicmode = BFI_FWBOOT_DEVMODE(ioc->asic_gen, ioc->asic_mode, - ioc->port0_mode, ioc->port1_mode); - bfa_mem_write(ioc->ioc_regs.smem_page_start, BFI_FWBOOT_DEVMODE_OFF, - swab32(asicmode)); - bfa_mem_write(ioc->ioc_regs.smem_page_start, BFI_FWBOOT_TYPE_OFF, + * Set boot type and boot param at the end. + */ + bfa_mem_write(ioc->ioc_regs.smem_page_start, BFI_BOOT_TYPE_OFF, swab32(boot_type)); - bfa_mem_write(ioc->ioc_regs.smem_page_start, BFI_FWBOOT_ENV_OFF, + bfa_mem_write(ioc->ioc_regs.smem_page_start, BFI_BOOT_LOADER_OFF, swab32(boot_env)); } @@ -1771,7 +1636,6 @@ bfa_ioc_getattr_reply(struct bfa_ioc_s *ioc) attr->adapter_prop = be32_to_cpu(attr->adapter_prop); attr->card_type = be32_to_cpu(attr->card_type); attr->maxfrsize = be16_to_cpu(attr->maxfrsize); - ioc->fcmode = (attr->port_mode == BFI_PORT_MODE_FC); bfa_fsm_send_event(ioc, IOC_E_FWRSP_GETATTR); } @@ -1826,7 +1690,7 @@ bfa_ioc_mbox_poll(struct bfa_ioc_s *ioc) * Cleanup any pending requests. */ static void -bfa_ioc_mbox_flush(struct bfa_ioc_s *ioc) +bfa_ioc_mbox_hbfail(struct bfa_ioc_s *ioc) { struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod; struct bfa_mbox_cmd_s *cmd; @@ -1888,7 +1752,6 @@ bfa_ioc_smem_read(struct bfa_ioc_s *ioc, void *tbuf, u32 soff, u32 sz) /* * release semaphore. */ - readl(ioc->ioc_regs.ioc_init_sem_reg); writel(1, ioc->ioc_regs.ioc_init_sem_reg); bfa_trc(ioc, pgnum); @@ -1945,7 +1808,6 @@ bfa_ioc_smem_clr(struct bfa_ioc_s *ioc, u32 soff, u32 sz) /* * release semaphore. */ - readl(ioc->ioc_regs.ioc_init_sem_reg); writel(1, ioc->ioc_regs.ioc_init_sem_reg); bfa_trc(ioc, pgnum); return BFA_STATUS_OK; @@ -1954,13 +1816,18 @@ bfa_ioc_smem_clr(struct bfa_ioc_s *ioc, u32 soff, u32 sz) static void bfa_ioc_fail_notify(struct bfa_ioc_s *ioc) { + struct list_head *qe; + struct bfa_ioc_hbfail_notify_s *notify; struct bfad_s *bfad = (struct bfad_s *)ioc->bfa->bfad; /* * Notify driver and common modules registered for notification. */ ioc->cbfn->hbfail_cbfn(ioc->bfa); - bfa_ioc_event_notify(ioc, BFA_IOC_E_FAILED); + list_for_each(qe, &ioc->hb_notify_q) { + notify = (struct bfa_ioc_hbfail_notify_s *) qe; + notify->cbfn(notify->cbarg); + } bfa_ioc_debug_save_ftrc(ioc); @@ -1997,7 +1864,6 @@ bfa_ioc_pll_init(struct bfa_ioc_s *ioc) /* * release semaphore. */ - readl(ioc->ioc_regs.ioc_init_sem_reg); writel(1, ioc->ioc_regs.ioc_init_sem_reg); return BFA_STATUS_OK; @@ -2010,6 +1876,8 @@ bfa_ioc_pll_init(struct bfa_ioc_s *ioc) void bfa_ioc_boot(struct bfa_ioc_s *ioc, u32 boot_type, u32 boot_env) { + void __iomem *rb; + bfa_ioc_stats(ioc, ioc_boots); if (bfa_ioc_pll_init(ioc) != BFA_STATUS_OK) @@ -2018,16 +1886,22 @@ bfa_ioc_boot(struct bfa_ioc_s *ioc, u32 boot_type, u32 boot_env) /* * Initialize IOC state of all functions on a chip reset. */ - if (boot_type == BFI_FWBOOT_TYPE_MEMTEST) { - writel(BFI_IOC_MEMTEST, ioc->ioc_regs.ioc_fwstate); - writel(BFI_IOC_MEMTEST, ioc->ioc_regs.alt_ioc_fwstate); + rb = ioc->pcidev.pci_bar_kva; + if (boot_type == BFI_BOOT_TYPE_MEMTEST) { + writel(BFI_IOC_MEMTEST, (rb + BFA_IOC0_STATE_REG)); + writel(BFI_IOC_MEMTEST, (rb + BFA_IOC1_STATE_REG)); } else { - writel(BFI_IOC_INITING, ioc->ioc_regs.ioc_fwstate); - writel(BFI_IOC_INITING, ioc->ioc_regs.alt_ioc_fwstate); + writel(BFI_IOC_INITING, (rb + BFA_IOC0_STATE_REG)); + writel(BFI_IOC_INITING, (rb + BFA_IOC1_STATE_REG)); } bfa_ioc_msgflush(ioc); bfa_ioc_download_fw(ioc, boot_type, boot_env); + + /* + * Enable interrupts just before starting LPU + */ + ioc->cbfn->reset_cbfn(ioc->bfa); bfa_ioc_lpu_start(ioc); } @@ -2058,17 +1932,13 @@ bfa_ioc_is_initialized(struct bfa_ioc_s *ioc) (r32 != BFI_IOC_MEMTEST)); } -bfa_boolean_t +void bfa_ioc_msgget(struct bfa_ioc_s *ioc, void *mbmsg) { __be32 *msgp = mbmsg; u32 r32; int i; - r32 = readl(ioc->ioc_regs.lpu_mbox_cmd); - if ((r32 & 1) == 0) - return BFA_FALSE; - /* * read the MBOX msg */ @@ -2084,8 +1954,6 @@ bfa_ioc_msgget(struct bfa_ioc_s *ioc, void *mbmsg) */ writel(1, ioc->ioc_regs.lpu_mbox_cmd); readl(ioc->ioc_regs.lpu_mbox_cmd); - - return BFA_TRUE; } void @@ -2102,10 +1970,11 @@ bfa_ioc_isr(struct bfa_ioc_s *ioc, struct bfi_mbmsg_s *m) case BFI_IOC_I2H_HBEAT: break; + case BFI_IOC_I2H_READY_EVENT: + bfa_fsm_send_event(iocpf, IOCPF_E_FWREADY); + break; + case BFI_IOC_I2H_ENABLE_REPLY: - ioc->port_mode = ioc->port_mode_cfg = - (enum bfa_mode_s)msg->fw_event.port_mode; - ioc->ad_cap_bm = msg->fw_event.cap_bm; bfa_fsm_send_event(iocpf, IOCPF_E_FWRSP_ENABLE); break; @@ -2117,10 +1986,6 @@ bfa_ioc_isr(struct bfa_ioc_s *ioc, struct bfi_mbmsg_s *m) bfa_ioc_getattr_reply(ioc); break; - case BFI_IOC_I2H_ACQ_ADDR_REPLY: - bfa_fsm_send_event(ioc, IOC_E_FWRSP_ACQ_ADDR); - break; - default: bfa_trc(ioc, msg->mh.msg_id); WARN_ON(1); @@ -2146,7 +2011,7 @@ bfa_ioc_attach(struct bfa_ioc_s *ioc, void *bfa, struct bfa_ioc_cbfn_s *cbfn, ioc->iocpf.ioc = ioc; bfa_ioc_mbox_attach(ioc); - INIT_LIST_HEAD(&ioc->notify_q); + INIT_LIST_HEAD(&ioc->hb_notify_q); bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit); bfa_fsm_send_event(ioc, IOC_E_RESET); @@ -2159,7 +2024,6 @@ void bfa_ioc_detach(struct bfa_ioc_s *ioc) { bfa_fsm_send_event(ioc, IOC_E_DETACH); - INIT_LIST_HEAD(&ioc->notify_q); } /* @@ -2169,80 +2033,20 @@ bfa_ioc_detach(struct bfa_ioc_s *ioc) */ void bfa_ioc_pci_init(struct bfa_ioc_s *ioc, struct bfa_pcidev_s *pcidev, - enum bfi_pcifn_class clscode) + enum bfi_mclass mc) { - ioc->clscode = clscode; + ioc->ioc_mc = mc; ioc->pcidev = *pcidev; - - /* - * Initialize IOC and device personality - */ - ioc->port0_mode = ioc->port1_mode = BFI_PORT_MODE_FC; - ioc->asic_mode = BFI_ASIC_MODE_FC; - - switch (pcidev->device_id) { - case BFA_PCI_DEVICE_ID_FC_8G1P: - case BFA_PCI_DEVICE_ID_FC_8G2P: - ioc->asic_gen = BFI_ASIC_GEN_CB; - ioc->fcmode = BFA_TRUE; - ioc->port_mode = ioc->port_mode_cfg = BFA_MODE_HBA; - ioc->ad_cap_bm = BFA_CM_HBA; - break; - - case BFA_PCI_DEVICE_ID_CT: - ioc->asic_gen = BFI_ASIC_GEN_CT; - ioc->port0_mode = ioc->port1_mode = BFI_PORT_MODE_ETH; - ioc->asic_mode = BFI_ASIC_MODE_ETH; - ioc->port_mode = ioc->port_mode_cfg = BFA_MODE_CNA; - ioc->ad_cap_bm = BFA_CM_CNA; - break; - - case BFA_PCI_DEVICE_ID_CT_FC: - ioc->asic_gen = BFI_ASIC_GEN_CT; - ioc->fcmode = BFA_TRUE; - ioc->port_mode = ioc->port_mode_cfg = BFA_MODE_HBA; - ioc->ad_cap_bm = BFA_CM_HBA; - break; - - case BFA_PCI_DEVICE_ID_CT2: - ioc->asic_gen = BFI_ASIC_GEN_CT2; - if (clscode == BFI_PCIFN_CLASS_FC && - pcidev->ssid == BFA_PCI_CT2_SSID_FC) { - ioc->asic_mode = BFI_ASIC_MODE_FC16; - ioc->fcmode = BFA_TRUE; - ioc->port_mode = ioc->port_mode_cfg = BFA_MODE_HBA; - ioc->ad_cap_bm = BFA_CM_HBA; - } else { - ioc->port0_mode = ioc->port1_mode = BFI_PORT_MODE_ETH; - ioc->asic_mode = BFI_ASIC_MODE_ETH; - if (pcidev->ssid == BFA_PCI_CT2_SSID_FCoE) { - ioc->port_mode = - ioc->port_mode_cfg = BFA_MODE_CNA; - ioc->ad_cap_bm = BFA_CM_CNA; - } else { - ioc->port_mode = - ioc->port_mode_cfg = BFA_MODE_NIC; - ioc->ad_cap_bm = BFA_CM_NIC; - } - } - break; - - default: - WARN_ON(1); - } + ioc->ctdev = bfa_asic_id_ct(ioc->pcidev.device_id); + ioc->cna = ioc->ctdev && !ioc->fcmode; /* * Set asic specific interfaces. See bfa_ioc_cb.c and bfa_ioc_ct.c */ - if (ioc->asic_gen == BFI_ASIC_GEN_CB) - bfa_ioc_set_cb_hwif(ioc); - else if (ioc->asic_gen == BFI_ASIC_GEN_CT) + if (ioc->ctdev) bfa_ioc_set_ct_hwif(ioc); - else { - WARN_ON(ioc->asic_gen != BFI_ASIC_GEN_CT2); - bfa_ioc_set_ct2_hwif(ioc); - bfa_ioc_ct2_poweron(ioc); - } + else + bfa_ioc_set_cb_hwif(ioc); bfa_ioc_map_port(ioc); bfa_ioc_reg_init(ioc); @@ -2368,38 +2172,36 @@ bfa_ioc_mbox_isr(struct bfa_ioc_s *ioc) struct bfi_mbmsg_s m; int mc; - if (bfa_ioc_msgget(ioc, &m)) { - /* - * Treat IOC message class as special. - */ - mc = m.mh.msg_class; - if (mc == BFI_MC_IOC) { - bfa_ioc_isr(ioc, &m); - return; - } - - if ((mc > BFI_MC_MAX) || (mod->mbhdlr[mc].cbfn == NULL)) - return; + bfa_ioc_msgget(ioc, &m); - mod->mbhdlr[mc].cbfn(mod->mbhdlr[mc].cbarg, &m); + /* + * Treat IOC message class as special. + */ + mc = m.mh.msg_class; + if (mc == BFI_MC_IOC) { + bfa_ioc_isr(ioc, &m); + return; } - bfa_ioc_lpu_read_stat(ioc); + if ((mc > BFI_MC_MAX) || (mod->mbhdlr[mc].cbfn == NULL)) + return; - /* - * Try to send pending mailbox commands - */ - bfa_ioc_mbox_poll(ioc); + mod->mbhdlr[mc].cbfn(mod->mbhdlr[mc].cbarg, &m); } void bfa_ioc_error_isr(struct bfa_ioc_s *ioc) { - bfa_ioc_stats(ioc, ioc_hbfails); - ioc->stats.hb_count = ioc->hb_count; bfa_fsm_send_event(ioc, IOC_E_HWERROR); } +void +bfa_ioc_set_fcmode(struct bfa_ioc_s *ioc) +{ + ioc->fcmode = BFA_TRUE; + ioc->port_id = bfa_ioc_pcifn(ioc); +} + /* * return true if IOC is disabled */ @@ -2410,15 +2212,6 @@ bfa_ioc_is_disabled(struct bfa_ioc_s *ioc) bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabled); } -/* - * Return TRUE if IOC is in acquiring address state - */ -bfa_boolean_t -bfa_ioc_is_acq_addr(struct bfa_ioc_s *ioc) -{ - return bfa_fsm_cmp_state(ioc, bfa_ioc_sm_acq_addr); -} - /* * return true if IOC firmware is different. */ @@ -2446,16 +2239,17 @@ bfa_boolean_t bfa_ioc_adapter_is_disabled(struct bfa_ioc_s *ioc) { u32 ioc_state; + void __iomem *rb = ioc->pcidev.pci_bar_kva; if (!bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabled)) return BFA_FALSE; - ioc_state = readl(ioc->ioc_regs.ioc_fwstate); + ioc_state = readl(rb + BFA_IOC0_STATE_REG); if (!bfa_ioc_state_disabled(ioc_state)) return BFA_FALSE; if (ioc->pcidev.device_id != BFA_PCI_DEVICE_ID_FC_8G1P) { - ioc_state = readl(ioc->ioc_regs.alt_ioc_fwstate); + ioc_state = readl(rb + BFA_IOC1_STATE_REG); if (!bfa_ioc_state_disabled(ioc_state)) return BFA_FALSE; } @@ -2514,21 +2308,24 @@ bfa_ioc_get_adapter_attr(struct bfa_ioc_s *ioc, bfa_ioc_get_pci_chip_rev(ioc, ad_attr->hw_ver); - ad_attr->cna_capable = bfa_ioc_is_cna(ioc); - ad_attr->trunk_capable = (ad_attr->nports > 1) && - !bfa_ioc_is_cna(ioc) && !ad_attr->is_mezz; + ad_attr->cna_capable = ioc->cna; + ad_attr->trunk_capable = (ad_attr->nports > 1) && !ioc->cna && + !ad_attr->is_mezz; } enum bfa_ioc_type_e bfa_ioc_get_type(struct bfa_ioc_s *ioc) { - if (ioc->clscode == BFI_PCIFN_CLASS_ETH) + if (!ioc->ctdev || ioc->fcmode) + return BFA_IOC_TYPE_FC; + else if (ioc->ioc_mc == BFI_MC_IOCFC) + return BFA_IOC_TYPE_FCoE; + else if (ioc->ioc_mc == BFI_MC_LL) return BFA_IOC_TYPE_LL; - - WARN_ON(ioc->clscode != BFI_PCIFN_CLASS_FC); - - return (ioc->attr->port_mode == BFI_PORT_MODE_FC) - ? BFA_IOC_TYPE_FC : BFA_IOC_TYPE_FCoE; + else { + WARN_ON(ioc->ioc_mc != BFI_MC_LL); + return BFA_IOC_TYPE_LL; + } } void @@ -2587,8 +2384,11 @@ bfa_ioc_get_adapter_model(struct bfa_ioc_s *ioc, char *model) ioc_attr = ioc->attr; + /* + * model name + */ snprintf(model, BFA_ADAPTER_MODEL_NAME_LEN, "%s-%u", - BFA_MFG_NAME, ioc_attr->card_type); + BFA_MFG_NAME, ioc_attr->card_type); } enum bfa_ioc_state @@ -2638,9 +2438,6 @@ bfa_ioc_get_attr(struct bfa_ioc_s *ioc, struct bfa_ioc_attr_s *ioc_attr) ioc_attr->state = bfa_ioc_get_state(ioc); ioc_attr->port_id = ioc->port_id; - ioc_attr->port_mode = ioc->port_mode; - ioc_attr->port_mode_cfg = ioc->port_mode_cfg; - ioc_attr->cap_bm = ioc->ad_cap_bm; ioc_attr->ioc_type = bfa_ioc_get_type(ioc); @@ -2678,6 +2475,12 @@ bfa_ioc_get_mfg_mac(struct bfa_ioc_s *ioc) return m; } +bfa_boolean_t +bfa_ioc_get_fcmode(struct bfa_ioc_s *ioc) +{ + return ioc->fcmode || !bfa_asic_id_ct(ioc->pcidev.device_id); +} + /* * Retrieve saved firmware trace from a prior IOC failure. */ @@ -2728,7 +2531,7 @@ bfa_ioc_send_fwsync(struct bfa_ioc_s *ioc) bfi_h2i_set(req->mh, BFI_MC_IOC, BFI_IOC_H2I_DBG_SYNC, bfa_ioc_portid(ioc)); - req->clscode = cpu_to_be16(ioc->clscode); + req->ioc_class = ioc->ioc_mc; bfa_ioc_mbox_queue(ioc, &cmd); } @@ -2870,7 +2673,6 @@ static void bfa_ioc_recover(struct bfa_ioc_s *ioc) { bfa_ioc_stats(ioc, ioc_hbfails); - ioc->stats.hb_count = ioc->hb_count; bfa_fsm_send_event(ioc, IOC_E_HBFAIL); } @@ -2901,34 +2703,6 @@ bfa_iocpf_sem_timeout(void *ioc_arg) bfa_ioc_hw_sem_get(ioc); } -static void -bfa_ioc_poll_fwinit(struct bfa_ioc_s *ioc) -{ - u32 fwstate = readl(ioc->ioc_regs.ioc_fwstate); - - bfa_trc(ioc, fwstate); - - if (fwstate == BFI_IOC_DISABLED) { - bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_FWREADY); - return; - } - - if (ioc->iocpf.poll_time >= BFA_IOC_TOV) - bfa_iocpf_timeout(ioc); - else { - ioc->iocpf.poll_time += BFA_IOC_POLL_TOV; - bfa_iocpf_poll_timer_start(ioc); - } -} - -static void -bfa_iocpf_poll_timeout(void *ioc_arg) -{ - struct bfa_ioc_s *ioc = (struct bfa_ioc_s *) ioc_arg; - - bfa_ioc_poll_fwinit(ioc); -} - /* * bfa timer function */ @@ -2996,2423 +2770,3 @@ bfa_timer_stop(struct bfa_timer_s *timer) list_del(&timer->qe); } - -/* - * ASIC block related - */ -static void -bfa_ablk_config_swap(struct bfa_ablk_cfg_s *cfg) -{ - struct bfa_ablk_cfg_inst_s *cfg_inst; - int i, j; - u16 be16; - u32 be32; - - for (i = 0; i < BFA_ABLK_MAX; i++) { - cfg_inst = &cfg->inst[i]; - for (j = 0; j < BFA_ABLK_MAX_PFS; j++) { - be16 = cfg_inst->pf_cfg[j].pers; - cfg_inst->pf_cfg[j].pers = be16_to_cpu(be16); - be16 = cfg_inst->pf_cfg[j].num_qpairs; - cfg_inst->pf_cfg[j].num_qpairs = be16_to_cpu(be16); - be16 = cfg_inst->pf_cfg[j].num_vectors; - cfg_inst->pf_cfg[j].num_vectors = be16_to_cpu(be16); - be32 = cfg_inst->pf_cfg[j].bw; - cfg_inst->pf_cfg[j].bw = be16_to_cpu(be32); - } - } -} - -static void -bfa_ablk_isr(void *cbarg, struct bfi_mbmsg_s *msg) -{ - struct bfa_ablk_s *ablk = (struct bfa_ablk_s *)cbarg; - struct bfi_ablk_i2h_rsp_s *rsp = (struct bfi_ablk_i2h_rsp_s *)msg; - bfa_ablk_cbfn_t cbfn; - - WARN_ON(msg->mh.msg_class != BFI_MC_ABLK); - bfa_trc(ablk->ioc, msg->mh.msg_id); - - switch (msg->mh.msg_id) { - case BFI_ABLK_I2H_QUERY: - if (rsp->status == BFA_STATUS_OK) { - memcpy(ablk->cfg, ablk->dma_addr.kva, - sizeof(struct bfa_ablk_cfg_s)); - bfa_ablk_config_swap(ablk->cfg); - ablk->cfg = NULL; - } - break; - - case BFI_ABLK_I2H_ADPT_CONFIG: - case BFI_ABLK_I2H_PORT_CONFIG: - /* update config port mode */ - ablk->ioc->port_mode_cfg = rsp->port_mode; - - case BFI_ABLK_I2H_PF_DELETE: - case BFI_ABLK_I2H_PF_UPDATE: - case BFI_ABLK_I2H_OPTROM_ENABLE: - case BFI_ABLK_I2H_OPTROM_DISABLE: - /* No-op */ - break; - - case BFI_ABLK_I2H_PF_CREATE: - *(ablk->pcifn) = rsp->pcifn; - ablk->pcifn = NULL; - break; - - default: - WARN_ON(1); - } - - ablk->busy = BFA_FALSE; - if (ablk->cbfn) { - cbfn = ablk->cbfn; - ablk->cbfn = NULL; - cbfn(ablk->cbarg, rsp->status); - } -} - -static void -bfa_ablk_notify(void *cbarg, enum bfa_ioc_event_e event) -{ - struct bfa_ablk_s *ablk = (struct bfa_ablk_s *)cbarg; - - bfa_trc(ablk->ioc, event); - - switch (event) { - case BFA_IOC_E_ENABLED: - WARN_ON(ablk->busy != BFA_FALSE); - break; - - case BFA_IOC_E_DISABLED: - case BFA_IOC_E_FAILED: - /* Fail any pending requests */ - ablk->pcifn = NULL; - if (ablk->busy) { - if (ablk->cbfn) - ablk->cbfn(ablk->cbarg, BFA_STATUS_FAILED); - ablk->cbfn = NULL; - ablk->busy = BFA_FALSE; - } - break; - - default: - WARN_ON(1); - break; - } -} - -u32 -bfa_ablk_meminfo(void) -{ - return BFA_ROUNDUP(sizeof(struct bfa_ablk_cfg_s), BFA_DMA_ALIGN_SZ); -} - -void -bfa_ablk_memclaim(struct bfa_ablk_s *ablk, u8 *dma_kva, u64 dma_pa) -{ - ablk->dma_addr.kva = dma_kva; - ablk->dma_addr.pa = dma_pa; -} - -void -bfa_ablk_attach(struct bfa_ablk_s *ablk, struct bfa_ioc_s *ioc) -{ - ablk->ioc = ioc; - - bfa_ioc_mbox_regisr(ablk->ioc, BFI_MC_ABLK, bfa_ablk_isr, ablk); - bfa_q_qe_init(&ablk->ioc_notify); - bfa_ioc_notify_init(&ablk->ioc_notify, bfa_ablk_notify, ablk); - list_add_tail(&ablk->ioc_notify.qe, &ablk->ioc->notify_q); -} - -bfa_status_t -bfa_ablk_query(struct bfa_ablk_s *ablk, struct bfa_ablk_cfg_s *ablk_cfg, - bfa_ablk_cbfn_t cbfn, void *cbarg) -{ - struct bfi_ablk_h2i_query_s *m; - - WARN_ON(!ablk_cfg); - - if (!bfa_ioc_is_operational(ablk->ioc)) { - bfa_trc(ablk->ioc, BFA_STATUS_IOC_FAILURE); - return BFA_STATUS_IOC_FAILURE; - } - - if (ablk->busy) { - bfa_trc(ablk->ioc, BFA_STATUS_DEVBUSY); - return BFA_STATUS_DEVBUSY; - } - - ablk->cfg = ablk_cfg; - ablk->cbfn = cbfn; - ablk->cbarg = cbarg; - ablk->busy = BFA_TRUE; - - m = (struct bfi_ablk_h2i_query_s *)ablk->mb.msg; - bfi_h2i_set(m->mh, BFI_MC_ABLK, BFI_ABLK_H2I_QUERY, - bfa_ioc_portid(ablk->ioc)); - bfa_dma_be_addr_set(m->addr, ablk->dma_addr.pa); - bfa_ioc_mbox_queue(ablk->ioc, &ablk->mb); - - return BFA_STATUS_OK; -} - -bfa_status_t -bfa_ablk_pf_create(struct bfa_ablk_s *ablk, u16 *pcifn, - u8 port, enum bfi_pcifn_class personality, int bw, - bfa_ablk_cbfn_t cbfn, void *cbarg) -{ - struct bfi_ablk_h2i_pf_req_s *m; - - if (!bfa_ioc_is_operational(ablk->ioc)) { - bfa_trc(ablk->ioc, BFA_STATUS_IOC_FAILURE); - return BFA_STATUS_IOC_FAILURE; - } - - if (ablk->busy) { - bfa_trc(ablk->ioc, BFA_STATUS_DEVBUSY); - return BFA_STATUS_DEVBUSY; - } - - ablk->pcifn = pcifn; - ablk->cbfn = cbfn; - ablk->cbarg = cbarg; - ablk->busy = BFA_TRUE; - - m = (struct bfi_ablk_h2i_pf_req_s *)ablk->mb.msg; - bfi_h2i_set(m->mh, BFI_MC_ABLK, BFI_ABLK_H2I_PF_CREATE, - bfa_ioc_portid(ablk->ioc)); - m->pers = cpu_to_be16((u16)personality); - m->bw = cpu_to_be32(bw); - m->port = port; - bfa_ioc_mbox_queue(ablk->ioc, &ablk->mb); - - return BFA_STATUS_OK; -} - -bfa_status_t -bfa_ablk_pf_delete(struct bfa_ablk_s *ablk, int pcifn, - bfa_ablk_cbfn_t cbfn, void *cbarg) -{ - struct bfi_ablk_h2i_pf_req_s *m; - - if (!bfa_ioc_is_operational(ablk->ioc)) { - bfa_trc(ablk->ioc, BFA_STATUS_IOC_FAILURE); - return BFA_STATUS_IOC_FAILURE; - } - - if (ablk->busy) { - bfa_trc(ablk->ioc, BFA_STATUS_DEVBUSY); - return BFA_STATUS_DEVBUSY; - } - - ablk->cbfn = cbfn; - ablk->cbarg = cbarg; - ablk->busy = BFA_TRUE; - - m = (struct bfi_ablk_h2i_pf_req_s *)ablk->mb.msg; - bfi_h2i_set(m->mh, BFI_MC_ABLK, BFI_ABLK_H2I_PF_DELETE, - bfa_ioc_portid(ablk->ioc)); - m->pcifn = (u8)pcifn; - bfa_ioc_mbox_queue(ablk->ioc, &ablk->mb); - - return BFA_STATUS_OK; -} - -bfa_status_t -bfa_ablk_adapter_config(struct bfa_ablk_s *ablk, enum bfa_mode_s mode, - int max_pf, int max_vf, bfa_ablk_cbfn_t cbfn, void *cbarg) -{ - struct bfi_ablk_h2i_cfg_req_s *m; - - if (!bfa_ioc_is_operational(ablk->ioc)) { - bfa_trc(ablk->ioc, BFA_STATUS_IOC_FAILURE); - return BFA_STATUS_IOC_FAILURE; - } - - if (ablk->busy) { - bfa_trc(ablk->ioc, BFA_STATUS_DEVBUSY); - return BFA_STATUS_DEVBUSY; - } - - ablk->cbfn = cbfn; - ablk->cbarg = cbarg; - ablk->busy = BFA_TRUE; - - m = (struct bfi_ablk_h2i_cfg_req_s *)ablk->mb.msg; - bfi_h2i_set(m->mh, BFI_MC_ABLK, BFI_ABLK_H2I_ADPT_CONFIG, - bfa_ioc_portid(ablk->ioc)); - m->mode = (u8)mode; - m->max_pf = (u8)max_pf; - m->max_vf = (u8)max_vf; - bfa_ioc_mbox_queue(ablk->ioc, &ablk->mb); - - return BFA_STATUS_OK; -} - -bfa_status_t -bfa_ablk_port_config(struct bfa_ablk_s *ablk, int port, enum bfa_mode_s mode, - int max_pf, int max_vf, bfa_ablk_cbfn_t cbfn, void *cbarg) -{ - struct bfi_ablk_h2i_cfg_req_s *m; - - if (!bfa_ioc_is_operational(ablk->ioc)) { - bfa_trc(ablk->ioc, BFA_STATUS_IOC_FAILURE); - return BFA_STATUS_IOC_FAILURE; - } - - if (ablk->busy) { - bfa_trc(ablk->ioc, BFA_STATUS_DEVBUSY); - return BFA_STATUS_DEVBUSY; - } - - ablk->cbfn = cbfn; - ablk->cbarg = cbarg; - ablk->busy = BFA_TRUE; - - m = (struct bfi_ablk_h2i_cfg_req_s *)ablk->mb.msg; - bfi_h2i_set(m->mh, BFI_MC_ABLK, BFI_ABLK_H2I_PORT_CONFIG, - bfa_ioc_portid(ablk->ioc)); - m->port = (u8)port; - m->mode = (u8)mode; - m->max_pf = (u8)max_pf; - m->max_vf = (u8)max_vf; - bfa_ioc_mbox_queue(ablk->ioc, &ablk->mb); - - return BFA_STATUS_OK; -} - -bfa_status_t -bfa_ablk_pf_update(struct bfa_ablk_s *ablk, int pcifn, int bw, - bfa_ablk_cbfn_t cbfn, void *cbarg) -{ - struct bfi_ablk_h2i_pf_req_s *m; - - if (!bfa_ioc_is_operational(ablk->ioc)) { - bfa_trc(ablk->ioc, BFA_STATUS_IOC_FAILURE); - return BFA_STATUS_IOC_FAILURE; - } - - if (ablk->busy) { - bfa_trc(ablk->ioc, BFA_STATUS_DEVBUSY); - return BFA_STATUS_DEVBUSY; - } - - ablk->cbfn = cbfn; - ablk->cbarg = cbarg; - ablk->busy = BFA_TRUE; - - m = (struct bfi_ablk_h2i_pf_req_s *)ablk->mb.msg; - bfi_h2i_set(m->mh, BFI_MC_ABLK, BFI_ABLK_H2I_PF_UPDATE, - bfa_ioc_portid(ablk->ioc)); - m->pcifn = (u8)pcifn; - m->bw = cpu_to_be32(bw); - bfa_ioc_mbox_queue(ablk->ioc, &ablk->mb); - - return BFA_STATUS_OK; -} - -bfa_status_t -bfa_ablk_optrom_en(struct bfa_ablk_s *ablk, bfa_ablk_cbfn_t cbfn, void *cbarg) -{ - struct bfi_ablk_h2i_optrom_s *m; - - if (!bfa_ioc_is_operational(ablk->ioc)) { - bfa_trc(ablk->ioc, BFA_STATUS_IOC_FAILURE); - return BFA_STATUS_IOC_FAILURE; - } - - if (ablk->busy) { - bfa_trc(ablk->ioc, BFA_STATUS_DEVBUSY); - return BFA_STATUS_DEVBUSY; - } - - ablk->cbfn = cbfn; - ablk->cbarg = cbarg; - ablk->busy = BFA_TRUE; - - m = (struct bfi_ablk_h2i_optrom_s *)ablk->mb.msg; - bfi_h2i_set(m->mh, BFI_MC_ABLK, BFI_ABLK_H2I_OPTROM_ENABLE, - bfa_ioc_portid(ablk->ioc)); - bfa_ioc_mbox_queue(ablk->ioc, &ablk->mb); - - return BFA_STATUS_OK; -} - -bfa_status_t -bfa_ablk_optrom_dis(struct bfa_ablk_s *ablk, bfa_ablk_cbfn_t cbfn, void *cbarg) -{ - struct bfi_ablk_h2i_optrom_s *m; - - if (!bfa_ioc_is_operational(ablk->ioc)) { - bfa_trc(ablk->ioc, BFA_STATUS_IOC_FAILURE); - return BFA_STATUS_IOC_FAILURE; - } - - if (ablk->busy) { - bfa_trc(ablk->ioc, BFA_STATUS_DEVBUSY); - return BFA_STATUS_DEVBUSY; - } - - ablk->cbfn = cbfn; - ablk->cbarg = cbarg; - ablk->busy = BFA_TRUE; - - m = (struct bfi_ablk_h2i_optrom_s *)ablk->mb.msg; - bfi_h2i_set(m->mh, BFI_MC_ABLK, BFI_ABLK_H2I_OPTROM_DISABLE, - bfa_ioc_portid(ablk->ioc)); - bfa_ioc_mbox_queue(ablk->ioc, &ablk->mb); - - return BFA_STATUS_OK; -} - -/* - * SFP module specific - */ - -/* forward declarations */ -static void bfa_sfp_getdata_send(struct bfa_sfp_s *sfp); -static void bfa_sfp_media_get(struct bfa_sfp_s *sfp); -static bfa_status_t bfa_sfp_speed_valid(struct bfa_sfp_s *sfp, - enum bfa_port_speed portspeed); - -static void -bfa_cb_sfp_show(struct bfa_sfp_s *sfp) -{ - bfa_trc(sfp, sfp->lock); - if (sfp->cbfn) - sfp->cbfn(sfp->cbarg, sfp->status); - sfp->lock = 0; - sfp->cbfn = NULL; -} - -static void -bfa_cb_sfp_state_query(struct bfa_sfp_s *sfp) -{ - bfa_trc(sfp, sfp->portspeed); - if (sfp->media) { - bfa_sfp_media_get(sfp); - if (sfp->state_query_cbfn) - sfp->state_query_cbfn(sfp->state_query_cbarg, - sfp->status); - sfp->media = NULL; - } - - if (sfp->portspeed) { - sfp->status = bfa_sfp_speed_valid(sfp, sfp->portspeed); - if (sfp->state_query_cbfn) - sfp->state_query_cbfn(sfp->state_query_cbarg, - sfp->status); - sfp->portspeed = BFA_PORT_SPEED_UNKNOWN; - } - - sfp->state_query_lock = 0; - sfp->state_query_cbfn = NULL; -} - -/* - * IOC event handler. - */ -static void -bfa_sfp_notify(void *sfp_arg, enum bfa_ioc_event_e event) -{ - struct bfa_sfp_s *sfp = sfp_arg; - - bfa_trc(sfp, event); - bfa_trc(sfp, sfp->lock); - bfa_trc(sfp, sfp->state_query_lock); - - switch (event) { - case BFA_IOC_E_DISABLED: - case BFA_IOC_E_FAILED: - if (sfp->lock) { - sfp->status = BFA_STATUS_IOC_FAILURE; - bfa_cb_sfp_show(sfp); - } - - if (sfp->state_query_lock) { - sfp->status = BFA_STATUS_IOC_FAILURE; - bfa_cb_sfp_state_query(sfp); - } - break; - - default: - break; - } -} - -/* - * SFP get data send - */ -static void -bfa_sfp_getdata_send(struct bfa_sfp_s *sfp) -{ - struct bfi_sfp_req_s *req = (struct bfi_sfp_req_s *)sfp->mbcmd.msg; - - bfa_trc(sfp, req->memtype); - - /* build host command */ - bfi_h2i_set(req->mh, BFI_MC_SFP, BFI_SFP_H2I_SHOW, - bfa_ioc_portid(sfp->ioc)); - - /* send mbox cmd */ - bfa_ioc_mbox_queue(sfp->ioc, &sfp->mbcmd); -} - -/* - * SFP is valid, read sfp data - */ -static void -bfa_sfp_getdata(struct bfa_sfp_s *sfp, enum bfi_sfp_mem_e memtype) -{ - struct bfi_sfp_req_s *req = (struct bfi_sfp_req_s *)sfp->mbcmd.msg; - - WARN_ON(sfp->lock != 0); - bfa_trc(sfp, sfp->state); - - sfp->lock = 1; - sfp->memtype = memtype; - req->memtype = memtype; - - /* Setup SG list */ - bfa_alen_set(&req->alen, sizeof(struct sfp_mem_s), sfp->dbuf_pa); - - bfa_sfp_getdata_send(sfp); -} - -/* - * SFP show complete - */ -static void -bfa_sfp_show_comp(struct bfa_sfp_s *sfp, struct bfi_mbmsg_s *msg) -{ - struct bfi_sfp_rsp_s *rsp = (struct bfi_sfp_rsp_s *) msg; - - if (!sfp->lock) { - /* - * receiving response after ioc failure - */ - bfa_trc(sfp, sfp->lock); - return; - } - - bfa_trc(sfp, rsp->status); - if (rsp->status == BFA_STATUS_OK) { - sfp->data_valid = 1; - if (sfp->state == BFA_SFP_STATE_VALID) - sfp->status = BFA_STATUS_OK; - else if (sfp->state == BFA_SFP_STATE_UNSUPPORT) - sfp->status = BFA_STATUS_SFP_UNSUPP; - else - bfa_trc(sfp, sfp->state); - } else { - sfp->data_valid = 0; - sfp->status = rsp->status; - /* sfpshow shouldn't change sfp state */ - } - - bfa_trc(sfp, sfp->memtype); - if (sfp->memtype == BFI_SFP_MEM_DIAGEXT) { - bfa_trc(sfp, sfp->data_valid); - if (sfp->data_valid) { - u32 size = sizeof(struct sfp_mem_s); - u8 *des = (u8 *) &(sfp->sfpmem->srlid_base); - memcpy(des, sfp->dbuf_kva, size); - } - /* - * Queue completion callback. - */ - bfa_cb_sfp_show(sfp); - } else - sfp->lock = 0; - - bfa_trc(sfp, sfp->state_query_lock); - if (sfp->state_query_lock) { - sfp->state = rsp->state; - /* Complete callback */ - bfa_cb_sfp_state_query(sfp); - } -} - -/* - * SFP query fw sfp state - */ -static void -bfa_sfp_state_query(struct bfa_sfp_s *sfp) -{ - struct bfi_sfp_req_s *req = (struct bfi_sfp_req_s *)sfp->mbcmd.msg; - - /* Should not be doing query if not in _INIT state */ - WARN_ON(sfp->state != BFA_SFP_STATE_INIT); - WARN_ON(sfp->state_query_lock != 0); - bfa_trc(sfp, sfp->state); - - sfp->state_query_lock = 1; - req->memtype = 0; - - if (!sfp->lock) - bfa_sfp_getdata(sfp, BFI_SFP_MEM_ALL); -} - -static void -bfa_sfp_media_get(struct bfa_sfp_s *sfp) -{ - enum bfa_defs_sfp_media_e *media = sfp->media; - - *media = BFA_SFP_MEDIA_UNKNOWN; - - if (sfp->state == BFA_SFP_STATE_UNSUPPORT) - *media = BFA_SFP_MEDIA_UNSUPPORT; - else if (sfp->state == BFA_SFP_STATE_VALID) { - union sfp_xcvr_e10g_code_u e10g; - struct sfp_mem_s *sfpmem = (struct sfp_mem_s *)sfp->dbuf_kva; - u16 xmtr_tech = (sfpmem->srlid_base.xcvr[4] & 0x3) << 7 | - (sfpmem->srlid_base.xcvr[5] >> 1); - - e10g.b = sfpmem->srlid_base.xcvr[0]; - bfa_trc(sfp, e10g.b); - bfa_trc(sfp, xmtr_tech); - /* check fc transmitter tech */ - if ((xmtr_tech & SFP_XMTR_TECH_CU) || - (xmtr_tech & SFP_XMTR_TECH_CP) || - (xmtr_tech & SFP_XMTR_TECH_CA)) - *media = BFA_SFP_MEDIA_CU; - else if ((xmtr_tech & SFP_XMTR_TECH_EL_INTRA) || - (xmtr_tech & SFP_XMTR_TECH_EL_INTER)) - *media = BFA_SFP_MEDIA_EL; - else if ((xmtr_tech & SFP_XMTR_TECH_LL) || - (xmtr_tech & SFP_XMTR_TECH_LC)) - *media = BFA_SFP_MEDIA_LW; - else if ((xmtr_tech & SFP_XMTR_TECH_SL) || - (xmtr_tech & SFP_XMTR_TECH_SN) || - (xmtr_tech & SFP_XMTR_TECH_SA)) - *media = BFA_SFP_MEDIA_SW; - /* Check 10G Ethernet Compilance code */ - else if (e10g.b & 0x10) - *media = BFA_SFP_MEDIA_SW; - else if (e10g.b & 0x60) - *media = BFA_SFP_MEDIA_LW; - else if (e10g.r.e10g_unall & 0x80) - *media = BFA_SFP_MEDIA_UNKNOWN; - else - bfa_trc(sfp, 0); - } else - bfa_trc(sfp, sfp->state); -} - -static bfa_status_t -bfa_sfp_speed_valid(struct bfa_sfp_s *sfp, enum bfa_port_speed portspeed) -{ - struct sfp_mem_s *sfpmem = (struct sfp_mem_s *)sfp->dbuf_kva; - struct sfp_xcvr_s *xcvr = (struct sfp_xcvr_s *) sfpmem->srlid_base.xcvr; - union sfp_xcvr_fc3_code_u fc3 = xcvr->fc3; - union sfp_xcvr_e10g_code_u e10g = xcvr->e10g; - - if (portspeed == BFA_PORT_SPEED_10GBPS) { - if (e10g.r.e10g_sr || e10g.r.e10g_lr) - return BFA_STATUS_OK; - else { - bfa_trc(sfp, e10g.b); - return BFA_STATUS_UNSUPP_SPEED; - } - } - if (((portspeed & BFA_PORT_SPEED_16GBPS) && fc3.r.mb1600) || - ((portspeed & BFA_PORT_SPEED_8GBPS) && fc3.r.mb800) || - ((portspeed & BFA_PORT_SPEED_4GBPS) && fc3.r.mb400) || - ((portspeed & BFA_PORT_SPEED_2GBPS) && fc3.r.mb200) || - ((portspeed & BFA_PORT_SPEED_1GBPS) && fc3.r.mb100)) - return BFA_STATUS_OK; - else { - bfa_trc(sfp, portspeed); - bfa_trc(sfp, fc3.b); - bfa_trc(sfp, e10g.b); - return BFA_STATUS_UNSUPP_SPEED; - } -} - -/* - * SFP hmbox handler - */ -void -bfa_sfp_intr(void *sfparg, struct bfi_mbmsg_s *msg) -{ - struct bfa_sfp_s *sfp = sfparg; - - switch (msg->mh.msg_id) { - case BFI_SFP_I2H_SHOW: - bfa_sfp_show_comp(sfp, msg); - break; - - case BFI_SFP_I2H_SCN: - bfa_trc(sfp, msg->mh.msg_id); - break; - - default: - bfa_trc(sfp, msg->mh.msg_id); - WARN_ON(1); - } -} - -/* - * Return DMA memory needed by sfp module. - */ -u32 -bfa_sfp_meminfo(void) -{ - return BFA_ROUNDUP(sizeof(struct sfp_mem_s), BFA_DMA_ALIGN_SZ); -} - -/* - * Attach virtual and physical memory for SFP. - */ -void -bfa_sfp_attach(struct bfa_sfp_s *sfp, struct bfa_ioc_s *ioc, void *dev, - struct bfa_trc_mod_s *trcmod) -{ - sfp->dev = dev; - sfp->ioc = ioc; - sfp->trcmod = trcmod; - - sfp->cbfn = NULL; - sfp->cbarg = NULL; - sfp->sfpmem = NULL; - sfp->lock = 0; - sfp->data_valid = 0; - sfp->state = BFA_SFP_STATE_INIT; - sfp->state_query_lock = 0; - sfp->state_query_cbfn = NULL; - sfp->state_query_cbarg = NULL; - sfp->media = NULL; - sfp->portspeed = BFA_PORT_SPEED_UNKNOWN; - sfp->is_elb = BFA_FALSE; - - bfa_ioc_mbox_regisr(sfp->ioc, BFI_MC_SFP, bfa_sfp_intr, sfp); - bfa_q_qe_init(&sfp->ioc_notify); - bfa_ioc_notify_init(&sfp->ioc_notify, bfa_sfp_notify, sfp); - list_add_tail(&sfp->ioc_notify.qe, &sfp->ioc->notify_q); -} - -/* - * Claim Memory for SFP - */ -void -bfa_sfp_memclaim(struct bfa_sfp_s *sfp, u8 *dm_kva, u64 dm_pa) -{ - sfp->dbuf_kva = dm_kva; - sfp->dbuf_pa = dm_pa; - memset(sfp->dbuf_kva, 0, sizeof(struct sfp_mem_s)); - - dm_kva += BFA_ROUNDUP(sizeof(struct sfp_mem_s), BFA_DMA_ALIGN_SZ); - dm_pa += BFA_ROUNDUP(sizeof(struct sfp_mem_s), BFA_DMA_ALIGN_SZ); -} - -/* - * Show SFP eeprom content - * - * @param[in] sfp - bfa sfp module - * - * @param[out] sfpmem - sfp eeprom data - * - */ -bfa_status_t -bfa_sfp_show(struct bfa_sfp_s *sfp, struct sfp_mem_s *sfpmem, - bfa_cb_sfp_t cbfn, void *cbarg) -{ - - if (!bfa_ioc_is_operational(sfp->ioc)) { - bfa_trc(sfp, 0); - return BFA_STATUS_IOC_NON_OP; - } - - if (sfp->lock) { - bfa_trc(sfp, 0); - return BFA_STATUS_DEVBUSY; - } - - sfp->cbfn = cbfn; - sfp->cbarg = cbarg; - sfp->sfpmem = sfpmem; - - bfa_sfp_getdata(sfp, BFI_SFP_MEM_DIAGEXT); - return BFA_STATUS_OK; -} - -/* - * Return SFP Media type - * - * @param[in] sfp - bfa sfp module - * - * @param[out] media - port speed from user - * - */ -bfa_status_t -bfa_sfp_media(struct bfa_sfp_s *sfp, enum bfa_defs_sfp_media_e *media, - bfa_cb_sfp_t cbfn, void *cbarg) -{ - if (!bfa_ioc_is_operational(sfp->ioc)) { - bfa_trc(sfp, 0); - return BFA_STATUS_IOC_NON_OP; - } - - sfp->media = media; - if (sfp->state == BFA_SFP_STATE_INIT) { - if (sfp->state_query_lock) { - bfa_trc(sfp, 0); - return BFA_STATUS_DEVBUSY; - } else { - sfp->state_query_cbfn = cbfn; - sfp->state_query_cbarg = cbarg; - bfa_sfp_state_query(sfp); - return BFA_STATUS_SFP_NOT_READY; - } - } - - bfa_sfp_media_get(sfp); - return BFA_STATUS_OK; -} - -/* - * Check if user set port speed is allowed by the SFP - * - * @param[in] sfp - bfa sfp module - * @param[in] portspeed - port speed from user - * - */ -bfa_status_t -bfa_sfp_speed(struct bfa_sfp_s *sfp, enum bfa_port_speed portspeed, - bfa_cb_sfp_t cbfn, void *cbarg) -{ - WARN_ON(portspeed == BFA_PORT_SPEED_UNKNOWN); - - if (!bfa_ioc_is_operational(sfp->ioc)) - return BFA_STATUS_IOC_NON_OP; - - /* For Mezz card, all speed is allowed */ - if (bfa_mfg_is_mezz(sfp->ioc->attr->card_type)) - return BFA_STATUS_OK; - - /* Check SFP state */ - sfp->portspeed = portspeed; - if (sfp->state == BFA_SFP_STATE_INIT) { - if (sfp->state_query_lock) { - bfa_trc(sfp, 0); - return BFA_STATUS_DEVBUSY; - } else { - sfp->state_query_cbfn = cbfn; - sfp->state_query_cbarg = cbarg; - bfa_sfp_state_query(sfp); - return BFA_STATUS_SFP_NOT_READY; - } - } - - if (sfp->state == BFA_SFP_STATE_REMOVED || - sfp->state == BFA_SFP_STATE_FAILED) { - bfa_trc(sfp, sfp->state); - return BFA_STATUS_NO_SFP_DEV; - } - - if (sfp->state == BFA_SFP_STATE_INSERTED) { - bfa_trc(sfp, sfp->state); - return BFA_STATUS_DEVBUSY; /* sfp is reading data */ - } - - /* For eloopback, all speed is allowed */ - if (sfp->is_elb) - return BFA_STATUS_OK; - - return bfa_sfp_speed_valid(sfp, portspeed); -} - -/* - * Flash module specific - */ - -/* - * FLASH DMA buffer should be big enough to hold both MFG block and - * asic block(64k) at the same time and also should be 2k aligned to - * avoid write segement to cross sector boundary. - */ -#define BFA_FLASH_SEG_SZ 2048 -#define BFA_FLASH_DMA_BUF_SZ \ - BFA_ROUNDUP(0x010000 + sizeof(struct bfa_mfg_block_s), BFA_FLASH_SEG_SZ) - -static void -bfa_flash_cb(struct bfa_flash_s *flash) -{ - flash->op_busy = 0; - if (flash->cbfn) - flash->cbfn(flash->cbarg, flash->status); -} - -static void -bfa_flash_notify(void *cbarg, enum bfa_ioc_event_e event) -{ - struct bfa_flash_s *flash = cbarg; - - bfa_trc(flash, event); - switch (event) { - case BFA_IOC_E_DISABLED: - case BFA_IOC_E_FAILED: - if (flash->op_busy) { - flash->status = BFA_STATUS_IOC_FAILURE; - flash->cbfn(flash->cbarg, flash->status); - flash->op_busy = 0; - } - break; - - default: - break; - } -} - -/* - * Send flash attribute query request. - * - * @param[in] cbarg - callback argument - */ -static void -bfa_flash_query_send(void *cbarg) -{ - struct bfa_flash_s *flash = cbarg; - struct bfi_flash_query_req_s *msg = - (struct bfi_flash_query_req_s *) flash->mb.msg; - - bfi_h2i_set(msg->mh, BFI_MC_FLASH, BFI_FLASH_H2I_QUERY_REQ, - bfa_ioc_portid(flash->ioc)); - bfa_alen_set(&msg->alen, sizeof(struct bfa_flash_attr_s), - flash->dbuf_pa); - bfa_ioc_mbox_queue(flash->ioc, &flash->mb); -} - -/* - * Send flash write request. - * - * @param[in] cbarg - callback argument - */ -static void -bfa_flash_write_send(struct bfa_flash_s *flash) -{ - struct bfi_flash_write_req_s *msg = - (struct bfi_flash_write_req_s *) flash->mb.msg; - u32 len; - - msg->type = be32_to_cpu(flash->type); - msg->instance = flash->instance; - msg->offset = be32_to_cpu(flash->addr_off + flash->offset); - len = (flash->residue < BFA_FLASH_DMA_BUF_SZ) ? - flash->residue : BFA_FLASH_DMA_BUF_SZ; - msg->length = be32_to_cpu(len); - - /* indicate if it's the last msg of the whole write operation */ - msg->last = (len == flash->residue) ? 1 : 0; - - bfi_h2i_set(msg->mh, BFI_MC_FLASH, BFI_FLASH_H2I_WRITE_REQ, - bfa_ioc_portid(flash->ioc)); - bfa_alen_set(&msg->alen, len, flash->dbuf_pa); - memcpy(flash->dbuf_kva, flash->ubuf + flash->offset, len); - bfa_ioc_mbox_queue(flash->ioc, &flash->mb); - - flash->residue -= len; - flash->offset += len; -} - -/* - * Send flash read request. - * - * @param[in] cbarg - callback argument - */ -static void -bfa_flash_read_send(void *cbarg) -{ - struct bfa_flash_s *flash = cbarg; - struct bfi_flash_read_req_s *msg = - (struct bfi_flash_read_req_s *) flash->mb.msg; - u32 len; - - msg->type = be32_to_cpu(flash->type); - msg->instance = flash->instance; - msg->offset = be32_to_cpu(flash->addr_off + flash->offset); - len = (flash->residue < BFA_FLASH_DMA_BUF_SZ) ? - flash->residue : BFA_FLASH_DMA_BUF_SZ; - msg->length = be32_to_cpu(len); - bfi_h2i_set(msg->mh, BFI_MC_FLASH, BFI_FLASH_H2I_READ_REQ, - bfa_ioc_portid(flash->ioc)); - bfa_alen_set(&msg->alen, len, flash->dbuf_pa); - bfa_ioc_mbox_queue(flash->ioc, &flash->mb); -} - -/* - * Send flash erase request. - * - * @param[in] cbarg - callback argument - */ -static void -bfa_flash_erase_send(void *cbarg) -{ - struct bfa_flash_s *flash = cbarg; - struct bfi_flash_erase_req_s *msg = - (struct bfi_flash_erase_req_s *) flash->mb.msg; - - msg->type = be32_to_cpu(flash->type); - msg->instance = flash->instance; - bfi_h2i_set(msg->mh, BFI_MC_FLASH, BFI_FLASH_H2I_ERASE_REQ, - bfa_ioc_portid(flash->ioc)); - bfa_ioc_mbox_queue(flash->ioc, &flash->mb); -} - -/* - * Process flash response messages upon receiving interrupts. - * - * @param[in] flasharg - flash structure - * @param[in] msg - message structure - */ -static void -bfa_flash_intr(void *flasharg, struct bfi_mbmsg_s *msg) -{ - struct bfa_flash_s *flash = flasharg; - u32 status; - - union { - struct bfi_flash_query_rsp_s *query; - struct bfi_flash_erase_rsp_s *erase; - struct bfi_flash_write_rsp_s *write; - struct bfi_flash_read_rsp_s *read; - struct bfi_mbmsg_s *msg; - } m; - - m.msg = msg; - bfa_trc(flash, msg->mh.msg_id); - - if (!flash->op_busy && msg->mh.msg_id != BFI_FLASH_I2H_EVENT) { - /* receiving response after ioc failure */ - bfa_trc(flash, 0x9999); - return; - } - - switch (msg->mh.msg_id) { - case BFI_FLASH_I2H_QUERY_RSP: - status = be32_to_cpu(m.query->status); - bfa_trc(flash, status); - if (status == BFA_STATUS_OK) { - u32 i; - struct bfa_flash_attr_s *attr, *f; - - attr = (struct bfa_flash_attr_s *) flash->ubuf; - f = (struct bfa_flash_attr_s *) flash->dbuf_kva; - attr->status = be32_to_cpu(f->status); - attr->npart = be32_to_cpu(f->npart); - bfa_trc(flash, attr->status); - bfa_trc(flash, attr->npart); - for (i = 0; i < attr->npart; i++) { - attr->part[i].part_type = - be32_to_cpu(f->part[i].part_type); - attr->part[i].part_instance = - be32_to_cpu(f->part[i].part_instance); - attr->part[i].part_off = - be32_to_cpu(f->part[i].part_off); - attr->part[i].part_size = - be32_to_cpu(f->part[i].part_size); - attr->part[i].part_len = - be32_to_cpu(f->part[i].part_len); - attr->part[i].part_status = - be32_to_cpu(f->part[i].part_status); - } - } - flash->status = status; - bfa_flash_cb(flash); - break; - case BFI_FLASH_I2H_ERASE_RSP: - status = be32_to_cpu(m.erase->status); - bfa_trc(flash, status); - flash->status = status; - bfa_flash_cb(flash); - break; - case BFI_FLASH_I2H_WRITE_RSP: - status = be32_to_cpu(m.write->status); - bfa_trc(flash, status); - if (status != BFA_STATUS_OK || flash->residue == 0) { - flash->status = status; - bfa_flash_cb(flash); - } else { - bfa_trc(flash, flash->offset); - bfa_flash_write_send(flash); - } - break; - case BFI_FLASH_I2H_READ_RSP: - status = be32_to_cpu(m.read->status); - bfa_trc(flash, status); - if (status != BFA_STATUS_OK) { - flash->status = status; - bfa_flash_cb(flash); - } else { - u32 len = be32_to_cpu(m.read->length); - bfa_trc(flash, flash->offset); - bfa_trc(flash, len); - memcpy(flash->ubuf + flash->offset, - flash->dbuf_kva, len); - flash->residue -= len; - flash->offset += len; - if (flash->residue == 0) { - flash->status = status; - bfa_flash_cb(flash); - } else - bfa_flash_read_send(flash); - } - break; - case BFI_FLASH_I2H_BOOT_VER_RSP: - case BFI_FLASH_I2H_EVENT: - bfa_trc(flash, msg->mh.msg_id); - break; - - default: - WARN_ON(1); - } -} - -/* - * Flash memory info API. - * - * @param[in] mincfg - minimal cfg variable - */ -u32 -bfa_flash_meminfo(bfa_boolean_t mincfg) -{ - /* min driver doesn't need flash */ - if (mincfg) - return 0; - return BFA_ROUNDUP(BFA_FLASH_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ); -} - -/* - * Flash attach API. - * - * @param[in] flash - flash structure - * @param[in] ioc - ioc structure - * @param[in] dev - device structure - * @param[in] trcmod - trace module - * @param[in] logmod - log module - */ -void -bfa_flash_attach(struct bfa_flash_s *flash, struct bfa_ioc_s *ioc, void *dev, - struct bfa_trc_mod_s *trcmod, bfa_boolean_t mincfg) -{ - flash->ioc = ioc; - flash->trcmod = trcmod; - flash->cbfn = NULL; - flash->cbarg = NULL; - flash->op_busy = 0; - - bfa_ioc_mbox_regisr(flash->ioc, BFI_MC_FLASH, bfa_flash_intr, flash); - bfa_q_qe_init(&flash->ioc_notify); - bfa_ioc_notify_init(&flash->ioc_notify, bfa_flash_notify, flash); - list_add_tail(&flash->ioc_notify.qe, &flash->ioc->notify_q); - - /* min driver doesn't need flash */ - if (mincfg) { - flash->dbuf_kva = NULL; - flash->dbuf_pa = 0; - } -} - -/* - * Claim memory for flash - * - * @param[in] flash - flash structure - * @param[in] dm_kva - pointer to virtual memory address - * @param[in] dm_pa - physical memory address - * @param[in] mincfg - minimal cfg variable - */ -void -bfa_flash_memclaim(struct bfa_flash_s *flash, u8 *dm_kva, u64 dm_pa, - bfa_boolean_t mincfg) -{ - if (mincfg) - return; - - flash->dbuf_kva = dm_kva; - flash->dbuf_pa = dm_pa; - memset(flash->dbuf_kva, 0, BFA_FLASH_DMA_BUF_SZ); - dm_kva += BFA_ROUNDUP(BFA_FLASH_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ); - dm_pa += BFA_ROUNDUP(BFA_FLASH_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ); -} - -/* - * Get flash attribute. - * - * @param[in] flash - flash structure - * @param[in] attr - flash attribute structure - * @param[in] cbfn - callback function - * @param[in] cbarg - callback argument - * - * Return status. - */ -bfa_status_t -bfa_flash_get_attr(struct bfa_flash_s *flash, struct bfa_flash_attr_s *attr, - bfa_cb_flash_t cbfn, void *cbarg) -{ - bfa_trc(flash, BFI_FLASH_H2I_QUERY_REQ); - - if (!bfa_ioc_is_operational(flash->ioc)) - return BFA_STATUS_IOC_NON_OP; - - if (flash->op_busy) { - bfa_trc(flash, flash->op_busy); - return BFA_STATUS_DEVBUSY; - } - - flash->op_busy = 1; - flash->cbfn = cbfn; - flash->cbarg = cbarg; - flash->ubuf = (u8 *) attr; - bfa_flash_query_send(flash); - - return BFA_STATUS_OK; -} - -/* - * Erase flash partition. - * - * @param[in] flash - flash structure - * @param[in] type - flash partition type - * @param[in] instance - flash partition instance - * @param[in] cbfn - callback function - * @param[in] cbarg - callback argument - * - * Return status. - */ -bfa_status_t -bfa_flash_erase_part(struct bfa_flash_s *flash, enum bfa_flash_part_type type, - u8 instance, bfa_cb_flash_t cbfn, void *cbarg) -{ - bfa_trc(flash, BFI_FLASH_H2I_ERASE_REQ); - bfa_trc(flash, type); - bfa_trc(flash, instance); - - if (!bfa_ioc_is_operational(flash->ioc)) - return BFA_STATUS_IOC_NON_OP; - - if (flash->op_busy) { - bfa_trc(flash, flash->op_busy); - return BFA_STATUS_DEVBUSY; - } - - flash->op_busy = 1; - flash->cbfn = cbfn; - flash->cbarg = cbarg; - flash->type = type; - flash->instance = instance; - - bfa_flash_erase_send(flash); - return BFA_STATUS_OK; -} - -/* - * Update flash partition. - * - * @param[in] flash - flash structure - * @param[in] type - flash partition type - * @param[in] instance - flash partition instance - * @param[in] buf - update data buffer - * @param[in] len - data buffer length - * @param[in] offset - offset relative to the partition starting address - * @param[in] cbfn - callback function - * @param[in] cbarg - callback argument - * - * Return status. - */ -bfa_status_t -bfa_flash_update_part(struct bfa_flash_s *flash, enum bfa_flash_part_type type, - u8 instance, void *buf, u32 len, u32 offset, - bfa_cb_flash_t cbfn, void *cbarg) -{ - bfa_trc(flash, BFI_FLASH_H2I_WRITE_REQ); - bfa_trc(flash, type); - bfa_trc(flash, instance); - bfa_trc(flash, len); - bfa_trc(flash, offset); - - if (!bfa_ioc_is_operational(flash->ioc)) - return BFA_STATUS_IOC_NON_OP; - - /* - * 'len' must be in word (4-byte) boundary - * 'offset' must be in sector (16kb) boundary - */ - if (!len || (len & 0x03) || (offset & 0x00003FFF)) - return BFA_STATUS_FLASH_BAD_LEN; - - if (type == BFA_FLASH_PART_MFG) - return BFA_STATUS_EINVAL; - - if (flash->op_busy) { - bfa_trc(flash, flash->op_busy); - return BFA_STATUS_DEVBUSY; - } - - flash->op_busy = 1; - flash->cbfn = cbfn; - flash->cbarg = cbarg; - flash->type = type; - flash->instance = instance; - flash->residue = len; - flash->offset = 0; - flash->addr_off = offset; - flash->ubuf = buf; - - bfa_flash_write_send(flash); - return BFA_STATUS_OK; -} - -/* - * Read flash partition. - * - * @param[in] flash - flash structure - * @param[in] type - flash partition type - * @param[in] instance - flash partition instance - * @param[in] buf - read data buffer - * @param[in] len - data buffer length - * @param[in] offset - offset relative to the partition starting address - * @param[in] cbfn - callback function - * @param[in] cbarg - callback argument - * - * Return status. - */ -bfa_status_t -bfa_flash_read_part(struct bfa_flash_s *flash, enum bfa_flash_part_type type, - u8 instance, void *buf, u32 len, u32 offset, - bfa_cb_flash_t cbfn, void *cbarg) -{ - bfa_trc(flash, BFI_FLASH_H2I_READ_REQ); - bfa_trc(flash, type); - bfa_trc(flash, instance); - bfa_trc(flash, len); - bfa_trc(flash, offset); - - if (!bfa_ioc_is_operational(flash->ioc)) - return BFA_STATUS_IOC_NON_OP; - - /* - * 'len' must be in word (4-byte) boundary - * 'offset' must be in sector (16kb) boundary - */ - if (!len || (len & 0x03) || (offset & 0x00003FFF)) - return BFA_STATUS_FLASH_BAD_LEN; - - if (flash->op_busy) { - bfa_trc(flash, flash->op_busy); - return BFA_STATUS_DEVBUSY; - } - - flash->op_busy = 1; - flash->cbfn = cbfn; - flash->cbarg = cbarg; - flash->type = type; - flash->instance = instance; - flash->residue = len; - flash->offset = 0; - flash->addr_off = offset; - flash->ubuf = buf; - bfa_flash_read_send(flash); - - return BFA_STATUS_OK; -} - -/* - * DIAG module specific - */ - -#define BFA_DIAG_MEMTEST_TOV 50000 /* memtest timeout in msec */ -#define BFA_DIAG_FWPING_TOV 1000 /* msec */ - -/* IOC event handler */ -static void -bfa_diag_notify(void *diag_arg, enum bfa_ioc_event_e event) -{ - struct bfa_diag_s *diag = diag_arg; - - bfa_trc(diag, event); - bfa_trc(diag, diag->block); - bfa_trc(diag, diag->fwping.lock); - bfa_trc(diag, diag->tsensor.lock); - - switch (event) { - case BFA_IOC_E_DISABLED: - case BFA_IOC_E_FAILED: - if (diag->fwping.lock) { - diag->fwping.status = BFA_STATUS_IOC_FAILURE; - diag->fwping.cbfn(diag->fwping.cbarg, - diag->fwping.status); - diag->fwping.lock = 0; - } - - if (diag->tsensor.lock) { - diag->tsensor.status = BFA_STATUS_IOC_FAILURE; - diag->tsensor.cbfn(diag->tsensor.cbarg, - diag->tsensor.status); - diag->tsensor.lock = 0; - } - - if (diag->block) { - if (diag->timer_active) { - bfa_timer_stop(&diag->timer); - diag->timer_active = 0; - } - - diag->status = BFA_STATUS_IOC_FAILURE; - diag->cbfn(diag->cbarg, diag->status); - diag->block = 0; - } - break; - - default: - break; - } -} - -static void -bfa_diag_memtest_done(void *cbarg) -{ - struct bfa_diag_s *diag = cbarg; - struct bfa_ioc_s *ioc = diag->ioc; - struct bfa_diag_memtest_result *res = diag->result; - u32 loff = BFI_BOOT_MEMTEST_RES_ADDR; - u32 pgnum, pgoff, i; - - pgnum = PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, loff); - pgoff = PSS_SMEM_PGOFF(loff); - - writel(pgnum, ioc->ioc_regs.host_page_num_fn); - - for (i = 0; i < (sizeof(struct bfa_diag_memtest_result) / - sizeof(u32)); i++) { - /* read test result from smem */ - *((u32 *) res + i) = - bfa_mem_read(ioc->ioc_regs.smem_page_start, loff); - loff += sizeof(u32); - } - - /* Reset IOC fwstates to BFI_IOC_UNINIT */ - bfa_ioc_reset_fwstate(ioc); - - res->status = swab32(res->status); - bfa_trc(diag, res->status); - - if (res->status == BFI_BOOT_MEMTEST_RES_SIG) - diag->status = BFA_STATUS_OK; - else { - diag->status = BFA_STATUS_MEMTEST_FAILED; - res->addr = swab32(res->addr); - res->exp = swab32(res->exp); - res->act = swab32(res->act); - res->err_status = swab32(res->err_status); - res->err_status1 = swab32(res->err_status1); - res->err_addr = swab32(res->err_addr); - bfa_trc(diag, res->addr); - bfa_trc(diag, res->exp); - bfa_trc(diag, res->act); - bfa_trc(diag, res->err_status); - bfa_trc(diag, res->err_status1); - bfa_trc(diag, res->err_addr); - } - diag->timer_active = 0; - diag->cbfn(diag->cbarg, diag->status); - diag->block = 0; -} - -/* - * Firmware ping - */ - -/* - * Perform DMA test directly - */ -static void -diag_fwping_send(struct bfa_diag_s *diag) -{ - struct bfi_diag_fwping_req_s *fwping_req; - u32 i; - - bfa_trc(diag, diag->fwping.dbuf_pa); - - /* fill DMA area with pattern */ - for (i = 0; i < (BFI_DIAG_DMA_BUF_SZ >> 2); i++) - *((u32 *)diag->fwping.dbuf_kva + i) = diag->fwping.data; - - /* Fill mbox msg */ - fwping_req = (struct bfi_diag_fwping_req_s *)diag->fwping.mbcmd.msg; - - /* Setup SG list */ - bfa_alen_set(&fwping_req->alen, BFI_DIAG_DMA_BUF_SZ, - diag->fwping.dbuf_pa); - /* Set up dma count */ - fwping_req->count = cpu_to_be32(diag->fwping.count); - /* Set up data pattern */ - fwping_req->data = diag->fwping.data; - - /* build host command */ - bfi_h2i_set(fwping_req->mh, BFI_MC_DIAG, BFI_DIAG_H2I_FWPING, - bfa_ioc_portid(diag->ioc)); - - /* send mbox cmd */ - bfa_ioc_mbox_queue(diag->ioc, &diag->fwping.mbcmd); -} - -static void -diag_fwping_comp(struct bfa_diag_s *diag, - struct bfi_diag_fwping_rsp_s *diag_rsp) -{ - u32 rsp_data = diag_rsp->data; - u8 rsp_dma_status = diag_rsp->dma_status; - - bfa_trc(diag, rsp_data); - bfa_trc(diag, rsp_dma_status); - - if (rsp_dma_status == BFA_STATUS_OK) { - u32 i, pat; - pat = (diag->fwping.count & 0x1) ? ~(diag->fwping.data) : - diag->fwping.data; - /* Check mbox data */ - if (diag->fwping.data != rsp_data) { - bfa_trc(diag, rsp_data); - diag->fwping.result->dmastatus = - BFA_STATUS_DATACORRUPTED; - diag->fwping.status = BFA_STATUS_DATACORRUPTED; - diag->fwping.cbfn(diag->fwping.cbarg, - diag->fwping.status); - diag->fwping.lock = 0; - return; - } - /* Check dma pattern */ - for (i = 0; i < (BFI_DIAG_DMA_BUF_SZ >> 2); i++) { - if (*((u32 *)diag->fwping.dbuf_kva + i) != pat) { - bfa_trc(diag, i); - bfa_trc(diag, pat); - bfa_trc(diag, - *((u32 *)diag->fwping.dbuf_kva + i)); - diag->fwping.result->dmastatus = - BFA_STATUS_DATACORRUPTED; - diag->fwping.status = BFA_STATUS_DATACORRUPTED; - diag->fwping.cbfn(diag->fwping.cbarg, - diag->fwping.status); - diag->fwping.lock = 0; - return; - } - } - diag->fwping.result->dmastatus = BFA_STATUS_OK; - diag->fwping.status = BFA_STATUS_OK; - diag->fwping.cbfn(diag->fwping.cbarg, diag->fwping.status); - diag->fwping.lock = 0; - } else { - diag->fwping.status = BFA_STATUS_HDMA_FAILED; - diag->fwping.cbfn(diag->fwping.cbarg, diag->fwping.status); - diag->fwping.lock = 0; - } -} - -/* - * Temperature Sensor - */ - -static void -diag_tempsensor_send(struct bfa_diag_s *diag) -{ - struct bfi_diag_ts_req_s *msg; - - msg = (struct bfi_diag_ts_req_s *)diag->tsensor.mbcmd.msg; - bfa_trc(diag, msg->temp); - /* build host command */ - bfi_h2i_set(msg->mh, BFI_MC_DIAG, BFI_DIAG_H2I_TEMPSENSOR, - bfa_ioc_portid(diag->ioc)); - /* send mbox cmd */ - bfa_ioc_mbox_queue(diag->ioc, &diag->tsensor.mbcmd); -} - -static void -diag_tempsensor_comp(struct bfa_diag_s *diag, bfi_diag_ts_rsp_t *rsp) -{ - if (!diag->tsensor.lock) { - /* receiving response after ioc failure */ - bfa_trc(diag, diag->tsensor.lock); - return; - } - - /* - * ASIC junction tempsensor is a reg read operation - * it will always return OK - */ - diag->tsensor.temp->temp = be16_to_cpu(rsp->temp); - diag->tsensor.temp->ts_junc = rsp->ts_junc; - diag->tsensor.temp->ts_brd = rsp->ts_brd; - diag->tsensor.temp->status = BFA_STATUS_OK; - - if (rsp->ts_brd) { - if (rsp->status == BFA_STATUS_OK) { - diag->tsensor.temp->brd_temp = - be16_to_cpu(rsp->brd_temp); - } else { - bfa_trc(diag, rsp->status); - diag->tsensor.temp->brd_temp = 0; - diag->tsensor.temp->status = BFA_STATUS_DEVBUSY; - } - } - bfa_trc(diag, rsp->ts_junc); - bfa_trc(diag, rsp->temp); - bfa_trc(diag, rsp->ts_brd); - bfa_trc(diag, rsp->brd_temp); - diag->tsensor.cbfn(diag->tsensor.cbarg, diag->tsensor.status); - diag->tsensor.lock = 0; -} - -/* - * LED Test command - */ -static void -diag_ledtest_send(struct bfa_diag_s *diag, struct bfa_diag_ledtest_s *ledtest) -{ - struct bfi_diag_ledtest_req_s *msg; - - msg = (struct bfi_diag_ledtest_req_s *)diag->ledtest.mbcmd.msg; - /* build host command */ - bfi_h2i_set(msg->mh, BFI_MC_DIAG, BFI_DIAG_H2I_LEDTEST, - bfa_ioc_portid(diag->ioc)); - - /* - * convert the freq from N blinks per 10 sec to - * crossbow ontime value. We do it here because division is need - */ - if (ledtest->freq) - ledtest->freq = 500 / ledtest->freq; - - if (ledtest->freq == 0) - ledtest->freq = 1; - - bfa_trc(diag, ledtest->freq); - /* mcpy(&ledtest_req->req, ledtest, sizeof(bfa_diag_ledtest_t)); */ - msg->cmd = (u8) ledtest->cmd; - msg->color = (u8) ledtest->color; - msg->portid = bfa_ioc_portid(diag->ioc); - msg->led = ledtest->led; - msg->freq = cpu_to_be16(ledtest->freq); - - /* send mbox cmd */ - bfa_ioc_mbox_queue(diag->ioc, &diag->ledtest.mbcmd); -} - -static void -diag_ledtest_comp(struct bfa_diag_s *diag, struct bfi_diag_ledtest_rsp_s * msg) -{ - bfa_trc(diag, diag->ledtest.lock); - diag->ledtest.lock = BFA_FALSE; - /* no bfa_cb_queue is needed because driver is not waiting */ -} - -/* - * Port beaconing - */ -static void -diag_portbeacon_send(struct bfa_diag_s *diag, bfa_boolean_t beacon, u32 sec) -{ - struct bfi_diag_portbeacon_req_s *msg; - - msg = (struct bfi_diag_portbeacon_req_s *)diag->beacon.mbcmd.msg; - /* build host command */ - bfi_h2i_set(msg->mh, BFI_MC_DIAG, BFI_DIAG_H2I_PORTBEACON, - bfa_ioc_portid(diag->ioc)); - msg->beacon = beacon; - msg->period = cpu_to_be32(sec); - /* send mbox cmd */ - bfa_ioc_mbox_queue(diag->ioc, &diag->beacon.mbcmd); -} - -static void -diag_portbeacon_comp(struct bfa_diag_s *diag) -{ - bfa_trc(diag, diag->beacon.state); - diag->beacon.state = BFA_FALSE; - if (diag->cbfn_beacon) - diag->cbfn_beacon(diag->dev, BFA_FALSE, diag->beacon.link_e2e); -} - -/* - * Diag hmbox handler - */ -void -bfa_diag_intr(void *diagarg, struct bfi_mbmsg_s *msg) -{ - struct bfa_diag_s *diag = diagarg; - - switch (msg->mh.msg_id) { - case BFI_DIAG_I2H_PORTBEACON: - diag_portbeacon_comp(diag); - break; - case BFI_DIAG_I2H_FWPING: - diag_fwping_comp(diag, (struct bfi_diag_fwping_rsp_s *) msg); - break; - case BFI_DIAG_I2H_TEMPSENSOR: - diag_tempsensor_comp(diag, (bfi_diag_ts_rsp_t *) msg); - break; - case BFI_DIAG_I2H_LEDTEST: - diag_ledtest_comp(diag, (struct bfi_diag_ledtest_rsp_s *) msg); - break; - default: - bfa_trc(diag, msg->mh.msg_id); - WARN_ON(1); - } -} - -/* - * Gen RAM Test - * - * @param[in] *diag - diag data struct - * @param[in] *memtest - mem test params input from upper layer, - * @param[in] pattern - mem test pattern - * @param[in] *result - mem test result - * @param[in] cbfn - mem test callback functioin - * @param[in] cbarg - callback functioin arg - * - * @param[out] - */ -bfa_status_t -bfa_diag_memtest(struct bfa_diag_s *diag, struct bfa_diag_memtest_s *memtest, - u32 pattern, struct bfa_diag_memtest_result *result, - bfa_cb_diag_t cbfn, void *cbarg) -{ - bfa_trc(diag, pattern); - - if (!bfa_ioc_adapter_is_disabled(diag->ioc)) - return BFA_STATUS_ADAPTER_ENABLED; - - /* check to see if there is another destructive diag cmd running */ - if (diag->block) { - bfa_trc(diag, diag->block); - return BFA_STATUS_DEVBUSY; - } else - diag->block = 1; - - diag->result = result; - diag->cbfn = cbfn; - diag->cbarg = cbarg; - - /* download memtest code and take LPU0 out of reset */ - bfa_ioc_boot(diag->ioc, BFI_FWBOOT_TYPE_MEMTEST, BFI_FWBOOT_ENV_OS); - - bfa_timer_begin(diag->ioc->timer_mod, &diag->timer, - bfa_diag_memtest_done, diag, BFA_DIAG_MEMTEST_TOV); - diag->timer_active = 1; - return BFA_STATUS_OK; -} - -/* - * DIAG firmware ping command - * - * @param[in] *diag - diag data struct - * @param[in] cnt - dma loop count for testing PCIE - * @param[in] data - data pattern to pass in fw - * @param[in] *result - pt to bfa_diag_fwping_result_t data struct - * @param[in] cbfn - callback function - * @param[in] *cbarg - callback functioin arg - * - * @param[out] - */ -bfa_status_t -bfa_diag_fwping(struct bfa_diag_s *diag, u32 cnt, u32 data, - struct bfa_diag_results_fwping *result, bfa_cb_diag_t cbfn, - void *cbarg) -{ - bfa_trc(diag, cnt); - bfa_trc(diag, data); - - if (!bfa_ioc_is_operational(diag->ioc)) - return BFA_STATUS_IOC_NON_OP; - - if (bfa_asic_id_ct2(bfa_ioc_devid((diag->ioc))) && - ((diag->ioc)->clscode == BFI_PCIFN_CLASS_ETH)) - return BFA_STATUS_CMD_NOTSUPP; - - /* check to see if there is another destructive diag cmd running */ - if (diag->block || diag->fwping.lock) { - bfa_trc(diag, diag->block); - bfa_trc(diag, diag->fwping.lock); - return BFA_STATUS_DEVBUSY; - } - - /* Initialization */ - diag->fwping.lock = 1; - diag->fwping.cbfn = cbfn; - diag->fwping.cbarg = cbarg; - diag->fwping.result = result; - diag->fwping.data = data; - diag->fwping.count = cnt; - - /* Init test results */ - diag->fwping.result->data = 0; - diag->fwping.result->status = BFA_STATUS_OK; - - /* kick off the first ping */ - diag_fwping_send(diag); - return BFA_STATUS_OK; -} - -/* - * Read Temperature Sensor - * - * @param[in] *diag - diag data struct - * @param[in] *result - pt to bfa_diag_temp_t data struct - * @param[in] cbfn - callback function - * @param[in] *cbarg - callback functioin arg - * - * @param[out] - */ -bfa_status_t -bfa_diag_tsensor_query(struct bfa_diag_s *diag, - struct bfa_diag_results_tempsensor_s *result, - bfa_cb_diag_t cbfn, void *cbarg) -{ - /* check to see if there is a destructive diag cmd running */ - if (diag->block || diag->tsensor.lock) { - bfa_trc(diag, diag->block); - bfa_trc(diag, diag->tsensor.lock); - return BFA_STATUS_DEVBUSY; - } - - if (!bfa_ioc_is_operational(diag->ioc)) - return BFA_STATUS_IOC_NON_OP; - - /* Init diag mod params */ - diag->tsensor.lock = 1; - diag->tsensor.temp = result; - diag->tsensor.cbfn = cbfn; - diag->tsensor.cbarg = cbarg; - - /* Send msg to fw */ - diag_tempsensor_send(diag); - - return BFA_STATUS_OK; -} - -/* - * LED Test command - * - * @param[in] *diag - diag data struct - * @param[in] *ledtest - pt to ledtest data structure - * - * @param[out] - */ -bfa_status_t -bfa_diag_ledtest(struct bfa_diag_s *diag, struct bfa_diag_ledtest_s *ledtest) -{ - bfa_trc(diag, ledtest->cmd); - - if (!bfa_ioc_is_operational(diag->ioc)) - return BFA_STATUS_IOC_NON_OP; - - if (diag->beacon.state) - return BFA_STATUS_BEACON_ON; - - if (diag->ledtest.lock) - return BFA_STATUS_LEDTEST_OP; - - /* Send msg to fw */ - diag->ledtest.lock = BFA_TRUE; - diag_ledtest_send(diag, ledtest); - - return BFA_STATUS_OK; -} - -/* - * Port beaconing command - * - * @param[in] *diag - diag data struct - * @param[in] beacon - port beaconing 1:ON 0:OFF - * @param[in] link_e2e_beacon - link beaconing 1:ON 0:OFF - * @param[in] sec - beaconing duration in seconds - * - * @param[out] - */ -bfa_status_t -bfa_diag_beacon_port(struct bfa_diag_s *diag, bfa_boolean_t beacon, - bfa_boolean_t link_e2e_beacon, uint32_t sec) -{ - bfa_trc(diag, beacon); - bfa_trc(diag, link_e2e_beacon); - bfa_trc(diag, sec); - - if (!bfa_ioc_is_operational(diag->ioc)) - return BFA_STATUS_IOC_NON_OP; - - if (diag->ledtest.lock) - return BFA_STATUS_LEDTEST_OP; - - if (diag->beacon.state && beacon) /* beacon alread on */ - return BFA_STATUS_BEACON_ON; - - diag->beacon.state = beacon; - diag->beacon.link_e2e = link_e2e_beacon; - if (diag->cbfn_beacon) - diag->cbfn_beacon(diag->dev, beacon, link_e2e_beacon); - - /* Send msg to fw */ - diag_portbeacon_send(diag, beacon, sec); - - return BFA_STATUS_OK; -} - -/* - * Return DMA memory needed by diag module. - */ -u32 -bfa_diag_meminfo(void) -{ - return BFA_ROUNDUP(BFI_DIAG_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ); -} - -/* - * Attach virtual and physical memory for Diag. - */ -void -bfa_diag_attach(struct bfa_diag_s *diag, struct bfa_ioc_s *ioc, void *dev, - bfa_cb_diag_beacon_t cbfn_beacon, struct bfa_trc_mod_s *trcmod) -{ - diag->dev = dev; - diag->ioc = ioc; - diag->trcmod = trcmod; - - diag->block = 0; - diag->cbfn = NULL; - diag->cbarg = NULL; - diag->result = NULL; - diag->cbfn_beacon = cbfn_beacon; - - bfa_ioc_mbox_regisr(diag->ioc, BFI_MC_DIAG, bfa_diag_intr, diag); - bfa_q_qe_init(&diag->ioc_notify); - bfa_ioc_notify_init(&diag->ioc_notify, bfa_diag_notify, diag); - list_add_tail(&diag->ioc_notify.qe, &diag->ioc->notify_q); -} - -void -bfa_diag_memclaim(struct bfa_diag_s *diag, u8 *dm_kva, u64 dm_pa) -{ - diag->fwping.dbuf_kva = dm_kva; - diag->fwping.dbuf_pa = dm_pa; - memset(diag->fwping.dbuf_kva, 0, BFI_DIAG_DMA_BUF_SZ); -} - -/* - * PHY module specific - */ -#define BFA_PHY_DMA_BUF_SZ 0x02000 /* 8k dma buffer */ -#define BFA_PHY_LOCK_STATUS 0x018878 /* phy semaphore status reg */ - -static void -bfa_phy_ntoh32(u32 *obuf, u32 *ibuf, int sz) -{ - int i, m = sz >> 2; - - for (i = 0; i < m; i++) - obuf[i] = be32_to_cpu(ibuf[i]); -} - -static bfa_boolean_t -bfa_phy_present(struct bfa_phy_s *phy) -{ - return (phy->ioc->attr->card_type == BFA_MFG_TYPE_LIGHTNING); -} - -static void -bfa_phy_notify(void *cbarg, enum bfa_ioc_event_e event) -{ - struct bfa_phy_s *phy = cbarg; - - bfa_trc(phy, event); - - switch (event) { - case BFA_IOC_E_DISABLED: - case BFA_IOC_E_FAILED: - if (phy->op_busy) { - phy->status = BFA_STATUS_IOC_FAILURE; - phy->cbfn(phy->cbarg, phy->status); - phy->op_busy = 0; - } - break; - - default: - break; - } -} - -/* - * Send phy attribute query request. - * - * @param[in] cbarg - callback argument - */ -static void -bfa_phy_query_send(void *cbarg) -{ - struct bfa_phy_s *phy = cbarg; - struct bfi_phy_query_req_s *msg = - (struct bfi_phy_query_req_s *) phy->mb.msg; - - msg->instance = phy->instance; - bfi_h2i_set(msg->mh, BFI_MC_PHY, BFI_PHY_H2I_QUERY_REQ, - bfa_ioc_portid(phy->ioc)); - bfa_alen_set(&msg->alen, sizeof(struct bfa_phy_attr_s), phy->dbuf_pa); - bfa_ioc_mbox_queue(phy->ioc, &phy->mb); -} - -/* - * Send phy write request. - * - * @param[in] cbarg - callback argument - */ -static void -bfa_phy_write_send(void *cbarg) -{ - struct bfa_phy_s *phy = cbarg; - struct bfi_phy_write_req_s *msg = - (struct bfi_phy_write_req_s *) phy->mb.msg; - u32 len; - u16 *buf, *dbuf; - int i, sz; - - msg->instance = phy->instance; - msg->offset = cpu_to_be32(phy->addr_off + phy->offset); - len = (phy->residue < BFA_PHY_DMA_BUF_SZ) ? - phy->residue : BFA_PHY_DMA_BUF_SZ; - msg->length = cpu_to_be32(len); - - /* indicate if it's the last msg of the whole write operation */ - msg->last = (len == phy->residue) ? 1 : 0; - - bfi_h2i_set(msg->mh, BFI_MC_PHY, BFI_PHY_H2I_WRITE_REQ, - bfa_ioc_portid(phy->ioc)); - bfa_alen_set(&msg->alen, len, phy->dbuf_pa); - - buf = (u16 *) (phy->ubuf + phy->offset); - dbuf = (u16 *)phy->dbuf_kva; - sz = len >> 1; - for (i = 0; i < sz; i++) - buf[i] = cpu_to_be16(dbuf[i]); - - bfa_ioc_mbox_queue(phy->ioc, &phy->mb); - - phy->residue -= len; - phy->offset += len; -} - -/* - * Send phy read request. - * - * @param[in] cbarg - callback argument - */ -static void -bfa_phy_read_send(void *cbarg) -{ - struct bfa_phy_s *phy = cbarg; - struct bfi_phy_read_req_s *msg = - (struct bfi_phy_read_req_s *) phy->mb.msg; - u32 len; - - msg->instance = phy->instance; - msg->offset = cpu_to_be32(phy->addr_off + phy->offset); - len = (phy->residue < BFA_PHY_DMA_BUF_SZ) ? - phy->residue : BFA_PHY_DMA_BUF_SZ; - msg->length = cpu_to_be32(len); - bfi_h2i_set(msg->mh, BFI_MC_PHY, BFI_PHY_H2I_READ_REQ, - bfa_ioc_portid(phy->ioc)); - bfa_alen_set(&msg->alen, len, phy->dbuf_pa); - bfa_ioc_mbox_queue(phy->ioc, &phy->mb); -} - -/* - * Send phy stats request. - * - * @param[in] cbarg - callback argument - */ -static void -bfa_phy_stats_send(void *cbarg) -{ - struct bfa_phy_s *phy = cbarg; - struct bfi_phy_stats_req_s *msg = - (struct bfi_phy_stats_req_s *) phy->mb.msg; - - msg->instance = phy->instance; - bfi_h2i_set(msg->mh, BFI_MC_PHY, BFI_PHY_H2I_STATS_REQ, - bfa_ioc_portid(phy->ioc)); - bfa_alen_set(&msg->alen, sizeof(struct bfa_phy_stats_s), phy->dbuf_pa); - bfa_ioc_mbox_queue(phy->ioc, &phy->mb); -} - -/* - * Flash memory info API. - * - * @param[in] mincfg - minimal cfg variable - */ -u32 -bfa_phy_meminfo(bfa_boolean_t mincfg) -{ - /* min driver doesn't need phy */ - if (mincfg) - return 0; - - return BFA_ROUNDUP(BFA_PHY_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ); -} - -/* - * Flash attach API. - * - * @param[in] phy - phy structure - * @param[in] ioc - ioc structure - * @param[in] dev - device structure - * @param[in] trcmod - trace module - * @param[in] logmod - log module - */ -void -bfa_phy_attach(struct bfa_phy_s *phy, struct bfa_ioc_s *ioc, void *dev, - struct bfa_trc_mod_s *trcmod, bfa_boolean_t mincfg) -{ - phy->ioc = ioc; - phy->trcmod = trcmod; - phy->cbfn = NULL; - phy->cbarg = NULL; - phy->op_busy = 0; - - bfa_ioc_mbox_regisr(phy->ioc, BFI_MC_PHY, bfa_phy_intr, phy); - bfa_q_qe_init(&phy->ioc_notify); - bfa_ioc_notify_init(&phy->ioc_notify, bfa_phy_notify, phy); - list_add_tail(&phy->ioc_notify.qe, &phy->ioc->notify_q); - - /* min driver doesn't need phy */ - if (mincfg) { - phy->dbuf_kva = NULL; - phy->dbuf_pa = 0; - } -} - -/* - * Claim memory for phy - * - * @param[in] phy - phy structure - * @param[in] dm_kva - pointer to virtual memory address - * @param[in] dm_pa - physical memory address - * @param[in] mincfg - minimal cfg variable - */ -void -bfa_phy_memclaim(struct bfa_phy_s *phy, u8 *dm_kva, u64 dm_pa, - bfa_boolean_t mincfg) -{ - if (mincfg) - return; - - phy->dbuf_kva = dm_kva; - phy->dbuf_pa = dm_pa; - memset(phy->dbuf_kva, 0, BFA_PHY_DMA_BUF_SZ); - dm_kva += BFA_ROUNDUP(BFA_PHY_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ); - dm_pa += BFA_ROUNDUP(BFA_PHY_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ); -} - -bfa_boolean_t -bfa_phy_busy(struct bfa_ioc_s *ioc) -{ - void __iomem *rb; - - rb = bfa_ioc_bar0(ioc); - return readl(rb + BFA_PHY_LOCK_STATUS); -} - -/* - * Get phy attribute. - * - * @param[in] phy - phy structure - * @param[in] attr - phy attribute structure - * @param[in] cbfn - callback function - * @param[in] cbarg - callback argument - * - * Return status. - */ -bfa_status_t -bfa_phy_get_attr(struct bfa_phy_s *phy, u8 instance, - struct bfa_phy_attr_s *attr, bfa_cb_phy_t cbfn, void *cbarg) -{ - bfa_trc(phy, BFI_PHY_H2I_QUERY_REQ); - bfa_trc(phy, instance); - - if (!bfa_phy_present(phy)) - return BFA_STATUS_PHY_NOT_PRESENT; - - if (!bfa_ioc_is_operational(phy->ioc)) - return BFA_STATUS_IOC_NON_OP; - - if (phy->op_busy || bfa_phy_busy(phy->ioc)) { - bfa_trc(phy, phy->op_busy); - return BFA_STATUS_DEVBUSY; - } - - phy->op_busy = 1; - phy->cbfn = cbfn; - phy->cbarg = cbarg; - phy->instance = instance; - phy->ubuf = (uint8_t *) attr; - bfa_phy_query_send(phy); - - return BFA_STATUS_OK; -} - -/* - * Get phy stats. - * - * @param[in] phy - phy structure - * @param[in] instance - phy image instance - * @param[in] stats - pointer to phy stats - * @param[in] cbfn - callback function - * @param[in] cbarg - callback argument - * - * Return status. - */ -bfa_status_t -bfa_phy_get_stats(struct bfa_phy_s *phy, u8 instance, - struct bfa_phy_stats_s *stats, - bfa_cb_phy_t cbfn, void *cbarg) -{ - bfa_trc(phy, BFI_PHY_H2I_STATS_REQ); - bfa_trc(phy, instance); - - if (!bfa_phy_present(phy)) - return BFA_STATUS_PHY_NOT_PRESENT; - - if (!bfa_ioc_is_operational(phy->ioc)) - return BFA_STATUS_IOC_NON_OP; - - if (phy->op_busy || bfa_phy_busy(phy->ioc)) { - bfa_trc(phy, phy->op_busy); - return BFA_STATUS_DEVBUSY; - } - - phy->op_busy = 1; - phy->cbfn = cbfn; - phy->cbarg = cbarg; - phy->instance = instance; - phy->ubuf = (u8 *) stats; - bfa_phy_stats_send(phy); - - return BFA_STATUS_OK; -} - -/* - * Update phy image. - * - * @param[in] phy - phy structure - * @param[in] instance - phy image instance - * @param[in] buf - update data buffer - * @param[in] len - data buffer length - * @param[in] offset - offset relative to starting address - * @param[in] cbfn - callback function - * @param[in] cbarg - callback argument - * - * Return status. - */ -bfa_status_t -bfa_phy_update(struct bfa_phy_s *phy, u8 instance, - void *buf, u32 len, u32 offset, - bfa_cb_phy_t cbfn, void *cbarg) -{ - bfa_trc(phy, BFI_PHY_H2I_WRITE_REQ); - bfa_trc(phy, instance); - bfa_trc(phy, len); - bfa_trc(phy, offset); - - if (!bfa_phy_present(phy)) - return BFA_STATUS_PHY_NOT_PRESENT; - - if (!bfa_ioc_is_operational(phy->ioc)) - return BFA_STATUS_IOC_NON_OP; - - /* 'len' must be in word (4-byte) boundary */ - if (!len || (len & 0x03)) - return BFA_STATUS_FAILED; - - if (phy->op_busy || bfa_phy_busy(phy->ioc)) { - bfa_trc(phy, phy->op_busy); - return BFA_STATUS_DEVBUSY; - } - - phy->op_busy = 1; - phy->cbfn = cbfn; - phy->cbarg = cbarg; - phy->instance = instance; - phy->residue = len; - phy->offset = 0; - phy->addr_off = offset; - phy->ubuf = buf; - - bfa_phy_write_send(phy); - return BFA_STATUS_OK; -} - -/* - * Read phy image. - * - * @param[in] phy - phy structure - * @param[in] instance - phy image instance - * @param[in] buf - read data buffer - * @param[in] len - data buffer length - * @param[in] offset - offset relative to starting address - * @param[in] cbfn - callback function - * @param[in] cbarg - callback argument - * - * Return status. - */ -bfa_status_t -bfa_phy_read(struct bfa_phy_s *phy, u8 instance, - void *buf, u32 len, u32 offset, - bfa_cb_phy_t cbfn, void *cbarg) -{ - bfa_trc(phy, BFI_PHY_H2I_READ_REQ); - bfa_trc(phy, instance); - bfa_trc(phy, len); - bfa_trc(phy, offset); - - if (!bfa_phy_present(phy)) - return BFA_STATUS_PHY_NOT_PRESENT; - - if (!bfa_ioc_is_operational(phy->ioc)) - return BFA_STATUS_IOC_NON_OP; - - /* 'len' must be in word (4-byte) boundary */ - if (!len || (len & 0x03)) - return BFA_STATUS_FAILED; - - if (phy->op_busy || bfa_phy_busy(phy->ioc)) { - bfa_trc(phy, phy->op_busy); - return BFA_STATUS_DEVBUSY; - } - - phy->op_busy = 1; - phy->cbfn = cbfn; - phy->cbarg = cbarg; - phy->instance = instance; - phy->residue = len; - phy->offset = 0; - phy->addr_off = offset; - phy->ubuf = buf; - bfa_phy_read_send(phy); - - return BFA_STATUS_OK; -} - -/* - * Process phy response messages upon receiving interrupts. - * - * @param[in] phyarg - phy structure - * @param[in] msg - message structure - */ -void -bfa_phy_intr(void *phyarg, struct bfi_mbmsg_s *msg) -{ - struct bfa_phy_s *phy = phyarg; - u32 status; - - union { - struct bfi_phy_query_rsp_s *query; - struct bfi_phy_stats_rsp_s *stats; - struct bfi_phy_write_rsp_s *write; - struct bfi_phy_read_rsp_s *read; - struct bfi_mbmsg_s *msg; - } m; - - m.msg = msg; - bfa_trc(phy, msg->mh.msg_id); - - if (!phy->op_busy) { - /* receiving response after ioc failure */ - bfa_trc(phy, 0x9999); - return; - } - - switch (msg->mh.msg_id) { - case BFI_PHY_I2H_QUERY_RSP: - status = be32_to_cpu(m.query->status); - bfa_trc(phy, status); - - if (status == BFA_STATUS_OK) { - struct bfa_phy_attr_s *attr = - (struct bfa_phy_attr_s *) phy->ubuf; - bfa_phy_ntoh32((u32 *)attr, (u32 *)phy->dbuf_kva, - sizeof(struct bfa_phy_attr_s)); - bfa_trc(phy, attr->status); - bfa_trc(phy, attr->length); - } - - phy->status = status; - phy->op_busy = 0; - if (phy->cbfn) - phy->cbfn(phy->cbarg, phy->status); - break; - case BFI_PHY_I2H_STATS_RSP: - status = be32_to_cpu(m.stats->status); - bfa_trc(phy, status); - - if (status == BFA_STATUS_OK) { - struct bfa_phy_stats_s *stats = - (struct bfa_phy_stats_s *) phy->ubuf; - bfa_phy_ntoh32((u32 *)stats, (u32 *)phy->dbuf_kva, - sizeof(struct bfa_phy_stats_s)); - bfa_trc(phy, stats->status); - } - - phy->status = status; - phy->op_busy = 0; - if (phy->cbfn) - phy->cbfn(phy->cbarg, phy->status); - break; - case BFI_PHY_I2H_WRITE_RSP: - status = be32_to_cpu(m.write->status); - bfa_trc(phy, status); - - if (status != BFA_STATUS_OK || phy->residue == 0) { - phy->status = status; - phy->op_busy = 0; - if (phy->cbfn) - phy->cbfn(phy->cbarg, phy->status); - } else { - bfa_trc(phy, phy->offset); - bfa_phy_write_send(phy); - } - break; - case BFI_PHY_I2H_READ_RSP: - status = be32_to_cpu(m.read->status); - bfa_trc(phy, status); - - if (status != BFA_STATUS_OK) { - phy->status = status; - phy->op_busy = 0; - if (phy->cbfn) - phy->cbfn(phy->cbarg, phy->status); - } else { - u32 len = be32_to_cpu(m.read->length); - u16 *buf = (u16 *)(phy->ubuf + phy->offset); - u16 *dbuf = (u16 *)phy->dbuf_kva; - int i, sz = len >> 1; - - bfa_trc(phy, phy->offset); - bfa_trc(phy, len); - - for (i = 0; i < sz; i++) - buf[i] = be16_to_cpu(dbuf[i]); - - phy->residue -= len; - phy->offset += len; - - if (phy->residue == 0) { - phy->status = status; - phy->op_busy = 0; - if (phy->cbfn) - phy->cbfn(phy->cbarg, phy->status); - } else - bfa_phy_read_send(phy); - } - break; - default: - WARN_ON(1); - } -} diff --git a/trunk/drivers/scsi/bfa/bfa_ioc.h b/trunk/drivers/scsi/bfa/bfa_ioc.h index c5ecd2edc95d..c85182a704fb 100644 --- a/trunk/drivers/scsi/bfa/bfa_ioc.h +++ b/trunk/drivers/scsi/bfa/bfa_ioc.h @@ -84,68 +84,6 @@ struct bfa_sge_s { #define bfa_sgaddr_le(_x) (_x) #endif -/* - * BFA memory resources - */ -struct bfa_mem_dma_s { - struct list_head qe; /* Queue of DMA elements */ - u32 mem_len; /* Total Length in Bytes */ - u8 *kva; /* kernel virtual address */ - u64 dma; /* dma address if DMA memory */ - u8 *kva_curp; /* kva allocation cursor */ - u64 dma_curp; /* dma allocation cursor */ -}; -#define bfa_mem_dma_t struct bfa_mem_dma_s - -struct bfa_mem_kva_s { - struct list_head qe; /* Queue of KVA elements */ - u32 mem_len; /* Total Length in Bytes */ - u8 *kva; /* kernel virtual address */ - u8 *kva_curp; /* kva allocation cursor */ -}; -#define bfa_mem_kva_t struct bfa_mem_kva_s - -struct bfa_meminfo_s { - struct bfa_mem_dma_s dma_info; - struct bfa_mem_kva_s kva_info; -}; - -/* BFA memory segment setup macros */ -#define bfa_mem_dma_setup(_meminfo, _dm_ptr, _seg_sz) do { \ - ((bfa_mem_dma_t *)(_dm_ptr))->mem_len = (_seg_sz); \ - if (_seg_sz) \ - list_add_tail(&((bfa_mem_dma_t *)_dm_ptr)->qe, \ - &(_meminfo)->dma_info.qe); \ -} while (0) - -#define bfa_mem_kva_setup(_meminfo, _kva_ptr, _seg_sz) do { \ - ((bfa_mem_kva_t *)(_kva_ptr))->mem_len = (_seg_sz); \ - if (_seg_sz) \ - list_add_tail(&((bfa_mem_kva_t *)_kva_ptr)->qe, \ - &(_meminfo)->kva_info.qe); \ -} while (0) - -/* BFA dma memory segments iterator */ -#define bfa_mem_dma_sptr(_mod, _i) (&(_mod)->dma_seg[(_i)]) -#define bfa_mem_dma_seg_iter(_mod, _sptr, _nr, _i) \ - for (_i = 0, _sptr = bfa_mem_dma_sptr(_mod, _i); _i < (_nr); \ - _i++, _sptr = bfa_mem_dma_sptr(_mod, _i)) - -#define bfa_mem_kva_curp(_mod) ((_mod)->kva_seg.kva_curp) -#define bfa_mem_dma_virt(_sptr) ((_sptr)->kva_curp) -#define bfa_mem_dma_phys(_sptr) ((_sptr)->dma_curp) -#define bfa_mem_dma_len(_sptr) ((_sptr)->mem_len) - -/* Get the corresponding dma buf kva for a req - from the tag */ -#define bfa_mem_get_dmabuf_kva(_mod, _tag, _rqsz) \ - (((u8 *)(_mod)->dma_seg[BFI_MEM_SEG_FROM_TAG(_tag, _rqsz)].kva_curp) +\ - BFI_MEM_SEG_REQ_OFFSET(_tag, _rqsz) * (_rqsz)) - -/* Get the corresponding dma buf pa for a req - from the tag */ -#define bfa_mem_get_dmabuf_pa(_mod, _tag, _rqsz) \ - ((_mod)->dma_seg[BFI_MEM_SEG_FROM_TAG(_tag, _rqsz)].dma_curp + \ - BFI_MEM_SEG_REQ_OFFSET(_tag, _rqsz) * (_rqsz)) - /* * PCI device information required by IOC */ @@ -153,7 +91,6 @@ struct bfa_pcidev_s { int pci_slot; u8 pci_func; u16 device_id; - u16 ssid; void __iomem *pci_bar_kva; }; @@ -175,23 +112,25 @@ struct bfa_dma_s { #define BFI_SMEM_CB_SIZE 0x200000U /* ! 2MB for crossbow */ #define BFI_SMEM_CT_SIZE 0x280000U /* ! 2.5MB for catapult */ -#define bfa_dma_be_addr_set(dma_addr, pa) \ - __bfa_dma_be_addr_set(&dma_addr, (u64)pa) + +#define bfa_dma_addr_set(dma_addr, pa) \ + __bfa_dma_addr_set(&dma_addr, (u64)pa) + static inline void -__bfa_dma_be_addr_set(union bfi_addr_u *dma_addr, u64 pa) +__bfa_dma_addr_set(union bfi_addr_u *dma_addr, u64 pa) { - dma_addr->a32.addr_lo = cpu_to_be32(pa); - dma_addr->a32.addr_hi = cpu_to_be32(pa >> 32); + dma_addr->a32.addr_lo = (__be32) pa; + dma_addr->a32.addr_hi = (__be32) (pa >> 32); } -#define bfa_alen_set(__alen, __len, __pa) \ - __bfa_alen_set(__alen, __len, (u64)__pa) +#define bfa_dma_be_addr_set(dma_addr, pa) \ + __bfa_dma_be_addr_set(&dma_addr, (u64)pa) static inline void -__bfa_alen_set(struct bfi_alen_s *alen, u32 len, u64 pa) +__bfa_dma_be_addr_set(union bfi_addr_u *dma_addr, u64 pa) { - alen->al_len = cpu_to_be32(len); - bfa_dma_be_addr_set(alen->al_addr, pa); + dma_addr->a32.addr_lo = cpu_to_be32(pa); + dma_addr->a32.addr_hi = cpu_to_be32(pa >> 32); } struct bfa_ioc_regs_s { @@ -199,7 +138,6 @@ struct bfa_ioc_regs_s { void __iomem *hfn_mbox; void __iomem *lpu_mbox_cmd; void __iomem *lpu_mbox; - void __iomem *lpu_read_stat; void __iomem *pss_ctl_reg; void __iomem *pss_err_status_reg; void __iomem *app_pll_fast_ctl_reg; @@ -261,26 +199,18 @@ struct bfa_ioc_cbfn_s { }; /* - * IOC event notification mechanism. + * Heartbeat failure notification queue element. */ -enum bfa_ioc_event_e { - BFA_IOC_E_ENABLED = 1, - BFA_IOC_E_DISABLED = 2, - BFA_IOC_E_FAILED = 3, -}; - -typedef void (*bfa_ioc_notify_cbfn_t)(void *, enum bfa_ioc_event_e); - -struct bfa_ioc_notify_s { +struct bfa_ioc_hbfail_notify_s { struct list_head qe; - bfa_ioc_notify_cbfn_t cbfn; + bfa_ioc_hbfail_cbfn_t cbfn; void *cbarg; }; /* - * Initialize a IOC event notification structure + * Initialize a heartbeat failure notification structure */ -#define bfa_ioc_notify_init(__notify, __cbfn, __cbarg) do { \ +#define bfa_ioc_hbfail_init(__notify, __cbfn, __cbarg) do { \ (__notify)->cbfn = (__cbfn); \ (__notify)->cbarg = (__cbarg); \ } while (0) @@ -288,9 +218,8 @@ struct bfa_ioc_notify_s { struct bfa_iocpf_s { bfa_fsm_t fsm; struct bfa_ioc_s *ioc; - bfa_boolean_t fw_mismatch_notified; + u32 retry_count; bfa_boolean_t auto_recover; - u32 poll_time; }; struct bfa_ioc_s { @@ -302,15 +231,17 @@ struct bfa_ioc_s { struct bfa_timer_s sem_timer; struct bfa_timer_s hb_timer; u32 hb_count; - struct list_head notify_q; + struct list_head hb_notify_q; void *dbg_fwsave; int dbg_fwsave_len; bfa_boolean_t dbg_fwsave_once; - enum bfi_pcifn_class clscode; + enum bfi_mclass ioc_mc; struct bfa_ioc_regs_s ioc_regs; struct bfa_trc_mod_s *trcmod; struct bfa_ioc_drv_stats_s stats; bfa_boolean_t fcmode; + bfa_boolean_t ctdev; + bfa_boolean_t cna; bfa_boolean_t pllinit; bfa_boolean_t stats_busy; /* outstanding stats */ u8 port_id; @@ -320,17 +251,10 @@ struct bfa_ioc_s { struct bfa_ioc_mbox_mod_s mbox_mod; struct bfa_ioc_hwif_s *ioc_hwif; struct bfa_iocpf_s iocpf; - enum bfi_asic_gen asic_gen; - enum bfi_asic_mode asic_mode; - enum bfi_port_mode port0_mode; - enum bfi_port_mode port1_mode; - enum bfa_mode_s port_mode; - u8 ad_cap_bm; /* adapter cap bit mask */ - u8 port_mode_cfg; /* config port mode */ }; struct bfa_ioc_hwif_s { - bfa_status_t (*ioc_pll_init) (void __iomem *rb, enum bfi_asic_mode m); + bfa_status_t (*ioc_pll_init) (void __iomem *rb, bfa_boolean_t fcmode); bfa_boolean_t (*ioc_firmware_lock) (struct bfa_ioc_s *ioc); void (*ioc_firmware_unlock) (struct bfa_ioc_s *ioc); void (*ioc_reg_init) (struct bfa_ioc_s *ioc); @@ -344,356 +268,12 @@ struct bfa_ioc_hwif_s { void (*ioc_sync_leave) (struct bfa_ioc_s *ioc); void (*ioc_sync_ack) (struct bfa_ioc_s *ioc); bfa_boolean_t (*ioc_sync_complete) (struct bfa_ioc_s *ioc); - bfa_boolean_t (*ioc_lpu_read_stat) (struct bfa_ioc_s *ioc); -}; - -/* - * Queue element to wait for room in request queue. FIFO order is - * maintained when fullfilling requests. - */ -struct bfa_reqq_wait_s { - struct list_head qe; - void (*qresume) (void *cbarg); - void *cbarg; -}; - -typedef void (*bfa_cb_cbfn_t) (void *cbarg, bfa_boolean_t complete); - -/* - * Generic BFA callback element. - */ -struct bfa_cb_qe_s { - struct list_head qe; - bfa_cb_cbfn_t cbfn; - bfa_boolean_t once; - void *cbarg; -}; - -/* - * ASIC block configurtion related - */ - -typedef void (*bfa_ablk_cbfn_t)(void *, enum bfa_status); - -struct bfa_ablk_s { - struct bfa_ioc_s *ioc; - struct bfa_ablk_cfg_s *cfg; - u16 *pcifn; - struct bfa_dma_s dma_addr; - bfa_boolean_t busy; - struct bfa_mbox_cmd_s mb; - bfa_ablk_cbfn_t cbfn; - void *cbarg; - struct bfa_ioc_notify_s ioc_notify; - struct bfa_mem_dma_s ablk_dma; -}; -#define BFA_MEM_ABLK_DMA(__bfa) (&((__bfa)->modules.ablk.ablk_dma)) - -/* - * SFP module specific - */ -typedef void (*bfa_cb_sfp_t) (void *cbarg, bfa_status_t status); - -struct bfa_sfp_s { - void *dev; - struct bfa_ioc_s *ioc; - struct bfa_trc_mod_s *trcmod; - struct sfp_mem_s *sfpmem; - bfa_cb_sfp_t cbfn; - void *cbarg; - enum bfi_sfp_mem_e memtype; /* mem access type */ - u32 status; - struct bfa_mbox_cmd_s mbcmd; - u8 *dbuf_kva; /* dma buf virtual address */ - u64 dbuf_pa; /* dma buf physical address */ - struct bfa_ioc_notify_s ioc_notify; - enum bfa_defs_sfp_media_e *media; - enum bfa_port_speed portspeed; - bfa_cb_sfp_t state_query_cbfn; - void *state_query_cbarg; - u8 lock; - u8 data_valid; /* data in dbuf is valid */ - u8 state; /* sfp state */ - u8 state_query_lock; - struct bfa_mem_dma_s sfp_dma; - u8 is_elb; /* eloopback */ -}; - -#define BFA_SFP_MOD(__bfa) (&(__bfa)->modules.sfp) -#define BFA_MEM_SFP_DMA(__bfa) (&(BFA_SFP_MOD(__bfa)->sfp_dma)) - -u32 bfa_sfp_meminfo(void); - -void bfa_sfp_attach(struct bfa_sfp_s *sfp, struct bfa_ioc_s *ioc, - void *dev, struct bfa_trc_mod_s *trcmod); - -void bfa_sfp_memclaim(struct bfa_sfp_s *diag, u8 *dm_kva, u64 dm_pa); -void bfa_sfp_intr(void *bfaarg, struct bfi_mbmsg_s *msg); - -bfa_status_t bfa_sfp_show(struct bfa_sfp_s *sfp, struct sfp_mem_s *sfpmem, - bfa_cb_sfp_t cbfn, void *cbarg); - -bfa_status_t bfa_sfp_media(struct bfa_sfp_s *sfp, - enum bfa_defs_sfp_media_e *media, - bfa_cb_sfp_t cbfn, void *cbarg); - -bfa_status_t bfa_sfp_speed(struct bfa_sfp_s *sfp, - enum bfa_port_speed portspeed, - bfa_cb_sfp_t cbfn, void *cbarg); - -/* - * Flash module specific - */ -typedef void (*bfa_cb_flash_t) (void *cbarg, bfa_status_t status); - -struct bfa_flash_s { - struct bfa_ioc_s *ioc; /* back pointer to ioc */ - struct bfa_trc_mod_s *trcmod; - u32 type; /* partition type */ - u8 instance; /* partition instance */ - u8 rsv[3]; - u32 op_busy; /* operation busy flag */ - u32 residue; /* residual length */ - u32 offset; /* offset */ - bfa_status_t status; /* status */ - u8 *dbuf_kva; /* dma buf virtual address */ - u64 dbuf_pa; /* dma buf physical address */ - struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */ - bfa_cb_flash_t cbfn; /* user callback function */ - void *cbarg; /* user callback arg */ - u8 *ubuf; /* user supplied buffer */ - struct bfa_cb_qe_s hcb_qe; /* comp: BFA callback qelem */ - u32 addr_off; /* partition address offset */ - struct bfa_mbox_cmd_s mb; /* mailbox */ - struct bfa_ioc_notify_s ioc_notify; /* ioc event notify */ - struct bfa_mem_dma_s flash_dma; -}; - -#define BFA_FLASH(__bfa) (&(__bfa)->modules.flash) -#define BFA_MEM_FLASH_DMA(__bfa) (&(BFA_FLASH(__bfa)->flash_dma)) - -bfa_status_t bfa_flash_get_attr(struct bfa_flash_s *flash, - struct bfa_flash_attr_s *attr, - bfa_cb_flash_t cbfn, void *cbarg); -bfa_status_t bfa_flash_erase_part(struct bfa_flash_s *flash, - enum bfa_flash_part_type type, u8 instance, - bfa_cb_flash_t cbfn, void *cbarg); -bfa_status_t bfa_flash_update_part(struct bfa_flash_s *flash, - enum bfa_flash_part_type type, u8 instance, - void *buf, u32 len, u32 offset, - bfa_cb_flash_t cbfn, void *cbarg); -bfa_status_t bfa_flash_read_part(struct bfa_flash_s *flash, - enum bfa_flash_part_type type, u8 instance, void *buf, - u32 len, u32 offset, bfa_cb_flash_t cbfn, void *cbarg); -u32 bfa_flash_meminfo(bfa_boolean_t mincfg); -void bfa_flash_attach(struct bfa_flash_s *flash, struct bfa_ioc_s *ioc, - void *dev, struct bfa_trc_mod_s *trcmod, bfa_boolean_t mincfg); -void bfa_flash_memclaim(struct bfa_flash_s *flash, - u8 *dm_kva, u64 dm_pa, bfa_boolean_t mincfg); - -/* - * DIAG module specific - */ - -typedef void (*bfa_cb_diag_t) (void *cbarg, bfa_status_t status); -typedef void (*bfa_cb_diag_beacon_t) (void *dev, bfa_boolean_t beacon, - bfa_boolean_t link_e2e_beacon); - -/* - * Firmware ping test results - */ -struct bfa_diag_results_fwping { - u32 data; /* store the corrupted data */ - u32 status; - u32 dmastatus; - u8 rsvd[4]; -}; - -struct bfa_diag_qtest_result_s { - u32 status; - u16 count; /* sucessful queue test count */ - u8 queue; - u8 rsvd; /* 64-bit align */ -}; - -/* - * Firmware ping test results - */ -struct bfa_diag_fwping_s { - struct bfa_diag_results_fwping *result; - bfa_cb_diag_t cbfn; - void *cbarg; - u32 data; - u8 lock; - u8 rsv[3]; - u32 status; - u32 count; - struct bfa_mbox_cmd_s mbcmd; - u8 *dbuf_kva; /* dma buf virtual address */ - u64 dbuf_pa; /* dma buf physical address */ -}; - -/* - * Temperature sensor query results - */ -struct bfa_diag_results_tempsensor_s { - u32 status; - u16 temp; /* 10-bit A/D value */ - u16 brd_temp; /* 9-bit board temp */ - u8 ts_junc; /* show junction tempsensor */ - u8 ts_brd; /* show board tempsensor */ - u8 rsvd[6]; /* keep 8 bytes alignment */ -}; - -struct bfa_diag_tsensor_s { - bfa_cb_diag_t cbfn; - void *cbarg; - struct bfa_diag_results_tempsensor_s *temp; - u8 lock; - u8 rsv[3]; - u32 status; - struct bfa_mbox_cmd_s mbcmd; }; -struct bfa_diag_sfpshow_s { - struct sfp_mem_s *sfpmem; - bfa_cb_diag_t cbfn; - void *cbarg; - u8 lock; - u8 static_data; - u8 rsv[2]; - u32 status; - struct bfa_mbox_cmd_s mbcmd; - u8 *dbuf_kva; /* dma buf virtual address */ - u64 dbuf_pa; /* dma buf physical address */ -}; - -struct bfa_diag_led_s { - struct bfa_mbox_cmd_s mbcmd; - bfa_boolean_t lock; /* 1: ledtest is operating */ -}; - -struct bfa_diag_beacon_s { - struct bfa_mbox_cmd_s mbcmd; - bfa_boolean_t state; /* port beacon state */ - bfa_boolean_t link_e2e; /* link beacon state */ -}; - -struct bfa_diag_s { - void *dev; - struct bfa_ioc_s *ioc; - struct bfa_trc_mod_s *trcmod; - struct bfa_diag_fwping_s fwping; - struct bfa_diag_tsensor_s tsensor; - struct bfa_diag_sfpshow_s sfpshow; - struct bfa_diag_led_s ledtest; - struct bfa_diag_beacon_s beacon; - void *result; - struct bfa_timer_s timer; - bfa_cb_diag_beacon_t cbfn_beacon; - bfa_cb_diag_t cbfn; - void *cbarg; - u8 block; - u8 timer_active; - u8 rsvd[2]; - u32 status; - struct bfa_ioc_notify_s ioc_notify; - struct bfa_mem_dma_s diag_dma; -}; - -#define BFA_DIAG_MOD(__bfa) (&(__bfa)->modules.diag_mod) -#define BFA_MEM_DIAG_DMA(__bfa) (&(BFA_DIAG_MOD(__bfa)->diag_dma)) - -u32 bfa_diag_meminfo(void); -void bfa_diag_memclaim(struct bfa_diag_s *diag, u8 *dm_kva, u64 dm_pa); -void bfa_diag_attach(struct bfa_diag_s *diag, struct bfa_ioc_s *ioc, void *dev, - bfa_cb_diag_beacon_t cbfn_beacon, - struct bfa_trc_mod_s *trcmod); -bfa_status_t bfa_diag_reg_read(struct bfa_diag_s *diag, u32 offset, - u32 len, u32 *buf, u32 force); -bfa_status_t bfa_diag_reg_write(struct bfa_diag_s *diag, u32 offset, - u32 len, u32 value, u32 force); -bfa_status_t bfa_diag_tsensor_query(struct bfa_diag_s *diag, - struct bfa_diag_results_tempsensor_s *result, - bfa_cb_diag_t cbfn, void *cbarg); -bfa_status_t bfa_diag_fwping(struct bfa_diag_s *diag, u32 cnt, - u32 pattern, struct bfa_diag_results_fwping *result, - bfa_cb_diag_t cbfn, void *cbarg); -bfa_status_t bfa_diag_sfpshow(struct bfa_diag_s *diag, - struct sfp_mem_s *sfpmem, u8 static_data, - bfa_cb_diag_t cbfn, void *cbarg); -bfa_status_t bfa_diag_memtest(struct bfa_diag_s *diag, - struct bfa_diag_memtest_s *memtest, u32 pattern, - struct bfa_diag_memtest_result *result, - bfa_cb_diag_t cbfn, void *cbarg); -bfa_status_t bfa_diag_ledtest(struct bfa_diag_s *diag, - struct bfa_diag_ledtest_s *ledtest); -bfa_status_t bfa_diag_beacon_port(struct bfa_diag_s *diag, - bfa_boolean_t beacon, bfa_boolean_t link_e2e_beacon, - u32 sec); - -/* - * PHY module specific - */ -typedef void (*bfa_cb_phy_t) (void *cbarg, bfa_status_t status); - -struct bfa_phy_s { - struct bfa_ioc_s *ioc; /* back pointer to ioc */ - struct bfa_trc_mod_s *trcmod; /* trace module */ - u8 instance; /* port instance */ - u8 op_busy; /* operation busy flag */ - u8 rsv[2]; - u32 residue; /* residual length */ - u32 offset; /* offset */ - bfa_status_t status; /* status */ - u8 *dbuf_kva; /* dma buf virtual address */ - u64 dbuf_pa; /* dma buf physical address */ - struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */ - bfa_cb_phy_t cbfn; /* user callback function */ - void *cbarg; /* user callback arg */ - u8 *ubuf; /* user supplied buffer */ - struct bfa_cb_qe_s hcb_qe; /* comp: BFA callback qelem */ - u32 addr_off; /* phy address offset */ - struct bfa_mbox_cmd_s mb; /* mailbox */ - struct bfa_ioc_notify_s ioc_notify; /* ioc event notify */ - struct bfa_mem_dma_s phy_dma; -}; - -#define BFA_PHY(__bfa) (&(__bfa)->modules.phy) -#define BFA_MEM_PHY_DMA(__bfa) (&(BFA_PHY(__bfa)->phy_dma)) - -bfa_boolean_t bfa_phy_busy(struct bfa_ioc_s *ioc); -bfa_status_t bfa_phy_get_attr(struct bfa_phy_s *phy, u8 instance, - struct bfa_phy_attr_s *attr, - bfa_cb_phy_t cbfn, void *cbarg); -bfa_status_t bfa_phy_get_stats(struct bfa_phy_s *phy, u8 instance, - struct bfa_phy_stats_s *stats, - bfa_cb_phy_t cbfn, void *cbarg); -bfa_status_t bfa_phy_update(struct bfa_phy_s *phy, u8 instance, - void *buf, u32 len, u32 offset, - bfa_cb_phy_t cbfn, void *cbarg); -bfa_status_t bfa_phy_read(struct bfa_phy_s *phy, u8 instance, - void *buf, u32 len, u32 offset, - bfa_cb_phy_t cbfn, void *cbarg); - -u32 bfa_phy_meminfo(bfa_boolean_t mincfg); -void bfa_phy_attach(struct bfa_phy_s *phy, struct bfa_ioc_s *ioc, - void *dev, struct bfa_trc_mod_s *trcmod, bfa_boolean_t mincfg); -void bfa_phy_memclaim(struct bfa_phy_s *phy, - u8 *dm_kva, u64 dm_pa, bfa_boolean_t mincfg); -void bfa_phy_intr(void *phyarg, struct bfi_mbmsg_s *msg); - -/* - * IOC specfic macros - */ #define bfa_ioc_pcifn(__ioc) ((__ioc)->pcidev.pci_func) #define bfa_ioc_devid(__ioc) ((__ioc)->pcidev.device_id) #define bfa_ioc_bar0(__ioc) ((__ioc)->pcidev.pci_bar_kva) #define bfa_ioc_portid(__ioc) ((__ioc)->port_id) -#define bfa_ioc_asic_gen(__ioc) ((__ioc)->asic_gen) -#define bfa_ioc_is_cna(__ioc) \ - ((bfa_ioc_get_type(__ioc) == BFA_IOC_TYPE_FCoE) || \ - (bfa_ioc_get_type(__ioc) == BFA_IOC_TYPE_LL)) #define bfa_ioc_fetch_stats(__ioc, __stats) \ (((__stats)->drv_stats) = (__ioc)->stats) #define bfa_ioc_clr_stats(__ioc) \ @@ -707,9 +287,12 @@ void bfa_phy_intr(void *phyarg, struct bfi_mbmsg_s *msg); #define bfa_ioc_stats(_ioc, _stats) ((_ioc)->stats._stats++) #define BFA_IOC_FWIMG_MINSZ (16 * 1024) -#define BFA_IOC_FW_SMEM_SIZE(__ioc) \ - ((bfa_ioc_asic_gen(__ioc) == BFI_ASIC_GEN_CB) \ - ? BFI_SMEM_CB_SIZE : BFI_SMEM_CT_SIZE) +#define BFA_IOC_FWIMG_TYPE(__ioc) \ + (((__ioc)->ctdev) ? \ + (((__ioc)->fcmode) ? BFI_IMAGE_CT_FC : BFI_IMAGE_CT_CNA) : \ + BFI_IMAGE_CB_FC) +#define BFA_IOC_FW_SMEM_SIZE(__ioc) \ + (((__ioc)->ctdev) ? BFI_SMEM_CT_SIZE : BFI_SMEM_CB_SIZE) #define BFA_IOC_FLASH_CHUNK_NO(off) (off / BFI_FLASH_CHUNK_SZ_WORDS) #define BFA_IOC_FLASH_OFFSET_IN_CHUNK(off) (off % BFI_FLASH_CHUNK_SZ_WORDS) #define BFA_IOC_FLASH_CHUNK_ADDR(chunkno) (chunkno * BFI_FLASH_CHUNK_SZ_WORDS) @@ -722,7 +305,7 @@ void bfa_ioc_mbox_register(struct bfa_ioc_s *ioc, bfa_ioc_mbox_mcfunc_t *mcfuncs); void bfa_ioc_mbox_isr(struct bfa_ioc_s *ioc); void bfa_ioc_mbox_send(struct bfa_ioc_s *ioc, void *ioc_msg, int len); -bfa_boolean_t bfa_ioc_msgget(struct bfa_ioc_s *ioc, void *mbmsg); +void bfa_ioc_msgget(struct bfa_ioc_s *ioc, void *mbmsg); void bfa_ioc_mbox_regisr(struct bfa_ioc_s *ioc, enum bfi_mclass mc, bfa_ioc_mbox_mcfunc_t cbfn, void *cbarg); @@ -732,49 +315,40 @@ void bfa_ioc_mbox_regisr(struct bfa_ioc_s *ioc, enum bfi_mclass mc, #define bfa_ioc_pll_init_asic(__ioc) \ ((__ioc)->ioc_hwif->ioc_pll_init((__ioc)->pcidev.pci_bar_kva, \ - (__ioc)->asic_mode)) + (__ioc)->fcmode)) bfa_status_t bfa_ioc_pll_init(struct bfa_ioc_s *ioc); -bfa_status_t bfa_ioc_cb_pll_init(void __iomem *rb, enum bfi_asic_mode mode); -bfa_status_t bfa_ioc_ct_pll_init(void __iomem *rb, enum bfi_asic_mode mode); -bfa_status_t bfa_ioc_ct2_pll_init(void __iomem *rb, enum bfi_asic_mode mode); +bfa_status_t bfa_ioc_cb_pll_init(void __iomem *rb, bfa_boolean_t fcmode); +bfa_boolean_t bfa_ioc_ct_pll_init_complete(void __iomem *rb); +bfa_status_t bfa_ioc_ct_pll_init(void __iomem *rb, bfa_boolean_t fcmode); -#define bfa_ioc_isr_mode_set(__ioc, __msix) do { \ - if ((__ioc)->ioc_hwif->ioc_isr_mode_set) \ - ((__ioc)->ioc_hwif->ioc_isr_mode_set(__ioc, __msix)); \ -} while (0) +#define bfa_ioc_isr_mode_set(__ioc, __msix) \ + ((__ioc)->ioc_hwif->ioc_isr_mode_set(__ioc, __msix)) #define bfa_ioc_ownership_reset(__ioc) \ ((__ioc)->ioc_hwif->ioc_ownership_reset(__ioc)) -#define bfa_ioc_get_fcmode(__ioc) ((__ioc)->fcmode) -#define bfa_ioc_lpu_read_stat(__ioc) do { \ - if ((__ioc)->ioc_hwif->ioc_lpu_read_stat) \ - ((__ioc)->ioc_hwif->ioc_lpu_read_stat(__ioc)); \ -} while (0) -void bfa_ioc_set_cb_hwif(struct bfa_ioc_s *ioc); + void bfa_ioc_set_ct_hwif(struct bfa_ioc_s *ioc); -void bfa_ioc_set_ct2_hwif(struct bfa_ioc_s *ioc); -void bfa_ioc_ct2_poweron(struct bfa_ioc_s *ioc); +void bfa_ioc_set_cb_hwif(struct bfa_ioc_s *ioc); void bfa_ioc_attach(struct bfa_ioc_s *ioc, void *bfa, struct bfa_ioc_cbfn_s *cbfn, struct bfa_timer_mod_s *timer_mod); void bfa_ioc_auto_recover(bfa_boolean_t auto_recover); void bfa_ioc_detach(struct bfa_ioc_s *ioc); void bfa_ioc_pci_init(struct bfa_ioc_s *ioc, struct bfa_pcidev_s *pcidev, - enum bfi_pcifn_class clscode); + enum bfi_mclass mc); void bfa_ioc_mem_claim(struct bfa_ioc_s *ioc, u8 *dm_kva, u64 dm_pa); void bfa_ioc_enable(struct bfa_ioc_s *ioc); void bfa_ioc_disable(struct bfa_ioc_s *ioc); bfa_boolean_t bfa_ioc_intx_claim(struct bfa_ioc_s *ioc); void bfa_ioc_boot(struct bfa_ioc_s *ioc, u32 boot_type, - u32 boot_env); + u32 boot_param); void bfa_ioc_isr(struct bfa_ioc_s *ioc, struct bfi_mbmsg_s *msg); void bfa_ioc_error_isr(struct bfa_ioc_s *ioc); bfa_boolean_t bfa_ioc_is_operational(struct bfa_ioc_s *ioc); bfa_boolean_t bfa_ioc_is_initialized(struct bfa_ioc_s *ioc); bfa_boolean_t bfa_ioc_is_disabled(struct bfa_ioc_s *ioc); -bfa_boolean_t bfa_ioc_is_acq_addr(struct bfa_ioc_s *ioc); bfa_boolean_t bfa_ioc_fw_mismatch(struct bfa_ioc_s *ioc); bfa_boolean_t bfa_ioc_adapter_is_disabled(struct bfa_ioc_s *ioc); void bfa_ioc_reset_fwstate(struct bfa_ioc_s *ioc); @@ -798,6 +372,8 @@ bfa_status_t bfa_ioc_debug_fwtrc(struct bfa_ioc_s *ioc, void *trcdata, int *trclen); bfa_status_t bfa_ioc_debug_fwcore(struct bfa_ioc_s *ioc, void *buf, u32 *offset, int *buflen); +void bfa_ioc_set_fcmode(struct bfa_ioc_s *ioc); +bfa_boolean_t bfa_ioc_get_fcmode(struct bfa_ioc_s *ioc); bfa_boolean_t bfa_ioc_sem_get(void __iomem *sem_reg); void bfa_ioc_fwver_get(struct bfa_ioc_s *ioc, struct bfi_ioc_image_hdr_s *fwhdr); @@ -806,33 +382,6 @@ bfa_boolean_t bfa_ioc_fwver_cmp(struct bfa_ioc_s *ioc, bfa_status_t bfa_ioc_fw_stats_get(struct bfa_ioc_s *ioc, void *stats); bfa_status_t bfa_ioc_fw_stats_clear(struct bfa_ioc_s *ioc); -/* - * asic block configuration related APIs - */ -u32 bfa_ablk_meminfo(void); -void bfa_ablk_memclaim(struct bfa_ablk_s *ablk, u8 *dma_kva, u64 dma_pa); -void bfa_ablk_attach(struct bfa_ablk_s *ablk, struct bfa_ioc_s *ioc); -bfa_status_t bfa_ablk_query(struct bfa_ablk_s *ablk, - struct bfa_ablk_cfg_s *ablk_cfg, - bfa_ablk_cbfn_t cbfn, void *cbarg); -bfa_status_t bfa_ablk_adapter_config(struct bfa_ablk_s *ablk, - enum bfa_mode_s mode, int max_pf, int max_vf, - bfa_ablk_cbfn_t cbfn, void *cbarg); -bfa_status_t bfa_ablk_port_config(struct bfa_ablk_s *ablk, int port, - enum bfa_mode_s mode, int max_pf, int max_vf, - bfa_ablk_cbfn_t cbfn, void *cbarg); -bfa_status_t bfa_ablk_pf_create(struct bfa_ablk_s *ablk, u16 *pcifn, - u8 port, enum bfi_pcifn_class personality, int bw, - bfa_ablk_cbfn_t cbfn, void *cbarg); -bfa_status_t bfa_ablk_pf_delete(struct bfa_ablk_s *ablk, int pcifn, - bfa_ablk_cbfn_t cbfn, void *cbarg); -bfa_status_t bfa_ablk_pf_update(struct bfa_ablk_s *ablk, int pcifn, int bw, - bfa_ablk_cbfn_t cbfn, void *cbarg); -bfa_status_t bfa_ablk_optrom_en(struct bfa_ablk_s *ablk, - bfa_ablk_cbfn_t cbfn, void *cbarg); -bfa_status_t bfa_ablk_optrom_dis(struct bfa_ablk_s *ablk, - bfa_ablk_cbfn_t cbfn, void *cbarg); - /* * bfa mfg wwn API functions */ @@ -842,64 +391,50 @@ mac_t bfa_ioc_get_mfg_mac(struct bfa_ioc_s *ioc); /* * F/W Image Size & Chunk */ -extern u32 bfi_image_cb_size; -extern u32 bfi_image_ct_size; -extern u32 bfi_image_ct2_size; -extern u32 *bfi_image_cb; -extern u32 *bfi_image_ct; -extern u32 *bfi_image_ct2; +extern u32 bfi_image_ct_fc_size; +extern u32 bfi_image_ct_cna_size; +extern u32 bfi_image_cb_fc_size; +extern u32 *bfi_image_ct_fc; +extern u32 *bfi_image_ct_cna; +extern u32 *bfi_image_cb_fc; static inline u32 * -bfi_image_cb_get_chunk(u32 off) -{ - return (u32 *)(bfi_image_cb + off); -} +bfi_image_ct_fc_get_chunk(u32 off) +{ return (u32 *)(bfi_image_ct_fc + off); } static inline u32 * -bfi_image_ct_get_chunk(u32 off) -{ - return (u32 *)(bfi_image_ct + off); -} +bfi_image_ct_cna_get_chunk(u32 off) +{ return (u32 *)(bfi_image_ct_cna + off); } static inline u32 * -bfi_image_ct2_get_chunk(u32 off) -{ - return (u32 *)(bfi_image_ct2 + off); -} +bfi_image_cb_fc_get_chunk(u32 off) +{ return (u32 *)(bfi_image_cb_fc + off); } static inline u32* -bfa_cb_image_get_chunk(enum bfi_asic_gen asic_gen, u32 off) +bfa_cb_image_get_chunk(int type, u32 off) { - switch (asic_gen) { - case BFI_ASIC_GEN_CB: - return bfi_image_cb_get_chunk(off); - break; - case BFI_ASIC_GEN_CT: - return bfi_image_ct_get_chunk(off); - break; - case BFI_ASIC_GEN_CT2: - return bfi_image_ct2_get_chunk(off); - break; - default: - return NULL; + switch (type) { + case BFI_IMAGE_CT_FC: + return bfi_image_ct_fc_get_chunk(off); break; + case BFI_IMAGE_CT_CNA: + return bfi_image_ct_cna_get_chunk(off); break; + case BFI_IMAGE_CB_FC: + return bfi_image_cb_fc_get_chunk(off); break; + default: return NULL; } } static inline u32 -bfa_cb_image_get_size(enum bfi_asic_gen asic_gen) +bfa_cb_image_get_size(int type) { - switch (asic_gen) { - case BFI_ASIC_GEN_CB: - return bfi_image_cb_size; - break; - case BFI_ASIC_GEN_CT: - return bfi_image_ct_size; - break; - case BFI_ASIC_GEN_CT2: - return bfi_image_ct2_size; - break; - default: - return 0; + switch (type) { + case BFI_IMAGE_CT_FC: + return bfi_image_ct_fc_size; break; + case BFI_IMAGE_CT_CNA: + return bfi_image_ct_cna_size; break; + case BFI_IMAGE_CB_FC: + return bfi_image_cb_fc_size; break; + default: return 0; } } diff --git a/trunk/drivers/scsi/bfa/bfa_ioc_cb.c b/trunk/drivers/scsi/bfa/bfa_ioc_cb.c index 30df8a284715..89ae4c8f95a2 100644 --- a/trunk/drivers/scsi/bfa/bfa_ioc_cb.c +++ b/trunk/drivers/scsi/bfa/bfa_ioc_cb.c @@ -17,7 +17,7 @@ #include "bfad_drv.h" #include "bfa_ioc.h" -#include "bfi_reg.h" +#include "bfi_cbreg.h" #include "bfa_defs.h" BFA_TRC_FILE(CNA, IOC_CB); @@ -69,6 +69,21 @@ bfa_ioc_set_cb_hwif(struct bfa_ioc_s *ioc) static bfa_boolean_t bfa_ioc_cb_firmware_lock(struct bfa_ioc_s *ioc) { + struct bfi_ioc_image_hdr_s fwhdr; + uint32_t fwstate = readl(ioc->ioc_regs.ioc_fwstate); + + if (fwstate == BFI_IOC_UNINIT) + return BFA_TRUE; + + bfa_ioc_fwver_get(ioc, &fwhdr); + + if (swab32(fwhdr.exec) == BFI_BOOT_TYPE_NORMAL) + return BFA_TRUE; + + bfa_trc(ioc, fwstate); + bfa_trc(ioc, fwhdr.exec); + writel(BFI_IOC_UNINIT, ioc->ioc_regs.ioc_fwstate); + return BFA_TRUE; } @@ -83,7 +98,7 @@ bfa_ioc_cb_firmware_unlock(struct bfa_ioc_s *ioc) static void bfa_ioc_cb_notify_fail(struct bfa_ioc_s *ioc) { - writel(~0U, ioc->ioc_regs.err_set); + writel(__PSS_ERR_STATUS_SET, ioc->ioc_regs.err_set); readl(ioc->ioc_regs.err_set); } @@ -137,8 +152,8 @@ bfa_ioc_cb_reg_init(struct bfa_ioc_s *ioc) */ ioc->ioc_regs.pss_ctl_reg = (rb + PSS_CTL_REG); ioc->ioc_regs.pss_err_status_reg = (rb + PSS_ERR_STATUS_REG); - ioc->ioc_regs.app_pll_fast_ctl_reg = (rb + APP_PLL_LCLK_CTL_REG); - ioc->ioc_regs.app_pll_slow_ctl_reg = (rb + APP_PLL_SCLK_CTL_REG); + ioc->ioc_regs.app_pll_fast_ctl_reg = (rb + APP_PLL_400_CTL_REG); + ioc->ioc_regs.app_pll_slow_ctl_reg = (rb + APP_PLL_212_CTL_REG); /* * IOC semaphore registers and serialization @@ -270,18 +285,18 @@ bfa_ioc_cb_sync_complete(struct bfa_ioc_s *ioc) } bfa_status_t -bfa_ioc_cb_pll_init(void __iomem *rb, enum bfi_asic_mode fcmode) +bfa_ioc_cb_pll_init(void __iomem *rb, bfa_boolean_t fcmode) { u32 pll_sclk, pll_fclk; - pll_sclk = __APP_PLL_SCLK_ENABLE | __APP_PLL_SCLK_LRESETN | - __APP_PLL_SCLK_P0_1(3U) | - __APP_PLL_SCLK_JITLMT0_1(3U) | - __APP_PLL_SCLK_CNTLMT0_1(3U); - pll_fclk = __APP_PLL_LCLK_ENABLE | __APP_PLL_LCLK_LRESETN | - __APP_PLL_LCLK_RSEL200500 | __APP_PLL_LCLK_P0_1(3U) | - __APP_PLL_LCLK_JITLMT0_1(3U) | - __APP_PLL_LCLK_CNTLMT0_1(3U); + pll_sclk = __APP_PLL_212_ENABLE | __APP_PLL_212_LRESETN | + __APP_PLL_212_P0_1(3U) | + __APP_PLL_212_JITLMT0_1(3U) | + __APP_PLL_212_CNTLMT0_1(3U); + pll_fclk = __APP_PLL_400_ENABLE | __APP_PLL_400_LRESETN | + __APP_PLL_400_RSEL200500 | __APP_PLL_400_P0_1(3U) | + __APP_PLL_400_JITLMT0_1(3U) | + __APP_PLL_400_CNTLMT0_1(3U); writel(BFI_IOC_UNINIT, (rb + BFA_IOC0_STATE_REG)); writel(BFI_IOC_UNINIT, (rb + BFA_IOC1_STATE_REG)); writel(0xffffffffU, (rb + HOSTFN0_INT_MSK)); @@ -290,24 +305,24 @@ bfa_ioc_cb_pll_init(void __iomem *rb, enum bfi_asic_mode fcmode) writel(0xffffffffU, (rb + HOSTFN1_INT_STATUS)); writel(0xffffffffU, (rb + HOSTFN0_INT_MSK)); writel(0xffffffffU, (rb + HOSTFN1_INT_MSK)); - writel(__APP_PLL_SCLK_LOGIC_SOFT_RESET, rb + APP_PLL_SCLK_CTL_REG); - writel(__APP_PLL_SCLK_BYPASS | __APP_PLL_SCLK_LOGIC_SOFT_RESET, - rb + APP_PLL_SCLK_CTL_REG); - writel(__APP_PLL_LCLK_LOGIC_SOFT_RESET, rb + APP_PLL_LCLK_CTL_REG); - writel(__APP_PLL_LCLK_BYPASS | __APP_PLL_LCLK_LOGIC_SOFT_RESET, - rb + APP_PLL_LCLK_CTL_REG); + writel(__APP_PLL_212_LOGIC_SOFT_RESET, rb + APP_PLL_212_CTL_REG); + writel(__APP_PLL_212_BYPASS | __APP_PLL_212_LOGIC_SOFT_RESET, + rb + APP_PLL_212_CTL_REG); + writel(__APP_PLL_400_LOGIC_SOFT_RESET, rb + APP_PLL_400_CTL_REG); + writel(__APP_PLL_400_BYPASS | __APP_PLL_400_LOGIC_SOFT_RESET, + rb + APP_PLL_400_CTL_REG); udelay(2); - writel(__APP_PLL_SCLK_LOGIC_SOFT_RESET, rb + APP_PLL_SCLK_CTL_REG); - writel(__APP_PLL_LCLK_LOGIC_SOFT_RESET, rb + APP_PLL_LCLK_CTL_REG); - writel(pll_sclk | __APP_PLL_SCLK_LOGIC_SOFT_RESET, - rb + APP_PLL_SCLK_CTL_REG); - writel(pll_fclk | __APP_PLL_LCLK_LOGIC_SOFT_RESET, - rb + APP_PLL_LCLK_CTL_REG); + writel(__APP_PLL_212_LOGIC_SOFT_RESET, rb + APP_PLL_212_CTL_REG); + writel(__APP_PLL_400_LOGIC_SOFT_RESET, rb + APP_PLL_400_CTL_REG); + writel(pll_sclk | __APP_PLL_212_LOGIC_SOFT_RESET, + rb + APP_PLL_212_CTL_REG); + writel(pll_fclk | __APP_PLL_400_LOGIC_SOFT_RESET, + rb + APP_PLL_400_CTL_REG); udelay(2000); writel(0xffffffffU, (rb + HOSTFN0_INT_STATUS)); writel(0xffffffffU, (rb + HOSTFN1_INT_STATUS)); - writel(pll_sclk, (rb + APP_PLL_SCLK_CTL_REG)); - writel(pll_fclk, (rb + APP_PLL_LCLK_CTL_REG)); + writel(pll_sclk, (rb + APP_PLL_212_CTL_REG)); + writel(pll_fclk, (rb + APP_PLL_400_CTL_REG)); return BFA_STATUS_OK; } diff --git a/trunk/drivers/scsi/bfa/bfa_ioc_ct.c b/trunk/drivers/scsi/bfa/bfa_ioc_ct.c index d1b8f0caaa79..93612520f0d2 100644 --- a/trunk/drivers/scsi/bfa/bfa_ioc_ct.c +++ b/trunk/drivers/scsi/bfa/bfa_ioc_ct.c @@ -17,7 +17,7 @@ #include "bfad_drv.h" #include "bfa_ioc.h" -#include "bfi_reg.h" +#include "bfi_ctreg.h" #include "bfa_defs.h" BFA_TRC_FILE(CNA, IOC_CT); @@ -36,6 +36,9 @@ BFA_TRC_FILE(CNA, IOC_CT); */ static bfa_boolean_t bfa_ioc_ct_firmware_lock(struct bfa_ioc_s *ioc); static void bfa_ioc_ct_firmware_unlock(struct bfa_ioc_s *ioc); +static void bfa_ioc_ct_reg_init(struct bfa_ioc_s *ioc); +static void bfa_ioc_ct_map_port(struct bfa_ioc_s *ioc); +static void bfa_ioc_ct_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix); static void bfa_ioc_ct_notify_fail(struct bfa_ioc_s *ioc); static void bfa_ioc_ct_ownership_reset(struct bfa_ioc_s *ioc); static bfa_boolean_t bfa_ioc_ct_sync_start(struct bfa_ioc_s *ioc); @@ -45,7 +48,29 @@ static void bfa_ioc_ct_sync_ack(struct bfa_ioc_s *ioc); static bfa_boolean_t bfa_ioc_ct_sync_complete(struct bfa_ioc_s *ioc); static struct bfa_ioc_hwif_s hwif_ct; -static struct bfa_ioc_hwif_s hwif_ct2; + +/* + * Called from bfa_ioc_attach() to map asic specific calls. + */ +void +bfa_ioc_set_ct_hwif(struct bfa_ioc_s *ioc) +{ + hwif_ct.ioc_pll_init = bfa_ioc_ct_pll_init; + hwif_ct.ioc_firmware_lock = bfa_ioc_ct_firmware_lock; + hwif_ct.ioc_firmware_unlock = bfa_ioc_ct_firmware_unlock; + hwif_ct.ioc_reg_init = bfa_ioc_ct_reg_init; + hwif_ct.ioc_map_port = bfa_ioc_ct_map_port; + hwif_ct.ioc_isr_mode_set = bfa_ioc_ct_isr_mode_set; + hwif_ct.ioc_notify_fail = bfa_ioc_ct_notify_fail; + hwif_ct.ioc_ownership_reset = bfa_ioc_ct_ownership_reset; + hwif_ct.ioc_sync_start = bfa_ioc_ct_sync_start; + hwif_ct.ioc_sync_join = bfa_ioc_ct_sync_join; + hwif_ct.ioc_sync_leave = bfa_ioc_ct_sync_leave; + hwif_ct.ioc_sync_ack = bfa_ioc_ct_sync_ack; + hwif_ct.ioc_sync_complete = bfa_ioc_ct_sync_complete; + + ioc->ioc_hwif = &hwif_ct; +} /* * Return true if firmware of current driver matches the running firmware. @@ -57,10 +82,16 @@ bfa_ioc_ct_firmware_lock(struct bfa_ioc_s *ioc) u32 usecnt; struct bfi_ioc_image_hdr_s fwhdr; + /* + * Firmware match check is relevant only for CNA. + */ + if (!ioc->cna) + return BFA_TRUE; + /* * If bios boot (flash based) -- do not increment usage count */ - if (bfa_cb_image_get_size(bfa_ioc_asic_gen(ioc)) < + if (bfa_cb_image_get_size(BFA_IOC_FWIMG_TYPE(ioc)) < BFA_IOC_FWIMG_MINSZ) return BFA_TRUE; @@ -72,7 +103,6 @@ bfa_ioc_ct_firmware_lock(struct bfa_ioc_s *ioc) */ if (usecnt == 0) { writel(1, ioc->ioc_regs.ioc_usage_reg); - readl(ioc->ioc_regs.ioc_usage_sem_reg); writel(1, ioc->ioc_regs.ioc_usage_sem_reg); writel(0, ioc->ioc_regs.ioc_fail_sync); bfa_trc(ioc, usecnt); @@ -92,7 +122,6 @@ bfa_ioc_ct_firmware_lock(struct bfa_ioc_s *ioc) */ bfa_ioc_fwver_get(ioc, &fwhdr); if (!bfa_ioc_fwver_cmp(ioc, &fwhdr)) { - readl(ioc->ioc_regs.ioc_usage_sem_reg); writel(1, ioc->ioc_regs.ioc_usage_sem_reg); bfa_trc(ioc, usecnt); return BFA_FALSE; @@ -103,7 +132,6 @@ bfa_ioc_ct_firmware_lock(struct bfa_ioc_s *ioc) */ usecnt++; writel(usecnt, ioc->ioc_regs.ioc_usage_reg); - readl(ioc->ioc_regs.ioc_usage_sem_reg); writel(1, ioc->ioc_regs.ioc_usage_sem_reg); bfa_trc(ioc, usecnt); return BFA_TRUE; @@ -114,10 +142,16 @@ bfa_ioc_ct_firmware_unlock(struct bfa_ioc_s *ioc) { u32 usecnt; + /* + * Firmware lock is relevant only for CNA. + */ + if (!ioc->cna) + return; + /* * If bios boot (flash based) -- do not decrement usage count */ - if (bfa_cb_image_get_size(bfa_ioc_asic_gen(ioc)) < + if (bfa_cb_image_get_size(BFA_IOC_FWIMG_TYPE(ioc)) < BFA_IOC_FWIMG_MINSZ) return; @@ -132,7 +166,6 @@ bfa_ioc_ct_firmware_unlock(struct bfa_ioc_s *ioc) writel(usecnt, ioc->ioc_regs.ioc_usage_reg); bfa_trc(ioc, usecnt); - readl(ioc->ioc_regs.ioc_usage_sem_reg); writel(1, ioc->ioc_regs.ioc_usage_sem_reg); } @@ -142,14 +175,14 @@ bfa_ioc_ct_firmware_unlock(struct bfa_ioc_s *ioc) static void bfa_ioc_ct_notify_fail(struct bfa_ioc_s *ioc) { - if (bfa_ioc_is_cna(ioc)) { + if (ioc->cna) { writel(__FW_INIT_HALT_P, ioc->ioc_regs.ll_halt); writel(__FW_INIT_HALT_P, ioc->ioc_regs.alt_ll_halt); /* Wait for halt to take effect */ readl(ioc->ioc_regs.ll_halt); readl(ioc->ioc_regs.alt_ll_halt); } else { - writel(~0U, ioc->ioc_regs.err_set); + writel(__PSS_ERR_STATUS_SET, ioc->ioc_regs.err_set); readl(ioc->ioc_regs.err_set); } } @@ -157,7 +190,7 @@ bfa_ioc_ct_notify_fail(struct bfa_ioc_s *ioc) /* * Host to LPU mailbox message addresses */ -static struct { u32 hfn_mbox, lpu_mbox, hfn_pgn; } ct_fnreg[] = { +static struct { u32 hfn_mbox, lpu_mbox, hfn_pgn; } iocreg_fnreg[] = { { HOSTFN0_LPU_MBOX0_0, LPU_HOSTFN0_MBOX0_0, HOST_PAGE_NUM_FN0 }, { HOSTFN1_LPU_MBOX0_8, LPU_HOSTFN1_MBOX0_8, HOST_PAGE_NUM_FN1 }, { HOSTFN2_LPU_MBOX0_0, LPU_HOSTFN2_MBOX0_0, HOST_PAGE_NUM_FN2 }, @@ -167,31 +200,21 @@ static struct { u32 hfn_mbox, lpu_mbox, hfn_pgn; } ct_fnreg[] = { /* * Host <-> LPU mailbox command/status registers - port 0 */ -static struct { u32 hfn, lpu; } ct_p0reg[] = { - { HOSTFN0_LPU0_CMD_STAT, LPU0_HOSTFN0_CMD_STAT }, - { HOSTFN1_LPU0_CMD_STAT, LPU0_HOSTFN1_CMD_STAT }, - { HOSTFN2_LPU0_CMD_STAT, LPU0_HOSTFN2_CMD_STAT }, - { HOSTFN3_LPU0_CMD_STAT, LPU0_HOSTFN3_CMD_STAT } +static struct { u32 hfn, lpu; } iocreg_mbcmd_p0[] = { + { HOSTFN0_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN0_MBOX0_CMD_STAT }, + { HOSTFN1_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN1_MBOX0_CMD_STAT }, + { HOSTFN2_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN2_MBOX0_CMD_STAT }, + { HOSTFN3_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN3_MBOX0_CMD_STAT } }; /* * Host <-> LPU mailbox command/status registers - port 1 */ -static struct { u32 hfn, lpu; } ct_p1reg[] = { - { HOSTFN0_LPU1_CMD_STAT, LPU1_HOSTFN0_CMD_STAT }, - { HOSTFN1_LPU1_CMD_STAT, LPU1_HOSTFN1_CMD_STAT }, - { HOSTFN2_LPU1_CMD_STAT, LPU1_HOSTFN2_CMD_STAT }, - { HOSTFN3_LPU1_CMD_STAT, LPU1_HOSTFN3_CMD_STAT } -}; - -static struct { uint32_t hfn_mbox, lpu_mbox, hfn_pgn, hfn, lpu, lpu_read; } - ct2_reg[] = { - { CT2_HOSTFN_LPU0_MBOX0, CT2_LPU0_HOSTFN_MBOX0, CT2_HOSTFN_PAGE_NUM, - CT2_HOSTFN_LPU0_CMD_STAT, CT2_LPU0_HOSTFN_CMD_STAT, - CT2_HOSTFN_LPU0_READ_STAT}, - { CT2_HOSTFN_LPU1_MBOX0, CT2_LPU1_HOSTFN_MBOX0, CT2_HOSTFN_PAGE_NUM, - CT2_HOSTFN_LPU1_CMD_STAT, CT2_LPU1_HOSTFN_CMD_STAT, - CT2_HOSTFN_LPU1_READ_STAT}, +static struct { u32 hfn, lpu; } iocreg_mbcmd_p1[] = { + { HOSTFN0_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN0_MBOX0_CMD_STAT }, + { HOSTFN1_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN1_MBOX0_CMD_STAT }, + { HOSTFN2_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN2_MBOX0_CMD_STAT }, + { HOSTFN3_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN3_MBOX0_CMD_STAT } }; static void @@ -202,24 +225,24 @@ bfa_ioc_ct_reg_init(struct bfa_ioc_s *ioc) rb = bfa_ioc_bar0(ioc); - ioc->ioc_regs.hfn_mbox = rb + ct_fnreg[pcifn].hfn_mbox; - ioc->ioc_regs.lpu_mbox = rb + ct_fnreg[pcifn].lpu_mbox; - ioc->ioc_regs.host_page_num_fn = rb + ct_fnreg[pcifn].hfn_pgn; + ioc->ioc_regs.hfn_mbox = rb + iocreg_fnreg[pcifn].hfn_mbox; + ioc->ioc_regs.lpu_mbox = rb + iocreg_fnreg[pcifn].lpu_mbox; + ioc->ioc_regs.host_page_num_fn = rb + iocreg_fnreg[pcifn].hfn_pgn; if (ioc->port_id == 0) { ioc->ioc_regs.heartbeat = rb + BFA_IOC0_HBEAT_REG; ioc->ioc_regs.ioc_fwstate = rb + BFA_IOC0_STATE_REG; ioc->ioc_regs.alt_ioc_fwstate = rb + BFA_IOC1_STATE_REG; - ioc->ioc_regs.hfn_mbox_cmd = rb + ct_p0reg[pcifn].hfn; - ioc->ioc_regs.lpu_mbox_cmd = rb + ct_p0reg[pcifn].lpu; + ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd_p0[pcifn].hfn; + ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd_p0[pcifn].lpu; ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P0; ioc->ioc_regs.alt_ll_halt = rb + FW_INIT_HALT_P1; } else { ioc->ioc_regs.heartbeat = (rb + BFA_IOC1_HBEAT_REG); ioc->ioc_regs.ioc_fwstate = (rb + BFA_IOC1_STATE_REG); ioc->ioc_regs.alt_ioc_fwstate = rb + BFA_IOC0_STATE_REG; - ioc->ioc_regs.hfn_mbox_cmd = rb + ct_p1reg[pcifn].hfn; - ioc->ioc_regs.lpu_mbox_cmd = rb + ct_p1reg[pcifn].lpu; + ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd_p1[pcifn].hfn; + ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd_p1[pcifn].lpu; ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P1; ioc->ioc_regs.alt_ll_halt = rb + FW_INIT_HALT_P0; } @@ -229,8 +252,8 @@ bfa_ioc_ct_reg_init(struct bfa_ioc_s *ioc) */ ioc->ioc_regs.pss_ctl_reg = (rb + PSS_CTL_REG); ioc->ioc_regs.pss_err_status_reg = (rb + PSS_ERR_STATUS_REG); - ioc->ioc_regs.app_pll_fast_ctl_reg = (rb + APP_PLL_LCLK_CTL_REG); - ioc->ioc_regs.app_pll_slow_ctl_reg = (rb + APP_PLL_SCLK_CTL_REG); + ioc->ioc_regs.app_pll_fast_ctl_reg = (rb + APP_PLL_425_CTL_REG); + ioc->ioc_regs.app_pll_slow_ctl_reg = (rb + APP_PLL_312_CTL_REG); /* * IOC semaphore registers and serialization @@ -253,64 +276,6 @@ bfa_ioc_ct_reg_init(struct bfa_ioc_s *ioc) ioc->ioc_regs.err_set = (rb + ERR_SET_REG); } -static void -bfa_ioc_ct2_reg_init(struct bfa_ioc_s *ioc) -{ - void __iomem *rb; - int port = bfa_ioc_portid(ioc); - - rb = bfa_ioc_bar0(ioc); - - ioc->ioc_regs.hfn_mbox = rb + ct2_reg[port].hfn_mbox; - ioc->ioc_regs.lpu_mbox = rb + ct2_reg[port].lpu_mbox; - ioc->ioc_regs.host_page_num_fn = rb + ct2_reg[port].hfn_pgn; - ioc->ioc_regs.hfn_mbox_cmd = rb + ct2_reg[port].hfn; - ioc->ioc_regs.lpu_mbox_cmd = rb + ct2_reg[port].lpu; - ioc->ioc_regs.lpu_read_stat = rb + ct2_reg[port].lpu_read; - - if (port == 0) { - ioc->ioc_regs.heartbeat = rb + CT2_BFA_IOC0_HBEAT_REG; - ioc->ioc_regs.ioc_fwstate = rb + CT2_BFA_IOC0_STATE_REG; - ioc->ioc_regs.alt_ioc_fwstate = rb + CT2_BFA_IOC1_STATE_REG; - ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P0; - ioc->ioc_regs.alt_ll_halt = rb + FW_INIT_HALT_P1; - } else { - ioc->ioc_regs.heartbeat = (rb + CT2_BFA_IOC1_HBEAT_REG); - ioc->ioc_regs.ioc_fwstate = (rb + CT2_BFA_IOC1_STATE_REG); - ioc->ioc_regs.alt_ioc_fwstate = rb + CT2_BFA_IOC0_STATE_REG; - ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P1; - ioc->ioc_regs.alt_ll_halt = rb + FW_INIT_HALT_P0; - } - - /* - * PSS control registers - */ - ioc->ioc_regs.pss_ctl_reg = (rb + PSS_CTL_REG); - ioc->ioc_regs.pss_err_status_reg = (rb + PSS_ERR_STATUS_REG); - ioc->ioc_regs.app_pll_fast_ctl_reg = (rb + CT2_APP_PLL_LCLK_CTL_REG); - ioc->ioc_regs.app_pll_slow_ctl_reg = (rb + CT2_APP_PLL_SCLK_CTL_REG); - - /* - * IOC semaphore registers and serialization - */ - ioc->ioc_regs.ioc_sem_reg = (rb + CT2_HOST_SEM0_REG); - ioc->ioc_regs.ioc_usage_sem_reg = (rb + CT2_HOST_SEM1_REG); - ioc->ioc_regs.ioc_init_sem_reg = (rb + CT2_HOST_SEM2_REG); - ioc->ioc_regs.ioc_usage_reg = (rb + CT2_BFA_FW_USE_COUNT); - ioc->ioc_regs.ioc_fail_sync = (rb + CT2_BFA_IOC_FAIL_SYNC); - - /* - * sram memory access - */ - ioc->ioc_regs.smem_page_start = (rb + PSS_SMEM_PAGE_START); - ioc->ioc_regs.smem_pg0 = BFI_IOC_SMEM_PG0_CT; - - /* - * err set reg : for notification of hb failure in fcmode - */ - ioc->ioc_regs.err_set = (rb + ERR_SET_REG); -} - /* * Initialize IOC to port mapping. */ @@ -333,19 +298,6 @@ bfa_ioc_ct_map_port(struct bfa_ioc_s *ioc) bfa_trc(ioc, ioc->port_id); } -static void -bfa_ioc_ct2_map_port(struct bfa_ioc_s *ioc) -{ - void __iomem *rb = ioc->pcidev.pci_bar_kva; - u32 r32; - - r32 = readl(rb + CT2_HOSTFN_PERSONALITY0); - ioc->port_id = ((r32 & __FC_LL_PORT_MAP__MK) >> __FC_LL_PORT_MAP__SH); - - bfa_trc(ioc, bfa_ioc_pcifn(ioc)); - bfa_trc(ioc, ioc->port_id); -} - /* * Set interrupt mode for a function: INTX or MSIX */ @@ -364,7 +316,7 @@ bfa_ioc_ct_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix) /* * If already in desired mode, do not change anything */ - if ((!msix && mode) || (msix && !mode)) + if (!msix && mode) return; if (msix) @@ -379,20 +331,6 @@ bfa_ioc_ct_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix) writel(r32, rb + FNC_PERS_REG); } -bfa_boolean_t -bfa_ioc_ct2_lpu_read_stat(struct bfa_ioc_s *ioc) -{ - u32 r32; - - r32 = readl(ioc->ioc_regs.lpu_read_stat); - if (r32) { - writel(1, ioc->ioc_regs.lpu_read_stat); - return BFA_TRUE; - } - - return BFA_FALSE; -} - /* * Cleanup hw semaphore and usecnt registers */ @@ -400,10 +338,9 @@ static void bfa_ioc_ct_ownership_reset(struct bfa_ioc_s *ioc) { - if (bfa_ioc_is_cna(ioc)) { + if (ioc->cna) { bfa_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg); writel(0, ioc->ioc_regs.ioc_usage_reg); - readl(ioc->ioc_regs.ioc_usage_sem_reg); writel(1, ioc->ioc_regs.ioc_usage_sem_reg); } @@ -512,99 +449,32 @@ bfa_ioc_ct_sync_complete(struct bfa_ioc_s *ioc) return BFA_FALSE; } -/** - * Called from bfa_ioc_attach() to map asic specific calls. - */ -static void -bfa_ioc_set_ctx_hwif(struct bfa_ioc_s *ioc, struct bfa_ioc_hwif_s *hwif) -{ - hwif->ioc_firmware_lock = bfa_ioc_ct_firmware_lock; - hwif->ioc_firmware_unlock = bfa_ioc_ct_firmware_unlock; - hwif->ioc_notify_fail = bfa_ioc_ct_notify_fail; - hwif->ioc_ownership_reset = bfa_ioc_ct_ownership_reset; - hwif->ioc_sync_start = bfa_ioc_ct_sync_start; - hwif->ioc_sync_join = bfa_ioc_ct_sync_join; - hwif->ioc_sync_leave = bfa_ioc_ct_sync_leave; - hwif->ioc_sync_ack = bfa_ioc_ct_sync_ack; - hwif->ioc_sync_complete = bfa_ioc_ct_sync_complete; -} - -/** - * Called from bfa_ioc_attach() to map asic specific calls. - */ -void -bfa_ioc_set_ct_hwif(struct bfa_ioc_s *ioc) -{ - bfa_ioc_set_ctx_hwif(ioc, &hwif_ct); - - hwif_ct.ioc_pll_init = bfa_ioc_ct_pll_init; - hwif_ct.ioc_reg_init = bfa_ioc_ct_reg_init; - hwif_ct.ioc_map_port = bfa_ioc_ct_map_port; - hwif_ct.ioc_isr_mode_set = bfa_ioc_ct_isr_mode_set; - ioc->ioc_hwif = &hwif_ct; -} - -/** - * Called from bfa_ioc_attach() to map asic specific calls. - */ -void -bfa_ioc_set_ct2_hwif(struct bfa_ioc_s *ioc) -{ - bfa_ioc_set_ctx_hwif(ioc, &hwif_ct2); - - hwif_ct2.ioc_pll_init = bfa_ioc_ct2_pll_init; - hwif_ct2.ioc_reg_init = bfa_ioc_ct2_reg_init; - hwif_ct2.ioc_map_port = bfa_ioc_ct2_map_port; - hwif_ct2.ioc_lpu_read_stat = bfa_ioc_ct2_lpu_read_stat; - hwif_ct2.ioc_isr_mode_set = NULL; - ioc->ioc_hwif = &hwif_ct2; -} - /* - * Workaround for MSI-X resource allocation for catapult-2 with no asic block + * Check the firmware state to know if pll_init has been completed already */ -#define HOSTFN_MSIX_DEFAULT 64 -#define HOSTFN_MSIX_VT_INDEX_MBOX_ERR 0x30138 -#define HOSTFN_MSIX_VT_OFST_NUMVT 0x3013c -#define __MSIX_VT_NUMVT__MK 0x003ff800 -#define __MSIX_VT_NUMVT__SH 11 -#define __MSIX_VT_NUMVT_(_v) ((_v) << __MSIX_VT_NUMVT__SH) -#define __MSIX_VT_OFST_ 0x000007ff -void -bfa_ioc_ct2_poweron(struct bfa_ioc_s *ioc) +bfa_boolean_t +bfa_ioc_ct_pll_init_complete(void __iomem *rb) { - void __iomem *rb = ioc->pcidev.pci_bar_kva; - u32 r32; - - r32 = readl(rb + HOSTFN_MSIX_VT_OFST_NUMVT); - if (r32 & __MSIX_VT_NUMVT__MK) { - writel(r32 & __MSIX_VT_OFST_, - rb + HOSTFN_MSIX_VT_INDEX_MBOX_ERR); - return; - } + if ((readl(rb + BFA_IOC0_STATE_REG) == BFI_IOC_OP) || + (readl(rb + BFA_IOC1_STATE_REG) == BFI_IOC_OP)) + return BFA_TRUE; - writel(__MSIX_VT_NUMVT_(HOSTFN_MSIX_DEFAULT - 1) | - HOSTFN_MSIX_DEFAULT * bfa_ioc_pcifn(ioc), - rb + HOSTFN_MSIX_VT_OFST_NUMVT); - writel(HOSTFN_MSIX_DEFAULT * bfa_ioc_pcifn(ioc), - rb + HOSTFN_MSIX_VT_INDEX_MBOX_ERR); + return BFA_FALSE; } bfa_status_t -bfa_ioc_ct_pll_init(void __iomem *rb, enum bfi_asic_mode mode) +bfa_ioc_ct_pll_init(void __iomem *rb, bfa_boolean_t fcmode) { u32 pll_sclk, pll_fclk, r32; - bfa_boolean_t fcmode = (mode == BFI_ASIC_MODE_FC); - - pll_sclk = __APP_PLL_SCLK_LRESETN | __APP_PLL_SCLK_ENARST | - __APP_PLL_SCLK_RSEL200500 | __APP_PLL_SCLK_P0_1(3U) | - __APP_PLL_SCLK_JITLMT0_1(3U) | - __APP_PLL_SCLK_CNTLMT0_1(1U); - pll_fclk = __APP_PLL_LCLK_LRESETN | __APP_PLL_LCLK_ENARST | - __APP_PLL_LCLK_RSEL200500 | __APP_PLL_LCLK_P0_1(3U) | - __APP_PLL_LCLK_JITLMT0_1(3U) | - __APP_PLL_LCLK_CNTLMT0_1(1U); + pll_sclk = __APP_PLL_312_LRESETN | __APP_PLL_312_ENARST | + __APP_PLL_312_RSEL200500 | __APP_PLL_312_P0_1(3U) | + __APP_PLL_312_JITLMT0_1(3U) | + __APP_PLL_312_CNTLMT0_1(1U); + pll_fclk = __APP_PLL_425_LRESETN | __APP_PLL_425_ENARST | + __APP_PLL_425_RSEL200500 | __APP_PLL_425_P0_1(3U) | + __APP_PLL_425_JITLMT0_1(3U) | + __APP_PLL_425_CNTLMT0_1(1U); if (fcmode) { writel(0, (rb + OP_MODE)); writel(__APP_EMS_CMLCKSEL | __APP_EMS_REFCKBUFEN2 | @@ -621,21 +491,20 @@ bfa_ioc_ct_pll_init(void __iomem *rb, enum bfi_asic_mode mode) writel(0xffffffffU, (rb + HOSTFN1_INT_STATUS)); writel(0xffffffffU, (rb + HOSTFN0_INT_MSK)); writel(0xffffffffU, (rb + HOSTFN1_INT_MSK)); - writel(pll_sclk | __APP_PLL_SCLK_LOGIC_SOFT_RESET, - rb + APP_PLL_SCLK_CTL_REG); - writel(pll_fclk | __APP_PLL_LCLK_LOGIC_SOFT_RESET, - rb + APP_PLL_LCLK_CTL_REG); - writel(pll_sclk | __APP_PLL_SCLK_LOGIC_SOFT_RESET | - __APP_PLL_SCLK_ENABLE, rb + APP_PLL_SCLK_CTL_REG); - writel(pll_fclk | __APP_PLL_LCLK_LOGIC_SOFT_RESET | - __APP_PLL_LCLK_ENABLE, rb + APP_PLL_LCLK_CTL_REG); + writel(pll_sclk | __APP_PLL_312_LOGIC_SOFT_RESET, + rb + APP_PLL_312_CTL_REG); + writel(pll_fclk | __APP_PLL_425_LOGIC_SOFT_RESET, + rb + APP_PLL_425_CTL_REG); + writel(pll_sclk | __APP_PLL_312_LOGIC_SOFT_RESET | __APP_PLL_312_ENABLE, + rb + APP_PLL_312_CTL_REG); + writel(pll_fclk | __APP_PLL_425_LOGIC_SOFT_RESET | __APP_PLL_425_ENABLE, + rb + APP_PLL_425_CTL_REG); readl(rb + HOSTFN0_INT_MSK); udelay(2000); writel(0xffffffffU, (rb + HOSTFN0_INT_STATUS)); writel(0xffffffffU, (rb + HOSTFN1_INT_STATUS)); - writel(pll_sclk | __APP_PLL_SCLK_ENABLE, rb + APP_PLL_SCLK_CTL_REG); - writel(pll_fclk | __APP_PLL_LCLK_ENABLE, rb + APP_PLL_LCLK_CTL_REG); - + writel(pll_sclk | __APP_PLL_312_ENABLE, rb + APP_PLL_312_CTL_REG); + writel(pll_fclk | __APP_PLL_425_ENABLE, rb + APP_PLL_425_CTL_REG); if (!fcmode) { writel(__PMM_1T_RESET_P, (rb + PMM_1T_RESET_REG_P0)); writel(__PMM_1T_RESET_P, (rb + PMM_1T_RESET_REG_P1)); @@ -655,206 +524,3 @@ bfa_ioc_ct_pll_init(void __iomem *rb, enum bfi_asic_mode mode) writel(0, (rb + MBIST_CTL_REG)); return BFA_STATUS_OK; } - -static void -bfa_ioc_ct2_sclk_init(void __iomem *rb) -{ - u32 r32; - - /* - * put s_clk PLL and PLL FSM in reset - */ - r32 = readl((rb + CT2_APP_PLL_SCLK_CTL_REG)); - r32 &= ~(__APP_PLL_SCLK_ENABLE | __APP_PLL_SCLK_LRESETN); - r32 |= (__APP_PLL_SCLK_ENARST | __APP_PLL_SCLK_BYPASS | - __APP_PLL_SCLK_LOGIC_SOFT_RESET); - writel(r32, (rb + CT2_APP_PLL_SCLK_CTL_REG)); - - /* - * Ignore mode and program for the max clock (which is FC16) - * Firmware/NFC will do the PLL init appropiately - */ - r32 = readl((rb + CT2_APP_PLL_SCLK_CTL_REG)); - r32 &= ~(__APP_PLL_SCLK_REFCLK_SEL | __APP_PLL_SCLK_CLK_DIV2); - writel(r32, (rb + CT2_APP_PLL_SCLK_CTL_REG)); - - /* - * while doing PLL init dont clock gate ethernet subsystem - */ - r32 = readl((rb + CT2_CHIP_MISC_PRG)); - writel(r32 | __ETH_CLK_ENABLE_PORT0, (rb + CT2_CHIP_MISC_PRG)); - - r32 = readl((rb + CT2_PCIE_MISC_REG)); - writel(r32 | __ETH_CLK_ENABLE_PORT1, (rb + CT2_PCIE_MISC_REG)); - - /* - * set sclk value - */ - r32 = readl((rb + CT2_APP_PLL_SCLK_CTL_REG)); - r32 &= (__P_SCLK_PLL_LOCK | __APP_PLL_SCLK_REFCLK_SEL | - __APP_PLL_SCLK_CLK_DIV2); - writel(r32 | 0x1061731b, (rb + CT2_APP_PLL_SCLK_CTL_REG)); - - /* - * poll for s_clk lock or delay 1ms - */ - udelay(1000); -} - -static void -bfa_ioc_ct2_lclk_init(void __iomem *rb) -{ - u32 r32; - - /* - * put l_clk PLL and PLL FSM in reset - */ - r32 = readl((rb + CT2_APP_PLL_LCLK_CTL_REG)); - r32 &= ~(__APP_PLL_LCLK_ENABLE | __APP_PLL_LCLK_LRESETN); - r32 |= (__APP_PLL_LCLK_ENARST | __APP_PLL_LCLK_BYPASS | - __APP_PLL_LCLK_LOGIC_SOFT_RESET); - writel(r32, (rb + CT2_APP_PLL_LCLK_CTL_REG)); - - /* - * set LPU speed (set for FC16 which will work for other modes) - */ - r32 = readl((rb + CT2_CHIP_MISC_PRG)); - writel(r32, (rb + CT2_CHIP_MISC_PRG)); - - /* - * set LPU half speed (set for FC16 which will work for other modes) - */ - r32 = readl((rb + CT2_APP_PLL_LCLK_CTL_REG)); - writel(r32, (rb + CT2_APP_PLL_LCLK_CTL_REG)); - - /* - * set lclk for mode (set for FC16) - */ - r32 = readl((rb + CT2_APP_PLL_LCLK_CTL_REG)); - r32 &= (__P_LCLK_PLL_LOCK | __APP_LPUCLK_HALFSPEED); - r32 |= 0x20c1731b; - writel(r32, (rb + CT2_APP_PLL_LCLK_CTL_REG)); - - /* - * poll for s_clk lock or delay 1ms - */ - udelay(1000); -} - -static void -bfa_ioc_ct2_mem_init(void __iomem *rb) -{ - u32 r32; - - r32 = readl((rb + PSS_CTL_REG)); - r32 &= ~__PSS_LMEM_RESET; - writel(r32, (rb + PSS_CTL_REG)); - udelay(1000); - - writel(__EDRAM_BISTR_START, (rb + CT2_MBIST_CTL_REG)); - udelay(1000); - writel(0, (rb + CT2_MBIST_CTL_REG)); -} - -void -bfa_ioc_ct2_mac_reset(void __iomem *rb) -{ - u32 r32; - - bfa_ioc_ct2_sclk_init(rb); - bfa_ioc_ct2_lclk_init(rb); - - /* - * release soft reset on s_clk & l_clk - */ - r32 = readl((rb + CT2_APP_PLL_SCLK_CTL_REG)); - writel(r32 & ~__APP_PLL_SCLK_LOGIC_SOFT_RESET, - (rb + CT2_APP_PLL_SCLK_CTL_REG)); - - /* - * release soft reset on s_clk & l_clk - */ - r32 = readl((rb + CT2_APP_PLL_LCLK_CTL_REG)); - writel(r32 & ~__APP_PLL_LCLK_LOGIC_SOFT_RESET, - (rb + CT2_APP_PLL_LCLK_CTL_REG)); - - /* put port0, port1 MAC & AHB in reset */ - writel((__CSI_MAC_RESET | __CSI_MAC_AHB_RESET), - rb + CT2_CSI_MAC_CONTROL_REG(0)); - writel((__CSI_MAC_RESET | __CSI_MAC_AHB_RESET), - rb + CT2_CSI_MAC_CONTROL_REG(1)); -} - -#define CT2_NFC_MAX_DELAY 1000 -bfa_status_t -bfa_ioc_ct2_pll_init(void __iomem *rb, enum bfi_asic_mode mode) -{ - u32 wgn, r32; - int i; - - /* - * Initialize PLL if not already done by NFC - */ - wgn = readl(rb + CT2_WGN_STATUS); - if (!(wgn & __GLBL_PF_VF_CFG_RDY)) { - writel(__HALT_NFC_CONTROLLER, rb + CT2_NFC_CSR_SET_REG); - for (i = 0; i < CT2_NFC_MAX_DELAY; i++) { - r32 = readl(rb + CT2_NFC_CSR_SET_REG); - if (r32 & __NFC_CONTROLLER_HALTED) - break; - udelay(1000); - } - } - - /* - * Mask the interrupts and clear any - * pending interrupts. - */ - writel(1, (rb + CT2_LPU0_HOSTFN_MBOX0_MSK)); - writel(1, (rb + CT2_LPU1_HOSTFN_MBOX0_MSK)); - - r32 = readl((rb + CT2_LPU0_HOSTFN_CMD_STAT)); - if (r32 == 1) { - writel(1, (rb + CT2_LPU0_HOSTFN_CMD_STAT)); - readl((rb + CT2_LPU0_HOSTFN_CMD_STAT)); - } - r32 = readl((rb + CT2_LPU1_HOSTFN_CMD_STAT)); - if (r32 == 1) { - writel(1, (rb + CT2_LPU1_HOSTFN_CMD_STAT)); - readl((rb + CT2_LPU1_HOSTFN_CMD_STAT)); - } - - bfa_ioc_ct2_mac_reset(rb); - bfa_ioc_ct2_sclk_init(rb); - bfa_ioc_ct2_lclk_init(rb); - - /* - * release soft reset on s_clk & l_clk - */ - r32 = readl((rb + CT2_APP_PLL_SCLK_CTL_REG)); - writel(r32 & ~__APP_PLL_SCLK_LOGIC_SOFT_RESET, - (rb + CT2_APP_PLL_SCLK_CTL_REG)); - - /* - * release soft reset on s_clk & l_clk - */ - r32 = readl((rb + CT2_APP_PLL_LCLK_CTL_REG)); - writel(r32 & ~__APP_PLL_LCLK_LOGIC_SOFT_RESET, - (rb + CT2_APP_PLL_LCLK_CTL_REG)); - - /* - * Announce flash device presence, if flash was corrupted. - */ - if (wgn == (__WGN_READY | __GLBL_PF_VF_CFG_RDY)) { - r32 = readl((rb + PSS_GPIO_OUT_REG)); - writel(r32 & ~1, (rb + PSS_GPIO_OUT_REG)); - r32 = readl((rb + PSS_GPIO_OE_REG)); - writel(r32 | 1, (rb + PSS_GPIO_OE_REG)); - } - - bfa_ioc_ct2_mem_init(rb); - - writel(BFI_IOC_UNINIT, (rb + CT2_BFA_IOC0_STATE_REG)); - writel(BFI_IOC_UNINIT, (rb + CT2_BFA_IOC1_STATE_REG)); - return BFA_STATUS_OK; -} diff --git a/trunk/drivers/scsi/bfa/bfa_modules.h b/trunk/drivers/scsi/bfa/bfa_modules.h index 1c6efd40a673..ab79ff6fdeea 100644 --- a/trunk/drivers/scsi/bfa/bfa_modules.h +++ b/trunk/drivers/scsi/bfa/bfa_modules.h @@ -29,21 +29,14 @@ #include "bfa_port.h" struct bfa_modules_s { - struct bfa_fcdiag_s fcdiag; /* fcdiag module */ struct bfa_fcport_s fcport; /* fc port module */ struct bfa_fcxp_mod_s fcxp_mod; /* fcxp module */ struct bfa_lps_mod_s lps_mod; /* fcxp module */ struct bfa_uf_mod_s uf_mod; /* unsolicited frame module */ struct bfa_rport_mod_s rport_mod; /* remote port module */ - struct bfa_fcp_mod_s fcp_mod; /* FCP initiator module */ + struct bfa_fcpim_mod_s fcpim_mod; /* FCP initiator module */ struct bfa_sgpg_mod_s sgpg_mod; /* SG page module */ struct bfa_port_s port; /* Physical port module */ - struct bfa_ablk_s ablk; /* ASIC block config module */ - struct bfa_cee_s cee; /* CEE Module */ - struct bfa_sfp_s sfp; /* SFP module */ - struct bfa_flash_s flash; /* flash module */ - struct bfa_diag_s diag_mod; /* diagnostics module */ - struct bfa_phy_s phy; /* phy module */ }; /* @@ -58,16 +51,17 @@ enum { BFA_TRC_HAL_IOCFC_CB = 5, }; + /* * Macro to define a new BFA module */ #define BFA_MODULE(__mod) \ static void bfa_ ## __mod ## _meminfo( \ - struct bfa_iocfc_cfg_s *cfg, \ - struct bfa_meminfo_s *meminfo, \ - struct bfa_s *bfa); \ + struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, \ + u32 *dm_len); \ static void bfa_ ## __mod ## _attach(struct bfa_s *bfa, \ void *bfad, struct bfa_iocfc_cfg_s *cfg, \ + struct bfa_meminfo_s *meminfo, \ struct bfa_pcidev_s *pcidev); \ static void bfa_ ## __mod ## _detach(struct bfa_s *bfa); \ static void bfa_ ## __mod ## _start(struct bfa_s *bfa); \ @@ -93,11 +87,11 @@ enum { * can leave entry points as NULL) */ struct bfa_module_s { - void (*meminfo) (struct bfa_iocfc_cfg_s *cfg, - struct bfa_meminfo_s *meminfo, - struct bfa_s *bfa); + void (*meminfo) (struct bfa_iocfc_cfg_s *cfg, u32 *km_len, + u32 *dm_len); void (*attach) (struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, + struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev); void (*detach) (struct bfa_s *bfa); void (*start) (struct bfa_s *bfa); @@ -115,20 +109,19 @@ struct bfa_s { struct bfa_timer_mod_s timer_mod; /* timer module */ struct bfa_modules_s modules; /* BFA modules */ struct list_head comp_q; /* pending completions */ - bfa_boolean_t queue_process; /* queue processing enabled */ + bfa_boolean_t rme_process; /* RME processing enabled */ struct list_head reqq_waitq[BFI_IOC_MAX_CQS]; bfa_boolean_t fcs; /* FCS is attached to BFA */ struct bfa_msix_s msix; }; extern bfa_boolean_t bfa_auto_recover; -extern struct bfa_module_s hal_mod_fcdiag; extern struct bfa_module_s hal_mod_sgpg; extern struct bfa_module_s hal_mod_fcport; extern struct bfa_module_s hal_mod_fcxp; extern struct bfa_module_s hal_mod_lps; extern struct bfa_module_s hal_mod_uf; extern struct bfa_module_s hal_mod_rport; -extern struct bfa_module_s hal_mod_fcp; +extern struct bfa_module_s hal_mod_fcpim; #endif /* __BFA_MODULES_H__ */ diff --git a/trunk/drivers/scsi/bfa/bfa_port.c b/trunk/drivers/scsi/bfa/bfa_port.c index 95e4ad8759ac..3f8e9d6066ec 100644 --- a/trunk/drivers/scsi/bfa/bfa_port.c +++ b/trunk/drivers/scsi/bfa/bfa_port.c @@ -24,6 +24,8 @@ BFA_TRC_FILE(CNA, PORT); +#define bfa_ioc_portid(__ioc) ((__ioc)->port_id) + static void bfa_port_stats_swap(struct bfa_port_s *port, union bfa_port_stats_u *stats) { @@ -234,12 +236,6 @@ bfa_port_enable(struct bfa_port_s *port, bfa_port_endis_cbfn_t cbfn, { struct bfi_port_generic_req_s *m; - /* If port is PBC disabled, return error */ - if (port->pbc_disabled) { - bfa_trc(port, BFA_STATUS_PBC); - return BFA_STATUS_PBC; - } - if (bfa_ioc_is_disabled(port->ioc)) { bfa_trc(port, BFA_STATUS_IOC_DISABLED); return BFA_STATUS_IOC_DISABLED; @@ -284,12 +280,6 @@ bfa_port_disable(struct bfa_port_s *port, bfa_port_endis_cbfn_t cbfn, { struct bfi_port_generic_req_s *m; - /* If port is PBC disabled, return error */ - if (port->pbc_disabled) { - bfa_trc(port, BFA_STATUS_PBC); - return BFA_STATUS_PBC; - } - if (bfa_ioc_is_disabled(port->ioc)) { bfa_trc(port, BFA_STATUS_IOC_DISABLED); return BFA_STATUS_IOC_DISABLED; @@ -397,43 +387,32 @@ bfa_port_clear_stats(struct bfa_port_s *port, bfa_port_stats_cbfn_t cbfn, } /* - * bfa_port_notify() + * bfa_port_hbfail() * - * Port module IOC event handler * * @param[in] Pointer to the Port module data structure. - * @param[in] IOC event structure * * @return void */ void -bfa_port_notify(void *arg, enum bfa_ioc_event_e event) +bfa_port_hbfail(void *arg) { struct bfa_port_s *port = (struct bfa_port_s *) arg; - switch (event) { - case BFA_IOC_E_DISABLED: - case BFA_IOC_E_FAILED: - /* Fail any pending get_stats/clear_stats requests */ - if (port->stats_busy) { - if (port->stats_cbfn) - port->stats_cbfn(port->stats_cbarg, - BFA_STATUS_FAILED); - port->stats_cbfn = NULL; - port->stats_busy = BFA_FALSE; - } - - /* Clear any enable/disable is pending */ - if (port->endis_pending) { - if (port->endis_cbfn) - port->endis_cbfn(port->endis_cbarg, - BFA_STATUS_FAILED); - port->endis_cbfn = NULL; - port->endis_pending = BFA_FALSE; - } - break; - default: - break; + /* Fail any pending get_stats/clear_stats requests */ + if (port->stats_busy) { + if (port->stats_cbfn) + port->stats_cbfn(port->stats_cbarg, BFA_STATUS_FAILED); + port->stats_cbfn = NULL; + port->stats_busy = BFA_FALSE; + } + + /* Clear any enable/disable is pending */ + if (port->endis_pending) { + if (port->endis_cbfn) + port->endis_cbfn(port->endis_cbarg, BFA_STATUS_FAILED); + port->endis_cbfn = NULL; + port->endis_pending = BFA_FALSE; } } @@ -466,12 +445,10 @@ bfa_port_attach(struct bfa_port_s *port, struct bfa_ioc_s *ioc, port->endis_pending = BFA_FALSE; port->stats_cbfn = NULL; port->endis_cbfn = NULL; - port->pbc_disabled = BFA_FALSE; bfa_ioc_mbox_regisr(port->ioc, BFI_MC_PORT, bfa_port_isr, port); - bfa_q_qe_init(&port->ioc_notify); - bfa_ioc_notify_init(&port->ioc_notify, bfa_port_notify, port); - list_add_tail(&port->ioc_notify.qe, &port->ioc->notify_q); + bfa_ioc_hbfail_init(&port->hbfail, bfa_port_hbfail, port); + list_add_tail(&port->hbfail.qe, &port->ioc->hb_notify_q); /* * initialize time stamp for stats reset @@ -481,368 +458,3 @@ bfa_port_attach(struct bfa_port_s *port, struct bfa_ioc_s *ioc, bfa_trc(port, 0); } - -/* - * CEE module specific definitions - */ - -/* - * bfa_cee_get_attr_isr() - * - * @brief CEE ISR for get-attributes responses from f/w - * - * @param[in] cee - Pointer to the CEE module - * status - Return status from the f/w - * - * @return void - */ -static void -bfa_cee_get_attr_isr(struct bfa_cee_s *cee, bfa_status_t status) -{ - struct bfa_cee_lldp_cfg_s *lldp_cfg = &cee->attr->lldp_remote; - - cee->get_attr_status = status; - bfa_trc(cee, 0); - if (status == BFA_STATUS_OK) { - bfa_trc(cee, 0); - memcpy(cee->attr, cee->attr_dma.kva, - sizeof(struct bfa_cee_attr_s)); - lldp_cfg->time_to_live = be16_to_cpu(lldp_cfg->time_to_live); - lldp_cfg->enabled_system_cap = - be16_to_cpu(lldp_cfg->enabled_system_cap); - } - cee->get_attr_pending = BFA_FALSE; - if (cee->cbfn.get_attr_cbfn) { - bfa_trc(cee, 0); - cee->cbfn.get_attr_cbfn(cee->cbfn.get_attr_cbarg, status); - } -} - -/* - * bfa_cee_get_stats_isr() - * - * @brief CEE ISR for get-stats responses from f/w - * - * @param[in] cee - Pointer to the CEE module - * status - Return status from the f/w - * - * @return void - */ -static void -bfa_cee_get_stats_isr(struct bfa_cee_s *cee, bfa_status_t status) -{ - u32 *buffer; - int i; - - cee->get_stats_status = status; - bfa_trc(cee, 0); - if (status == BFA_STATUS_OK) { - bfa_trc(cee, 0); - memcpy(cee->stats, cee->stats_dma.kva, - sizeof(struct bfa_cee_stats_s)); - /* swap the cee stats */ - buffer = (u32 *)cee->stats; - for (i = 0; i < (sizeof(struct bfa_cee_stats_s) / - sizeof(u32)); i++) - buffer[i] = cpu_to_be32(buffer[i]); - } - cee->get_stats_pending = BFA_FALSE; - bfa_trc(cee, 0); - if (cee->cbfn.get_stats_cbfn) { - bfa_trc(cee, 0); - cee->cbfn.get_stats_cbfn(cee->cbfn.get_stats_cbarg, status); - } -} - -/* - * bfa_cee_reset_stats_isr() - * - * @brief CEE ISR for reset-stats responses from f/w - * - * @param[in] cee - Pointer to the CEE module - * status - Return status from the f/w - * - * @return void - */ -static void -bfa_cee_reset_stats_isr(struct bfa_cee_s *cee, bfa_status_t status) -{ - cee->reset_stats_status = status; - cee->reset_stats_pending = BFA_FALSE; - if (cee->cbfn.reset_stats_cbfn) - cee->cbfn.reset_stats_cbfn(cee->cbfn.reset_stats_cbarg, status); -} - -/* - * bfa_cee_meminfo() - * - * @brief Returns the size of the DMA memory needed by CEE module - * - * @param[in] void - * - * @return Size of DMA region - */ -u32 -bfa_cee_meminfo(void) -{ - return BFA_ROUNDUP(sizeof(struct bfa_cee_attr_s), BFA_DMA_ALIGN_SZ) + - BFA_ROUNDUP(sizeof(struct bfa_cee_stats_s), BFA_DMA_ALIGN_SZ); -} - -/* - * bfa_cee_mem_claim() - * - * @brief Initialized CEE DMA Memory - * - * @param[in] cee CEE module pointer - * dma_kva Kernel Virtual Address of CEE DMA Memory - * dma_pa Physical Address of CEE DMA Memory - * - * @return void - */ -void -bfa_cee_mem_claim(struct bfa_cee_s *cee, u8 *dma_kva, u64 dma_pa) -{ - cee->attr_dma.kva = dma_kva; - cee->attr_dma.pa = dma_pa; - cee->stats_dma.kva = dma_kva + BFA_ROUNDUP( - sizeof(struct bfa_cee_attr_s), BFA_DMA_ALIGN_SZ); - cee->stats_dma.pa = dma_pa + BFA_ROUNDUP( - sizeof(struct bfa_cee_attr_s), BFA_DMA_ALIGN_SZ); - cee->attr = (struct bfa_cee_attr_s *) dma_kva; - cee->stats = (struct bfa_cee_stats_s *) (dma_kva + BFA_ROUNDUP( - sizeof(struct bfa_cee_attr_s), BFA_DMA_ALIGN_SZ)); -} - -/* - * bfa_cee_get_attr() - * - * @brief - * Send the request to the f/w to fetch CEE attributes. - * - * @param[in] Pointer to the CEE module data structure. - * - * @return Status - */ - -bfa_status_t -bfa_cee_get_attr(struct bfa_cee_s *cee, struct bfa_cee_attr_s *attr, - bfa_cee_get_attr_cbfn_t cbfn, void *cbarg) -{ - struct bfi_cee_get_req_s *cmd; - - WARN_ON((cee == NULL) || (cee->ioc == NULL)); - bfa_trc(cee, 0); - if (!bfa_ioc_is_operational(cee->ioc)) { - bfa_trc(cee, 0); - return BFA_STATUS_IOC_FAILURE; - } - if (cee->get_attr_pending == BFA_TRUE) { - bfa_trc(cee, 0); - return BFA_STATUS_DEVBUSY; - } - cee->get_attr_pending = BFA_TRUE; - cmd = (struct bfi_cee_get_req_s *) cee->get_cfg_mb.msg; - cee->attr = attr; - cee->cbfn.get_attr_cbfn = cbfn; - cee->cbfn.get_attr_cbarg = cbarg; - bfi_h2i_set(cmd->mh, BFI_MC_CEE, BFI_CEE_H2I_GET_CFG_REQ, - bfa_ioc_portid(cee->ioc)); - bfa_dma_be_addr_set(cmd->dma_addr, cee->attr_dma.pa); - bfa_ioc_mbox_queue(cee->ioc, &cee->get_cfg_mb); - - return BFA_STATUS_OK; -} - -/* - * bfa_cee_get_stats() - * - * @brief - * Send the request to the f/w to fetch CEE statistics. - * - * @param[in] Pointer to the CEE module data structure. - * - * @return Status - */ - -bfa_status_t -bfa_cee_get_stats(struct bfa_cee_s *cee, struct bfa_cee_stats_s *stats, - bfa_cee_get_stats_cbfn_t cbfn, void *cbarg) -{ - struct bfi_cee_get_req_s *cmd; - - WARN_ON((cee == NULL) || (cee->ioc == NULL)); - - if (!bfa_ioc_is_operational(cee->ioc)) { - bfa_trc(cee, 0); - return BFA_STATUS_IOC_FAILURE; - } - if (cee->get_stats_pending == BFA_TRUE) { - bfa_trc(cee, 0); - return BFA_STATUS_DEVBUSY; - } - cee->get_stats_pending = BFA_TRUE; - cmd = (struct bfi_cee_get_req_s *) cee->get_stats_mb.msg; - cee->stats = stats; - cee->cbfn.get_stats_cbfn = cbfn; - cee->cbfn.get_stats_cbarg = cbarg; - bfi_h2i_set(cmd->mh, BFI_MC_CEE, BFI_CEE_H2I_GET_STATS_REQ, - bfa_ioc_portid(cee->ioc)); - bfa_dma_be_addr_set(cmd->dma_addr, cee->stats_dma.pa); - bfa_ioc_mbox_queue(cee->ioc, &cee->get_stats_mb); - - return BFA_STATUS_OK; -} - -/* - * bfa_cee_reset_stats() - * - * @brief Clears CEE Stats in the f/w. - * - * @param[in] Pointer to the CEE module data structure. - * - * @return Status - */ - -bfa_status_t -bfa_cee_reset_stats(struct bfa_cee_s *cee, - bfa_cee_reset_stats_cbfn_t cbfn, void *cbarg) -{ - struct bfi_cee_reset_stats_s *cmd; - - WARN_ON((cee == NULL) || (cee->ioc == NULL)); - if (!bfa_ioc_is_operational(cee->ioc)) { - bfa_trc(cee, 0); - return BFA_STATUS_IOC_FAILURE; - } - if (cee->reset_stats_pending == BFA_TRUE) { - bfa_trc(cee, 0); - return BFA_STATUS_DEVBUSY; - } - cee->reset_stats_pending = BFA_TRUE; - cmd = (struct bfi_cee_reset_stats_s *) cee->reset_stats_mb.msg; - cee->cbfn.reset_stats_cbfn = cbfn; - cee->cbfn.reset_stats_cbarg = cbarg; - bfi_h2i_set(cmd->mh, BFI_MC_CEE, BFI_CEE_H2I_RESET_STATS, - bfa_ioc_portid(cee->ioc)); - bfa_ioc_mbox_queue(cee->ioc, &cee->reset_stats_mb); - - return BFA_STATUS_OK; -} - -/* - * bfa_cee_isrs() - * - * @brief Handles Mail-box interrupts for CEE module. - * - * @param[in] Pointer to the CEE module data structure. - * - * @return void - */ - -void -bfa_cee_isr(void *cbarg, struct bfi_mbmsg_s *m) -{ - union bfi_cee_i2h_msg_u *msg; - struct bfi_cee_get_rsp_s *get_rsp; - struct bfa_cee_s *cee = (struct bfa_cee_s *) cbarg; - msg = (union bfi_cee_i2h_msg_u *) m; - get_rsp = (struct bfi_cee_get_rsp_s *) m; - bfa_trc(cee, msg->mh.msg_id); - switch (msg->mh.msg_id) { - case BFI_CEE_I2H_GET_CFG_RSP: - bfa_trc(cee, get_rsp->cmd_status); - bfa_cee_get_attr_isr(cee, get_rsp->cmd_status); - break; - case BFI_CEE_I2H_GET_STATS_RSP: - bfa_cee_get_stats_isr(cee, get_rsp->cmd_status); - break; - case BFI_CEE_I2H_RESET_STATS_RSP: - bfa_cee_reset_stats_isr(cee, get_rsp->cmd_status); - break; - default: - WARN_ON(1); - } -} - -/* - * bfa_cee_notify() - * - * @brief CEE module IOC event handler. - * - * @param[in] Pointer to the CEE module data structure. - * @param[in] IOC event type - * - * @return void - */ - -void -bfa_cee_notify(void *arg, enum bfa_ioc_event_e event) -{ - struct bfa_cee_s *cee = (struct bfa_cee_s *) arg; - - bfa_trc(cee, event); - - switch (event) { - case BFA_IOC_E_DISABLED: - case BFA_IOC_E_FAILED: - if (cee->get_attr_pending == BFA_TRUE) { - cee->get_attr_status = BFA_STATUS_FAILED; - cee->get_attr_pending = BFA_FALSE; - if (cee->cbfn.get_attr_cbfn) { - cee->cbfn.get_attr_cbfn( - cee->cbfn.get_attr_cbarg, - BFA_STATUS_FAILED); - } - } - if (cee->get_stats_pending == BFA_TRUE) { - cee->get_stats_status = BFA_STATUS_FAILED; - cee->get_stats_pending = BFA_FALSE; - if (cee->cbfn.get_stats_cbfn) { - cee->cbfn.get_stats_cbfn( - cee->cbfn.get_stats_cbarg, - BFA_STATUS_FAILED); - } - } - if (cee->reset_stats_pending == BFA_TRUE) { - cee->reset_stats_status = BFA_STATUS_FAILED; - cee->reset_stats_pending = BFA_FALSE; - if (cee->cbfn.reset_stats_cbfn) { - cee->cbfn.reset_stats_cbfn( - cee->cbfn.reset_stats_cbarg, - BFA_STATUS_FAILED); - } - } - break; - - default: - break; - } -} - -/* - * bfa_cee_attach() - * - * @brief CEE module-attach API - * - * @param[in] cee - Pointer to the CEE module data structure - * ioc - Pointer to the ioc module data structure - * dev - Pointer to the device driver module data structure - * The device driver specific mbox ISR functions have - * this pointer as one of the parameters. - * - * @return void - */ -void -bfa_cee_attach(struct bfa_cee_s *cee, struct bfa_ioc_s *ioc, - void *dev) -{ - WARN_ON(cee == NULL); - cee->dev = dev; - cee->ioc = ioc; - - bfa_ioc_mbox_regisr(cee->ioc, BFI_MC_CEE, bfa_cee_isr, cee); - bfa_q_qe_init(&cee->ioc_notify); - bfa_ioc_notify_init(&cee->ioc_notify, bfa_cee_notify, cee); - list_add_tail(&cee->ioc_notify.qe, &cee->ioc->notify_q); -} diff --git a/trunk/drivers/scsi/bfa/bfa_port.h b/trunk/drivers/scsi/bfa/bfa_port.h index 947f897328d6..c4ee9db6b470 100644 --- a/trunk/drivers/scsi/bfa/bfa_port.h +++ b/trunk/drivers/scsi/bfa/bfa_port.h @@ -43,16 +43,12 @@ struct bfa_port_s { bfa_port_endis_cbfn_t endis_cbfn; void *endis_cbarg; bfa_status_t endis_status; - struct bfa_ioc_notify_s ioc_notify; - bfa_boolean_t pbc_disabled; - struct bfa_mem_dma_s port_dma; + struct bfa_ioc_hbfail_notify_s hbfail; }; -#define BFA_MEM_PORT_DMA(__bfa) (&((__bfa)->modules.port.port_dma)) - void bfa_port_attach(struct bfa_port_s *port, struct bfa_ioc_s *ioc, void *dev, struct bfa_trc_mod_s *trcmod); -void bfa_port_notify(void *arg, enum bfa_ioc_event_e event); +void bfa_port_hbfail(void *arg); bfa_status_t bfa_port_get_stats(struct bfa_port_s *port, union bfa_port_stats_u *stats, @@ -66,58 +62,4 @@ bfa_status_t bfa_port_disable(struct bfa_port_s *port, u32 bfa_port_meminfo(void); void bfa_port_mem_claim(struct bfa_port_s *port, u8 *dma_kva, u64 dma_pa); - -/* - * CEE declaration - */ -typedef void (*bfa_cee_get_attr_cbfn_t) (void *dev, bfa_status_t status); -typedef void (*bfa_cee_get_stats_cbfn_t) (void *dev, bfa_status_t status); -typedef void (*bfa_cee_reset_stats_cbfn_t) (void *dev, bfa_status_t status); - -struct bfa_cee_cbfn_s { - bfa_cee_get_attr_cbfn_t get_attr_cbfn; - void *get_attr_cbarg; - bfa_cee_get_stats_cbfn_t get_stats_cbfn; - void *get_stats_cbarg; - bfa_cee_reset_stats_cbfn_t reset_stats_cbfn; - void *reset_stats_cbarg; -}; - -struct bfa_cee_s { - void *dev; - bfa_boolean_t get_attr_pending; - bfa_boolean_t get_stats_pending; - bfa_boolean_t reset_stats_pending; - bfa_status_t get_attr_status; - bfa_status_t get_stats_status; - bfa_status_t reset_stats_status; - struct bfa_cee_cbfn_s cbfn; - struct bfa_ioc_notify_s ioc_notify; - struct bfa_trc_mod_s *trcmod; - struct bfa_cee_attr_s *attr; - struct bfa_cee_stats_s *stats; - struct bfa_dma_s attr_dma; - struct bfa_dma_s stats_dma; - struct bfa_ioc_s *ioc; - struct bfa_mbox_cmd_s get_cfg_mb; - struct bfa_mbox_cmd_s get_stats_mb; - struct bfa_mbox_cmd_s reset_stats_mb; - struct bfa_mem_dma_s cee_dma; -}; - -#define BFA_MEM_CEE_DMA(__bfa) (&((__bfa)->modules.cee.cee_dma)) - -u32 bfa_cee_meminfo(void); -void bfa_cee_mem_claim(struct bfa_cee_s *cee, u8 *dma_kva, u64 dma_pa); -void bfa_cee_attach(struct bfa_cee_s *cee, - struct bfa_ioc_s *ioc, void *dev); -bfa_status_t bfa_cee_get_attr(struct bfa_cee_s *cee, - struct bfa_cee_attr_s *attr, - bfa_cee_get_attr_cbfn_t cbfn, void *cbarg); -bfa_status_t bfa_cee_get_stats(struct bfa_cee_s *cee, - struct bfa_cee_stats_s *stats, - bfa_cee_get_stats_cbfn_t cbfn, void *cbarg); -bfa_status_t bfa_cee_reset_stats(struct bfa_cee_s *cee, - bfa_cee_reset_stats_cbfn_t cbfn, void *cbarg); - #endif /* __BFA_PORT_H__ */ diff --git a/trunk/drivers/scsi/bfa/bfa_svc.c b/trunk/drivers/scsi/bfa/bfa_svc.c index 21caaefce99f..16d9a5f61c18 100644 --- a/trunk/drivers/scsi/bfa/bfa_svc.c +++ b/trunk/drivers/scsi/bfa/bfa_svc.c @@ -21,7 +21,6 @@ #include "bfa_modules.h" BFA_TRC_FILE(HAL, FCXP); -BFA_MODULE(fcdiag); BFA_MODULE(fcxp); BFA_MODULE(sgpg); BFA_MODULE(lps); @@ -114,10 +113,11 @@ static void bfa_fcxp_queue(struct bfa_fcxp_s *fcxp, /* * forward declarations for LPS functions */ -static void bfa_lps_meminfo(struct bfa_iocfc_cfg_s *cfg, - struct bfa_meminfo_s *minfo, struct bfa_s *bfa); +static void bfa_lps_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, + u32 *dm_len); static void bfa_lps_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, + struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev); static void bfa_lps_detach(struct bfa_s *bfa); static void bfa_lps_start(struct bfa_s *bfa); @@ -125,7 +125,6 @@ static void bfa_lps_stop(struct bfa_s *bfa); static void bfa_lps_iocdisable(struct bfa_s *bfa); static void bfa_lps_login_rsp(struct bfa_s *bfa, struct bfi_lps_login_rsp_s *rsp); -static void bfa_lps_no_res(struct bfa_lps_s *first_lps, u8 count); static void bfa_lps_logout_rsp(struct bfa_s *bfa, struct bfi_lps_logout_rsp_s *rsp); static void bfa_lps_reqq_resume(void *lps_arg); @@ -431,17 +430,51 @@ bfa_plog_fchdr_and_pl(struct bfa_plog_s *plog, enum bfa_plog_mid mid, */ static void -claim_fcxps_mem(struct bfa_fcxp_mod_s *mod) +claim_fcxp_req_rsp_mem(struct bfa_fcxp_mod_s *mod, struct bfa_meminfo_s *mi) +{ + u8 *dm_kva = NULL; + u64 dm_pa; + u32 buf_pool_sz; + + dm_kva = bfa_meminfo_dma_virt(mi); + dm_pa = bfa_meminfo_dma_phys(mi); + + buf_pool_sz = mod->req_pld_sz * mod->num_fcxps; + + /* + * Initialize the fcxp req payload list + */ + mod->req_pld_list_kva = dm_kva; + mod->req_pld_list_pa = dm_pa; + dm_kva += buf_pool_sz; + dm_pa += buf_pool_sz; + memset(mod->req_pld_list_kva, 0, buf_pool_sz); + + /* + * Initialize the fcxp rsp payload list + */ + buf_pool_sz = mod->rsp_pld_sz * mod->num_fcxps; + mod->rsp_pld_list_kva = dm_kva; + mod->rsp_pld_list_pa = dm_pa; + dm_kva += buf_pool_sz; + dm_pa += buf_pool_sz; + memset(mod->rsp_pld_list_kva, 0, buf_pool_sz); + + bfa_meminfo_dma_virt(mi) = dm_kva; + bfa_meminfo_dma_phys(mi) = dm_pa; +} + +static void +claim_fcxps_mem(struct bfa_fcxp_mod_s *mod, struct bfa_meminfo_s *mi) { u16 i; struct bfa_fcxp_s *fcxp; - fcxp = (struct bfa_fcxp_s *) bfa_mem_kva_curp(mod); + fcxp = (struct bfa_fcxp_s *) bfa_meminfo_kva(mi); memset(fcxp, 0, sizeof(struct bfa_fcxp_s) * mod->num_fcxps); INIT_LIST_HEAD(&mod->fcxp_free_q); INIT_LIST_HEAD(&mod->fcxp_active_q); - INIT_LIST_HEAD(&mod->fcxp_unused_q); mod->fcxp_list = fcxp; @@ -456,53 +489,40 @@ claim_fcxps_mem(struct bfa_fcxp_mod_s *mod) fcxp = fcxp + 1; } - bfa_mem_kva_curp(mod) = (void *)fcxp; + bfa_meminfo_kva(mi) = (void *)fcxp; } static void -bfa_fcxp_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *minfo, - struct bfa_s *bfa) +bfa_fcxp_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, + u32 *dm_len) { - struct bfa_fcxp_mod_s *fcxp_mod = BFA_FCXP_MOD(bfa); - struct bfa_mem_kva_s *fcxp_kva = BFA_MEM_FCXP_KVA(bfa); - struct bfa_mem_dma_s *seg_ptr; - u16 nsegs, idx, per_seg_fcxp; - u16 num_fcxps = cfg->fwcfg.num_fcxp_reqs; - u32 per_fcxp_sz; + u16 num_fcxp_reqs = cfg->fwcfg.num_fcxp_reqs; - if (num_fcxps == 0) + if (num_fcxp_reqs == 0) return; + /* + * Account for req/rsp payload + */ + *dm_len += BFA_FCXP_MAX_IBUF_SZ * num_fcxp_reqs; if (cfg->drvcfg.min_cfg) - per_fcxp_sz = 2 * BFA_FCXP_MAX_IBUF_SZ; + *dm_len += BFA_FCXP_MAX_IBUF_SZ * num_fcxp_reqs; else - per_fcxp_sz = BFA_FCXP_MAX_IBUF_SZ + BFA_FCXP_MAX_LBUF_SZ; - - /* dma memory */ - nsegs = BFI_MEM_DMA_NSEGS(num_fcxps, per_fcxp_sz); - per_seg_fcxp = BFI_MEM_NREQS_SEG(per_fcxp_sz); - - bfa_mem_dma_seg_iter(fcxp_mod, seg_ptr, nsegs, idx) { - if (num_fcxps >= per_seg_fcxp) { - num_fcxps -= per_seg_fcxp; - bfa_mem_dma_setup(minfo, seg_ptr, - per_seg_fcxp * per_fcxp_sz); - } else - bfa_mem_dma_setup(minfo, seg_ptr, - num_fcxps * per_fcxp_sz); - } + *dm_len += BFA_FCXP_MAX_LBUF_SZ * num_fcxp_reqs; - /* kva memory */ - bfa_mem_kva_setup(minfo, fcxp_kva, - cfg->fwcfg.num_fcxp_reqs * sizeof(struct bfa_fcxp_s)); + /* + * Account for fcxp structs + */ + *ndm_len += sizeof(struct bfa_fcxp_s) * num_fcxp_reqs; } static void bfa_fcxp_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_pcidev_s *pcidev) + struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) { struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); + memset(mod, 0, sizeof(struct bfa_fcxp_mod_s)); mod->bfa = bfa; mod->num_fcxps = cfg->fwcfg.num_fcxp_reqs; @@ -515,7 +535,8 @@ bfa_fcxp_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, INIT_LIST_HEAD(&mod->wait_q); - claim_fcxps_mem(mod); + claim_fcxp_req_rsp_mem(mod, meminfo); + claim_fcxps_mem(mod, meminfo); } static void @@ -540,9 +561,6 @@ bfa_fcxp_iocdisable(struct bfa_s *bfa) struct bfa_fcxp_s *fcxp; struct list_head *qe, *qen; - /* Enqueue unused fcxp resources to free_q */ - list_splice_tail_init(&mod->fcxp_unused_q, &mod->fcxp_free_q); - list_for_each_safe(qe, qen, &mod->fcxp_active_q) { fcxp = (struct bfa_fcxp_s *) qe; if (fcxp->caller == NULL) { @@ -731,6 +749,23 @@ hal_fcxp_send_comp(struct bfa_s *bfa, struct bfi_fcxp_send_rsp_s *fcxp_rsp) } } +static void +hal_fcxp_set_local_sges(struct bfi_sge_s *sge, u32 reqlen, u64 req_pa) +{ + union bfi_addr_u sga_zero = { {0} }; + + sge->sg_len = reqlen; + sge->flags = BFI_SGE_DATA_LAST; + bfa_dma_addr_set(sge[0].sga, req_pa); + bfa_sge_to_be(sge); + sge++; + + sge->sga = sga_zero; + sge->sg_len = reqlen; + sge->flags = BFI_SGE_PGDLEN; + bfa_sge_to_be(sge); +} + static void hal_fcxp_tx_plog(struct bfa_s *bfa, u32 reqlen, struct bfa_fcxp_s *fcxp, struct fchs_s *fchs) @@ -811,7 +846,7 @@ bfa_fcxp_queue(struct bfa_fcxp_s *fcxp, struct bfi_fcxp_send_req_s *send_req) struct bfa_rport_s *rport = reqi->bfa_rport; bfi_h2i_set(send_req->mh, BFI_MC_FCXP, BFI_FCXP_H2I_SEND_REQ, - bfa_fn_lpu(bfa)); + bfa_lpuid(bfa)); send_req->fcxp_tag = cpu_to_be16(fcxp->fcxp_tag); if (rport) { @@ -825,7 +860,7 @@ bfa_fcxp_queue(struct bfa_fcxp_s *fcxp, struct bfi_fcxp_send_req_s *send_req) } send_req->vf_id = cpu_to_be16(reqi->vf_id); - send_req->lp_fwtag = bfa_lps_get_fwtag(bfa, reqi->lp_tag); + send_req->lp_tag = reqi->lp_tag; send_req->class = reqi->class; send_req->rsp_timeout = rspi->rsp_timeout; send_req->cts = reqi->cts; @@ -838,16 +873,18 @@ bfa_fcxp_queue(struct bfa_fcxp_s *fcxp, struct bfi_fcxp_send_req_s *send_req) * setup req sgles */ if (fcxp->use_ireqbuf == 1) { - bfa_alen_set(&send_req->req_alen, reqi->req_tot_len, + hal_fcxp_set_local_sges(send_req->req_sge, reqi->req_tot_len, BFA_FCXP_REQ_PLD_PA(fcxp)); } else { if (fcxp->nreq_sgles > 0) { WARN_ON(fcxp->nreq_sgles != 1); - bfa_alen_set(&send_req->req_alen, reqi->req_tot_len, - fcxp->req_sga_cbfn(fcxp->caller, 0)); + hal_fcxp_set_local_sges(send_req->req_sge, + reqi->req_tot_len, + fcxp->req_sga_cbfn(fcxp->caller, + 0)); } else { WARN_ON(reqi->req_tot_len != 0); - bfa_alen_set(&send_req->rsp_alen, 0, 0); + hal_fcxp_set_local_sges(send_req->rsp_sge, 0, 0); } } @@ -857,23 +894,25 @@ bfa_fcxp_queue(struct bfa_fcxp_s *fcxp, struct bfi_fcxp_send_req_s *send_req) if (fcxp->use_irspbuf == 1) { WARN_ON(rspi->rsp_maxlen > BFA_FCXP_MAX_LBUF_SZ); - bfa_alen_set(&send_req->rsp_alen, rspi->rsp_maxlen, + hal_fcxp_set_local_sges(send_req->rsp_sge, rspi->rsp_maxlen, BFA_FCXP_RSP_PLD_PA(fcxp)); + } else { if (fcxp->nrsp_sgles > 0) { WARN_ON(fcxp->nrsp_sgles != 1); - bfa_alen_set(&send_req->rsp_alen, rspi->rsp_maxlen, - fcxp->rsp_sga_cbfn(fcxp->caller, 0)); - + hal_fcxp_set_local_sges(send_req->rsp_sge, + rspi->rsp_maxlen, + fcxp->rsp_sga_cbfn(fcxp->caller, + 0)); } else { WARN_ON(rspi->rsp_maxlen != 0); - bfa_alen_set(&send_req->rsp_alen, 0, 0); + hal_fcxp_set_local_sges(send_req->rsp_sge, 0, 0); } } hal_fcxp_tx_plog(bfa, reqi->req_tot_len, fcxp, &reqi->fchs); - bfa_reqq_produce(bfa, BFA_REQQ_FCXP, send_req->mh); + bfa_reqq_produce(bfa, BFA_REQQ_FCXP); bfa_trc(bfa, bfa_reqq_pi(bfa, BFA_REQQ_FCXP)); bfa_trc(bfa, bfa_reqq_ci(bfa, BFA_REQQ_FCXP)); @@ -939,8 +978,8 @@ bfa_fcxp_get_reqbuf(struct bfa_fcxp_s *fcxp) void *reqbuf; WARN_ON(fcxp->use_ireqbuf != 1); - reqbuf = bfa_mem_get_dmabuf_kva(mod, fcxp->fcxp_tag, - mod->req_pld_sz + mod->rsp_pld_sz); + reqbuf = ((u8 *)mod->req_pld_list_kva) + + fcxp->fcxp_tag * mod->req_pld_sz; return reqbuf; } @@ -963,15 +1002,13 @@ void * bfa_fcxp_get_rspbuf(struct bfa_fcxp_s *fcxp) { struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod; - void *fcxp_buf; + void *rspbuf; WARN_ON(fcxp->use_irspbuf != 1); - fcxp_buf = bfa_mem_get_dmabuf_kva(mod, fcxp->fcxp_tag, - mod->req_pld_sz + mod->rsp_pld_sz); - - /* fcxp_buf = req_buf + rsp_buf :- add req_buf_sz to get to rsp_buf */ - return ((u8 *) fcxp_buf) + mod->req_pld_sz; + rspbuf = ((u8 *)mod->rsp_pld_list_kva) + + fcxp->fcxp_tag * mod->rsp_pld_sz; + return rspbuf; } /* @@ -1144,18 +1181,6 @@ bfa_fcxp_get_maxrsp(struct bfa_s *bfa) return mod->rsp_pld_sz; } -void -bfa_fcxp_res_recfg(struct bfa_s *bfa, u16 num_fcxp_fw) -{ - struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); - struct list_head *qe; - int i; - - for (i = 0; i < (mod->num_fcxps - num_fcxp_fw); i++) { - bfa_q_deq_tail(&mod->fcxp_free_q, &qe); - list_add_tail(qe, &mod->fcxp_unused_q); - } -} /* * BFA LPS state machine functions @@ -1167,7 +1192,7 @@ bfa_fcxp_res_recfg(struct bfa_s *bfa, u16 num_fcxp_fw) static void bfa_lps_sm_init(struct bfa_lps_s *lps, enum bfa_lps_event event) { - bfa_trc(lps->bfa, lps->bfa_tag); + bfa_trc(lps->bfa, lps->lp_tag); bfa_trc(lps->bfa, event); switch (event) { @@ -1219,7 +1244,7 @@ bfa_lps_sm_init(struct bfa_lps_s *lps, enum bfa_lps_event event) static void bfa_lps_sm_login(struct bfa_lps_s *lps, enum bfa_lps_event event) { - bfa_trc(lps->bfa, lps->bfa_tag); + bfa_trc(lps->bfa, lps->lp_tag); bfa_trc(lps->bfa, event); switch (event) { @@ -1253,7 +1278,6 @@ bfa_lps_sm_login(struct bfa_lps_s *lps, enum bfa_lps_event event) break; case BFA_LPS_SM_OFFLINE: - case BFA_LPS_SM_DELETE: bfa_sm_set_state(lps, bfa_lps_sm_init); break; @@ -1273,7 +1297,7 @@ bfa_lps_sm_login(struct bfa_lps_s *lps, enum bfa_lps_event event) static void bfa_lps_sm_loginwait(struct bfa_lps_s *lps, enum bfa_lps_event event) { - bfa_trc(lps->bfa, lps->bfa_tag); + bfa_trc(lps->bfa, lps->lp_tag); bfa_trc(lps->bfa, event); switch (event) { @@ -1282,7 +1306,6 @@ bfa_lps_sm_loginwait(struct bfa_lps_s *lps, enum bfa_lps_event event) break; case BFA_LPS_SM_OFFLINE: - case BFA_LPS_SM_DELETE: bfa_sm_set_state(lps, bfa_lps_sm_init); bfa_reqq_wcancel(&lps->wqe); break; @@ -1306,7 +1329,7 @@ bfa_lps_sm_loginwait(struct bfa_lps_s *lps, enum bfa_lps_event event) static void bfa_lps_sm_online(struct bfa_lps_s *lps, enum bfa_lps_event event) { - bfa_trc(lps->bfa, lps->bfa_tag); + bfa_trc(lps->bfa, lps->lp_tag); bfa_trc(lps->bfa, event); switch (event) { @@ -1355,7 +1378,7 @@ bfa_lps_sm_online(struct bfa_lps_s *lps, enum bfa_lps_event event) static void bfa_lps_sm_online_n2n_pid_wait(struct bfa_lps_s *lps, enum bfa_lps_event event) { - bfa_trc(lps->bfa, lps->bfa_tag); + bfa_trc(lps->bfa, lps->lp_tag); bfa_trc(lps->bfa, event); switch (event) { @@ -1397,7 +1420,7 @@ bfa_lps_sm_online_n2n_pid_wait(struct bfa_lps_s *lps, enum bfa_lps_event event) static void bfa_lps_sm_logout(struct bfa_lps_s *lps, enum bfa_lps_event event) { - bfa_trc(lps->bfa, lps->bfa_tag); + bfa_trc(lps->bfa, lps->lp_tag); bfa_trc(lps->bfa, event); switch (event) { @@ -1407,7 +1430,6 @@ bfa_lps_sm_logout(struct bfa_lps_s *lps, enum bfa_lps_event event) break; case BFA_LPS_SM_OFFLINE: - case BFA_LPS_SM_DELETE: bfa_sm_set_state(lps, bfa_lps_sm_init); break; @@ -1422,7 +1444,7 @@ bfa_lps_sm_logout(struct bfa_lps_s *lps, enum bfa_lps_event event) static void bfa_lps_sm_logowait(struct bfa_lps_s *lps, enum bfa_lps_event event) { - bfa_trc(lps->bfa, lps->bfa_tag); + bfa_trc(lps->bfa, lps->lp_tag); bfa_trc(lps->bfa, event); switch (event) { @@ -1432,7 +1454,6 @@ bfa_lps_sm_logowait(struct bfa_lps_s *lps, enum bfa_lps_event event) break; case BFA_LPS_SM_OFFLINE: - case BFA_LPS_SM_DELETE: bfa_sm_set_state(lps, bfa_lps_sm_init); bfa_reqq_wcancel(&lps->wqe); break; @@ -1452,17 +1473,13 @@ bfa_lps_sm_logowait(struct bfa_lps_s *lps, enum bfa_lps_event event) * return memory requirement */ static void -bfa_lps_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *minfo, - struct bfa_s *bfa) +bfa_lps_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, + u32 *dm_len) { - struct bfa_mem_kva_s *lps_kva = BFA_MEM_LPS_KVA(bfa); - if (cfg->drvcfg.min_cfg) - bfa_mem_kva_setup(minfo, lps_kva, - sizeof(struct bfa_lps_s) * BFA_LPS_MIN_LPORTS); + *ndm_len += sizeof(struct bfa_lps_s) * BFA_LPS_MIN_LPORTS; else - bfa_mem_kva_setup(minfo, lps_kva, - sizeof(struct bfa_lps_s) * BFA_LPS_MAX_LPORTS); + *ndm_len += sizeof(struct bfa_lps_s) * BFA_LPS_MAX_LPORTS; } /* @@ -1470,28 +1487,28 @@ bfa_lps_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *minfo, */ static void bfa_lps_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_pcidev_s *pcidev) + struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) { struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); struct bfa_lps_s *lps; int i; + memset(mod, 0, sizeof(struct bfa_lps_mod_s)); mod->num_lps = BFA_LPS_MAX_LPORTS; if (cfg->drvcfg.min_cfg) mod->num_lps = BFA_LPS_MIN_LPORTS; else mod->num_lps = BFA_LPS_MAX_LPORTS; - mod->lps_arr = lps = (struct bfa_lps_s *) bfa_mem_kva_curp(mod); + mod->lps_arr = lps = (struct bfa_lps_s *) bfa_meminfo_kva(meminfo); - bfa_mem_kva_curp(mod) += mod->num_lps * sizeof(struct bfa_lps_s); + bfa_meminfo_kva(meminfo) += mod->num_lps * sizeof(struct bfa_lps_s); INIT_LIST_HEAD(&mod->lps_free_q); INIT_LIST_HEAD(&mod->lps_active_q); - INIT_LIST_HEAD(&mod->lps_login_q); for (i = 0; i < mod->num_lps; i++, lps++) { lps->bfa = bfa; - lps->bfa_tag = (u8) i; + lps->lp_tag = (u8) i; lps->reqq = BFA_REQQ_LPS; bfa_reqq_winit(&lps->wqe, bfa_lps_reqq_resume, lps); list_add_tail(&lps->qe, &mod->lps_free_q); @@ -1527,11 +1544,6 @@ bfa_lps_iocdisable(struct bfa_s *bfa) lps = (struct bfa_lps_s *) qe; bfa_sm_send_event(lps, BFA_LPS_SM_OFFLINE); } - list_for_each_safe(qe, qen, &mod->lps_login_q) { - lps = (struct bfa_lps_s *) qe; - bfa_sm_send_event(lps, BFA_LPS_SM_OFFLINE); - } - list_splice_tail_init(&mod->lps_login_q, &mod->lps_active_q); } /* @@ -1543,13 +1555,12 @@ bfa_lps_login_rsp(struct bfa_s *bfa, struct bfi_lps_login_rsp_s *rsp) struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); struct bfa_lps_s *lps; - WARN_ON(rsp->bfa_tag >= mod->num_lps); - lps = BFA_LPS_FROM_TAG(mod, rsp->bfa_tag); + WARN_ON(rsp->lp_tag >= mod->num_lps); + lps = BFA_LPS_FROM_TAG(mod, rsp->lp_tag); lps->status = rsp->status; switch (rsp->status) { case BFA_STATUS_OK: - lps->fw_tag = rsp->fw_tag; lps->fport = rsp->f_port; if (lps->fport) lps->lp_pid = rsp->lp_pid; @@ -1561,7 +1572,6 @@ bfa_lps_login_rsp(struct bfa_s *bfa, struct bfi_lps_login_rsp_s *rsp) lps->lp_mac = rsp->lp_mac; lps->brcd_switch = rsp->brcd_switch; lps->fcf_mac = rsp->fcf_mac; - lps->pr_bbscn = rsp->bb_scn; break; @@ -1576,46 +1586,14 @@ bfa_lps_login_rsp(struct bfa_s *bfa, struct bfi_lps_login_rsp_s *rsp) break; - case BFA_STATUS_VPORT_MAX: - if (!rsp->ext_status) - bfa_lps_no_res(lps, rsp->ext_status); - break; - default: /* Nothing to do with other status */ break; } - list_del(&lps->qe); - list_add_tail(&lps->qe, &mod->lps_active_q); bfa_sm_send_event(lps, BFA_LPS_SM_FWRSP); } -static void -bfa_lps_no_res(struct bfa_lps_s *first_lps, u8 count) -{ - struct bfa_s *bfa = first_lps->bfa; - struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); - struct list_head *qe, *qe_next; - struct bfa_lps_s *lps; - - bfa_trc(bfa, count); - - qe = bfa_q_next(first_lps); - - while (count && qe) { - qe_next = bfa_q_next(qe); - lps = (struct bfa_lps_s *)qe; - bfa_trc(bfa, lps->bfa_tag); - lps->status = first_lps->status; - list_del(&lps->qe); - list_add_tail(&lps->qe, &mod->lps_active_q); - bfa_sm_send_event(lps, BFA_LPS_SM_FWRSP); - qe = qe_next; - count--; - } -} - /* * Firmware logout response */ @@ -1625,8 +1603,8 @@ bfa_lps_logout_rsp(struct bfa_s *bfa, struct bfi_lps_logout_rsp_s *rsp) struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); struct bfa_lps_s *lps; - WARN_ON(rsp->bfa_tag >= mod->num_lps); - lps = BFA_LPS_FROM_TAG(mod, rsp->bfa_tag); + WARN_ON(rsp->lp_tag >= mod->num_lps); + lps = BFA_LPS_FROM_TAG(mod, rsp->lp_tag); bfa_sm_send_event(lps, BFA_LPS_SM_FWRSP); } @@ -1640,7 +1618,7 @@ bfa_lps_rx_cvl_event(struct bfa_s *bfa, struct bfi_lps_cvl_event_s *cvl) struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); struct bfa_lps_s *lps; - lps = BFA_LPS_FROM_TAG(mod, cvl->bfa_tag); + lps = BFA_LPS_FROM_TAG(mod, cvl->lp_tag); bfa_sm_send_event(lps, BFA_LPS_SM_RX_CVL); } @@ -1675,27 +1653,23 @@ bfa_lps_free(struct bfa_lps_s *lps) static void bfa_lps_send_login(struct bfa_lps_s *lps) { - struct bfa_lps_mod_s *mod = BFA_LPS_MOD(lps->bfa); struct bfi_lps_login_req_s *m; m = bfa_reqq_next(lps->bfa, lps->reqq); WARN_ON(!m); bfi_h2i_set(m->mh, BFI_MC_LPS, BFI_LPS_H2I_LOGIN_REQ, - bfa_fn_lpu(lps->bfa)); + bfa_lpuid(lps->bfa)); - m->bfa_tag = lps->bfa_tag; + m->lp_tag = lps->lp_tag; m->alpa = lps->alpa; m->pdu_size = cpu_to_be16(lps->pdusz); m->pwwn = lps->pwwn; m->nwwn = lps->nwwn; m->fdisc = lps->fdisc; m->auth_en = lps->auth_en; - m->bb_scn = lps->bb_scn; - bfa_reqq_produce(lps->bfa, lps->reqq, m->mh); - list_del(&lps->qe); - list_add_tail(&lps->qe, &mod->lps_login_q); + bfa_reqq_produce(lps->bfa, lps->reqq); } /* @@ -1710,11 +1684,11 @@ bfa_lps_send_logout(struct bfa_lps_s *lps) WARN_ON(!m); bfi_h2i_set(m->mh, BFI_MC_LPS, BFI_LPS_H2I_LOGOUT_REQ, - bfa_fn_lpu(lps->bfa)); + bfa_lpuid(lps->bfa)); - m->fw_tag = lps->fw_tag; + m->lp_tag = lps->lp_tag; m->port_name = lps->pwwn; - bfa_reqq_produce(lps->bfa, lps->reqq, m->mh); + bfa_reqq_produce(lps->bfa, lps->reqq); } /* @@ -1729,11 +1703,11 @@ bfa_lps_send_set_n2n_pid(struct bfa_lps_s *lps) WARN_ON(!m); bfi_h2i_set(m->mh, BFI_MC_LPS, BFI_LPS_H2I_N2N_PID_REQ, - bfa_fn_lpu(lps->bfa)); + bfa_lpuid(lps->bfa)); - m->fw_tag = lps->fw_tag; + m->lp_tag = lps->lp_tag; m->lp_pid = lps->lp_pid; - bfa_reqq_produce(lps->bfa, lps->reqq, m->mh); + bfa_reqq_produce(lps->bfa, lps->reqq); } /* @@ -1885,7 +1859,7 @@ bfa_lps_delete(struct bfa_lps_s *lps) */ void bfa_lps_flogi(struct bfa_lps_s *lps, void *uarg, u8 alpa, u16 pdusz, - wwn_t pwwn, wwn_t nwwn, bfa_boolean_t auth_en, uint8_t bb_scn) + wwn_t pwwn, wwn_t nwwn, bfa_boolean_t auth_en) { lps->uarg = uarg; lps->alpa = alpa; @@ -1894,7 +1868,6 @@ bfa_lps_flogi(struct bfa_lps_s *lps, void *uarg, u8 alpa, u16 pdusz, lps->nwwn = nwwn; lps->fdisc = BFA_FALSE; lps->auth_en = auth_en; - lps->bb_scn = bb_scn; bfa_sm_send_event(lps, BFA_LPS_SM_LOGIN); } @@ -1925,13 +1898,6 @@ bfa_lps_fdisclogo(struct bfa_lps_s *lps) bfa_sm_send_event(lps, BFA_LPS_SM_LOGOUT); } -u8 -bfa_lps_get_fwtag(struct bfa_s *bfa, u8 lp_tag) -{ - struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); - - return BFA_LPS_FROM_TAG(mod, lp_tag)->fw_tag; -} /* * Return lport services tag given the pid @@ -1945,7 +1911,7 @@ bfa_lps_get_tag_from_pid(struct bfa_s *bfa, u32 pid) for (i = 0, lps = mod->lps_arr; i < mod->num_lps; i++, lps++) { if (lps->lp_pid == pid) - return lps->bfa_tag; + return lps->lp_tag; } /* Return base port tag anyway */ @@ -1970,7 +1936,7 @@ bfa_lps_get_base_pid(struct bfa_s *bfa) void bfa_lps_set_n2n_pid(struct bfa_lps_s *lps, uint32_t n2n_pid) { - bfa_trc(lps->bfa, lps->bfa_tag); + bfa_trc(lps->bfa, lps->lp_tag); bfa_trc(lps->bfa, n2n_pid); lps->lp_pid = n2n_pid; @@ -1989,15 +1955,15 @@ bfa_lps_isr(struct bfa_s *bfa, struct bfi_msg_s *m) msg.msg = m; switch (m->mhdr.msg_id) { - case BFI_LPS_I2H_LOGIN_RSP: + case BFI_LPS_H2I_LOGIN_RSP: bfa_lps_login_rsp(bfa, msg.login_rsp); break; - case BFI_LPS_I2H_LOGOUT_RSP: + case BFI_LPS_H2I_LOGOUT_RSP: bfa_lps_logout_rsp(bfa, msg.logout_rsp); break; - case BFI_LPS_I2H_CVL_EVENT: + case BFI_LPS_H2I_CVL_EVENT: bfa_lps_rx_cvl_event(bfa, msg.cvl_event); break; @@ -2811,12 +2777,10 @@ bfa_fcport_queue_cb(struct bfa_fcport_ln_s *ln, enum bfa_port_linkstate event) BFA_CACHELINE_SZ)) static void -bfa_fcport_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *minfo, - struct bfa_s *bfa) +bfa_fcport_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, + u32 *dm_len) { - struct bfa_mem_dma_s *fcport_dma = BFA_MEM_FCPORT_DMA(bfa); - - bfa_mem_dma_setup(minfo, fcport_dma, FCPORT_STATS_DMA_SZ); + *dm_len += FCPORT_STATS_DMA_SZ; } static void @@ -2828,14 +2792,23 @@ bfa_fcport_qresume(void *cbarg) } static void -bfa_fcport_mem_claim(struct bfa_fcport_s *fcport) +bfa_fcport_mem_claim(struct bfa_fcport_s *fcport, struct bfa_meminfo_s *meminfo) { - struct bfa_mem_dma_s *fcport_dma = &fcport->fcport_dma; + u8 *dm_kva; + u64 dm_pa; - fcport->stats_kva = bfa_mem_dma_virt(fcport_dma); - fcport->stats_pa = bfa_mem_dma_phys(fcport_dma); - fcport->stats = (union bfa_fcport_stats_u *) - bfa_mem_dma_virt(fcport_dma); + dm_kva = bfa_meminfo_dma_virt(meminfo); + dm_pa = bfa_meminfo_dma_phys(meminfo); + + fcport->stats_kva = dm_kva; + fcport->stats_pa = dm_pa; + fcport->stats = (union bfa_fcport_stats_u *) dm_kva; + + dm_kva += FCPORT_STATS_DMA_SZ; + dm_pa += FCPORT_STATS_DMA_SZ; + + bfa_meminfo_dma_virt(meminfo) = dm_kva; + bfa_meminfo_dma_phys(meminfo) = dm_pa; } /* @@ -2843,17 +2816,18 @@ bfa_fcport_mem_claim(struct bfa_fcport_s *fcport) */ static void bfa_fcport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_pcidev_s *pcidev) + struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) { struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); struct bfa_port_cfg_s *port_cfg = &fcport->cfg; struct bfa_fcport_ln_s *ln = &fcport->ln; struct timeval tv; + memset(fcport, 0, sizeof(struct bfa_fcport_s)); fcport->bfa = bfa; ln->fcport = fcport; - bfa_fcport_mem_claim(fcport); + bfa_fcport_mem_claim(fcport, meminfo); bfa_sm_set_state(fcport, bfa_fcport_sm_uninit); bfa_sm_set_state(ln, bfa_fcport_ln_sm_dn); @@ -2947,7 +2921,6 @@ bfa_fcport_reset_linkinfo(struct bfa_fcport_s *fcport) { fcport->speed = BFA_PORT_SPEED_UNKNOWN; fcport->topology = BFA_PORT_TOPOLOGY_NONE; - fcport->bbsc_op_state = BFA_FALSE; } /* @@ -2975,7 +2948,7 @@ bfa_fcport_send_enable(struct bfa_fcport_s *fcport) } bfi_h2i_set(m->mh, BFI_MC_FCPORT, BFI_FCPORT_H2I_ENABLE_REQ, - bfa_fn_lpu(fcport->bfa)); + bfa_lpuid(fcport->bfa)); m->nwwn = fcport->nwwn; m->pwwn = fcport->pwwn; m->port_cfg = fcport->cfg; @@ -2989,7 +2962,7 @@ bfa_fcport_send_enable(struct bfa_fcport_s *fcport) /* * queue I/O message to firmware */ - bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT, m->mh); + bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT); return BFA_TRUE; } @@ -3018,13 +2991,13 @@ bfa_fcport_send_disable(struct bfa_fcport_s *fcport) } bfi_h2i_set(m->mh, BFI_MC_FCPORT, BFI_FCPORT_H2I_DISABLE_REQ, - bfa_fn_lpu(fcport->bfa)); + bfa_lpuid(fcport->bfa)); m->msgtag = fcport->msgtag; /* * queue I/O message to firmware */ - bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT, m->mh); + bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT); return BFA_TRUE; } @@ -3056,14 +3029,13 @@ bfa_fcport_send_txcredit(void *port_cbarg) } bfi_h2i_set(m->mh, BFI_MC_FCPORT, BFI_FCPORT_H2I_SET_SVC_PARAMS_REQ, - bfa_fn_lpu(fcport->bfa)); + bfa_lpuid(fcport->bfa)); m->tx_bbcredit = cpu_to_be16((u16)fcport->cfg.tx_bbcredit); - m->bb_scn = fcport->cfg.bb_scn; /* * queue I/O message to firmware */ - bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT, m->mh); + bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT); } static void @@ -3167,8 +3139,8 @@ bfa_fcport_send_stats_get(void *cbarg) memset(msg, 0, sizeof(struct bfi_fcport_req_s)); bfi_h2i_set(msg->mh, BFI_MC_FCPORT, BFI_FCPORT_H2I_STATS_GET_REQ, - bfa_fn_lpu(fcport->bfa)); - bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT, msg->mh); + bfa_lpuid(fcport->bfa)); + bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT); } static void @@ -3229,8 +3201,8 @@ bfa_fcport_send_stats_clear(void *cbarg) memset(msg, 0, sizeof(struct bfi_fcport_req_s)); bfi_h2i_set(msg->mh, BFI_MC_FCPORT, BFI_FCPORT_H2I_STATS_CLEAR_REQ, - bfa_fn_lpu(fcport->bfa)); - bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT, msg->mh); + bfa_lpuid(fcport->bfa)); + bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT); } /* @@ -3357,9 +3329,6 @@ bfa_fcport_init(struct bfa_s *bfa) fcport->cfg.rx_bbcredit = bfa_ioc_rx_bbcredit(&bfa->ioc); fcport->speed_sup = bfa_ioc_speed_sup(&bfa->ioc); - if (bfa_fcport_is_pbcdisabled(bfa)) - bfa->modules.port.pbc_disabled = BFA_TRUE; - WARN_ON(!fcport->cfg.maxfrsize); WARN_ON(!fcport->cfg.rx_bbcredit); WARN_ON(!fcport->speed_sup); @@ -3484,9 +3453,6 @@ bfa_fcport_enable(struct bfa_s *bfa) { struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - if (bfa_fcport_is_pbcdisabled(bfa)) - return BFA_STATUS_PBC; - if (bfa_ioc_is_disabled(&bfa->ioc)) return BFA_STATUS_IOC_DISABLED; @@ -3500,8 +3466,6 @@ bfa_fcport_enable(struct bfa_s *bfa) bfa_status_t bfa_fcport_disable(struct bfa_s *bfa) { - if (bfa_fcport_is_pbcdisabled(bfa)) - return BFA_STATUS_PBC; if (bfa_ioc_is_disabled(&bfa->ioc)) return BFA_STATUS_IOC_DISABLED; @@ -3510,21 +3474,6 @@ bfa_fcport_disable(struct bfa_s *bfa) return BFA_STATUS_OK; } -/* If PBC is disabled on port, return error */ -bfa_status_t -bfa_fcport_is_pbcdisabled(struct bfa_s *bfa) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp; - - if (cfgrsp->pbc_cfg.port_enabled == BFI_PBC_PORT_DISABLED) { - bfa_trc(bfa, fcport->pwwn); - return BFA_STATUS_PBC; - } - return BFA_STATUS_OK; -} - /* * Configure port speed. */ @@ -3542,28 +3491,6 @@ bfa_fcport_cfg_speed(struct bfa_s *bfa, enum bfa_port_speed speed) return BFA_STATUS_UNSUPP_SPEED; } - /* For Mezz card, port speed entered needs to be checked */ - if (bfa_mfg_is_mezz(fcport->bfa->ioc.attr->card_type)) { - if (bfa_ioc_get_type(&fcport->bfa->ioc) == BFA_IOC_TYPE_FC) { - /* For CT2, 1G is not supported */ - if ((speed == BFA_PORT_SPEED_1GBPS) && - (bfa_asic_id_ct2(bfa->ioc.pcidev.device_id))) - return BFA_STATUS_UNSUPP_SPEED; - - /* Already checked for Auto Speed and Max Speed supp */ - if (!(speed == BFA_PORT_SPEED_1GBPS || - speed == BFA_PORT_SPEED_2GBPS || - speed == BFA_PORT_SPEED_4GBPS || - speed == BFA_PORT_SPEED_8GBPS || - speed == BFA_PORT_SPEED_16GBPS || - speed == BFA_PORT_SPEED_AUTO)) - return BFA_STATUS_UNSUPP_SPEED; - } else { - if (speed != BFA_PORT_SPEED_10GBPS) - return BFA_STATUS_UNSUPP_SPEED; - } - } - fcport->cfg.speed = speed; return BFA_STATUS_OK; @@ -3697,14 +3624,11 @@ bfa_fcport_get_rx_bbcredit(struct bfa_s *bfa) } void -bfa_fcport_set_tx_bbcredit(struct bfa_s *bfa, u16 tx_bbcredit, u8 bb_scn) +bfa_fcport_set_tx_bbcredit(struct bfa_s *bfa, u16 tx_bbcredit) { struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); fcport->cfg.tx_bbcredit = (u8)tx_bbcredit; - fcport->cfg.bb_scn = bb_scn; - if (bb_scn) - fcport->bbsc_op_state = BFA_TRUE; bfa_fcport_send_txcredit(fcport); } @@ -3751,23 +3675,16 @@ bfa_fcport_get_attr(struct bfa_s *bfa, struct bfa_port_attr_s *attr) /* beacon attributes */ attr->beacon = fcport->beacon; attr->link_e2e_beacon = fcport->link_e2e_beacon; + attr->plog_enabled = (bfa_boolean_t)fcport->bfa->plog->plog_enabled; + attr->io_profile = bfa_fcpim_get_io_profile(fcport->bfa); attr->pport_cfg.path_tov = bfa_fcpim_path_tov_get(bfa); attr->pport_cfg.q_depth = bfa_fcpim_qdepth_get(bfa); attr->port_state = bfa_sm_to_state(hal_port_sm_table, fcport->sm); - attr->bbsc_op_status = fcport->bbsc_op_state; - - /* PBC Disabled State */ - if (bfa_fcport_is_pbcdisabled(bfa)) - attr->port_state = BFA_PORT_ST_PREBOOT_DISABLED; - else { - if (bfa_ioc_is_disabled(&fcport->bfa->ioc)) - attr->port_state = BFA_PORT_ST_IOCDIS; - else if (bfa_ioc_fw_mismatch(&fcport->bfa->ioc)) - attr->port_state = BFA_PORT_ST_FWMISMATCH; - else if (bfa_ioc_is_acq_addr(&fcport->bfa->ioc)) - attr->port_state = BFA_PORT_ST_ACQ_ADDR; - } + if (bfa_ioc_is_disabled(&fcport->bfa->ioc)) + attr->port_state = BFA_PORT_ST_IOCDIS; + else if (bfa_ioc_fw_mismatch(&fcport->bfa->ioc)) + attr->port_state = BFA_PORT_ST_FWMISMATCH; /* FCoE vlan */ attr->fcoe_vlan = fcport->fcoe_vlan; @@ -3848,18 +3765,6 @@ bfa_fcport_is_ratelim(struct bfa_s *bfa) } -/* - * Enable/Disable FAA feature in port config - */ -void -bfa_fcport_cfg_faa(struct bfa_s *bfa, u8 state) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - bfa_trc(bfa, state); - fcport->cfg.faa_state = state; -} - /* * Get default minimum ratelim speed */ @@ -3873,22 +3778,6 @@ bfa_fcport_get_ratelim_speed(struct bfa_s *bfa) } -void -bfa_fcport_beacon(void *dev, bfa_boolean_t beacon, - bfa_boolean_t link_e2e_beacon) -{ - struct bfa_s *bfa = dev; - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - bfa_trc(bfa, beacon); - bfa_trc(bfa, link_e2e_beacon); - bfa_trc(bfa, fcport->beacon); - bfa_trc(bfa, fcport->link_e2e_beacon); - - fcport->beacon = beacon; - fcport->link_e2e_beacon = link_e2e_beacon; -} - bfa_boolean_t bfa_fcport_is_linkup(struct bfa_s *bfa) { @@ -3908,14 +3797,6 @@ bfa_fcport_is_qos_enabled(struct bfa_s *bfa) return fcport->cfg.qos_enabled; } -bfa_boolean_t -bfa_fcport_is_trunk_enabled(struct bfa_s *bfa) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - return fcport->cfg.trunked; -} - /* * Rport State machine functions */ @@ -4405,22 +4286,18 @@ bfa_rport_qresume(void *cbarg) } static void -bfa_rport_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *minfo, - struct bfa_s *bfa) +bfa_rport_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len, + u32 *dm_len) { - struct bfa_mem_kva_s *rport_kva = BFA_MEM_RPORT_KVA(bfa); - if (cfg->fwcfg.num_rports < BFA_RPORT_MIN) cfg->fwcfg.num_rports = BFA_RPORT_MIN; - /* kva memory */ - bfa_mem_kva_setup(minfo, rport_kva, - cfg->fwcfg.num_rports * sizeof(struct bfa_rport_s)); + *km_len += cfg->fwcfg.num_rports * sizeof(struct bfa_rport_s); } static void bfa_rport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_pcidev_s *pcidev) + struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) { struct bfa_rport_mod_s *mod = BFA_RPORT_MOD(bfa); struct bfa_rport_s *rp; @@ -4428,9 +4305,8 @@ bfa_rport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, INIT_LIST_HEAD(&mod->rp_free_q); INIT_LIST_HEAD(&mod->rp_active_q); - INIT_LIST_HEAD(&mod->rp_unused_q); - rp = (struct bfa_rport_s *) bfa_mem_kva_curp(mod); + rp = (struct bfa_rport_s *) bfa_meminfo_kva(meminfo); mod->rps_list = rp; mod->num_rports = cfg->fwcfg.num_rports; @@ -4455,7 +4331,7 @@ bfa_rport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, /* * consume memory */ - bfa_mem_kva_curp(mod) = (u8 *) rp; + bfa_meminfo_kva(meminfo) = (u8 *) rp; } static void @@ -4480,9 +4356,6 @@ bfa_rport_iocdisable(struct bfa_s *bfa) struct bfa_rport_s *rport; struct list_head *qe, *qen; - /* Enqueue unused rport resources to free_q */ - list_splice_tail_init(&mod->rp_unused_q, &mod->rp_free_q); - list_for_each_safe(qe, qen, &mod->rp_active_q) { rport = (struct bfa_rport_s *) qe; bfa_sm_send_event(rport, BFA_RPORT_SM_HWFAIL); @@ -4526,11 +4399,11 @@ bfa_rport_send_fwcreate(struct bfa_rport_s *rp) } bfi_h2i_set(m->mh, BFI_MC_RPORT, BFI_RPORT_H2I_CREATE_REQ, - bfa_fn_lpu(rp->bfa)); + bfa_lpuid(rp->bfa)); m->bfa_handle = rp->rport_tag; m->max_frmsz = cpu_to_be16(rp->rport_info.max_frmsz); m->pid = rp->rport_info.pid; - m->lp_fwtag = bfa_lps_get_fwtag(rp->bfa, (u8)rp->rport_info.lp_tag); + m->lp_tag = rp->rport_info.lp_tag; m->local_pid = rp->rport_info.local_pid; m->fc_class = rp->rport_info.fc_class; m->vf_en = rp->rport_info.vf_en; @@ -4540,7 +4413,7 @@ bfa_rport_send_fwcreate(struct bfa_rport_s *rp) /* * queue I/O message to firmware */ - bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT, m->mh); + bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT); return BFA_TRUE; } @@ -4559,13 +4432,13 @@ bfa_rport_send_fwdelete(struct bfa_rport_s *rp) } bfi_h2i_set(m->mh, BFI_MC_RPORT, BFI_RPORT_H2I_DELETE_REQ, - bfa_fn_lpu(rp->bfa)); + bfa_lpuid(rp->bfa)); m->fw_handle = rp->fw_handle; /* * queue I/O message to firmware */ - bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT, m->mh); + bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT); return BFA_TRUE; } @@ -4584,14 +4457,14 @@ bfa_rport_send_fwspeed(struct bfa_rport_s *rp) } bfi_h2i_set(m->mh, BFI_MC_RPORT, BFI_RPORT_H2I_SET_SPEED_REQ, - bfa_fn_lpu(rp->bfa)); + bfa_lpuid(rp->bfa)); m->fw_handle = rp->fw_handle; m->speed = (u8)rp->rport_info.speed; /* * queue I/O message to firmware */ - bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT, m->mh); + bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT); return BFA_TRUE; } @@ -4641,18 +4514,7 @@ bfa_rport_isr(struct bfa_s *bfa, struct bfi_msg_s *m) } } -void -bfa_rport_res_recfg(struct bfa_s *bfa, u16 num_rport_fw) -{ - struct bfa_rport_mod_s *mod = BFA_RPORT_MOD(bfa); - struct list_head *qe; - int i; - for (i = 0; i < (mod->num_rports - num_rport_fw); i++) { - bfa_q_deq_tail(&mod->rp_free_q, &qe); - list_add_tail(qe, &mod->rp_unused_q); - } -} /* * bfa_rport_api @@ -4715,51 +4577,26 @@ bfa_rport_speed(struct bfa_rport_s *rport, enum bfa_port_speed speed) * Compute and return memory needed by FCP(im) module. */ static void -bfa_sgpg_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *minfo, - struct bfa_s *bfa) +bfa_sgpg_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len, + u32 *dm_len) { - struct bfa_sgpg_mod_s *sgpg_mod = BFA_SGPG_MOD(bfa); - struct bfa_mem_kva_s *sgpg_kva = BFA_MEM_SGPG_KVA(bfa); - struct bfa_mem_dma_s *seg_ptr; - u16 nsegs, idx, per_seg_sgpg, num_sgpg; - u32 sgpg_sz = sizeof(struct bfi_sgpg_s); - if (cfg->drvcfg.num_sgpgs < BFA_SGPG_MIN) cfg->drvcfg.num_sgpgs = BFA_SGPG_MIN; - else if (cfg->drvcfg.num_sgpgs > BFA_SGPG_MAX) - cfg->drvcfg.num_sgpgs = BFA_SGPG_MAX; - - num_sgpg = cfg->drvcfg.num_sgpgs; - nsegs = BFI_MEM_DMA_NSEGS(num_sgpg, sgpg_sz); - per_seg_sgpg = BFI_MEM_NREQS_SEG(sgpg_sz); - - bfa_mem_dma_seg_iter(sgpg_mod, seg_ptr, nsegs, idx) { - if (num_sgpg >= per_seg_sgpg) { - num_sgpg -= per_seg_sgpg; - bfa_mem_dma_setup(minfo, seg_ptr, - per_seg_sgpg * sgpg_sz); - } else - bfa_mem_dma_setup(minfo, seg_ptr, - num_sgpg * sgpg_sz); - } - - /* kva memory */ - bfa_mem_kva_setup(minfo, sgpg_kva, - cfg->drvcfg.num_sgpgs * sizeof(struct bfa_sgpg_s)); + *km_len += (cfg->drvcfg.num_sgpgs + 1) * sizeof(struct bfa_sgpg_s); + *dm_len += (cfg->drvcfg.num_sgpgs + 1) * sizeof(struct bfi_sgpg_s); } + static void bfa_sgpg_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_pcidev_s *pcidev) + struct bfa_meminfo_s *minfo, struct bfa_pcidev_s *pcidev) { struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa); + int i; struct bfa_sgpg_s *hsgpg; struct bfi_sgpg_s *sgpg; u64 align_len; - struct bfa_mem_dma_s *seg_ptr; - u32 sgpg_sz = sizeof(struct bfi_sgpg_s); - u16 i, idx, nsegs, per_seg_sgpg, num_sgpg; union { u64 pa; @@ -4771,45 +4608,39 @@ bfa_sgpg_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, bfa_trc(bfa, cfg->drvcfg.num_sgpgs); - mod->free_sgpgs = mod->num_sgpgs = cfg->drvcfg.num_sgpgs; - - num_sgpg = cfg->drvcfg.num_sgpgs; - nsegs = BFI_MEM_DMA_NSEGS(num_sgpg, sgpg_sz); - - /* dma/kva mem claim */ - hsgpg = (struct bfa_sgpg_s *) bfa_mem_kva_curp(mod); - - bfa_mem_dma_seg_iter(mod, seg_ptr, nsegs, idx) { - - if (!bfa_mem_dma_virt(seg_ptr)) - break; - - align_len = BFA_SGPG_ROUNDUP(bfa_mem_dma_phys(seg_ptr)) - - bfa_mem_dma_phys(seg_ptr); - - sgpg = (struct bfi_sgpg_s *) - (((u8 *) bfa_mem_dma_virt(seg_ptr)) + align_len); - sgpg_pa.pa = bfa_mem_dma_phys(seg_ptr) + align_len; - WARN_ON(sgpg_pa.pa & (sgpg_sz - 1)); - - per_seg_sgpg = (seg_ptr->mem_len - (u32)align_len) / sgpg_sz; - - for (i = 0; num_sgpg > 0 && i < per_seg_sgpg; i++, num_sgpg--) { - memset(hsgpg, 0, sizeof(*hsgpg)); - memset(sgpg, 0, sizeof(*sgpg)); - - hsgpg->sgpg = sgpg; - sgpg_pa_tmp.pa = bfa_sgaddr_le(sgpg_pa.pa); - hsgpg->sgpg_pa = sgpg_pa_tmp.addr; - list_add_tail(&hsgpg->qe, &mod->sgpg_q); - - sgpg++; - hsgpg++; - sgpg_pa.pa += sgpg_sz; - } + mod->num_sgpgs = cfg->drvcfg.num_sgpgs; + mod->sgpg_arr_pa = bfa_meminfo_dma_phys(minfo); + align_len = (BFA_SGPG_ROUNDUP(mod->sgpg_arr_pa) - mod->sgpg_arr_pa); + mod->sgpg_arr_pa += align_len; + mod->hsgpg_arr = (struct bfa_sgpg_s *) (bfa_meminfo_kva(minfo) + + align_len); + mod->sgpg_arr = (struct bfi_sgpg_s *) (bfa_meminfo_dma_virt(minfo) + + align_len); + + hsgpg = mod->hsgpg_arr; + sgpg = mod->sgpg_arr; + sgpg_pa.pa = mod->sgpg_arr_pa; + mod->free_sgpgs = mod->num_sgpgs; + + WARN_ON(sgpg_pa.pa & (sizeof(struct bfi_sgpg_s) - 1)); + + for (i = 0; i < mod->num_sgpgs; i++) { + memset(hsgpg, 0, sizeof(*hsgpg)); + memset(sgpg, 0, sizeof(*sgpg)); + + hsgpg->sgpg = sgpg; + sgpg_pa_tmp.pa = bfa_sgaddr_le(sgpg_pa.pa); + hsgpg->sgpg_pa = sgpg_pa_tmp.addr; + list_add_tail(&hsgpg->qe, &mod->sgpg_q); + + hsgpg++; + sgpg++; + sgpg_pa.pa += sizeof(struct bfi_sgpg_s); } - bfa_mem_kva_curp(mod) = (u8 *) hsgpg; + bfa_meminfo_kva(minfo) = (u8 *) hsgpg; + bfa_meminfo_dma_virt(minfo) = (u8 *) sgpg; + bfa_meminfo_dma_phys(minfo) = sgpg_pa.pa; } static void @@ -4951,13 +4782,31 @@ __bfa_cb_uf_recv(void *cbarg, bfa_boolean_t complete) } static void -claim_uf_post_msgs(struct bfa_uf_mod_s *ufm) +claim_uf_pbs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi) +{ + u32 uf_pb_tot_sz; + + ufm->uf_pbs_kva = (struct bfa_uf_buf_s *) bfa_meminfo_dma_virt(mi); + ufm->uf_pbs_pa = bfa_meminfo_dma_phys(mi); + uf_pb_tot_sz = BFA_ROUNDUP((sizeof(struct bfa_uf_buf_s) * ufm->num_ufs), + BFA_DMA_ALIGN_SZ); + + bfa_meminfo_dma_virt(mi) += uf_pb_tot_sz; + bfa_meminfo_dma_phys(mi) += uf_pb_tot_sz; + + memset((void *)ufm->uf_pbs_kva, 0, uf_pb_tot_sz); +} + +static void +claim_uf_post_msgs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi) { struct bfi_uf_buf_post_s *uf_bp_msg; + struct bfi_sge_s *sge; + union bfi_addr_u sga_zero = { {0} }; u16 i; u16 buf_len; - ufm->uf_buf_posts = (struct bfi_uf_buf_post_s *) bfa_mem_kva_curp(ufm); + ufm->uf_buf_posts = (struct bfi_uf_buf_post_s *) bfa_meminfo_kva(mi); uf_bp_msg = ufm->uf_buf_posts; for (i = 0, uf_bp_msg = ufm->uf_buf_posts; i < ufm->num_ufs; @@ -4968,18 +4817,28 @@ claim_uf_post_msgs(struct bfa_uf_mod_s *ufm) buf_len = sizeof(struct bfa_uf_buf_s); uf_bp_msg->buf_len = cpu_to_be16(buf_len); bfi_h2i_set(uf_bp_msg->mh, BFI_MC_UF, BFI_UF_H2I_BUF_POST, - bfa_fn_lpu(ufm->bfa)); - bfa_alen_set(&uf_bp_msg->alen, buf_len, ufm_pbs_pa(ufm, i)); + bfa_lpuid(ufm->bfa)); + + sge = uf_bp_msg->sge; + sge[0].sg_len = buf_len; + sge[0].flags = BFI_SGE_DATA_LAST; + bfa_dma_addr_set(sge[0].sga, ufm_pbs_pa(ufm, i)); + bfa_sge_to_be(sge); + + sge[1].sg_len = buf_len; + sge[1].flags = BFI_SGE_PGDLEN; + sge[1].sga = sga_zero; + bfa_sge_to_be(&sge[1]); } /* * advance pointer beyond consumed memory */ - bfa_mem_kva_curp(ufm) = (u8 *) uf_bp_msg; + bfa_meminfo_kva(mi) = (u8 *) uf_bp_msg; } static void -claim_ufs(struct bfa_uf_mod_s *ufm) +claim_ufs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi) { u16 i; struct bfa_uf_s *uf; @@ -4987,7 +4846,7 @@ claim_ufs(struct bfa_uf_mod_s *ufm) /* * Claim block of memory for UF list */ - ufm->uf_list = (struct bfa_uf_s *) bfa_mem_kva_curp(ufm); + ufm->uf_list = (struct bfa_uf_s *) bfa_meminfo_kva(mi); /* * Initialize UFs and queue it in UF free queue @@ -4996,8 +4855,8 @@ claim_ufs(struct bfa_uf_mod_s *ufm) memset(uf, 0, sizeof(struct bfa_uf_s)); uf->bfa = ufm->bfa; uf->uf_tag = i; - uf->pb_len = BFA_PER_UF_DMA_SZ; - uf->buf_kva = bfa_mem_get_dmabuf_kva(ufm, i, BFA_PER_UF_DMA_SZ); + uf->pb_len = sizeof(struct bfa_uf_buf_s); + uf->buf_kva = (void *)&ufm->uf_pbs_kva[i]; uf->buf_pa = ufm_pbs_pa(ufm, i); list_add_tail(&uf->qe, &ufm->uf_free_q); } @@ -5005,57 +4864,48 @@ claim_ufs(struct bfa_uf_mod_s *ufm) /* * advance memory pointer */ - bfa_mem_kva_curp(ufm) = (u8 *) uf; + bfa_meminfo_kva(mi) = (u8 *) uf; } static void -uf_mem_claim(struct bfa_uf_mod_s *ufm) +uf_mem_claim(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi) { - claim_ufs(ufm); - claim_uf_post_msgs(ufm); + claim_uf_pbs(ufm, mi); + claim_ufs(ufm, mi); + claim_uf_post_msgs(ufm, mi); } static void -bfa_uf_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *minfo, - struct bfa_s *bfa) +bfa_uf_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, u32 *dm_len) { - struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa); - struct bfa_mem_kva_s *uf_kva = BFA_MEM_UF_KVA(bfa); - u32 num_ufs = cfg->fwcfg.num_uf_bufs; - struct bfa_mem_dma_s *seg_ptr; - u16 nsegs, idx, per_seg_uf = 0; - - nsegs = BFI_MEM_DMA_NSEGS(num_ufs, BFA_PER_UF_DMA_SZ); - per_seg_uf = BFI_MEM_NREQS_SEG(BFA_PER_UF_DMA_SZ); - - bfa_mem_dma_seg_iter(ufm, seg_ptr, nsegs, idx) { - if (num_ufs >= per_seg_uf) { - num_ufs -= per_seg_uf; - bfa_mem_dma_setup(minfo, seg_ptr, - per_seg_uf * BFA_PER_UF_DMA_SZ); - } else - bfa_mem_dma_setup(minfo, seg_ptr, - num_ufs * BFA_PER_UF_DMA_SZ); - } + u32 num_ufs = cfg->fwcfg.num_uf_bufs; - /* kva memory */ - bfa_mem_kva_setup(minfo, uf_kva, cfg->fwcfg.num_uf_bufs * - (sizeof(struct bfa_uf_s) + sizeof(struct bfi_uf_buf_post_s))); + /* + * dma-able memory for UF posted bufs + */ + *dm_len += BFA_ROUNDUP((sizeof(struct bfa_uf_buf_s) * num_ufs), + BFA_DMA_ALIGN_SZ); + + /* + * kernel Virtual memory for UFs and UF buf post msg copies + */ + *ndm_len += sizeof(struct bfa_uf_s) * num_ufs; + *ndm_len += sizeof(struct bfi_uf_buf_post_s) * num_ufs; } static void bfa_uf_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_pcidev_s *pcidev) + struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) { struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa); + memset(ufm, 0, sizeof(struct bfa_uf_mod_s)); ufm->bfa = bfa; ufm->num_ufs = cfg->fwcfg.num_uf_bufs; INIT_LIST_HEAD(&ufm->uf_free_q); INIT_LIST_HEAD(&ufm->uf_posted_q); - INIT_LIST_HEAD(&ufm->uf_unused_q); - uf_mem_claim(ufm); + uf_mem_claim(ufm, meminfo); } static void @@ -5089,7 +4939,7 @@ bfa_uf_post(struct bfa_uf_mod_s *ufm, struct bfa_uf_s *uf) memcpy(uf_post_msg, &ufm->uf_buf_posts[uf->uf_tag], sizeof(struct bfi_uf_buf_post_s)); - bfa_reqq_produce(ufm->bfa, BFA_REQQ_FCXP, uf_post_msg->mh); + bfa_reqq_produce(ufm->bfa, BFA_REQQ_FCXP); bfa_trc(ufm->bfa, uf->uf_tag); @@ -5113,15 +4963,11 @@ uf_recv(struct bfa_s *bfa, struct bfi_uf_frm_rcvd_s *m) { struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa); u16 uf_tag = m->buf_tag; + struct bfa_uf_buf_s *uf_buf = &ufm->uf_pbs_kva[uf_tag]; struct bfa_uf_s *uf = &ufm->uf_list[uf_tag]; - struct bfa_uf_buf_s *uf_buf; - uint8_t *buf; + u8 *buf = &uf_buf->d[0]; struct fchs_s *fchs; - uf_buf = (struct bfa_uf_buf_s *) - bfa_mem_get_dmabuf_kva(ufm, uf_tag, uf->pb_len); - buf = &uf_buf->d[0]; - m->frm_len = be16_to_cpu(m->frm_len); m->xfr_len = be16_to_cpu(m->xfr_len); @@ -5162,9 +5008,6 @@ bfa_uf_iocdisable(struct bfa_s *bfa) struct bfa_uf_s *uf; struct list_head *qe, *qen; - /* Enqueue unused uf resources to free_q */ - list_splice_tail_init(&ufm->uf_unused_q, &ufm->uf_free_q); - list_for_each_safe(qe, qen, &ufm->uf_posted_q) { uf = (struct bfa_uf_s *) qe; list_del(&uf->qe); @@ -5229,415 +5072,4 @@ bfa_uf_isr(struct bfa_s *bfa, struct bfi_msg_s *msg) } } -void -bfa_uf_res_recfg(struct bfa_s *bfa, u16 num_uf_fw) -{ - struct bfa_uf_mod_s *mod = BFA_UF_MOD(bfa); - struct list_head *qe; - int i; - - for (i = 0; i < (mod->num_ufs - num_uf_fw); i++) { - bfa_q_deq_tail(&mod->uf_free_q, &qe); - list_add_tail(qe, &mod->uf_unused_q); - } -} - -/* - * BFA fcdiag module - */ -#define BFA_DIAG_QTEST_TOV 1000 /* msec */ - -/* - * Set port status to busy - */ -static void -bfa_fcdiag_set_busy_status(struct bfa_fcdiag_s *fcdiag) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(fcdiag->bfa); - - if (fcdiag->lb.lock) - fcport->diag_busy = BFA_TRUE; - else - fcport->diag_busy = BFA_FALSE; -} - -static void -bfa_fcdiag_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo, - struct bfa_s *bfa) -{ -} - -static void -bfa_fcdiag_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_pcidev_s *pcidev) -{ - struct bfa_fcdiag_s *fcdiag = BFA_FCDIAG_MOD(bfa); - fcdiag->bfa = bfa; - fcdiag->trcmod = bfa->trcmod; - /* The common DIAG attach bfa_diag_attach() will do all memory claim */ -} - -static void -bfa_fcdiag_iocdisable(struct bfa_s *bfa) -{ - struct bfa_fcdiag_s *fcdiag = BFA_FCDIAG_MOD(bfa); - bfa_trc(fcdiag, fcdiag->lb.lock); - if (fcdiag->lb.lock) { - fcdiag->lb.status = BFA_STATUS_IOC_FAILURE; - fcdiag->lb.cbfn(fcdiag->lb.cbarg, fcdiag->lb.status); - fcdiag->lb.lock = 0; - bfa_fcdiag_set_busy_status(fcdiag); - } -} - -static void -bfa_fcdiag_detach(struct bfa_s *bfa) -{ -} - -static void -bfa_fcdiag_start(struct bfa_s *bfa) -{ -} - -static void -bfa_fcdiag_stop(struct bfa_s *bfa) -{ -} - -static void -bfa_fcdiag_queuetest_timeout(void *cbarg) -{ - struct bfa_fcdiag_s *fcdiag = cbarg; - struct bfa_diag_qtest_result_s *res = fcdiag->qtest.result; - - bfa_trc(fcdiag, fcdiag->qtest.all); - bfa_trc(fcdiag, fcdiag->qtest.count); - - fcdiag->qtest.timer_active = 0; - - res->status = BFA_STATUS_ETIMER; - res->count = QTEST_CNT_DEFAULT - fcdiag->qtest.count; - if (fcdiag->qtest.all) - res->queue = fcdiag->qtest.all; - - bfa_trc(fcdiag, BFA_STATUS_ETIMER); - fcdiag->qtest.status = BFA_STATUS_ETIMER; - fcdiag->qtest.cbfn(fcdiag->qtest.cbarg, fcdiag->qtest.status); - fcdiag->qtest.lock = 0; -} - -static bfa_status_t -bfa_fcdiag_queuetest_send(struct bfa_fcdiag_s *fcdiag) -{ - u32 i; - struct bfi_diag_qtest_req_s *req; - - req = bfa_reqq_next(fcdiag->bfa, fcdiag->qtest.queue); - if (!req) - return BFA_STATUS_DEVBUSY; - - /* build host command */ - bfi_h2i_set(req->mh, BFI_MC_DIAG, BFI_DIAG_H2I_QTEST, - bfa_fn_lpu(fcdiag->bfa)); - - for (i = 0; i < BFI_LMSG_PL_WSZ; i++) - req->data[i] = QTEST_PAT_DEFAULT; - - bfa_trc(fcdiag, fcdiag->qtest.queue); - /* ring door bell */ - bfa_reqq_produce(fcdiag->bfa, fcdiag->qtest.queue, req->mh); - return BFA_STATUS_OK; -} - -static void -bfa_fcdiag_queuetest_comp(struct bfa_fcdiag_s *fcdiag, - bfi_diag_qtest_rsp_t *rsp) -{ - struct bfa_diag_qtest_result_s *res = fcdiag->qtest.result; - bfa_status_t status = BFA_STATUS_OK; - int i; - - /* Check timer, should still be active */ - if (!fcdiag->qtest.timer_active) { - bfa_trc(fcdiag, fcdiag->qtest.timer_active); - return; - } - - /* update count */ - fcdiag->qtest.count--; - - /* Check result */ - for (i = 0; i < BFI_LMSG_PL_WSZ; i++) { - if (rsp->data[i] != ~(QTEST_PAT_DEFAULT)) { - res->status = BFA_STATUS_DATACORRUPTED; - break; - } - } - - if (res->status == BFA_STATUS_OK) { - if (fcdiag->qtest.count > 0) { - status = bfa_fcdiag_queuetest_send(fcdiag); - if (status == BFA_STATUS_OK) - return; - else - res->status = status; - } else if (fcdiag->qtest.all > 0 && - fcdiag->qtest.queue < (BFI_IOC_MAX_CQS - 1)) { - fcdiag->qtest.count = QTEST_CNT_DEFAULT; - fcdiag->qtest.queue++; - status = bfa_fcdiag_queuetest_send(fcdiag); - if (status == BFA_STATUS_OK) - return; - else - res->status = status; - } - } - - /* Stop timer when we comp all queue */ - if (fcdiag->qtest.timer_active) { - bfa_timer_stop(&fcdiag->qtest.timer); - fcdiag->qtest.timer_active = 0; - } - res->queue = fcdiag->qtest.queue; - res->count = QTEST_CNT_DEFAULT - fcdiag->qtest.count; - bfa_trc(fcdiag, res->count); - bfa_trc(fcdiag, res->status); - fcdiag->qtest.status = res->status; - fcdiag->qtest.cbfn(fcdiag->qtest.cbarg, fcdiag->qtest.status); - fcdiag->qtest.lock = 0; -} - -static void -bfa_fcdiag_loopback_comp(struct bfa_fcdiag_s *fcdiag, - struct bfi_diag_lb_rsp_s *rsp) -{ - struct bfa_diag_loopback_result_s *res = fcdiag->lb.result; - - res->numtxmfrm = be32_to_cpu(rsp->res.numtxmfrm); - res->numosffrm = be32_to_cpu(rsp->res.numosffrm); - res->numrcvfrm = be32_to_cpu(rsp->res.numrcvfrm); - res->badfrminf = be32_to_cpu(rsp->res.badfrminf); - res->badfrmnum = be32_to_cpu(rsp->res.badfrmnum); - res->status = rsp->res.status; - fcdiag->lb.status = rsp->res.status; - bfa_trc(fcdiag, fcdiag->lb.status); - fcdiag->lb.cbfn(fcdiag->lb.cbarg, fcdiag->lb.status); - fcdiag->lb.lock = 0; - bfa_fcdiag_set_busy_status(fcdiag); -} - -static bfa_status_t -bfa_fcdiag_loopback_send(struct bfa_fcdiag_s *fcdiag, - struct bfa_diag_loopback_s *loopback) -{ - struct bfi_diag_lb_req_s *lb_req; - - lb_req = bfa_reqq_next(fcdiag->bfa, BFA_REQQ_DIAG); - if (!lb_req) - return BFA_STATUS_DEVBUSY; - - /* build host command */ - bfi_h2i_set(lb_req->mh, BFI_MC_DIAG, BFI_DIAG_H2I_LOOPBACK, - bfa_fn_lpu(fcdiag->bfa)); - - lb_req->lb_mode = loopback->lb_mode; - lb_req->speed = loopback->speed; - lb_req->loopcnt = loopback->loopcnt; - lb_req->pattern = loopback->pattern; - - /* ring door bell */ - bfa_reqq_produce(fcdiag->bfa, BFA_REQQ_DIAG, lb_req->mh); - - bfa_trc(fcdiag, loopback->lb_mode); - bfa_trc(fcdiag, loopback->speed); - bfa_trc(fcdiag, loopback->loopcnt); - bfa_trc(fcdiag, loopback->pattern); - return BFA_STATUS_OK; -} - -/* - * cpe/rme intr handler - */ -void -bfa_fcdiag_intr(struct bfa_s *bfa, struct bfi_msg_s *msg) -{ - struct bfa_fcdiag_s *fcdiag = BFA_FCDIAG_MOD(bfa); - - switch (msg->mhdr.msg_id) { - case BFI_DIAG_I2H_LOOPBACK: - bfa_fcdiag_loopback_comp(fcdiag, - (struct bfi_diag_lb_rsp_s *) msg); - break; - case BFI_DIAG_I2H_QTEST: - bfa_fcdiag_queuetest_comp(fcdiag, (bfi_diag_qtest_rsp_t *)msg); - break; - default: - bfa_trc(fcdiag, msg->mhdr.msg_id); - WARN_ON(1); - } -} - -/* - * Loopback test - * - * @param[in] *bfa - bfa data struct - * @param[in] opmode - port operation mode - * @param[in] speed - port speed - * @param[in] lpcnt - loop count - * @param[in] pat - pattern to build packet - * @param[in] *result - pt to bfa_diag_loopback_result_t data struct - * @param[in] cbfn - callback function - * @param[in] cbarg - callback functioin arg - * - * @param[out] - */ -bfa_status_t -bfa_fcdiag_loopback(struct bfa_s *bfa, enum bfa_port_opmode opmode, - enum bfa_port_speed speed, u32 lpcnt, u32 pat, - struct bfa_diag_loopback_result_s *result, bfa_cb_diag_t cbfn, - void *cbarg) -{ - struct bfa_diag_loopback_s loopback; - struct bfa_port_attr_s attr; - bfa_status_t status; - struct bfa_fcdiag_s *fcdiag = BFA_FCDIAG_MOD(bfa); - - if (!bfa_iocfc_is_operational(bfa)) - return BFA_STATUS_IOC_NON_OP; - - /* if port is PBC disabled, return error */ - if (bfa_fcport_is_pbcdisabled(bfa)) { - bfa_trc(fcdiag, BFA_STATUS_PBC); - return BFA_STATUS_PBC; - } - if (bfa_fcport_is_disabled(bfa) == BFA_FALSE) { - bfa_trc(fcdiag, opmode); - return BFA_STATUS_PORT_NOT_DISABLED; - } - - /* Check if the speed is supported */ - bfa_fcport_get_attr(bfa, &attr); - bfa_trc(fcdiag, attr.speed_supported); - if (speed > attr.speed_supported) - return BFA_STATUS_UNSUPP_SPEED; - - /* For Mezz card, port speed entered needs to be checked */ - if (bfa_mfg_is_mezz(bfa->ioc.attr->card_type)) { - if (bfa_ioc_get_type(&bfa->ioc) == BFA_IOC_TYPE_FC) { - if ((speed == BFA_PORT_SPEED_1GBPS) && - (bfa_asic_id_ct2(bfa->ioc.pcidev.device_id))) - return BFA_STATUS_UNSUPP_SPEED; - if (!(speed == BFA_PORT_SPEED_1GBPS || - speed == BFA_PORT_SPEED_2GBPS || - speed == BFA_PORT_SPEED_4GBPS || - speed == BFA_PORT_SPEED_8GBPS || - speed == BFA_PORT_SPEED_16GBPS || - speed == BFA_PORT_SPEED_AUTO)) - return BFA_STATUS_UNSUPP_SPEED; - } else { - if (speed != BFA_PORT_SPEED_10GBPS) - return BFA_STATUS_UNSUPP_SPEED; - } - } - - /* check to see if there is another destructive diag cmd running */ - if (fcdiag->lb.lock) { - bfa_trc(fcdiag, fcdiag->lb.lock); - return BFA_STATUS_DEVBUSY; - } - - fcdiag->lb.lock = 1; - loopback.lb_mode = opmode; - loopback.speed = speed; - loopback.loopcnt = lpcnt; - loopback.pattern = pat; - fcdiag->lb.result = result; - fcdiag->lb.cbfn = cbfn; - fcdiag->lb.cbarg = cbarg; - memset(result, 0, sizeof(struct bfa_diag_loopback_result_s)); - bfa_fcdiag_set_busy_status(fcdiag); - - /* Send msg to fw */ - status = bfa_fcdiag_loopback_send(fcdiag, &loopback); - return status; -} - -/* - * DIAG queue test command - * - * @param[in] *bfa - bfa data struct - * @param[in] force - 1: don't do ioc op checking - * @param[in] queue - queue no. to test - * @param[in] *result - pt to bfa_diag_qtest_result_t data struct - * @param[in] cbfn - callback function - * @param[in] *cbarg - callback functioin arg - * - * @param[out] - */ -bfa_status_t -bfa_fcdiag_queuetest(struct bfa_s *bfa, u32 force, u32 queue, - struct bfa_diag_qtest_result_s *result, bfa_cb_diag_t cbfn, - void *cbarg) -{ - struct bfa_fcdiag_s *fcdiag = BFA_FCDIAG_MOD(bfa); - bfa_status_t status; - bfa_trc(fcdiag, force); - bfa_trc(fcdiag, queue); - - if (!force && !bfa_iocfc_is_operational(bfa)) - return BFA_STATUS_IOC_NON_OP; - - /* check to see if there is another destructive diag cmd running */ - if (fcdiag->qtest.lock) { - bfa_trc(fcdiag, fcdiag->qtest.lock); - return BFA_STATUS_DEVBUSY; - } - - /* Initialization */ - fcdiag->qtest.lock = 1; - fcdiag->qtest.cbfn = cbfn; - fcdiag->qtest.cbarg = cbarg; - fcdiag->qtest.result = result; - fcdiag->qtest.count = QTEST_CNT_DEFAULT; - - /* Init test results */ - fcdiag->qtest.result->status = BFA_STATUS_OK; - fcdiag->qtest.result->count = 0; - - /* send */ - if (queue < BFI_IOC_MAX_CQS) { - fcdiag->qtest.result->queue = (u8)queue; - fcdiag->qtest.queue = (u8)queue; - fcdiag->qtest.all = 0; - } else { - fcdiag->qtest.result->queue = 0; - fcdiag->qtest.queue = 0; - fcdiag->qtest.all = 1; - } - status = bfa_fcdiag_queuetest_send(fcdiag); - - /* Start a timer */ - if (status == BFA_STATUS_OK) { - bfa_timer_start(bfa, &fcdiag->qtest.timer, - bfa_fcdiag_queuetest_timeout, fcdiag, - BFA_DIAG_QTEST_TOV); - fcdiag->qtest.timer_active = 1; - } - return status; -} - -/* - * DIAG PLB is running - * - * @param[in] *bfa - bfa data struct - * - * @param[out] - */ -bfa_status_t -bfa_fcdiag_lb_is_running(struct bfa_s *bfa) -{ - struct bfa_fcdiag_s *fcdiag = BFA_FCDIAG_MOD(bfa); - return fcdiag->lb.lock ? BFA_STATUS_DIAG_BUSY : BFA_STATUS_OK; -} diff --git a/trunk/drivers/scsi/bfa/bfa_svc.h b/trunk/drivers/scsi/bfa/bfa_svc.h index fbe513a671b5..5902a45c080f 100644 --- a/trunk/drivers/scsi/bfa/bfa_svc.h +++ b/trunk/drivers/scsi/bfa/bfa_svc.h @@ -26,7 +26,6 @@ * Scatter-gather DMA related defines */ #define BFA_SGPG_MIN (16) -#define BFA_SGPG_MAX (8192) /* * Alignment macro for SG page allocation @@ -55,21 +54,17 @@ struct bfa_sgpg_s { */ #define BFA_SGPG_NPAGE(_nsges) (((_nsges) / BFI_SGPG_DATA_SGES) + 1) -/* Max SGPG dma segs required */ -#define BFA_SGPG_DMA_SEGS \ - BFI_MEM_DMA_NSEGS(BFA_SGPG_MAX, (uint32_t)sizeof(struct bfi_sgpg_s)) - struct bfa_sgpg_mod_s { struct bfa_s *bfa; int num_sgpgs; /* number of SG pages */ int free_sgpgs; /* number of free SG pages */ + struct bfa_sgpg_s *hsgpg_arr; /* BFA SG page array */ + struct bfi_sgpg_s *sgpg_arr; /* actual SG page array */ + u64 sgpg_arr_pa; /* SG page array DMA addr */ struct list_head sgpg_q; /* queue of free SG pages */ struct list_head sgpg_wait_q; /* wait queue for SG pages */ - struct bfa_mem_dma_s dma_seg[BFA_SGPG_DMA_SEGS]; - struct bfa_mem_kva_s kva_seg; }; #define BFA_SGPG_MOD(__bfa) (&(__bfa)->modules.sgpg_mod) -#define BFA_MEM_SGPG_KVA(__bfa) (&(BFA_SGPG_MOD(__bfa)->kva_seg)) bfa_status_t bfa_sgpg_malloc(struct bfa_s *bfa, struct list_head *sgpg_q, int nsgpgs); @@ -84,32 +79,26 @@ void bfa_sgpg_wcancel(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe); * FCXP related defines */ #define BFA_FCXP_MIN (1) -#define BFA_FCXP_MAX (256) #define BFA_FCXP_MAX_IBUF_SZ (2 * 1024 + 256) #define BFA_FCXP_MAX_LBUF_SZ (4 * 1024 + 256) -/* Max FCXP dma segs required */ -#define BFA_FCXP_DMA_SEGS \ - BFI_MEM_DMA_NSEGS(BFA_FCXP_MAX, \ - (u32)BFA_FCXP_MAX_IBUF_SZ + BFA_FCXP_MAX_LBUF_SZ) - struct bfa_fcxp_mod_s { struct bfa_s *bfa; /* backpointer to BFA */ struct bfa_fcxp_s *fcxp_list; /* array of FCXPs */ u16 num_fcxps; /* max num FCXP requests */ struct list_head fcxp_free_q; /* free FCXPs */ struct list_head fcxp_active_q; /* active FCXPs */ + void *req_pld_list_kva; /* list of FCXP req pld */ + u64 req_pld_list_pa; /* list of FCXP req pld */ + void *rsp_pld_list_kva; /* list of FCXP resp pld */ + u64 rsp_pld_list_pa; /* list of FCXP resp pld */ struct list_head wait_q; /* wait queue for free fcxp */ - struct list_head fcxp_unused_q; /* unused fcxps */ u32 req_pld_sz; u32 rsp_pld_sz; - struct bfa_mem_dma_s dma_seg[BFA_FCXP_DMA_SEGS]; - struct bfa_mem_kva_s kva_seg; }; #define BFA_FCXP_MOD(__bfa) (&(__bfa)->modules.fcxp_mod) #define BFA_FCXP_FROM_TAG(__mod, __tag) (&(__mod)->fcxp_list[__tag]) -#define BFA_MEM_FCXP_KVA(__bfa) (&(BFA_FCXP_MOD(__bfa)->kva_seg)) typedef void (*fcxp_send_cb_t) (struct bfa_s *ioc, struct bfa_fcxp_s *fcxp, void *cb_arg, bfa_status_t req_status, @@ -217,15 +206,13 @@ struct bfa_fcxp_wqe_s { #define BFA_FCXP_RSP_FCHS(_fcxp) (&((_fcxp)->rsp_info.fchs)) #define BFA_FCXP_RSP_PLD(_fcxp) (bfa_fcxp_get_rspbuf(_fcxp)) -#define BFA_FCXP_REQ_PLD_PA(_fcxp) \ - bfa_mem_get_dmabuf_pa((_fcxp)->fcxp_mod, (_fcxp)->fcxp_tag, \ - (_fcxp)->fcxp_mod->req_pld_sz + (_fcxp)->fcxp_mod->rsp_pld_sz) +#define BFA_FCXP_REQ_PLD_PA(_fcxp) \ + ((_fcxp)->fcxp_mod->req_pld_list_pa + \ + ((_fcxp)->fcxp_mod->req_pld_sz * (_fcxp)->fcxp_tag)) -/* fcxp_buf = req_buf + rsp_buf :- add req_buf_sz to get to rsp_buf */ -#define BFA_FCXP_RSP_PLD_PA(_fcxp) \ - (bfa_mem_get_dmabuf_pa((_fcxp)->fcxp_mod, (_fcxp)->fcxp_tag, \ - (_fcxp)->fcxp_mod->req_pld_sz + (_fcxp)->fcxp_mod->rsp_pld_sz) + \ - (_fcxp)->fcxp_mod->req_pld_sz) +#define BFA_FCXP_RSP_PLD_PA(_fcxp) \ + ((_fcxp)->fcxp_mod->rsp_pld_list_pa + \ + ((_fcxp)->fcxp_mod->rsp_pld_sz * (_fcxp)->fcxp_tag)) void bfa_fcxp_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); @@ -251,13 +238,10 @@ struct bfa_rport_mod_s { struct bfa_rport_s *rps_list; /* list of rports */ struct list_head rp_free_q; /* free bfa_rports */ struct list_head rp_active_q; /* free bfa_rports */ - struct list_head rp_unused_q; /* unused bfa rports */ u16 num_rports; /* number of rports */ - struct bfa_mem_kva_s kva_seg; }; #define BFA_RPORT_MOD(__bfa) (&(__bfa)->modules.rport_mod) -#define BFA_MEM_RPORT_KVA(__bfa) (&(BFA_RPORT_MOD(__bfa)->kva_seg)) /* * Convert rport tag to RPORT @@ -270,7 +254,6 @@ struct bfa_rport_mod_s { * protected functions */ void bfa_rport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); -void bfa_rport_res_recfg(struct bfa_s *bfa, u16 num_rport_fw); /* * BFA rport information. @@ -315,7 +298,7 @@ struct bfa_rport_s { */ #define BFA_UF_MIN (4) -#define BFA_UF_MAX (256) + struct bfa_uf_s { struct list_head qe; /* queue element */ @@ -343,41 +326,36 @@ struct bfa_uf_s { */ typedef void (*bfa_cb_uf_recv_t) (void *cbarg, struct bfa_uf_s *uf); -#define BFA_UF_BUFSZ (2 * 1024 + 256) - -struct bfa_uf_buf_s { - u8 d[BFA_UF_BUFSZ]; -}; - -#define BFA_PER_UF_DMA_SZ \ - (u32)BFA_ROUNDUP(sizeof(struct bfa_uf_buf_s), BFA_DMA_ALIGN_SZ) - -/* Max UF dma segs required */ -#define BFA_UF_DMA_SEGS BFI_MEM_DMA_NSEGS(BFA_UF_MAX, BFA_PER_UF_DMA_SZ) - struct bfa_uf_mod_s { struct bfa_s *bfa; /* back pointer to BFA */ struct bfa_uf_s *uf_list; /* array of UFs */ u16 num_ufs; /* num unsolicited rx frames */ struct list_head uf_free_q; /* free UFs */ struct list_head uf_posted_q; /* UFs posted to IOC */ - struct list_head uf_unused_q; /* unused UF's */ + struct bfa_uf_buf_s *uf_pbs_kva; /* list UF bufs request pld */ + u64 uf_pbs_pa; /* phy addr for UF bufs */ struct bfi_uf_buf_post_s *uf_buf_posts; /* pre-built UF post msgs */ bfa_cb_uf_recv_t ufrecv; /* uf recv handler function */ void *cbarg; /* uf receive handler arg */ - struct bfa_mem_dma_s dma_seg[BFA_UF_DMA_SEGS]; - struct bfa_mem_kva_s kva_seg; }; #define BFA_UF_MOD(__bfa) (&(__bfa)->modules.uf_mod) -#define BFA_MEM_UF_KVA(__bfa) (&(BFA_UF_MOD(__bfa)->kva_seg)) #define ufm_pbs_pa(_ufmod, _uftag) \ - bfa_mem_get_dmabuf_pa(_ufmod, _uftag, BFA_PER_UF_DMA_SZ) + ((_ufmod)->uf_pbs_pa + sizeof(struct bfa_uf_buf_s) * (_uftag)) void bfa_uf_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); -void bfa_uf_res_recfg(struct bfa_s *bfa, u16 num_uf_fw); + +#define BFA_UF_BUFSZ (2 * 1024 + 256) + +/* + * @todo private + */ +struct bfa_uf_buf_s { + u8 d[BFA_UF_BUFSZ]; +}; + /* * LPS - bfa lport login/logout service interface @@ -386,8 +364,7 @@ struct bfa_lps_s { struct list_head qe; /* queue element */ struct bfa_s *bfa; /* parent bfa instance */ bfa_sm_t sm; /* finite state machine */ - u8 bfa_tag; /* lport tag */ - u8 fw_tag; /* lport fw tag */ + u8 lp_tag; /* lport tag */ u8 reqq; /* lport request queue */ u8 alpa; /* ALPA for loop topologies */ u32 lp_pid; /* lport port ID */ @@ -400,8 +377,6 @@ struct bfa_lps_s { bfa_status_t status; /* login status */ u16 pdusz; /* max receive PDU size */ u16 pr_bbcred; /* BB_CREDIT from peer */ - u8 pr_bbscn; /* BB_SCN from peer */ - u8 bb_scn; /* local BB_SCN */ u8 lsrjt_rsn; /* LSRJT reason */ u8 lsrjt_expl; /* LSRJT explanation */ wwn_t pwwn; /* port wwn of lport */ @@ -420,15 +395,12 @@ struct bfa_lps_s { struct bfa_lps_mod_s { struct list_head lps_free_q; struct list_head lps_active_q; - struct list_head lps_login_q; struct bfa_lps_s *lps_arr; int num_lps; - struct bfa_mem_kva_s kva_seg; }; #define BFA_LPS_MOD(__bfa) (&(__bfa)->modules.lps_mod) #define BFA_LPS_FROM_TAG(__mod, __tag) (&(__mod)->lps_arr[__tag]) -#define BFA_MEM_LPS_KVA(__bfa) (&(BFA_LPS_MOD(__bfa)->kva_seg)) /* * external functions @@ -505,14 +477,11 @@ struct bfa_fcport_s { bfa_boolean_t diag_busy; /* diag busy status */ bfa_boolean_t beacon; /* port beacon status */ bfa_boolean_t link_e2e_beacon; /* link beacon status */ - bfa_boolean_t bbsc_op_state; /* Cred recov Oper State */ struct bfa_fcport_trunk_s trunk; u16 fcoe_vlan; - struct bfa_mem_dma_s fcport_dma; }; #define BFA_FCPORT_MOD(__bfa) (&(__bfa)->modules.fcport) -#define BFA_MEM_FCPORT_DMA(__bfa) (&(BFA_FCPORT_MOD(__bfa)->fcport_dma)) /* * protected functions @@ -546,10 +515,8 @@ void bfa_fcport_event_register(struct bfa_s *bfa, bfa_boolean_t bfa_fcport_is_disabled(struct bfa_s *bfa); enum bfa_port_speed bfa_fcport_get_ratelim_speed(struct bfa_s *bfa); -void bfa_fcport_set_tx_bbcredit(struct bfa_s *bfa, u16 tx_bbcredit, u8 bb_scn); +void bfa_fcport_set_tx_bbcredit(struct bfa_s *bfa, u16 tx_bbcredit); bfa_boolean_t bfa_fcport_is_ratelim(struct bfa_s *bfa); -void bfa_fcport_beacon(void *dev, bfa_boolean_t beacon, - bfa_boolean_t link_e2e_beacon); bfa_boolean_t bfa_fcport_is_linkup(struct bfa_s *bfa); bfa_status_t bfa_fcport_get_stats(struct bfa_s *bfa, union bfa_fcport_stats_u *stats, @@ -557,9 +524,6 @@ bfa_status_t bfa_fcport_get_stats(struct bfa_s *bfa, bfa_status_t bfa_fcport_clear_stats(struct bfa_s *bfa, bfa_cb_port_t cbfn, void *cbarg); bfa_boolean_t bfa_fcport_is_qos_enabled(struct bfa_s *bfa); -bfa_boolean_t bfa_fcport_is_trunk_enabled(struct bfa_s *bfa); -bfa_status_t bfa_fcport_is_pbcdisabled(struct bfa_s *bfa); -void bfa_fcport_cfg_faa(struct bfa_s *bfa, u8 state); /* * bfa rport API functions @@ -613,7 +577,6 @@ void bfa_fcxp_send(struct bfa_fcxp_s *fcxp, struct bfa_rport_s *rport, bfa_status_t bfa_fcxp_abort(struct bfa_fcxp_s *fcxp); u32 bfa_fcxp_get_reqbufsz(struct bfa_fcxp_s *fcxp); u32 bfa_fcxp_get_maxrsp(struct bfa_s *bfa); -void bfa_fcxp_res_recfg(struct bfa_s *bfa, u16 num_fcxp_fw); static inline void * bfa_uf_get_frmbuf(struct bfa_uf_s *uf) @@ -643,12 +606,11 @@ struct bfa_lps_s *bfa_lps_alloc(struct bfa_s *bfa); void bfa_lps_delete(struct bfa_lps_s *lps); void bfa_lps_flogi(struct bfa_lps_s *lps, void *uarg, u8 alpa, u16 pdusz, wwn_t pwwn, wwn_t nwwn, - bfa_boolean_t auth_en, u8 bb_scn); + bfa_boolean_t auth_en); void bfa_lps_fdisc(struct bfa_lps_s *lps, void *uarg, u16 pdusz, wwn_t pwwn, wwn_t nwwn); void bfa_lps_fdisclogo(struct bfa_lps_s *lps); void bfa_lps_set_n2n_pid(struct bfa_lps_s *lps, u32 n2n_pid); -u8 bfa_lps_get_fwtag(struct bfa_s *bfa, u8 lp_tag); u32 bfa_lps_get_base_pid(struct bfa_s *bfa); u8 bfa_lps_get_tag_from_pid(struct bfa_s *bfa, u32 pid); void bfa_cb_lps_flogi_comp(void *bfad, void *uarg, bfa_status_t status); @@ -656,57 +618,4 @@ void bfa_cb_lps_fdisc_comp(void *bfad, void *uarg, bfa_status_t status); void bfa_cb_lps_fdisclogo_comp(void *bfad, void *uarg); void bfa_cb_lps_cvl_event(void *bfad, void *uarg); -/* FAA specific APIs */ -bfa_status_t bfa_faa_enable(struct bfa_s *bfa, - bfa_cb_iocfc_t cbfn, void *cbarg); -bfa_status_t bfa_faa_disable(struct bfa_s *bfa, - bfa_cb_iocfc_t cbfn, void *cbarg); -bfa_status_t bfa_faa_query(struct bfa_s *bfa, struct bfa_faa_attr_s *attr, - bfa_cb_iocfc_t cbfn, void *cbarg); - -/* - * FC DIAG data structure - */ -struct bfa_fcdiag_qtest_s { - struct bfa_diag_qtest_result_s *result; - bfa_cb_diag_t cbfn; - void *cbarg; - struct bfa_timer_s timer; - u32 status; - u32 count; - u8 lock; - u8 queue; - u8 all; - u8 timer_active; -}; - -struct bfa_fcdiag_lb_s { - bfa_cb_diag_t cbfn; - void *cbarg; - void *result; - bfa_boolean_t lock; - u32 status; -}; - -struct bfa_fcdiag_s { - struct bfa_s *bfa; /* Back pointer to BFA */ - struct bfa_trc_mod_s *trcmod; - struct bfa_fcdiag_lb_s lb; - struct bfa_fcdiag_qtest_s qtest; -}; - -#define BFA_FCDIAG_MOD(__bfa) (&(__bfa)->modules.fcdiag) - -void bfa_fcdiag_intr(struct bfa_s *bfa, struct bfi_msg_s *msg); - -bfa_status_t bfa_fcdiag_loopback(struct bfa_s *bfa, - enum bfa_port_opmode opmode, - enum bfa_port_speed speed, u32 lpcnt, u32 pat, - struct bfa_diag_loopback_result_s *result, - bfa_cb_diag_t cbfn, void *cbarg); -bfa_status_t bfa_fcdiag_queuetest(struct bfa_s *bfa, u32 ignore, - u32 queue, struct bfa_diag_qtest_result_s *result, - bfa_cb_diag_t cbfn, void *cbarg); -bfa_status_t bfa_fcdiag_lb_is_running(struct bfa_s *bfa); - #endif /* __BFA_SVC_H__ */ diff --git a/trunk/drivers/scsi/bfa/bfad.c b/trunk/drivers/scsi/bfa/bfad.c index beb30a748ea5..59b5e9b61d71 100644 --- a/trunk/drivers/scsi/bfa/bfad.c +++ b/trunk/drivers/scsi/bfa/bfad.c @@ -56,15 +56,14 @@ int fdmi_enable = BFA_TRUE; int pcie_max_read_reqsz; int bfa_debugfs_enable = 1; int msix_disable_cb = 0, msix_disable_ct = 0; -int max_xfer_size = BFAD_MAX_SECTORS >> 1; /* Firmware releated */ -u32 bfi_image_cb_size, bfi_image_ct_size, bfi_image_ct2_size; -u32 *bfi_image_cb, *bfi_image_ct, *bfi_image_ct2; +u32 bfi_image_ct_fc_size, bfi_image_ct_cna_size, bfi_image_cb_fc_size; +u32 *bfi_image_ct_fc, *bfi_image_ct_cna, *bfi_image_cb_fc; -#define BFAD_FW_FILE_CB "cbfw.bin" -#define BFAD_FW_FILE_CT "ctfw.bin" -#define BFAD_FW_FILE_CT2 "ct2fw.bin" +#define BFAD_FW_FILE_CT_FC "ctfw_fc.bin" +#define BFAD_FW_FILE_CT_CNA "ctfw_cna.bin" +#define BFAD_FW_FILE_CB_FC "cbfw_fc.bin" static u32 *bfad_load_fwimg(struct pci_dev *pdev); static void bfad_free_fwimg(void); @@ -72,18 +71,18 @@ static void bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image, u32 *bfi_image_size, char *fw_name); static const char *msix_name_ct[] = { - "ctrl", "cpe0", "cpe1", "cpe2", "cpe3", - "rme0", "rme1", "rme2", "rme3" }; + "rme0", "rme1", "rme2", "rme3", + "ctrl" }; static const char *msix_name_cb[] = { "cpe0", "cpe1", "cpe2", "cpe3", "rme0", "rme1", "rme2", "rme3", "eemc", "elpu0", "elpu1", "epss", "mlpu" }; -MODULE_FIRMWARE(BFAD_FW_FILE_CB); -MODULE_FIRMWARE(BFAD_FW_FILE_CT); -MODULE_FIRMWARE(BFAD_FW_FILE_CT2); +MODULE_FIRMWARE(BFAD_FW_FILE_CT_FC); +MODULE_FIRMWARE(BFAD_FW_FILE_CT_CNA); +MODULE_FIRMWARE(BFAD_FW_FILE_CB_FC); module_param(os_name, charp, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(os_name, "OS name of the hba host machine"); @@ -145,9 +144,6 @@ MODULE_PARM_DESC(pcie_max_read_reqsz, "PCIe max read request size, default=0 " module_param(bfa_debugfs_enable, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(bfa_debugfs_enable, "Enables debugfs feature, default=1," " Range[false:0|true:1]"); -module_param(max_xfer_size, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(max_xfer_size, "default=32MB," - " Range[64k|128k|256k|512k|1024k|2048k]"); static void bfad_sm_uninit(struct bfad_s *bfad, enum bfad_sm_event event); @@ -531,26 +527,28 @@ bfa_fcb_pbc_vport_create(struct bfad_s *bfad, struct bfi_pbc_vport_s pbc_vport) void bfad_hal_mem_release(struct bfad_s *bfad) { + int i; struct bfa_meminfo_s *hal_meminfo = &bfad->meminfo; - struct bfa_mem_dma_s *dma_info, *dma_elem; - struct bfa_mem_kva_s *kva_info, *kva_elem; - struct list_head *dm_qe, *km_qe; - - dma_info = &hal_meminfo->dma_info; - kva_info = &hal_meminfo->kva_info; - - /* Iterate through the KVA meminfo queue */ - list_for_each(km_qe, &kva_info->qe) { - kva_elem = (struct bfa_mem_kva_s *) km_qe; - vfree(kva_elem->kva); - } - - /* Iterate through the DMA meminfo queue */ - list_for_each(dm_qe, &dma_info->qe) { - dma_elem = (struct bfa_mem_dma_s *) dm_qe; - dma_free_coherent(&bfad->pcidev->dev, - dma_elem->mem_len, dma_elem->kva, - (dma_addr_t) dma_elem->dma); + struct bfa_mem_elem_s *meminfo_elem; + + for (i = 0; i < BFA_MEM_TYPE_MAX; i++) { + meminfo_elem = &hal_meminfo->meminfo[i]; + if (meminfo_elem->kva != NULL) { + switch (meminfo_elem->mem_type) { + case BFA_MEM_TYPE_KVA: + vfree(meminfo_elem->kva); + break; + case BFA_MEM_TYPE_DMA: + dma_free_coherent(&bfad->pcidev->dev, + meminfo_elem->mem_len, + meminfo_elem->kva, + (dma_addr_t) meminfo_elem->dma); + break; + default: + WARN_ON(1); + break; + } + } } memset(hal_meminfo, 0, sizeof(struct bfa_meminfo_s)); @@ -565,15 +563,15 @@ bfad_update_hal_cfg(struct bfa_iocfc_cfg_s *bfa_cfg) bfa_cfg->fwcfg.num_ioim_reqs = num_ios; if (num_tms > 0) bfa_cfg->fwcfg.num_tskim_reqs = num_tms; - if (num_fcxps > 0 && num_fcxps <= BFA_FCXP_MAX) + if (num_fcxps > 0) bfa_cfg->fwcfg.num_fcxp_reqs = num_fcxps; - if (num_ufbufs > 0 && num_ufbufs <= BFA_UF_MAX) + if (num_ufbufs > 0) bfa_cfg->fwcfg.num_uf_bufs = num_ufbufs; if (reqq_size > 0) bfa_cfg->drvcfg.num_reqq_elems = reqq_size; if (rspq_size > 0) bfa_cfg->drvcfg.num_rspq_elems = rspq_size; - if (num_sgpgs > 0 && num_sgpgs <= BFA_SGPG_MAX) + if (num_sgpgs > 0) bfa_cfg->drvcfg.num_sgpgs = num_sgpgs; /* @@ -593,46 +591,85 @@ bfad_update_hal_cfg(struct bfa_iocfc_cfg_s *bfa_cfg) bfa_status_t bfad_hal_mem_alloc(struct bfad_s *bfad) { + int i; struct bfa_meminfo_s *hal_meminfo = &bfad->meminfo; - struct bfa_mem_dma_s *dma_info, *dma_elem; - struct bfa_mem_kva_s *kva_info, *kva_elem; - struct list_head *dm_qe, *km_qe; - bfa_status_t rc = BFA_STATUS_OK; + struct bfa_mem_elem_s *meminfo_elem; dma_addr_t phys_addr; + void *kva; + bfa_status_t rc = BFA_STATUS_OK; + int retry_count = 0; + int reset_value = 1; + int min_num_sgpgs = 512; bfa_cfg_get_default(&bfad->ioc_cfg); + +retry: bfad_update_hal_cfg(&bfad->ioc_cfg); bfad->cfg_data.ioc_queue_depth = bfad->ioc_cfg.fwcfg.num_ioim_reqs; - bfa_cfg_get_meminfo(&bfad->ioc_cfg, hal_meminfo, &bfad->bfa); - - dma_info = &hal_meminfo->dma_info; - kva_info = &hal_meminfo->kva_info; - - /* Iterate through the KVA meminfo queue */ - list_for_each(km_qe, &kva_info->qe) { - kva_elem = (struct bfa_mem_kva_s *) km_qe; - kva_elem->kva = vmalloc(kva_elem->mem_len); - if (kva_elem->kva == NULL) { - bfad_hal_mem_release(bfad); - rc = BFA_STATUS_ENOMEM; - goto ext; - } - memset(kva_elem->kva, 0, kva_elem->mem_len); - } + bfa_cfg_get_meminfo(&bfad->ioc_cfg, hal_meminfo); + + for (i = 0; i < BFA_MEM_TYPE_MAX; i++) { + meminfo_elem = &hal_meminfo->meminfo[i]; + switch (meminfo_elem->mem_type) { + case BFA_MEM_TYPE_KVA: + kva = vmalloc(meminfo_elem->mem_len); + if (kva == NULL) { + bfad_hal_mem_release(bfad); + rc = BFA_STATUS_ENOMEM; + goto ext; + } + memset(kva, 0, meminfo_elem->mem_len); + meminfo_elem->kva = kva; + break; + case BFA_MEM_TYPE_DMA: + kva = dma_alloc_coherent(&bfad->pcidev->dev, + meminfo_elem->mem_len, &phys_addr, GFP_KERNEL); + if (kva == NULL) { + bfad_hal_mem_release(bfad); + /* + * If we cannot allocate with default + * num_sgpages try with half the value. + */ + if (num_sgpgs > min_num_sgpgs) { + printk(KERN_INFO + "bfad[%d]: memory allocation failed" + " with num_sgpgs: %d\n", + bfad->inst_no, num_sgpgs); + nextLowerInt(&num_sgpgs); + printk(KERN_INFO + "bfad[%d]: trying to allocate memory" + " with num_sgpgs: %d\n", + bfad->inst_no, num_sgpgs); + retry_count++; + goto retry; + } else { + if (num_sgpgs_parm > 0) + num_sgpgs = num_sgpgs_parm; + else { + reset_value = + (1 << retry_count); + num_sgpgs *= reset_value; + } + rc = BFA_STATUS_ENOMEM; + goto ext; + } + } + + if (num_sgpgs_parm > 0) + num_sgpgs = num_sgpgs_parm; + else { + reset_value = (1 << retry_count); + num_sgpgs *= reset_value; + } + + memset(kva, 0, meminfo_elem->mem_len); + meminfo_elem->kva = kva; + meminfo_elem->dma = phys_addr; + break; + default: + break; - /* Iterate through the DMA meminfo queue */ - list_for_each(dm_qe, &dma_info->qe) { - dma_elem = (struct bfa_mem_dma_s *) dm_qe; - dma_elem->kva = dma_alloc_coherent(&bfad->pcidev->dev, - dma_elem->mem_len, - &phys_addr, GFP_KERNEL); - if (dma_elem->kva == NULL) { - bfad_hal_mem_release(bfad); - rc = BFA_STATUS_ENOMEM; - goto ext; } - dma_elem->dma = phys_addr; - memset(dma_elem->kva, 0, dma_elem->mem_len); } ext: return rc; @@ -743,17 +780,13 @@ bfad_pci_init(struct pci_dev *pdev, struct bfad_s *bfad) pci_set_master(pdev); - if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) || - (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) != 0)) { - if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) || - (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)) != 0)) { + if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) + if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) { printk(KERN_ERR "pci_set_dma_mask fail %p\n", pdev); goto out_release_region; } - } bfad->pci_bar0_kva = pci_iomap(pdev, 0, pci_resource_len(pdev, 0)); - bfad->pci_bar2_kva = pci_iomap(pdev, 2, pci_resource_len(pdev, 2)); if (bfad->pci_bar0_kva == NULL) { printk(KERN_ERR "Fail to map bar0\n"); @@ -764,7 +797,6 @@ bfad_pci_init(struct pci_dev *pdev, struct bfad_s *bfad) bfad->hal_pcidev.pci_func = PCI_FUNC(pdev->devfn); bfad->hal_pcidev.pci_bar_kva = bfad->pci_bar0_kva; bfad->hal_pcidev.device_id = pdev->device; - bfad->hal_pcidev.ssid = pdev->subsystem_device; bfad->pci_name = pci_name(pdev); bfad->pci_attr.vendor_id = pdev->vendor; @@ -836,7 +868,6 @@ void bfad_pci_uninit(struct pci_dev *pdev, struct bfad_s *bfad) { pci_iounmap(pdev, bfad->pci_bar0_kva); - pci_iounmap(pdev, bfad->pci_bar2_kva); pci_release_regions(pdev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); @@ -877,29 +908,12 @@ bfad_drv_init(struct bfad_s *bfad) bfad->bfa_fcs.trcmod = bfad->trcmod; bfa_fcs_attach(&bfad->bfa_fcs, &bfad->bfa, bfad, BFA_FALSE); bfad->bfa_fcs.fdmi_enabled = fdmi_enable; - bfa_fcs_init(&bfad->bfa_fcs); spin_unlock_irqrestore(&bfad->bfad_lock, flags); bfad->bfad_flags |= BFAD_DRV_INIT_DONE; - /* configure base port */ - rc = bfad_cfg_pport(bfad, BFA_LPORT_ROLE_FCP_IM); - if (rc != BFA_STATUS_OK) - goto out_cfg_pport_fail; - return BFA_STATUS_OK; -out_cfg_pport_fail: - /* fcs exit - on cfg pport failure */ - spin_lock_irqsave(&bfad->bfad_lock, flags); - init_completion(&bfad->comp); - bfad->pport.flags |= BFAD_PORT_DELETE; - bfa_fcs_exit(&bfad->bfa_fcs); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - wait_for_completion(&bfad->comp); - /* bfa detach - free hal memory */ - bfa_detach(&bfad->bfa); - bfad_hal_mem_release(bfad); out_hal_mem_alloc_failure: return BFA_STATUS_FAILED; } @@ -931,7 +945,6 @@ bfad_drv_start(struct bfad_s *bfad) spin_lock_irqsave(&bfad->bfad_lock, flags); bfa_iocfc_start(&bfad->bfa); - bfa_fcs_pbc_vport_init(&bfad->bfa_fcs); bfa_fcs_fabric_modstart(&bfad->bfa_fcs); bfad->bfad_flags |= BFAD_HAL_START_DONE; spin_unlock_irqrestore(&bfad->bfad_lock, flags); @@ -1019,12 +1032,6 @@ bfad_start_ops(struct bfad_s *bfad) { struct bfad_vport_s *vport, *vport_new; struct bfa_fcs_driver_info_s driver_info; - /* Limit min/max. xfer size to [64k-32MB] */ - if (max_xfer_size < BFAD_MIN_SECTORS >> 1) - max_xfer_size = BFAD_MIN_SECTORS >> 1; - if (max_xfer_size > BFAD_MAX_SECTORS >> 1) - max_xfer_size = BFAD_MAX_SECTORS >> 1; - /* Fill the driver_info info to fcs*/ memset(&driver_info, 0, sizeof(driver_info)); strncpy(driver_info.version, BFAD_DRIVER_VERSION, @@ -1042,19 +1049,19 @@ bfad_start_ops(struct bfad_s *bfad) { strncpy(driver_info.os_device_name, bfad->pci_name, sizeof(driver_info.os_device_name - 1)); - /* FCS driver info init */ + /* FCS INIT */ spin_lock_irqsave(&bfad->bfad_lock, flags); bfa_fcs_driver_info_init(&bfad->bfa_fcs, &driver_info); + bfa_fcs_init(&bfad->bfa_fcs); spin_unlock_irqrestore(&bfad->bfad_lock, flags); - /* - * FCS update cfg - reset the pwwn/nwwn of fabric base logical port - * with values learned during bfa_init firmware GETATTR REQ. - */ - bfa_fcs_update_cfg(&bfad->bfa_fcs); - - /* Setup fc host fixed attribute if the lk supports */ - bfad_fc_host_init(bfad->pport.im_port); + retval = bfad_cfg_pport(bfad, BFA_LPORT_ROLE_FCP_IM); + if (retval != BFA_STATUS_OK) { + if (bfa_sm_cmp_state(bfad, bfad_sm_initializing)) + bfa_sm_set_state(bfad, bfad_sm_failed); + bfad_stop(bfad); + return BFA_STATUS_FAILED; + } /* BFAD level FC4 IM specific resource allocation */ retval = bfad_im_probe(bfad); @@ -1226,8 +1233,8 @@ bfad_install_msix_handler(struct bfad_s *bfad) for (i = 0; i < bfad->nvec; i++) { sprintf(bfad->msix_tab[i].name, "bfa-%s-%s", bfad->pci_name, - ((bfa_asic_id_cb(bfad->hal_pcidev.device_id)) ? - msix_name_cb[i] : msix_name_ct[i])); + ((bfa_asic_id_ct(bfad->hal_pcidev.device_id)) ? + msix_name_ct[i] : msix_name_cb[i])); error = request_irq(bfad->msix_tab[i].msix.vector, (irq_handler_t) bfad_msix, 0, @@ -1241,9 +1248,6 @@ bfad_install_msix_handler(struct bfad_s *bfad) free_irq(bfad->msix_tab[j].msix.vector, &bfad->msix_tab[j]); - bfad->bfad_flags &= ~BFAD_MSIX_ON; - pci_disable_msix(bfad->pcidev); - return 1; } } @@ -1261,7 +1265,6 @@ bfad_setup_intr(struct bfad_s *bfad) u32 mask = 0, i, num_bit = 0, max_bit = 0; struct msix_entry msix_entries[MAX_MSIX_ENTRY]; struct pci_dev *pdev = bfad->pcidev; - u16 reg; /* Call BFA to get the msix map for this PCI function. */ bfa_msix_getvecs(&bfad->bfa, &mask, &num_bit, &max_bit); @@ -1269,8 +1272,8 @@ bfad_setup_intr(struct bfad_s *bfad) /* Set up the msix entry table */ bfad_init_msix_entry(bfad, msix_entries, mask, max_bit); - if ((bfa_asic_id_ctc(pdev->device) && !msix_disable_ct) || - (bfa_asic_id_cb(pdev->device) && !msix_disable_cb)) { + if ((bfa_asic_id_ct(pdev->device) && !msix_disable_ct) || + (!bfa_asic_id_ct(pdev->device) && !msix_disable_cb)) { error = pci_enable_msix(bfad->pcidev, msix_entries, bfad->nvec); if (error) { @@ -1291,13 +1294,6 @@ bfad_setup_intr(struct bfad_s *bfad) goto line_based; } - /* Disable INTX in MSI-X mode */ - pci_read_config_word(pdev, PCI_COMMAND, ®); - - if (!(reg & PCI_COMMAND_INTX_DISABLE)) - pci_write_config_word(pdev, PCI_COMMAND, - reg | PCI_COMMAND_INTX_DISABLE); - /* Save the vectors */ for (i = 0; i < bfad->nvec; i++) { bfa_trc(bfad, msix_entries[i].vector); @@ -1319,7 +1315,6 @@ bfad_setup_intr(struct bfad_s *bfad) /* Enable interrupt handler failed */ return 1; } - bfad->bfad_flags |= BFAD_INTX_ON; return error; } @@ -1336,7 +1331,7 @@ bfad_remove_intr(struct bfad_s *bfad) pci_disable_msix(bfad->pcidev); bfad->bfad_flags &= ~BFAD_MSIX_ON; - } else if (bfad->bfad_flags & BFAD_INTX_ON) { + } else { free_irq(bfad->pcidev->irq, bfad); } } @@ -1506,14 +1501,6 @@ struct pci_device_id bfad_id_table[] = { .class = (PCI_CLASS_SERIAL_FIBER << 8), .class_mask = ~0, }, - { - .vendor = BFA_PCI_VENDOR_ID_BROCADE, - .device = BFA_PCI_DEVICE_ID_CT2, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .class = (PCI_CLASS_SERIAL_FIBER << 8), - .class_mask = ~0, - }, {0, 0}, }; @@ -1607,33 +1594,33 @@ bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image, static u32 * bfad_load_fwimg(struct pci_dev *pdev) { - if (pdev->device == BFA_PCI_DEVICE_ID_CT2) { - if (bfi_image_ct2_size == 0) - bfad_read_firmware(pdev, &bfi_image_ct2, - &bfi_image_ct2_size, BFAD_FW_FILE_CT2); - return bfi_image_ct2; - } else if (bfa_asic_id_ct(pdev->device)) { - if (bfi_image_ct_size == 0) - bfad_read_firmware(pdev, &bfi_image_ct, - &bfi_image_ct_size, BFAD_FW_FILE_CT); - return bfi_image_ct; + if (pdev->device == BFA_PCI_DEVICE_ID_CT_FC) { + if (bfi_image_ct_fc_size == 0) + bfad_read_firmware(pdev, &bfi_image_ct_fc, + &bfi_image_ct_fc_size, BFAD_FW_FILE_CT_FC); + return bfi_image_ct_fc; + } else if (pdev->device == BFA_PCI_DEVICE_ID_CT) { + if (bfi_image_ct_cna_size == 0) + bfad_read_firmware(pdev, &bfi_image_ct_cna, + &bfi_image_ct_cna_size, BFAD_FW_FILE_CT_CNA); + return bfi_image_ct_cna; } else { - if (bfi_image_cb_size == 0) - bfad_read_firmware(pdev, &bfi_image_cb, - &bfi_image_cb_size, BFAD_FW_FILE_CB); - return bfi_image_cb; + if (bfi_image_cb_fc_size == 0) + bfad_read_firmware(pdev, &bfi_image_cb_fc, + &bfi_image_cb_fc_size, BFAD_FW_FILE_CB_FC); + return bfi_image_cb_fc; } } static void bfad_free_fwimg(void) { - if (bfi_image_ct2_size && bfi_image_ct2) - vfree(bfi_image_ct2); - if (bfi_image_ct_size && bfi_image_ct) - vfree(bfi_image_ct); - if (bfi_image_cb_size && bfi_image_cb) - vfree(bfi_image_cb); + if (bfi_image_ct_fc_size && bfi_image_ct_fc) + vfree(bfi_image_ct_fc); + if (bfi_image_ct_cna_size && bfi_image_ct_cna) + vfree(bfi_image_ct_cna); + if (bfi_image_cb_fc_size && bfi_image_cb_fc) + vfree(bfi_image_cb_fc); } module_init(bfad_init); diff --git a/trunk/drivers/scsi/bfa/bfad_attr.c b/trunk/drivers/scsi/bfa/bfad_attr.c index 9d95844ab463..a94ea4235433 100644 --- a/trunk/drivers/scsi/bfa/bfad_attr.c +++ b/trunk/drivers/scsi/bfa/bfad_attr.c @@ -218,9 +218,6 @@ bfad_im_get_host_speed(struct Scsi_Host *shost) case BFA_PORT_SPEED_10GBPS: fc_host_speed(shost) = FC_PORTSPEED_10GBIT; break; - case BFA_PORT_SPEED_16GBPS: - fc_host_speed(shost) = FC_PORTSPEED_16GBIT; - break; case BFA_PORT_SPEED_8GBPS: fc_host_speed(shost) = FC_PORTSPEED_8GBIT; break; @@ -583,8 +580,6 @@ struct fc_function_template bfad_im_fc_function_template = { .vport_create = bfad_im_vport_create, .vport_delete = bfad_im_vport_delete, .vport_disable = bfad_im_vport_disable, - .bsg_request = bfad_im_bsg_request, - .bsg_timeout = bfad_im_bsg_timeout, }; struct fc_function_template bfad_im_vport_fc_function_template = { @@ -679,10 +674,8 @@ bfad_im_model_desc_show(struct device *dev, struct device_attribute *attr, struct bfad_s *bfad = im_port->bfad; char model[BFA_ADAPTER_MODEL_NAME_LEN]; char model_descr[BFA_ADAPTER_MODEL_DESCR_LEN]; - int nports = 0; bfa_get_adapter_model(&bfad->bfa, model); - nports = bfa_get_nports(&bfad->bfa); if (!strcmp(model, "Brocade-425")) snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, "Brocade 4Gbps PCIe dual port FC HBA"); @@ -691,10 +684,10 @@ bfad_im_model_desc_show(struct device *dev, struct device_attribute *attr, "Brocade 8Gbps PCIe dual port FC HBA"); else if (!strcmp(model, "Brocade-42B")) snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 4Gbps PCIe dual port FC HBA for HP"); + "HP 4Gbps PCIe dual port FC HBA"); else if (!strcmp(model, "Brocade-82B")) snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 8Gbps PCIe dual port FC HBA for HP"); + "HP 8Gbps PCIe dual port FC HBA"); else if (!strcmp(model, "Brocade-1010")) snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, "Brocade 10Gbps single port CNA"); @@ -703,7 +696,7 @@ bfad_im_model_desc_show(struct device *dev, struct device_attribute *attr, "Brocade 10Gbps dual port CNA"); else if (!strcmp(model, "Brocade-1007")) snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 10Gbps CNA for IBM Blade Center"); + "Brocade 10Gbps CNA"); else if (!strcmp(model, "Brocade-415")) snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, "Brocade 4Gbps PCIe single port FC HBA"); @@ -712,45 +705,17 @@ bfad_im_model_desc_show(struct device *dev, struct device_attribute *attr, "Brocade 8Gbps PCIe single port FC HBA"); else if (!strcmp(model, "Brocade-41B")) snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 4Gbps PCIe single port FC HBA for HP"); + "HP 4Gbps PCIe single port FC HBA"); else if (!strcmp(model, "Brocade-81B")) snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 8Gbps PCIe single port FC HBA for HP"); + "HP 8Gbps PCIe single port FC HBA"); else if (!strcmp(model, "Brocade-804")) snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 8Gbps FC HBA for HP Bladesystem C-class"); - else if (!strcmp(model, "Brocade-902") || - !strcmp(model, "Brocade-1741")) + "HP Bladesystem C-class 8Gbps FC HBA"); + else if (!strcmp(model, "Brocade-902")) snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 10Gbps CNA for Dell M-Series Blade Servers"); - else if (strstr(model, "Brocade-1560")) { - if (nports == 1) - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 16Gbps PCIe single port FC HBA"); - else - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 16Gbps PCIe dual port FC HBA"); - } else if (strstr(model, "Brocade-1710")) { - if (nports == 1) - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 10Gbps single port CNA"); - else - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 10Gbps dual port CNA"); - } else if (strstr(model, "Brocade-1860")) { - if (nports == 1 && bfa_ioc_is_cna(&bfad->bfa.ioc)) - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 10Gbps single port CNA"); - else if (nports == 1 && !bfa_ioc_is_cna(&bfad->bfa.ioc)) - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 16Gbps PCIe single port FC HBA"); - else if (nports == 2 && bfa_ioc_is_cna(&bfad->bfa.ioc)) - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 10Gbps dual port CNA"); - else if (nports == 2 && !bfa_ioc_is_cna(&bfad->bfa.ioc)) - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 16Gbps PCIe dual port FC HBA"); - } else + "Brocade 10Gbps CNA"); + else snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, "Invalid Model"); diff --git a/trunk/drivers/scsi/bfa/bfad_bsg.c b/trunk/drivers/scsi/bfa/bfad_bsg.c deleted file mode 100644 index 89f863ed2334..000000000000 --- a/trunk/drivers/scsi/bfa/bfad_bsg.c +++ /dev/null @@ -1,2163 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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. - */ - -#include -#include "bfad_drv.h" -#include "bfad_im.h" -#include "bfad_bsg.h" - -BFA_TRC_FILE(LDRV, BSG); - -int -bfad_iocmd_ioc_enable(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd; - int rc = 0; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - /* If IOC is not in disabled state - return */ - if (!bfa_ioc_is_disabled(&bfad->bfa.ioc)) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_IOC_FAILURE; - return rc; - } - - init_completion(&bfad->enable_comp); - bfa_iocfc_enable(&bfad->bfa); - iocmd->status = BFA_STATUS_OK; - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - wait_for_completion(&bfad->enable_comp); - - return rc; -} - -int -bfad_iocmd_ioc_disable(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd; - int rc = 0; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - if (bfad->disable_active) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - return EBUSY; - } - - bfad->disable_active = BFA_TRUE; - init_completion(&bfad->disable_comp); - bfa_iocfc_disable(&bfad->bfa); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - wait_for_completion(&bfad->disable_comp); - bfad->disable_active = BFA_FALSE; - iocmd->status = BFA_STATUS_OK; - - return rc; -} - -static int -bfad_iocmd_ioc_get_info(struct bfad_s *bfad, void *cmd) -{ - int i; - struct bfa_bsg_ioc_info_s *iocmd = (struct bfa_bsg_ioc_info_s *)cmd; - struct bfad_im_port_s *im_port; - struct bfa_port_attr_s pattr; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - bfa_fcport_get_attr(&bfad->bfa, &pattr); - iocmd->nwwn = pattr.nwwn; - iocmd->pwwn = pattr.pwwn; - iocmd->ioc_type = bfa_get_type(&bfad->bfa); - iocmd->mac = bfa_get_mac(&bfad->bfa); - iocmd->factory_mac = bfa_get_mfg_mac(&bfad->bfa); - bfa_get_adapter_serial_num(&bfad->bfa, iocmd->serialnum); - iocmd->factorynwwn = pattr.factorynwwn; - iocmd->factorypwwn = pattr.factorypwwn; - im_port = bfad->pport.im_port; - iocmd->host = im_port->shost->host_no; - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - strcpy(iocmd->name, bfad->adapter_name); - strcpy(iocmd->port_name, bfad->port_name); - strcpy(iocmd->hwpath, bfad->pci_name); - - /* set adapter hw path */ - strcpy(iocmd->adapter_hwpath, bfad->pci_name); - i = strlen(iocmd->adapter_hwpath) - 1; - while (iocmd->adapter_hwpath[i] != '.') - i--; - iocmd->adapter_hwpath[i] = '\0'; - iocmd->status = BFA_STATUS_OK; - return 0; -} - -static int -bfad_iocmd_ioc_get_attr(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_ioc_attr_s *iocmd = (struct bfa_bsg_ioc_attr_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - bfa_ioc_get_attr(&bfad->bfa.ioc, &iocmd->ioc_attr); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - /* fill in driver attr info */ - strcpy(iocmd->ioc_attr.driver_attr.driver, BFAD_DRIVER_NAME); - strncpy(iocmd->ioc_attr.driver_attr.driver_ver, - BFAD_DRIVER_VERSION, BFA_VERSION_LEN); - strcpy(iocmd->ioc_attr.driver_attr.fw_ver, - iocmd->ioc_attr.adapter_attr.fw_ver); - strcpy(iocmd->ioc_attr.driver_attr.bios_ver, - iocmd->ioc_attr.adapter_attr.optrom_ver); - - /* copy chip rev info first otherwise it will be overwritten */ - memcpy(bfad->pci_attr.chip_rev, iocmd->ioc_attr.pci_attr.chip_rev, - sizeof(bfad->pci_attr.chip_rev)); - memcpy(&iocmd->ioc_attr.pci_attr, &bfad->pci_attr, - sizeof(struct bfa_ioc_pci_attr_s)); - - iocmd->status = BFA_STATUS_OK; - return 0; -} - -int -bfad_iocmd_ioc_get_stats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_ioc_stats_s *iocmd = (struct bfa_bsg_ioc_stats_s *)cmd; - - bfa_ioc_get_stats(&bfad->bfa, &iocmd->ioc_stats); - iocmd->status = BFA_STATUS_OK; - return 0; -} - -int -bfad_iocmd_ioc_get_fwstats(struct bfad_s *bfad, void *cmd, - unsigned int payload_len) -{ - struct bfa_bsg_ioc_fwstats_s *iocmd = - (struct bfa_bsg_ioc_fwstats_s *)cmd; - void *iocmd_bufptr; - unsigned long flags; - - if (bfad_chk_iocmd_sz(payload_len, - sizeof(struct bfa_bsg_ioc_fwstats_s), - sizeof(struct bfa_fw_stats_s)) != BFA_STATUS_OK) { - iocmd->status = BFA_STATUS_VERSION_FAIL; - goto out; - } - - iocmd_bufptr = (char *)iocmd + sizeof(struct bfa_bsg_ioc_fwstats_s); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_ioc_fw_stats_get(&bfad->bfa.ioc, iocmd_bufptr); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - if (iocmd->status != BFA_STATUS_OK) { - bfa_trc(bfad, iocmd->status); - goto out; - } -out: - bfa_trc(bfad, 0x6666); - return 0; -} - -int -bfad_iocmd_iocfc_get_attr(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_iocfc_attr_s *iocmd = (struct bfa_bsg_iocfc_attr_s *)cmd; - - iocmd->status = BFA_STATUS_OK; - bfa_iocfc_get_attr(&bfad->bfa, &iocmd->iocfc_attr); - - return 0; -} - -int -bfad_iocmd_iocfc_set_intr(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_iocfc_intr_s *iocmd = (struct bfa_bsg_iocfc_intr_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_iocfc_israttr_set(&bfad->bfa, &iocmd->attr); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - return 0; -} - -int -bfad_iocmd_port_enable(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_port_enable(&bfad->bfa.modules.port, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) { - bfa_trc(bfad, iocmd->status); - return 0; - } - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; - return 0; -} - -int -bfad_iocmd_port_disable(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_port_disable(&bfad->bfa.modules.port, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - if (iocmd->status != BFA_STATUS_OK) { - bfa_trc(bfad, iocmd->status); - return 0; - } - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; - return 0; -} - -static int -bfad_iocmd_port_get_attr(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_port_attr_s *iocmd = (struct bfa_bsg_port_attr_s *)cmd; - struct bfa_lport_attr_s port_attr; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - bfa_fcport_get_attr(&bfad->bfa, &iocmd->attr); - bfa_fcs_lport_get_attr(&bfad->bfa_fcs.fabric.bport, &port_attr); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - if (iocmd->attr.topology != BFA_PORT_TOPOLOGY_NONE) - iocmd->attr.pid = port_attr.pid; - else - iocmd->attr.pid = 0; - - iocmd->attr.port_type = port_attr.port_type; - iocmd->attr.loopback = port_attr.loopback; - iocmd->attr.authfail = port_attr.authfail; - strncpy(iocmd->attr.port_symname.symname, - port_attr.port_cfg.sym_name.symname, - sizeof(port_attr.port_cfg.sym_name.symname)); - - iocmd->status = BFA_STATUS_OK; - return 0; -} - -int -bfad_iocmd_port_get_stats(struct bfad_s *bfad, void *cmd, - unsigned int payload_len) -{ - struct bfa_bsg_port_stats_s *iocmd = (struct bfa_bsg_port_stats_s *)cmd; - struct bfad_hal_comp fcomp; - void *iocmd_bufptr; - unsigned long flags; - - if (bfad_chk_iocmd_sz(payload_len, - sizeof(struct bfa_bsg_port_stats_s), - sizeof(union bfa_port_stats_u)) != BFA_STATUS_OK) { - iocmd->status = BFA_STATUS_VERSION_FAIL; - return 0; - } - - iocmd_bufptr = (char *)iocmd + sizeof(struct bfa_bsg_port_stats_s); - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_port_get_stats(&bfad->bfa.modules.port, - iocmd_bufptr, bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) { - bfa_trc(bfad, iocmd->status); - goto out; - } - - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -static int -bfad_iocmd_lport_get_attr(struct bfad_s *bfad, void *cmd) -{ - struct bfa_fcs_lport_s *fcs_port; - struct bfa_bsg_lport_attr_s *iocmd = (struct bfa_bsg_lport_attr_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs, - iocmd->vf_id, iocmd->pwwn); - if (fcs_port == NULL) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_LWWN; - goto out; - } - - bfa_fcs_lport_get_attr(fcs_port, &iocmd->port_attr); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_OK; -out: - return 0; -} - -int -bfad_iocmd_lport_get_stats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_fcs_lport_s *fcs_port; - struct bfa_bsg_lport_stats_s *iocmd = - (struct bfa_bsg_lport_stats_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs, - iocmd->vf_id, iocmd->pwwn); - if (fcs_port == NULL) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_LWWN; - goto out; - } - - bfa_fcs_lport_get_stats(fcs_port, &iocmd->port_stats); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_OK; -out: - return 0; -} - -int -bfad_iocmd_lport_get_iostats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_fcs_lport_s *fcs_port; - struct bfa_bsg_lport_iostats_s *iocmd = - (struct bfa_bsg_lport_iostats_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs, - iocmd->vf_id, iocmd->pwwn); - if (fcs_port == NULL) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_LWWN; - goto out; - } - - bfa_fcpim_port_iostats(&bfad->bfa, &iocmd->iostats, - fcs_port->lp_tag); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_OK; -out: - return 0; -} - -int -bfad_iocmd_lport_get_rports(struct bfad_s *bfad, void *cmd, - unsigned int payload_len) -{ - struct bfa_bsg_lport_get_rports_s *iocmd = - (struct bfa_bsg_lport_get_rports_s *)cmd; - struct bfa_fcs_lport_s *fcs_port; - unsigned long flags; - void *iocmd_bufptr; - - if (iocmd->nrports == 0) - return EINVAL; - - if (bfad_chk_iocmd_sz(payload_len, - sizeof(struct bfa_bsg_lport_get_rports_s), - sizeof(wwn_t) * iocmd->nrports) != BFA_STATUS_OK) { - iocmd->status = BFA_STATUS_VERSION_FAIL; - return 0; - } - - iocmd_bufptr = (char *)iocmd + - sizeof(struct bfa_bsg_lport_get_rports_s); - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs, - iocmd->vf_id, iocmd->pwwn); - if (fcs_port == NULL) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - bfa_trc(bfad, 0); - iocmd->status = BFA_STATUS_UNKNOWN_LWWN; - goto out; - } - - bfa_fcs_lport_get_rports(fcs_port, (wwn_t *)iocmd_bufptr, - &iocmd->nrports); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_OK; -out: - return 0; -} - -int -bfad_iocmd_rport_get_attr(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_rport_attr_s *iocmd = (struct bfa_bsg_rport_attr_s *)cmd; - struct bfa_fcs_lport_s *fcs_port; - struct bfa_fcs_rport_s *fcs_rport; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs, - iocmd->vf_id, iocmd->pwwn); - if (fcs_port == NULL) { - bfa_trc(bfad, 0); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_LWWN; - goto out; - } - - fcs_rport = bfa_fcs_rport_lookup(fcs_port, iocmd->rpwwn); - if (fcs_rport == NULL) { - bfa_trc(bfad, 0); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_RWWN; - goto out; - } - - bfa_fcs_rport_get_attr(fcs_rport, &iocmd->attr); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_OK; -out: - return 0; -} - -static int -bfad_iocmd_rport_get_addr(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_rport_scsi_addr_s *iocmd = - (struct bfa_bsg_rport_scsi_addr_s *)cmd; - struct bfa_fcs_lport_s *fcs_port; - struct bfa_fcs_itnim_s *fcs_itnim; - struct bfad_itnim_s *drv_itnim; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs, - iocmd->vf_id, iocmd->pwwn); - if (fcs_port == NULL) { - bfa_trc(bfad, 0); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_LWWN; - goto out; - } - - fcs_itnim = bfa_fcs_itnim_lookup(fcs_port, iocmd->rpwwn); - if (fcs_itnim == NULL) { - bfa_trc(bfad, 0); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_RWWN; - goto out; - } - - drv_itnim = fcs_itnim->itnim_drv; - - if (drv_itnim && drv_itnim->im_port) - iocmd->host = drv_itnim->im_port->shost->host_no; - else { - bfa_trc(bfad, 0); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_RWWN; - goto out; - } - - iocmd->target = drv_itnim->scsi_tgt_id; - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - iocmd->bus = 0; - iocmd->lun = 0; - iocmd->status = BFA_STATUS_OK; -out: - return 0; -} - -int -bfad_iocmd_rport_get_stats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_rport_stats_s *iocmd = - (struct bfa_bsg_rport_stats_s *)cmd; - struct bfa_fcs_lport_s *fcs_port; - struct bfa_fcs_rport_s *fcs_rport; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs, - iocmd->vf_id, iocmd->pwwn); - if (fcs_port == NULL) { - bfa_trc(bfad, 0); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_LWWN; - goto out; - } - - fcs_rport = bfa_fcs_rport_lookup(fcs_port, iocmd->rpwwn); - if (fcs_rport == NULL) { - bfa_trc(bfad, 0); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_RWWN; - goto out; - } - - memcpy((void *)&iocmd->stats, (void *)&fcs_rport->stats, - sizeof(struct bfa_rport_stats_s)); - memcpy((void *)&iocmd->stats.hal_stats, - (void *)&(bfa_fcs_rport_get_halrport(fcs_rport)->stats), - sizeof(struct bfa_rport_hal_stats_s)); - - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_OK; -out: - return 0; -} - -static int -bfad_iocmd_fabric_get_lports(struct bfad_s *bfad, void *cmd, - unsigned int payload_len) -{ - struct bfa_bsg_fabric_get_lports_s *iocmd = - (struct bfa_bsg_fabric_get_lports_s *)cmd; - bfa_fcs_vf_t *fcs_vf; - uint32_t nports = iocmd->nports; - unsigned long flags; - void *iocmd_bufptr; - - if (nports == 0) { - iocmd->status = BFA_STATUS_EINVAL; - goto out; - } - - if (bfad_chk_iocmd_sz(payload_len, - sizeof(struct bfa_bsg_fabric_get_lports_s), - sizeof(wwn_t[iocmd->nports])) != BFA_STATUS_OK) { - iocmd->status = BFA_STATUS_VERSION_FAIL; - goto out; - } - - iocmd_bufptr = (char *)iocmd + - sizeof(struct bfa_bsg_fabric_get_lports_s); - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_vf = bfa_fcs_vf_lookup(&bfad->bfa_fcs, iocmd->vf_id); - if (fcs_vf == NULL) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_VFID; - goto out; - } - bfa_fcs_vf_get_ports(fcs_vf, (wwn_t *)iocmd_bufptr, &nports); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - iocmd->nports = nports; - iocmd->status = BFA_STATUS_OK; -out: - return 0; -} - -int -bfad_iocmd_fcpim_get_modstats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_fcpim_modstats_s *iocmd = - (struct bfa_bsg_fcpim_modstats_s *)cmd; - struct bfa_fcpim_s *fcpim = BFA_FCPIM(&bfad->bfa); - struct list_head *qe, *qen; - struct bfa_itnim_s *itnim; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - /* accumulate IO stats from itnim */ - memset((void *)&iocmd->modstats, 0, sizeof(struct bfa_itnim_iostats_s)); - list_for_each_safe(qe, qen, &fcpim->itnim_q) { - itnim = (struct bfa_itnim_s *) qe; - bfa_fcpim_add_stats(&iocmd->modstats, &(itnim->stats)); - } - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_OK; - return 0; -} - -int -bfad_iocmd_fcpim_get_del_itn_stats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_fcpim_del_itn_stats_s *iocmd = - (struct bfa_bsg_fcpim_del_itn_stats_s *)cmd; - struct bfa_fcpim_s *fcpim = BFA_FCPIM(&bfad->bfa); - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - memcpy((void *)&iocmd->modstats, (void *)&fcpim->del_itn_stats, - sizeof(struct bfa_fcpim_del_itn_stats_s)); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - iocmd->status = BFA_STATUS_OK; - return 0; -} - -static int -bfad_iocmd_itnim_get_attr(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_itnim_attr_s *iocmd = (struct bfa_bsg_itnim_attr_s *)cmd; - struct bfa_fcs_lport_s *fcs_port; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs, - iocmd->vf_id, iocmd->lpwwn); - if (!fcs_port) - iocmd->status = BFA_STATUS_UNKNOWN_LWWN; - else - iocmd->status = bfa_fcs_itnim_attr_get(fcs_port, - iocmd->rpwwn, &iocmd->attr); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - return 0; -} - -static int -bfad_iocmd_itnim_get_iostats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_itnim_iostats_s *iocmd = - (struct bfa_bsg_itnim_iostats_s *)cmd; - struct bfa_fcs_lport_s *fcs_port; - struct bfa_fcs_itnim_s *itnim; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs, - iocmd->vf_id, iocmd->lpwwn); - if (!fcs_port) { - iocmd->status = BFA_STATUS_UNKNOWN_LWWN; - bfa_trc(bfad, 0); - } else { - itnim = bfa_fcs_itnim_lookup(fcs_port, iocmd->rpwwn); - if (itnim == NULL) - iocmd->status = BFA_STATUS_UNKNOWN_RWWN; - else { - iocmd->status = BFA_STATUS_OK; - memcpy((void *)&iocmd->iostats, (void *) - &(bfa_fcs_itnim_get_halitn(itnim)->stats), - sizeof(struct bfa_itnim_iostats_s)); - } - } - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - return 0; -} - -static int -bfad_iocmd_itnim_get_itnstats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_itnim_itnstats_s *iocmd = - (struct bfa_bsg_itnim_itnstats_s *)cmd; - struct bfa_fcs_lport_s *fcs_port; - struct bfa_fcs_itnim_s *itnim; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs, - iocmd->vf_id, iocmd->lpwwn); - if (!fcs_port) { - iocmd->status = BFA_STATUS_UNKNOWN_LWWN; - bfa_trc(bfad, 0); - } else { - itnim = bfa_fcs_itnim_lookup(fcs_port, iocmd->rpwwn); - if (itnim == NULL) - iocmd->status = BFA_STATUS_UNKNOWN_RWWN; - else { - iocmd->status = BFA_STATUS_OK; - bfa_fcs_itnim_stats_get(fcs_port, iocmd->rpwwn, - &iocmd->itnstats); - } - } - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - return 0; -} - -int -bfad_iocmd_fcport_enable(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_fcport_enable(&bfad->bfa); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - return 0; -} - -int -bfad_iocmd_fcport_disable(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_fcport_disable(&bfad->bfa); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - return 0; -} - -int -bfad_iocmd_ioc_get_pcifn_cfg(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_pcifn_cfg_s *iocmd = (struct bfa_bsg_pcifn_cfg_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_ablk_query(&bfad->bfa.modules.ablk, - &iocmd->pcifn_cfg, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_pcifn_create(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_pcifn_s *iocmd = (struct bfa_bsg_pcifn_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_ablk_pf_create(&bfad->bfa.modules.ablk, - &iocmd->pcifn_id, iocmd->port, - iocmd->pcifn_class, iocmd->bandwidth, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_pcifn_delete(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_pcifn_s *iocmd = (struct bfa_bsg_pcifn_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_ablk_pf_delete(&bfad->bfa.modules.ablk, - iocmd->pcifn_id, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_pcifn_bw(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_pcifn_s *iocmd = (struct bfa_bsg_pcifn_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_ablk_pf_update(&bfad->bfa.modules.ablk, - iocmd->pcifn_id, iocmd->bandwidth, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - bfa_trc(bfad, iocmd->status); - if (iocmd->status != BFA_STATUS_OK) - goto out; - - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; - bfa_trc(bfad, iocmd->status); -out: - return 0; -} - -int -bfad_iocmd_adapter_cfg_mode(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_adapter_cfg_mode_s *iocmd = - (struct bfa_bsg_adapter_cfg_mode_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags = 0; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_ablk_adapter_config(&bfad->bfa.modules.ablk, - iocmd->cfg.mode, iocmd->cfg.max_pf, - iocmd->cfg.max_vf, bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_port_cfg_mode(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_port_cfg_mode_s *iocmd = - (struct bfa_bsg_port_cfg_mode_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags = 0; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_ablk_port_config(&bfad->bfa.modules.ablk, - iocmd->instance, iocmd->cfg.mode, - iocmd->cfg.max_pf, iocmd->cfg.max_vf, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_ablk_optrom(struct bfad_s *bfad, unsigned int cmd, void *pcmd) -{ - struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)pcmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - if (cmd == IOCMD_FLASH_ENABLE_OPTROM) - iocmd->status = bfa_ablk_optrom_en(&bfad->bfa.modules.ablk, - bfad_hcb_comp, &fcomp); - else - iocmd->status = bfa_ablk_optrom_dis(&bfad->bfa.modules.ablk, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - if (iocmd->status != BFA_STATUS_OK) - goto out; - - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_faa_enable(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd; - unsigned long flags; - struct bfad_hal_comp fcomp; - - init_completion(&fcomp.comp); - iocmd->status = BFA_STATUS_OK; - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_faa_enable(&bfad->bfa, bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - if (iocmd->status != BFA_STATUS_OK) - goto out; - - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_faa_disable(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd; - unsigned long flags; - struct bfad_hal_comp fcomp; - - init_completion(&fcomp.comp); - iocmd->status = BFA_STATUS_OK; - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_faa_disable(&bfad->bfa, bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - if (iocmd->status != BFA_STATUS_OK) - goto out; - - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_faa_query(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_faa_attr_s *iocmd = (struct bfa_bsg_faa_attr_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - iocmd->status = BFA_STATUS_OK; - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_faa_query(&bfad->bfa, &iocmd->faa_attr, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - if (iocmd->status != BFA_STATUS_OK) - goto out; - - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_cee_attr(struct bfad_s *bfad, void *cmd, unsigned int payload_len) -{ - struct bfa_bsg_cee_attr_s *iocmd = - (struct bfa_bsg_cee_attr_s *)cmd; - void *iocmd_bufptr; - struct bfad_hal_comp cee_comp; - unsigned long flags; - - if (bfad_chk_iocmd_sz(payload_len, - sizeof(struct bfa_bsg_cee_attr_s), - sizeof(struct bfa_cee_attr_s)) != BFA_STATUS_OK) { - iocmd->status = BFA_STATUS_VERSION_FAIL; - return 0; - } - - iocmd_bufptr = (char *)iocmd + sizeof(struct bfa_bsg_cee_attr_s); - - cee_comp.status = 0; - init_completion(&cee_comp.comp); - mutex_lock(&bfad_mutex); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_cee_get_attr(&bfad->bfa.modules.cee, iocmd_bufptr, - bfad_hcb_comp, &cee_comp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) { - mutex_unlock(&bfad_mutex); - bfa_trc(bfad, 0x5555); - goto out; - } - wait_for_completion(&cee_comp.comp); - mutex_unlock(&bfad_mutex); -out: - return 0; -} - -int -bfad_iocmd_cee_get_stats(struct bfad_s *bfad, void *cmd, - unsigned int payload_len) -{ - struct bfa_bsg_cee_stats_s *iocmd = - (struct bfa_bsg_cee_stats_s *)cmd; - void *iocmd_bufptr; - struct bfad_hal_comp cee_comp; - unsigned long flags; - - if (bfad_chk_iocmd_sz(payload_len, - sizeof(struct bfa_bsg_cee_stats_s), - sizeof(struct bfa_cee_stats_s)) != BFA_STATUS_OK) { - iocmd->status = BFA_STATUS_VERSION_FAIL; - return 0; - } - - iocmd_bufptr = (char *)iocmd + sizeof(struct bfa_bsg_cee_stats_s); - - cee_comp.status = 0; - init_completion(&cee_comp.comp); - mutex_lock(&bfad_mutex); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_cee_get_stats(&bfad->bfa.modules.cee, iocmd_bufptr, - bfad_hcb_comp, &cee_comp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) { - mutex_unlock(&bfad_mutex); - bfa_trc(bfad, 0x5555); - goto out; - } - wait_for_completion(&cee_comp.comp); - mutex_unlock(&bfad_mutex); -out: - return 0; -} - -int -bfad_iocmd_cee_reset_stats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_cee_reset_stats(&bfad->bfa.modules.cee, NULL, NULL); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - bfa_trc(bfad, 0x5555); - return 0; -} - -int -bfad_iocmd_sfp_media(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_sfp_media_s *iocmd = (struct bfa_bsg_sfp_media_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_sfp_media(BFA_SFP_MOD(&bfad->bfa), &iocmd->media, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - bfa_trc(bfad, iocmd->status); - if (iocmd->status != BFA_STATUS_SFP_NOT_READY) - goto out; - - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_sfp_speed(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_sfp_speed_s *iocmd = (struct bfa_bsg_sfp_speed_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_sfp_speed(BFA_SFP_MOD(&bfad->bfa), iocmd->speed, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - bfa_trc(bfad, iocmd->status); - if (iocmd->status != BFA_STATUS_SFP_NOT_READY) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_flash_get_attr(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_flash_attr_s *iocmd = - (struct bfa_bsg_flash_attr_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_flash_get_attr(BFA_FLASH(&bfad->bfa), &iocmd->attr, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_flash_erase_part(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_flash_s *iocmd = (struct bfa_bsg_flash_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_flash_erase_part(BFA_FLASH(&bfad->bfa), iocmd->type, - iocmd->instance, bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_flash_update_part(struct bfad_s *bfad, void *cmd, - unsigned int payload_len) -{ - struct bfa_bsg_flash_s *iocmd = (struct bfa_bsg_flash_s *)cmd; - void *iocmd_bufptr; - struct bfad_hal_comp fcomp; - unsigned long flags; - - if (bfad_chk_iocmd_sz(payload_len, - sizeof(struct bfa_bsg_flash_s), - iocmd->bufsz) != BFA_STATUS_OK) { - iocmd->status = BFA_STATUS_VERSION_FAIL; - return 0; - } - - iocmd_bufptr = (char *)iocmd + sizeof(struct bfa_bsg_flash_s); - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_flash_update_part(BFA_FLASH(&bfad->bfa), - iocmd->type, iocmd->instance, iocmd_bufptr, - iocmd->bufsz, 0, bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_flash_read_part(struct bfad_s *bfad, void *cmd, - unsigned int payload_len) -{ - struct bfa_bsg_flash_s *iocmd = (struct bfa_bsg_flash_s *)cmd; - struct bfad_hal_comp fcomp; - void *iocmd_bufptr; - unsigned long flags; - - if (bfad_chk_iocmd_sz(payload_len, - sizeof(struct bfa_bsg_flash_s), - iocmd->bufsz) != BFA_STATUS_OK) { - iocmd->status = BFA_STATUS_VERSION_FAIL; - return 0; - } - - iocmd_bufptr = (char *)iocmd + sizeof(struct bfa_bsg_flash_s); - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_flash_read_part(BFA_FLASH(&bfad->bfa), iocmd->type, - iocmd->instance, iocmd_bufptr, iocmd->bufsz, 0, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_diag_temp(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_diag_get_temp_s *iocmd = - (struct bfa_bsg_diag_get_temp_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_diag_tsensor_query(BFA_DIAG_MOD(&bfad->bfa), - &iocmd->result, bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - bfa_trc(bfad, iocmd->status); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_diag_memtest(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_diag_memtest_s *iocmd = - (struct bfa_bsg_diag_memtest_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_diag_memtest(BFA_DIAG_MOD(&bfad->bfa), - &iocmd->memtest, iocmd->pat, - &iocmd->result, bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - bfa_trc(bfad, iocmd->status); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_diag_loopback(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_diag_loopback_s *iocmd = - (struct bfa_bsg_diag_loopback_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_fcdiag_loopback(&bfad->bfa, iocmd->opmode, - iocmd->speed, iocmd->lpcnt, iocmd->pat, - &iocmd->result, bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - bfa_trc(bfad, iocmd->status); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_diag_fwping(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_diag_fwping_s *iocmd = - (struct bfa_bsg_diag_fwping_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_diag_fwping(BFA_DIAG_MOD(&bfad->bfa), iocmd->cnt, - iocmd->pattern, &iocmd->result, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - bfa_trc(bfad, iocmd->status); - if (iocmd->status != BFA_STATUS_OK) - goto out; - bfa_trc(bfad, 0x77771); - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_diag_queuetest(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_diag_qtest_s *iocmd = (struct bfa_bsg_diag_qtest_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_fcdiag_queuetest(&bfad->bfa, iocmd->force, - iocmd->queue, &iocmd->result, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_diag_sfp(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_sfp_show_s *iocmd = - (struct bfa_bsg_sfp_show_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_sfp_show(BFA_SFP_MOD(&bfad->bfa), &iocmd->sfp, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - bfa_trc(bfad, iocmd->status); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; - bfa_trc(bfad, iocmd->status); -out: - return 0; -} - -int -bfad_iocmd_diag_led(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_diag_led_s *iocmd = (struct bfa_bsg_diag_led_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_diag_ledtest(BFA_DIAG_MOD(&bfad->bfa), - &iocmd->ledtest); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - return 0; -} - -int -bfad_iocmd_diag_beacon_lport(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_diag_beacon_s *iocmd = - (struct bfa_bsg_diag_beacon_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_diag_beacon_port(BFA_DIAG_MOD(&bfad->bfa), - iocmd->beacon, iocmd->link_e2e_beacon, - iocmd->second); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - return 0; -} - -int -bfad_iocmd_diag_lb_stat(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_diag_lb_stat_s *iocmd = - (struct bfa_bsg_diag_lb_stat_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_fcdiag_lb_is_running(&bfad->bfa); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - bfa_trc(bfad, iocmd->status); - - return 0; -} - -int -bfad_iocmd_phy_get_attr(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_phy_attr_s *iocmd = - (struct bfa_bsg_phy_attr_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_phy_get_attr(BFA_PHY(&bfad->bfa), iocmd->instance, - &iocmd->attr, bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_phy_get_stats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_phy_stats_s *iocmd = - (struct bfa_bsg_phy_stats_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_phy_get_stats(BFA_PHY(&bfad->bfa), iocmd->instance, - &iocmd->stats, bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_phy_read(struct bfad_s *bfad, void *cmd, unsigned int payload_len) -{ - struct bfa_bsg_phy_s *iocmd = (struct bfa_bsg_phy_s *)cmd; - struct bfad_hal_comp fcomp; - void *iocmd_bufptr; - unsigned long flags; - - if (bfad_chk_iocmd_sz(payload_len, - sizeof(struct bfa_bsg_phy_s), - iocmd->bufsz) != BFA_STATUS_OK) { - iocmd->status = BFA_STATUS_VERSION_FAIL; - return 0; - } - - iocmd_bufptr = (char *)iocmd + sizeof(struct bfa_bsg_phy_s); - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_phy_read(BFA_PHY(&bfad->bfa), - iocmd->instance, iocmd_bufptr, iocmd->bufsz, - 0, bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; - if (iocmd->status != BFA_STATUS_OK) - goto out; -out: - return 0; -} - -int -bfad_iocmd_vhba_query(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_vhba_attr_s *iocmd = - (struct bfa_bsg_vhba_attr_s *)cmd; - struct bfa_vhba_attr_s *attr = &iocmd->attr; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - attr->pwwn = bfad->bfa.ioc.attr->pwwn; - attr->nwwn = bfad->bfa.ioc.attr->nwwn; - attr->plog_enabled = (bfa_boolean_t)bfad->bfa.plog->plog_enabled; - attr->io_profile = bfa_fcpim_get_io_profile(&bfad->bfa); - attr->path_tov = bfa_fcpim_path_tov_get(&bfad->bfa); - iocmd->status = BFA_STATUS_OK; - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - return 0; -} - -int -bfad_iocmd_phy_update(struct bfad_s *bfad, void *cmd, unsigned int payload_len) -{ - struct bfa_bsg_phy_s *iocmd = (struct bfa_bsg_phy_s *)cmd; - void *iocmd_bufptr; - struct bfad_hal_comp fcomp; - unsigned long flags; - - if (bfad_chk_iocmd_sz(payload_len, - sizeof(struct bfa_bsg_phy_s), - iocmd->bufsz) != BFA_STATUS_OK) { - iocmd->status = BFA_STATUS_VERSION_FAIL; - return 0; - } - - iocmd_bufptr = (char *)iocmd + sizeof(struct bfa_bsg_phy_s); - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_phy_update(BFA_PHY(&bfad->bfa), - iocmd->instance, iocmd_bufptr, iocmd->bufsz, - 0, bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_porglog_get(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_debug_s *iocmd = (struct bfa_bsg_debug_s *)cmd; - void *iocmd_bufptr; - - if (iocmd->bufsz < sizeof(struct bfa_plog_s)) { - bfa_trc(bfad, sizeof(struct bfa_plog_s)); - iocmd->status = BFA_STATUS_EINVAL; - goto out; - } - - iocmd->status = BFA_STATUS_OK; - iocmd_bufptr = (char *)iocmd + sizeof(struct bfa_bsg_debug_s); - memcpy(iocmd_bufptr, (u8 *) &bfad->plog_buf, sizeof(struct bfa_plog_s)); -out: - return 0; -} - -static int -bfad_iocmd_handler(struct bfad_s *bfad, unsigned int cmd, void *iocmd, - unsigned int payload_len) -{ - int rc = EINVAL; - - switch (cmd) { - case IOCMD_IOC_ENABLE: - rc = bfad_iocmd_ioc_enable(bfad, iocmd); - break; - case IOCMD_IOC_DISABLE: - rc = bfad_iocmd_ioc_disable(bfad, iocmd); - break; - case IOCMD_IOC_GET_INFO: - rc = bfad_iocmd_ioc_get_info(bfad, iocmd); - break; - case IOCMD_IOC_GET_ATTR: - rc = bfad_iocmd_ioc_get_attr(bfad, iocmd); - break; - case IOCMD_IOC_GET_STATS: - rc = bfad_iocmd_ioc_get_stats(bfad, iocmd); - break; - case IOCMD_IOC_GET_FWSTATS: - rc = bfad_iocmd_ioc_get_fwstats(bfad, iocmd, payload_len); - break; - case IOCMD_IOCFC_GET_ATTR: - rc = bfad_iocmd_iocfc_get_attr(bfad, iocmd); - break; - case IOCMD_IOCFC_SET_INTR: - rc = bfad_iocmd_iocfc_set_intr(bfad, iocmd); - break; - case IOCMD_PORT_ENABLE: - rc = bfad_iocmd_port_enable(bfad, iocmd); - break; - case IOCMD_PORT_DISABLE: - rc = bfad_iocmd_port_disable(bfad, iocmd); - break; - case IOCMD_PORT_GET_ATTR: - rc = bfad_iocmd_port_get_attr(bfad, iocmd); - break; - case IOCMD_PORT_GET_STATS: - rc = bfad_iocmd_port_get_stats(bfad, iocmd, payload_len); - break; - case IOCMD_LPORT_GET_ATTR: - rc = bfad_iocmd_lport_get_attr(bfad, iocmd); - break; - case IOCMD_LPORT_GET_STATS: - rc = bfad_iocmd_lport_get_stats(bfad, iocmd); - break; - case IOCMD_LPORT_GET_IOSTATS: - rc = bfad_iocmd_lport_get_iostats(bfad, iocmd); - break; - case IOCMD_LPORT_GET_RPORTS: - rc = bfad_iocmd_lport_get_rports(bfad, iocmd, payload_len); - break; - case IOCMD_RPORT_GET_ATTR: - rc = bfad_iocmd_rport_get_attr(bfad, iocmd); - break; - case IOCMD_RPORT_GET_ADDR: - rc = bfad_iocmd_rport_get_addr(bfad, iocmd); - break; - case IOCMD_RPORT_GET_STATS: - rc = bfad_iocmd_rport_get_stats(bfad, iocmd); - break; - case IOCMD_FABRIC_GET_LPORTS: - rc = bfad_iocmd_fabric_get_lports(bfad, iocmd, payload_len); - break; - case IOCMD_FCPIM_MODSTATS: - rc = bfad_iocmd_fcpim_get_modstats(bfad, iocmd); - break; - case IOCMD_FCPIM_DEL_ITN_STATS: - rc = bfad_iocmd_fcpim_get_del_itn_stats(bfad, iocmd); - break; - case IOCMD_ITNIM_GET_ATTR: - rc = bfad_iocmd_itnim_get_attr(bfad, iocmd); - break; - case IOCMD_ITNIM_GET_IOSTATS: - rc = bfad_iocmd_itnim_get_iostats(bfad, iocmd); - break; - case IOCMD_ITNIM_GET_ITNSTATS: - rc = bfad_iocmd_itnim_get_itnstats(bfad, iocmd); - break; - case IOCMD_FCPORT_ENABLE: - rc = bfad_iocmd_fcport_enable(bfad, iocmd); - break; - case IOCMD_FCPORT_DISABLE: - rc = bfad_iocmd_fcport_disable(bfad, iocmd); - break; - case IOCMD_IOC_PCIFN_CFG: - rc = bfad_iocmd_ioc_get_pcifn_cfg(bfad, iocmd); - break; - case IOCMD_PCIFN_CREATE: - rc = bfad_iocmd_pcifn_create(bfad, iocmd); - break; - case IOCMD_PCIFN_DELETE: - rc = bfad_iocmd_pcifn_delete(bfad, iocmd); - break; - case IOCMD_PCIFN_BW: - rc = bfad_iocmd_pcifn_bw(bfad, iocmd); - break; - case IOCMD_ADAPTER_CFG_MODE: - rc = bfad_iocmd_adapter_cfg_mode(bfad, iocmd); - break; - case IOCMD_PORT_CFG_MODE: - rc = bfad_iocmd_port_cfg_mode(bfad, iocmd); - break; - case IOCMD_FLASH_ENABLE_OPTROM: - case IOCMD_FLASH_DISABLE_OPTROM: - rc = bfad_iocmd_ablk_optrom(bfad, cmd, iocmd); - break; - case IOCMD_FAA_ENABLE: - rc = bfad_iocmd_faa_enable(bfad, iocmd); - break; - case IOCMD_FAA_DISABLE: - rc = bfad_iocmd_faa_disable(bfad, iocmd); - break; - case IOCMD_FAA_QUERY: - rc = bfad_iocmd_faa_query(bfad, iocmd); - break; - case IOCMD_CEE_GET_ATTR: - rc = bfad_iocmd_cee_attr(bfad, iocmd, payload_len); - break; - case IOCMD_CEE_GET_STATS: - rc = bfad_iocmd_cee_get_stats(bfad, iocmd, payload_len); - break; - case IOCMD_CEE_RESET_STATS: - rc = bfad_iocmd_cee_reset_stats(bfad, iocmd); - break; - case IOCMD_SFP_MEDIA: - rc = bfad_iocmd_sfp_media(bfad, iocmd); - break; - case IOCMD_SFP_SPEED: - rc = bfad_iocmd_sfp_speed(bfad, iocmd); - break; - case IOCMD_FLASH_GET_ATTR: - rc = bfad_iocmd_flash_get_attr(bfad, iocmd); - break; - case IOCMD_FLASH_ERASE_PART: - rc = bfad_iocmd_flash_erase_part(bfad, iocmd); - break; - case IOCMD_FLASH_UPDATE_PART: - rc = bfad_iocmd_flash_update_part(bfad, iocmd, payload_len); - break; - case IOCMD_FLASH_READ_PART: - rc = bfad_iocmd_flash_read_part(bfad, iocmd, payload_len); - break; - case IOCMD_DIAG_TEMP: - rc = bfad_iocmd_diag_temp(bfad, iocmd); - break; - case IOCMD_DIAG_MEMTEST: - rc = bfad_iocmd_diag_memtest(bfad, iocmd); - break; - case IOCMD_DIAG_LOOPBACK: - rc = bfad_iocmd_diag_loopback(bfad, iocmd); - break; - case IOCMD_DIAG_FWPING: - rc = bfad_iocmd_diag_fwping(bfad, iocmd); - break; - case IOCMD_DIAG_QUEUETEST: - rc = bfad_iocmd_diag_queuetest(bfad, iocmd); - break; - case IOCMD_DIAG_SFP: - rc = bfad_iocmd_diag_sfp(bfad, iocmd); - break; - case IOCMD_DIAG_LED: - rc = bfad_iocmd_diag_led(bfad, iocmd); - break; - case IOCMD_DIAG_BEACON_LPORT: - rc = bfad_iocmd_diag_beacon_lport(bfad, iocmd); - break; - case IOCMD_DIAG_LB_STAT: - rc = bfad_iocmd_diag_lb_stat(bfad, iocmd); - break; - case IOCMD_PHY_GET_ATTR: - rc = bfad_iocmd_phy_get_attr(bfad, iocmd); - break; - case IOCMD_PHY_GET_STATS: - rc = bfad_iocmd_phy_get_stats(bfad, iocmd); - break; - case IOCMD_PHY_UPDATE_FW: - rc = bfad_iocmd_phy_update(bfad, iocmd, payload_len); - break; - case IOCMD_PHY_READ_FW: - rc = bfad_iocmd_phy_read(bfad, iocmd, payload_len); - break; - case IOCMD_VHBA_QUERY: - rc = bfad_iocmd_vhba_query(bfad, iocmd); - break; - case IOCMD_DEBUG_PORTLOG: - rc = bfad_iocmd_porglog_get(bfad, iocmd); - break; - default: - rc = EINVAL; - break; - } - return -rc; -} - -static int -bfad_im_bsg_vendor_request(struct fc_bsg_job *job) -{ - uint32_t vendor_cmd = job->request->rqst_data.h_vendor.vendor_cmd[0]; - struct bfad_im_port_s *im_port = - (struct bfad_im_port_s *) job->shost->hostdata[0]; - struct bfad_s *bfad = im_port->bfad; - void *payload_kbuf; - int rc = -EINVAL; - - /* Allocate a temp buffer to hold the passed in user space command */ - payload_kbuf = kzalloc(job->request_payload.payload_len, GFP_KERNEL); - if (!payload_kbuf) { - rc = -ENOMEM; - goto out; - } - - /* Copy the sg_list passed in to a linear buffer: holds the cmnd data */ - sg_copy_to_buffer(job->request_payload.sg_list, - job->request_payload.sg_cnt, payload_kbuf, - job->request_payload.payload_len); - - /* Invoke IOCMD handler - to handle all the vendor command requests */ - rc = bfad_iocmd_handler(bfad, vendor_cmd, payload_kbuf, - job->request_payload.payload_len); - if (rc != BFA_STATUS_OK) - goto error; - - /* Copy the response data to the job->reply_payload sg_list */ - sg_copy_from_buffer(job->reply_payload.sg_list, - job->reply_payload.sg_cnt, - payload_kbuf, - job->reply_payload.payload_len); - - /* free the command buffer */ - kfree(payload_kbuf); - - /* Fill the BSG job reply data */ - job->reply_len = job->reply_payload.payload_len; - job->reply->reply_payload_rcv_len = job->reply_payload.payload_len; - job->reply->result = rc; - - job->job_done(job); - return rc; -error: - /* free the command buffer */ - kfree(payload_kbuf); -out: - job->reply->result = rc; - job->reply_len = sizeof(uint32_t); - job->reply->reply_payload_rcv_len = 0; - return rc; -} - -/* FC passthru call backs */ -u64 -bfad_fcxp_get_req_sgaddr_cb(void *bfad_fcxp, int sgeid) -{ - struct bfad_fcxp *drv_fcxp = bfad_fcxp; - struct bfa_sge_s *sge; - u64 addr; - - sge = drv_fcxp->req_sge + sgeid; - addr = (u64)(size_t) sge->sg_addr; - return addr; -} - -u32 -bfad_fcxp_get_req_sglen_cb(void *bfad_fcxp, int sgeid) -{ - struct bfad_fcxp *drv_fcxp = bfad_fcxp; - struct bfa_sge_s *sge; - - sge = drv_fcxp->req_sge + sgeid; - return sge->sg_len; -} - -u64 -bfad_fcxp_get_rsp_sgaddr_cb(void *bfad_fcxp, int sgeid) -{ - struct bfad_fcxp *drv_fcxp = bfad_fcxp; - struct bfa_sge_s *sge; - u64 addr; - - sge = drv_fcxp->rsp_sge + sgeid; - addr = (u64)(size_t) sge->sg_addr; - return addr; -} - -u32 -bfad_fcxp_get_rsp_sglen_cb(void *bfad_fcxp, int sgeid) -{ - struct bfad_fcxp *drv_fcxp = bfad_fcxp; - struct bfa_sge_s *sge; - - sge = drv_fcxp->rsp_sge + sgeid; - return sge->sg_len; -} - -void -bfad_send_fcpt_cb(void *bfad_fcxp, struct bfa_fcxp_s *fcxp, void *cbarg, - bfa_status_t req_status, u32 rsp_len, u32 resid_len, - struct fchs_s *rsp_fchs) -{ - struct bfad_fcxp *drv_fcxp = bfad_fcxp; - - drv_fcxp->req_status = req_status; - drv_fcxp->rsp_len = rsp_len; - - /* bfa_fcxp will be automatically freed by BFA */ - drv_fcxp->bfa_fcxp = NULL; - complete(&drv_fcxp->comp); -} - -struct bfad_buf_info * -bfad_fcxp_map_sg(struct bfad_s *bfad, void *payload_kbuf, - uint32_t payload_len, uint32_t *num_sgles) -{ - struct bfad_buf_info *buf_base, *buf_info; - struct bfa_sge_s *sg_table; - int sge_num = 1; - - buf_base = kzalloc((sizeof(struct bfad_buf_info) + - sizeof(struct bfa_sge_s)) * sge_num, GFP_KERNEL); - if (!buf_base) - return NULL; - - sg_table = (struct bfa_sge_s *) (((uint8_t *)buf_base) + - (sizeof(struct bfad_buf_info) * sge_num)); - - /* Allocate dma coherent memory */ - buf_info = buf_base; - buf_info->size = payload_len; - buf_info->virt = dma_alloc_coherent(&bfad->pcidev->dev, buf_info->size, - &buf_info->phys, GFP_KERNEL); - if (!buf_info->virt) - goto out_free_mem; - - /* copy the linear bsg buffer to buf_info */ - memset(buf_info->virt, 0, buf_info->size); - memcpy(buf_info->virt, payload_kbuf, buf_info->size); - - /* - * Setup SG table - */ - sg_table->sg_len = buf_info->size; - sg_table->sg_addr = (void *)(size_t) buf_info->phys; - - *num_sgles = sge_num; - - return buf_base; - -out_free_mem: - kfree(buf_base); - return NULL; -} - -void -bfad_fcxp_free_mem(struct bfad_s *bfad, struct bfad_buf_info *buf_base, - uint32_t num_sgles) -{ - int i; - struct bfad_buf_info *buf_info = buf_base; - - if (buf_base) { - for (i = 0; i < num_sgles; buf_info++, i++) { - if (buf_info->virt != NULL) - dma_free_coherent(&bfad->pcidev->dev, - buf_info->size, buf_info->virt, - buf_info->phys); - } - kfree(buf_base); - } -} - -int -bfad_fcxp_bsg_send(struct fc_bsg_job *job, struct bfad_fcxp *drv_fcxp, - bfa_bsg_fcpt_t *bsg_fcpt) -{ - struct bfa_fcxp_s *hal_fcxp; - struct bfad_s *bfad = drv_fcxp->port->bfad; - unsigned long flags; - uint8_t lp_tag; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - - /* Allocate bfa_fcxp structure */ - hal_fcxp = bfa_fcxp_alloc(drv_fcxp, &bfad->bfa, - drv_fcxp->num_req_sgles, - drv_fcxp->num_rsp_sgles, - bfad_fcxp_get_req_sgaddr_cb, - bfad_fcxp_get_req_sglen_cb, - bfad_fcxp_get_rsp_sgaddr_cb, - bfad_fcxp_get_rsp_sglen_cb); - if (!hal_fcxp) { - bfa_trc(bfad, 0); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - return BFA_STATUS_ENOMEM; - } - - drv_fcxp->bfa_fcxp = hal_fcxp; - - lp_tag = bfa_lps_get_tag_from_pid(&bfad->bfa, bsg_fcpt->fchs.s_id); - - bfa_fcxp_send(hal_fcxp, drv_fcxp->bfa_rport, bsg_fcpt->vf_id, lp_tag, - bsg_fcpt->cts, bsg_fcpt->cos, - job->request_payload.payload_len, - &bsg_fcpt->fchs, bfad_send_fcpt_cb, bfad, - job->reply_payload.payload_len, bsg_fcpt->tsecs); - - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - return BFA_STATUS_OK; -} - -int -bfad_im_bsg_els_ct_request(struct fc_bsg_job *job) -{ - struct bfa_bsg_data *bsg_data; - struct bfad_im_port_s *im_port = - (struct bfad_im_port_s *) job->shost->hostdata[0]; - struct bfad_s *bfad = im_port->bfad; - bfa_bsg_fcpt_t *bsg_fcpt; - struct bfad_fcxp *drv_fcxp; - struct bfa_fcs_lport_s *fcs_port; - struct bfa_fcs_rport_s *fcs_rport; - uint32_t command_type = job->request->msgcode; - unsigned long flags; - struct bfad_buf_info *rsp_buf_info; - void *req_kbuf = NULL, *rsp_kbuf = NULL; - int rc = -EINVAL; - - job->reply_len = sizeof(uint32_t); /* Atleast uint32_t reply_len */ - job->reply->reply_payload_rcv_len = 0; - - /* Get the payload passed in from userspace */ - bsg_data = (struct bfa_bsg_data *) (((char *)job->request) + - sizeof(struct fc_bsg_request)); - if (bsg_data == NULL) - goto out; - - /* - * Allocate buffer for bsg_fcpt and do a copy_from_user op for payload - * buffer of size bsg_data->payload_len - */ - bsg_fcpt = (struct bfa_bsg_fcpt_s *) - kzalloc(bsg_data->payload_len, GFP_KERNEL); - if (!bsg_fcpt) - goto out; - - if (copy_from_user((uint8_t *)bsg_fcpt, bsg_data->payload, - bsg_data->payload_len)) { - kfree(bsg_fcpt); - goto out; - } - - drv_fcxp = kzalloc(sizeof(struct bfad_fcxp), GFP_KERNEL); - if (drv_fcxp == NULL) { - rc = -ENOMEM; - goto out; - } - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs, bsg_fcpt->vf_id, - bsg_fcpt->lpwwn); - if (fcs_port == NULL) { - bsg_fcpt->status = BFA_STATUS_UNKNOWN_LWWN; - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - goto out_free_mem; - } - - /* Check if the port is online before sending FC Passthru cmd */ - if (!bfa_fcs_lport_is_online(fcs_port)) { - bsg_fcpt->status = BFA_STATUS_PORT_OFFLINE; - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - goto out_free_mem; - } - - drv_fcxp->port = fcs_port->bfad_port; - - if (drv_fcxp->port->bfad == 0) - drv_fcxp->port->bfad = bfad; - - /* Fetch the bfa_rport - if nexus needed */ - if (command_type == FC_BSG_HST_ELS_NOLOGIN || - command_type == FC_BSG_HST_CT) { - /* BSG HST commands: no nexus needed */ - drv_fcxp->bfa_rport = NULL; - - } else if (command_type == FC_BSG_RPT_ELS || - command_type == FC_BSG_RPT_CT) { - /* BSG RPT commands: nexus needed */ - fcs_rport = bfa_fcs_lport_get_rport_by_pwwn(fcs_port, - bsg_fcpt->dpwwn); - if (fcs_rport == NULL) { - bsg_fcpt->status = BFA_STATUS_UNKNOWN_RWWN; - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - goto out_free_mem; - } - - drv_fcxp->bfa_rport = fcs_rport->bfa_rport; - - } else { /* Unknown BSG msgcode; return -EINVAL */ - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - goto out_free_mem; - } - - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - /* allocate memory for req / rsp buffers */ - req_kbuf = kzalloc(job->request_payload.payload_len, GFP_KERNEL); - if (!req_kbuf) { - printk(KERN_INFO "bfa %s: fcpt request buffer alloc failed\n", - bfad->pci_name); - rc = -ENOMEM; - goto out_free_mem; - } - - rsp_kbuf = kzalloc(job->reply_payload.payload_len, GFP_KERNEL); - if (!rsp_kbuf) { - printk(KERN_INFO "bfa %s: fcpt response buffer alloc failed\n", - bfad->pci_name); - rc = -ENOMEM; - goto out_free_mem; - } - - /* map req sg - copy the sg_list passed in to the linear buffer */ - sg_copy_to_buffer(job->request_payload.sg_list, - job->request_payload.sg_cnt, req_kbuf, - job->request_payload.payload_len); - - drv_fcxp->reqbuf_info = bfad_fcxp_map_sg(bfad, req_kbuf, - job->request_payload.payload_len, - &drv_fcxp->num_req_sgles); - if (!drv_fcxp->reqbuf_info) { - printk(KERN_INFO "bfa %s: fcpt request fcxp_map_sg failed\n", - bfad->pci_name); - rc = -ENOMEM; - goto out_free_mem; - } - - drv_fcxp->req_sge = (struct bfa_sge_s *) - (((uint8_t *)drv_fcxp->reqbuf_info) + - (sizeof(struct bfad_buf_info) * - drv_fcxp->num_req_sgles)); - - /* map rsp sg */ - drv_fcxp->rspbuf_info = bfad_fcxp_map_sg(bfad, rsp_kbuf, - job->reply_payload.payload_len, - &drv_fcxp->num_rsp_sgles); - if (!drv_fcxp->rspbuf_info) { - printk(KERN_INFO "bfa %s: fcpt response fcxp_map_sg failed\n", - bfad->pci_name); - rc = -ENOMEM; - goto out_free_mem; - } - - rsp_buf_info = (struct bfad_buf_info *)drv_fcxp->rspbuf_info; - drv_fcxp->rsp_sge = (struct bfa_sge_s *) - (((uint8_t *)drv_fcxp->rspbuf_info) + - (sizeof(struct bfad_buf_info) * - drv_fcxp->num_rsp_sgles)); - - /* fcxp send */ - init_completion(&drv_fcxp->comp); - rc = bfad_fcxp_bsg_send(job, drv_fcxp, bsg_fcpt); - if (rc == BFA_STATUS_OK) { - wait_for_completion(&drv_fcxp->comp); - bsg_fcpt->status = drv_fcxp->req_status; - } else { - bsg_fcpt->status = rc; - goto out_free_mem; - } - - /* fill the job->reply data */ - if (drv_fcxp->req_status == BFA_STATUS_OK) { - job->reply_len = drv_fcxp->rsp_len; - job->reply->reply_payload_rcv_len = drv_fcxp->rsp_len; - job->reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_OK; - } else { - job->reply->reply_payload_rcv_len = - sizeof(struct fc_bsg_ctels_reply); - job->reply_len = sizeof(uint32_t); - job->reply->reply_data.ctels_reply.status = - FC_CTELS_STATUS_REJECT; - } - - /* Copy the response data to the reply_payload sg list */ - sg_copy_from_buffer(job->reply_payload.sg_list, - job->reply_payload.sg_cnt, - (uint8_t *)rsp_buf_info->virt, - job->reply_payload.payload_len); - -out_free_mem: - bfad_fcxp_free_mem(bfad, drv_fcxp->rspbuf_info, - drv_fcxp->num_rsp_sgles); - bfad_fcxp_free_mem(bfad, drv_fcxp->reqbuf_info, - drv_fcxp->num_req_sgles); - kfree(req_kbuf); - kfree(rsp_kbuf); - - /* Need a copy to user op */ - if (copy_to_user(bsg_data->payload, (void *) bsg_fcpt, - bsg_data->payload_len)) - rc = -EIO; - - kfree(bsg_fcpt); - kfree(drv_fcxp); -out: - job->reply->result = rc; - - if (rc == BFA_STATUS_OK) - job->job_done(job); - - return rc; -} - -int -bfad_im_bsg_request(struct fc_bsg_job *job) -{ - uint32_t rc = BFA_STATUS_OK; - - switch (job->request->msgcode) { - case FC_BSG_HST_VENDOR: - /* Process BSG HST Vendor requests */ - rc = bfad_im_bsg_vendor_request(job); - break; - case FC_BSG_HST_ELS_NOLOGIN: - case FC_BSG_RPT_ELS: - case FC_BSG_HST_CT: - case FC_BSG_RPT_CT: - /* Process BSG ELS/CT commands */ - rc = bfad_im_bsg_els_ct_request(job); - break; - default: - job->reply->result = rc = -EINVAL; - job->reply->reply_payload_rcv_len = 0; - break; - } - - return rc; -} - -int -bfad_im_bsg_timeout(struct fc_bsg_job *job) -{ - /* Don't complete the BSG job request - return -EAGAIN - * to reset bsg job timeout : for ELS/CT pass thru we - * already have timer to track the request. - */ - return -EAGAIN; -} diff --git a/trunk/drivers/scsi/bfa/bfad_bsg.h b/trunk/drivers/scsi/bfa/bfad_bsg.h deleted file mode 100644 index 99b0e8a70c89..000000000000 --- a/trunk/drivers/scsi/bfa/bfad_bsg.h +++ /dev/null @@ -1,509 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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. - */ -#ifndef BFAD_BSG_H -#define BFAD_BSG_H - -#include "bfa_defs.h" -#include "bfa_defs_fcs.h" - -/* Definitions of vendor unique structures and command codes passed in - * using FC_BSG_HST_VENDOR message code. - */ -enum { - IOCMD_IOC_ENABLE = 0x1, - IOCMD_IOC_DISABLE, - IOCMD_IOC_GET_ATTR, - IOCMD_IOC_GET_INFO, - IOCMD_IOC_GET_STATS, - IOCMD_IOC_GET_FWSTATS, - IOCMD_IOCFC_GET_ATTR, - IOCMD_IOCFC_SET_INTR, - IOCMD_PORT_ENABLE, - IOCMD_PORT_DISABLE, - IOCMD_PORT_GET_ATTR, - IOCMD_PORT_GET_STATS, - IOCMD_LPORT_GET_ATTR, - IOCMD_LPORT_GET_RPORTS, - IOCMD_LPORT_GET_STATS, - IOCMD_LPORT_GET_IOSTATS, - IOCMD_RPORT_GET_ATTR, - IOCMD_RPORT_GET_ADDR, - IOCMD_RPORT_GET_STATS, - IOCMD_FABRIC_GET_LPORTS, - IOCMD_FCPIM_MODSTATS, - IOCMD_FCPIM_DEL_ITN_STATS, - IOCMD_ITNIM_GET_ATTR, - IOCMD_ITNIM_GET_IOSTATS, - IOCMD_ITNIM_GET_ITNSTATS, - IOCMD_IOC_PCIFN_CFG, - IOCMD_FCPORT_ENABLE, - IOCMD_FCPORT_DISABLE, - IOCMD_PCIFN_CREATE, - IOCMD_PCIFN_DELETE, - IOCMD_PCIFN_BW, - IOCMD_ADAPTER_CFG_MODE, - IOCMD_PORT_CFG_MODE, - IOCMD_FLASH_ENABLE_OPTROM, - IOCMD_FLASH_DISABLE_OPTROM, - IOCMD_FAA_ENABLE, - IOCMD_FAA_DISABLE, - IOCMD_FAA_QUERY, - IOCMD_CEE_GET_ATTR, - IOCMD_CEE_GET_STATS, - IOCMD_CEE_RESET_STATS, - IOCMD_SFP_MEDIA, - IOCMD_SFP_SPEED, - IOCMD_FLASH_GET_ATTR, - IOCMD_FLASH_ERASE_PART, - IOCMD_FLASH_UPDATE_PART, - IOCMD_FLASH_READ_PART, - IOCMD_DIAG_TEMP, - IOCMD_DIAG_MEMTEST, - IOCMD_DIAG_LOOPBACK, - IOCMD_DIAG_FWPING, - IOCMD_DIAG_QUEUETEST, - IOCMD_DIAG_SFP, - IOCMD_DIAG_LED, - IOCMD_DIAG_BEACON_LPORT, - IOCMD_DIAG_LB_STAT, - IOCMD_PHY_GET_ATTR, - IOCMD_PHY_GET_STATS, - IOCMD_PHY_UPDATE_FW, - IOCMD_PHY_READ_FW, - IOCMD_VHBA_QUERY, - IOCMD_DEBUG_PORTLOG, -}; - -struct bfa_bsg_gen_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; -}; - -struct bfa_bsg_ioc_info_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - char serialnum[64]; - char hwpath[BFA_STRING_32]; - char adapter_hwpath[BFA_STRING_32]; - char guid[BFA_ADAPTER_SYM_NAME_LEN*2]; - char name[BFA_ADAPTER_SYM_NAME_LEN]; - char port_name[BFA_ADAPTER_SYM_NAME_LEN]; - char eth_name[BFA_ADAPTER_SYM_NAME_LEN]; - wwn_t pwwn; - wwn_t nwwn; - wwn_t factorypwwn; - wwn_t factorynwwn; - mac_t mac; - mac_t factory_mac; /* Factory mac address */ - mac_t current_mac; /* Currently assigned mac address */ - enum bfa_ioc_type_e ioc_type; - u16 pvid; /* Port vlan id */ - u16 rsvd1; - u32 host; - u32 bandwidth; /* For PF support */ - u32 rsvd2; -}; - -struct bfa_bsg_ioc_attr_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_ioc_attr_s ioc_attr; -}; - -struct bfa_bsg_ioc_stats_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_ioc_stats_s ioc_stats; -}; - -struct bfa_bsg_ioc_fwstats_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - u32 buf_size; - u32 rsvd1; - u64 buf_ptr; -}; - -struct bfa_bsg_iocfc_attr_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_iocfc_attr_s iocfc_attr; -}; - -struct bfa_bsg_iocfc_intr_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_iocfc_intr_attr_s attr; -}; - -struct bfa_bsg_port_attr_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_port_attr_s attr; -}; - -struct bfa_bsg_port_stats_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - u32 buf_size; - u32 rsvd1; - u64 buf_ptr; -}; - -struct bfa_bsg_lport_attr_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - wwn_t pwwn; - struct bfa_lport_attr_s port_attr; -}; - -struct bfa_bsg_lport_stats_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - wwn_t pwwn; - struct bfa_lport_stats_s port_stats; -}; - -struct bfa_bsg_lport_iostats_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - wwn_t pwwn; - struct bfa_itnim_iostats_s iostats; -}; - -struct bfa_bsg_lport_get_rports_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - wwn_t pwwn; - u64 rbuf_ptr; - u32 nrports; - u32 rsvd; -}; - -struct bfa_bsg_rport_attr_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - wwn_t pwwn; - wwn_t rpwwn; - struct bfa_rport_attr_s attr; -}; - -struct bfa_bsg_rport_stats_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - wwn_t pwwn; - wwn_t rpwwn; - struct bfa_rport_stats_s stats; -}; - -struct bfa_bsg_rport_scsi_addr_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - wwn_t pwwn; - wwn_t rpwwn; - u32 host; - u32 bus; - u32 target; - u32 lun; -}; - -struct bfa_bsg_fabric_get_lports_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - u64 buf_ptr; - u32 nports; - u32 rsvd; -}; - -struct bfa_bsg_fcpim_modstats_s { - bfa_status_t status; - u16 bfad_num; - struct bfa_itnim_iostats_s modstats; -}; - -struct bfa_bsg_fcpim_del_itn_stats_s { - bfa_status_t status; - u16 bfad_num; - struct bfa_fcpim_del_itn_stats_s modstats; -}; - -struct bfa_bsg_itnim_attr_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - wwn_t lpwwn; - wwn_t rpwwn; - struct bfa_itnim_attr_s attr; -}; - -struct bfa_bsg_itnim_iostats_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - wwn_t lpwwn; - wwn_t rpwwn; - struct bfa_itnim_iostats_s iostats; -}; - -struct bfa_bsg_itnim_itnstats_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - wwn_t lpwwn; - wwn_t rpwwn; - struct bfa_itnim_stats_s itnstats; -}; - -struct bfa_bsg_pcifn_cfg_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_ablk_cfg_s pcifn_cfg; -}; - -struct bfa_bsg_pcifn_s { - bfa_status_t status; - u16 bfad_num; - u16 pcifn_id; - u32 bandwidth; - u8 port; - enum bfi_pcifn_class pcifn_class; - u8 rsvd[1]; -}; - -struct bfa_bsg_adapter_cfg_mode_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_adapter_cfg_mode_s cfg; -}; - -struct bfa_bsg_port_cfg_mode_s { - bfa_status_t status; - u16 bfad_num; - u16 instance; - struct bfa_port_cfg_mode_s cfg; -}; - -struct bfa_bsg_faa_attr_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_faa_attr_s faa_attr; -}; - -struct bfa_bsg_cee_attr_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - u32 buf_size; - u32 rsvd1; - u64 buf_ptr; -}; - -struct bfa_bsg_cee_stats_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - u32 buf_size; - u32 rsvd1; - u64 buf_ptr; -}; - -struct bfa_bsg_sfp_media_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - enum bfa_defs_sfp_media_e media; -}; - -struct bfa_bsg_sfp_speed_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - enum bfa_port_speed speed; -}; - -struct bfa_bsg_flash_attr_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_flash_attr_s attr; -}; - -struct bfa_bsg_flash_s { - bfa_status_t status; - u16 bfad_num; - u8 instance; - u8 rsvd; - enum bfa_flash_part_type type; - int bufsz; - u64 buf_ptr; -}; - -struct bfa_bsg_diag_get_temp_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_diag_results_tempsensor_s result; -}; - -struct bfa_bsg_diag_memtest_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd[3]; - u32 pat; - struct bfa_diag_memtest_result result; - struct bfa_diag_memtest_s memtest; -}; - -struct bfa_bsg_diag_loopback_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - enum bfa_port_opmode opmode; - enum bfa_port_speed speed; - u32 lpcnt; - u32 pat; - struct bfa_diag_loopback_result_s result; -}; - -struct bfa_bsg_diag_fwping_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - u32 cnt; - u32 pattern; - struct bfa_diag_results_fwping result; -}; - -struct bfa_bsg_diag_qtest_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - u32 force; - u32 queue; - struct bfa_diag_qtest_result_s result; -}; - -struct bfa_bsg_sfp_show_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct sfp_mem_s sfp; -}; - -struct bfa_bsg_diag_led_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_diag_ledtest_s ledtest; -}; - -struct bfa_bsg_diag_beacon_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - bfa_boolean_t beacon; - bfa_boolean_t link_e2e_beacon; - u32 second; -}; - -struct bfa_bsg_diag_lb_stat_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; -}; - -struct bfa_bsg_phy_attr_s { - bfa_status_t status; - u16 bfad_num; - u16 instance; - struct bfa_phy_attr_s attr; -}; - -struct bfa_bsg_phy_s { - bfa_status_t status; - u16 bfad_num; - u16 instance; - u64 bufsz; - u64 buf_ptr; -}; - -struct bfa_bsg_debug_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - u32 bufsz; - int inst_no; - u64 buf_ptr; - u64 offset; -}; - -struct bfa_bsg_phy_stats_s { - bfa_status_t status; - u16 bfad_num; - u16 instance; - struct bfa_phy_stats_s stats; -}; - -struct bfa_bsg_vhba_attr_s { - bfa_status_t status; - u16 bfad_num; - u16 pcifn_id; - struct bfa_vhba_attr_s attr; -}; - -struct bfa_bsg_fcpt_s { - bfa_status_t status; - u16 vf_id; - wwn_t lpwwn; - wwn_t dpwwn; - u32 tsecs; - int cts; - enum fc_cos cos; - struct fchs_s fchs; -}; -#define bfa_bsg_fcpt_t struct bfa_bsg_fcpt_s - -struct bfa_bsg_data { - int payload_len; - void *payload; -}; - -#define bfad_chk_iocmd_sz(__payload_len, __hdrsz, __bufsz) \ - (((__payload_len) != ((__hdrsz) + (__bufsz))) ? \ - BFA_STATUS_FAILED : BFA_STATUS_OK) - -#endif /* BFAD_BSG_H */ diff --git a/trunk/drivers/scsi/bfa/bfad_debugfs.c b/trunk/drivers/scsi/bfa/bfad_debugfs.c index b412e0300dd4..48be0c54f2de 100644 --- a/trunk/drivers/scsi/bfa/bfad_debugfs.c +++ b/trunk/drivers/scsi/bfa/bfad_debugfs.c @@ -214,10 +214,10 @@ bfad_debugfs_read(struct file *file, char __user *buf, #define BFA_REG_CT_ADDRSZ (0x40000) #define BFA_REG_CB_ADDRSZ (0x20000) -#define BFA_REG_ADDRSZ(__ioc) \ - ((u32)(bfa_asic_id_ctc(bfa_ioc_devid(__ioc)) ? \ - BFA_REG_CT_ADDRSZ : BFA_REG_CB_ADDRSZ)) -#define BFA_REG_ADDRMSK(__ioc) (BFA_REG_ADDRSZ(__ioc) - 1) +#define BFA_REG_ADDRSZ(__bfa) \ + ((bfa_ioc_devid(&(__bfa)->ioc) == BFA_PCI_DEVICE_ID_CT) ? \ + BFA_REG_CT_ADDRSZ : BFA_REG_CB_ADDRSZ) +#define BFA_REG_ADDRMSK(__bfa) ((u32)(BFA_REG_ADDRSZ(__bfa) - 1)) static bfa_status_t bfad_reg_offset_check(struct bfa_s *bfa, u32 offset, u32 len) @@ -236,7 +236,7 @@ bfad_reg_offset_check(struct bfa_s *bfa, u32 offset, u32 len) return BFA_STATUS_EINVAL; } else { /* CB register space 64KB */ - if ((offset + (len<<2)) > BFA_REG_ADDRMSK(&bfa->ioc)) + if ((offset + (len<<2)) > BFA_REG_ADDRMSK(bfa)) return BFA_STATUS_EINVAL; } return BFA_STATUS_OK; @@ -317,7 +317,7 @@ bfad_debugfs_write_regrd(struct file *file, const char __user *buf, bfad->reglen = len << 2; rb = bfa_ioc_bar0(ioc); - addr &= BFA_REG_ADDRMSK(ioc); + addr &= BFA_REG_ADDRMSK(bfa); /* offset and len sanity check */ rc = bfad_reg_offset_check(bfa, addr, len); @@ -380,7 +380,7 @@ bfad_debugfs_write_regwr(struct file *file, const char __user *buf, } kfree(kern_buf); - addr &= BFA_REG_ADDRMSK(ioc); /* offset only 17 bit and word align */ + addr &= BFA_REG_ADDRMSK(bfa); /* offset only 17 bit and word align */ /* offset and len sanity check */ rc = bfad_reg_offset_check(bfa, addr, 1); diff --git a/trunk/drivers/scsi/bfa/bfad_drv.h b/trunk/drivers/scsi/bfa/bfad_drv.h index 48661a2726d7..7f9ea90254cd 100644 --- a/trunk/drivers/scsi/bfa/bfad_drv.h +++ b/trunk/drivers/scsi/bfa/bfad_drv.h @@ -43,7 +43,6 @@ #include #include #include -#include #include "bfa_modules.h" #include "bfa_fcs.h" @@ -56,7 +55,7 @@ #ifdef BFA_DRIVER_VERSION #define BFAD_DRIVER_VERSION BFA_DRIVER_VERSION #else -#define BFAD_DRIVER_VERSION "3.0.2.1" +#define BFAD_DRIVER_VERSION "2.3.2.3" #endif #define BFAD_PROTO_NAME FCPI_NAME @@ -80,7 +79,7 @@ #define BFAD_HAL_INIT_FAIL 0x00000100 #define BFAD_FC4_PROBE_DONE 0x00000200 #define BFAD_PORT_DELETE 0x00000001 -#define BFAD_INTX_ON 0x00000400 + /* * BFAD related definition */ @@ -93,8 +92,6 @@ */ #define BFAD_LUN_QUEUE_DEPTH 32 #define BFAD_IO_MAX_SGE SG_ALL -#define BFAD_MIN_SECTORS 128 /* 64k */ -#define BFAD_MAX_SECTORS 0xFFFF /* 32 MB */ #define bfad_isr_t irq_handler_t @@ -113,7 +110,6 @@ struct bfad_msix_s { enum { BFA_TRC_LDRV_BFAD = 1, BFA_TRC_LDRV_IM = 2, - BFA_TRC_LDRV_BSG = 3, }; enum bfad_port_pvb_type { @@ -193,10 +189,8 @@ struct bfad_s { struct bfa_pcidev_s hal_pcidev; struct bfa_ioc_pci_attr_s pci_attr; void __iomem *pci_bar0_kva; - void __iomem *pci_bar2_kva; struct completion comp; struct completion suspend; - struct completion enable_comp; struct completion disable_comp; bfa_boolean_t disable_active; struct bfad_port_s pport; /* physical port of the BFAD */ @@ -279,6 +273,21 @@ struct bfad_hal_comp { struct completion comp; }; +/* + * Macro to obtain the immediate lower power + * of two for the integer. + */ +#define nextLowerInt(x) \ +do { \ + int __i; \ + (*x)--; \ + for (__i = 1; __i < (sizeof(int)*8); __i <<= 1) \ + (*x) = (*x) | (*x) >> __i; \ + (*x)++; \ + (*x) = (*x) >> 1; \ +} while (0) + + #define BFA_LOG(level, bfad, mask, fmt, arg...) \ do { \ if (((mask) == 4) || (level[1] <= '4')) \ @@ -345,7 +354,6 @@ extern int msix_disable_ct; extern int fdmi_enable; extern int supported_fc4s; extern int pcie_max_read_reqsz; -extern int max_xfer_size; extern int bfa_debugfs_enable; extern struct mutex bfad_mutex; diff --git a/trunk/drivers/scsi/bfa/bfad_im.c b/trunk/drivers/scsi/bfa/bfad_im.c index f2bf81265ae5..c2b36179e8e8 100644 --- a/trunk/drivers/scsi/bfa/bfad_im.c +++ b/trunk/drivers/scsi/bfa/bfad_im.c @@ -175,11 +175,21 @@ bfad_im_info(struct Scsi_Host *shost) struct bfad_im_port_s *im_port = (struct bfad_im_port_s *) shost->hostdata[0]; struct bfad_s *bfad = im_port->bfad; + struct bfa_s *bfa = &bfad->bfa; + struct bfa_ioc_s *ioc = &bfa->ioc; + char model[BFA_ADAPTER_MODEL_NAME_LEN]; + + bfa_get_adapter_model(bfa, model); memset(bfa_buf, 0, sizeof(bfa_buf)); - snprintf(bfa_buf, sizeof(bfa_buf), - "Brocade FC/FCOE Adapter, " "hwpath: %s driver: %s", - bfad->pci_name, BFAD_DRIVER_VERSION); + if (ioc->ctdev && !ioc->fcmode) + snprintf(bfa_buf, sizeof(bfa_buf), + "Brocade FCOE Adapter, " "model: %s hwpath: %s driver: %s", + model, bfad->pci_name, BFAD_DRIVER_VERSION); + else + snprintf(bfa_buf, sizeof(bfa_buf), + "Brocade FC Adapter, " "model: %s hwpath: %s driver: %s", + model, bfad->pci_name, BFAD_DRIVER_VERSION); return bfa_buf; } @@ -562,6 +572,9 @@ bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port, goto out_fc_rel; } + /* setup host fixed attribute if the lk supports */ + bfad_fc_host_init(im_port); + return 0; out_fc_rel: @@ -700,9 +713,6 @@ bfad_scsi_host_alloc(struct bfad_im_port_s *im_port, struct bfad_s *bfad) else sht = &bfad_im_vport_template; - if (max_xfer_size != BFAD_MAX_SECTORS >> 1) - sht->max_sectors = max_xfer_size << 1; - sht->sg_tablesize = bfad->cfg_data.io_max_sge; return scsi_host_alloc(sht, sizeof(unsigned long)); @@ -780,8 +790,7 @@ struct scsi_host_template bfad_im_scsi_host_template = { .cmd_per_lun = 3, .use_clustering = ENABLE_CLUSTERING, .shost_attrs = bfad_im_host_attrs, - .max_sectors = BFAD_MAX_SECTORS, - .vendor_id = BFA_PCI_VENDOR_ID_BROCADE, + .max_sectors = 0xFFFF, }; struct scsi_host_template bfad_im_vport_template = { @@ -802,7 +811,7 @@ struct scsi_host_template bfad_im_vport_template = { .cmd_per_lun = 3, .use_clustering = ENABLE_CLUSTERING, .shost_attrs = bfad_im_vport_attrs, - .max_sectors = BFAD_MAX_SECTORS, + .max_sectors = 0xFFFF, }; bfa_status_t @@ -916,10 +925,7 @@ bfad_im_supported_speeds(struct bfa_s *bfa) return 0; bfa_ioc_get_attr(&bfa->ioc, ioc_attr); - if (ioc_attr->adapter_attr.max_speed == BFA_PORT_SPEED_16GBPS) - supported_speed |= FC_PORTSPEED_16GBIT | FC_PORTSPEED_8GBIT | - FC_PORTSPEED_4GBIT | FC_PORTSPEED_2GBIT; - else if (ioc_attr->adapter_attr.max_speed == BFA_PORT_SPEED_8GBPS) { + if (ioc_attr->adapter_attr.max_speed == BFA_PORT_SPEED_8GBPS) { if (ioc_attr->adapter_attr.is_mezz) { supported_speed |= FC_PORTSPEED_8GBIT | FC_PORTSPEED_4GBIT | diff --git a/trunk/drivers/scsi/bfa/bfad_im.h b/trunk/drivers/scsi/bfa/bfad_im.h index 4fe34d576b05..c296c8968511 100644 --- a/trunk/drivers/scsi/bfa/bfad_im.h +++ b/trunk/drivers/scsi/bfa/bfad_im.h @@ -141,7 +141,4 @@ extern struct device_attribute *bfad_im_vport_attrs[]; irqreturn_t bfad_intx(int irq, void *dev_id); -int bfad_im_bsg_request(struct fc_bsg_job *job); -int bfad_im_bsg_timeout(struct fc_bsg_job *job); - #endif diff --git a/trunk/drivers/scsi/bfa/bfi.h b/trunk/drivers/scsi/bfa/bfi.h index 1e258d5f8aec..72b69a0c3b51 100644 --- a/trunk/drivers/scsi/bfa/bfi.h +++ b/trunk/drivers/scsi/bfa/bfi.h @@ -23,29 +23,17 @@ #pragma pack(1) -/* Per dma segment max size */ -#define BFI_MEM_DMA_SEG_SZ (131072) - -/* Get number of dma segments required */ -#define BFI_MEM_DMA_NSEGS(_num_reqs, _req_sz) \ - ((u16)(((((_num_reqs) * (_req_sz)) + BFI_MEM_DMA_SEG_SZ - 1) & \ - ~(BFI_MEM_DMA_SEG_SZ - 1)) / BFI_MEM_DMA_SEG_SZ)) - -/* Get num dma reqs - that fit in a segment */ -#define BFI_MEM_NREQS_SEG(_rqsz) (BFI_MEM_DMA_SEG_SZ / (_rqsz)) - -/* Get segment num from tag */ -#define BFI_MEM_SEG_FROM_TAG(_tag, _rqsz) ((_tag) / BFI_MEM_NREQS_SEG(_rqsz)) - -/* Get dma req offset in a segment */ -#define BFI_MEM_SEG_REQ_OFFSET(_tag, _sz) \ - ((_tag) - (BFI_MEM_SEG_FROM_TAG(_tag, _sz) * BFI_MEM_NREQS_SEG(_sz))) - /* * BFI FW image type */ #define BFI_FLASH_CHUNK_SZ 256 /* Flash chunk size */ #define BFI_FLASH_CHUNK_SZ_WORDS (BFI_FLASH_CHUNK_SZ/sizeof(u32)) +enum { + BFI_IMAGE_CB_FC, + BFI_IMAGE_CT_FC, + BFI_IMAGE_CT_CNA, + BFI_IMAGE_MAX, +}; /* * Msg header common to all msgs @@ -55,20 +43,17 @@ struct bfi_mhdr_s { u8 msg_id; /* msg opcode with in the class */ union { struct { - u8 qid; - u8 fn_lpu; /* msg destination */ + u8 rsvd; + u8 lpu_id; /* msg destination */ } h2i; u16 i2htok; /* token in msgs to host */ } mtag; }; -#define bfi_fn_lpu(__fn, __lpu) ((__fn) << 1 | (__lpu)) -#define bfi_mhdr_2_fn(_mh) ((_mh)->mtag.h2i.fn_lpu >> 1) - -#define bfi_h2i_set(_mh, _mc, _op, _fn_lpu) do { \ +#define bfi_h2i_set(_mh, _mc, _op, _lpuid) do { \ (_mh).msg_class = (_mc); \ (_mh).msg_id = (_op); \ - (_mh).mtag.h2i.fn_lpu = (_fn_lpu); \ + (_mh).mtag.h2i.lpu_id = (_lpuid); \ } while (0) #define bfi_i2h_set(_mh, _mc, _op, _i2htok) do { \ @@ -116,7 +101,7 @@ union bfi_addr_u { }; /* - * Scatter Gather Element used for fast-path IO requests + * Scatter Gather Element */ struct bfi_sge_s { #ifdef __BIG_ENDIAN @@ -131,14 +116,6 @@ struct bfi_sge_s { union bfi_addr_u sga; }; -/** - * Generic DMA addr-len pair. - */ -struct bfi_alen_s { - union bfi_addr_u al_addr; /* DMA addr of buffer */ - u32 al_len; /* length of buffer */ -}; - /* * Scatter Gather Page */ @@ -150,12 +127,6 @@ struct bfi_sgpg_s { u32 rsvd[BFI_SGPG_RSVD_WD_LEN]; }; -/* FCP module definitions */ -#define BFI_IO_MAX (2000) -#define BFI_IOIM_SNSLEN (256) -#define BFI_IOIM_SNSBUF_SEGS \ - BFI_MEM_DMA_NSEGS(BFI_IO_MAX, BFI_IOIM_SNSLEN) - /* * Large Message structure - 128 Bytes size Msgs */ @@ -177,30 +148,19 @@ struct bfi_mbmsg_s { u32 pl[BFI_MBMSG_SZ]; }; -/* - * Supported PCI function class codes (personality) - */ -enum bfi_pcifn_class { - BFI_PCIFN_CLASS_FC = 0x0c04, - BFI_PCIFN_CLASS_ETH = 0x0200, -}; - /* * Message Classes */ enum bfi_mclass { BFI_MC_IOC = 1, /* IO Controller (IOC) */ - BFI_MC_DIAG = 2, /* Diagnostic Msgs */ - BFI_MC_FLASH = 3, /* Flash message class */ - BFI_MC_CEE = 4, /* CEE */ BFI_MC_FCPORT = 5, /* FC port */ BFI_MC_IOCFC = 6, /* FC - IO Controller (IOC) */ - BFI_MC_ABLK = 7, /* ASIC block configuration */ + BFI_MC_LL = 7, /* Link Layer */ BFI_MC_UF = 8, /* Unsolicited frame receive */ BFI_MC_FCXP = 9, /* FC Transport */ BFI_MC_LPS = 10, /* lport fc login services */ BFI_MC_RPORT = 11, /* Remote port */ - BFI_MC_ITN = 12, /* I-T nexus (Initiator mode) */ + BFI_MC_ITNIM = 12, /* I-T nexus (Initiator mode) */ BFI_MC_IOIM_READ = 13, /* read IO (Initiator mode) */ BFI_MC_IOIM_WRITE = 14, /* write IO (Initiator mode) */ BFI_MC_IOIM_IO = 15, /* IO (Initiator mode) */ @@ -208,8 +168,6 @@ enum bfi_mclass { BFI_MC_IOIM_IOCOM = 17, /* good IO completion */ BFI_MC_TSKIM = 18, /* Initiator Task management */ BFI_MC_PORT = 21, /* Physical port */ - BFI_MC_SFP = 22, /* SFP module */ - BFI_MC_PHY = 25, /* External PHY message class */ BFI_MC_MAX = 32 }; @@ -217,28 +175,23 @@ enum bfi_mclass { #define BFI_IOC_MAX_CQS_ASIC 8 #define BFI_IOC_MSGLEN_MAX 32 /* 32 bytes */ +#define BFI_BOOT_TYPE_OFF 8 +#define BFI_BOOT_LOADER_OFF 12 + +#define BFI_BOOT_TYPE_NORMAL 0 +#define BFI_BOOT_TYPE_FLASH 1 +#define BFI_BOOT_TYPE_MEMTEST 2 + +#define BFI_BOOT_LOADER_OS 0 +#define BFI_BOOT_LOADER_BIOS 1 +#define BFI_BOOT_LOADER_UEFI 2 + /* *---------------------------------------------------------------------- * IOC *---------------------------------------------------------------------- */ -/* - * Different asic generations - */ -enum bfi_asic_gen { - BFI_ASIC_GEN_CB = 1, /* crossbow 8G FC */ - BFI_ASIC_GEN_CT = 2, /* catapult 8G FC or 10G CNA */ - BFI_ASIC_GEN_CT2 = 3, /* catapult-2 16G FC or 10G CNA */ -}; - -enum bfi_asic_mode { - BFI_ASIC_MODE_FC = 1, /* FC upto 8G speed */ - BFI_ASIC_MODE_FC16 = 2, /* FC upto 16G speed */ - BFI_ASIC_MODE_ETH = 3, /* Ethernet ports */ - BFI_ASIC_MODE_COMBO = 4, /* FC 16G and Ethernet 10G port */ -}; - enum bfi_ioc_h2i_msgs { BFI_IOC_H2I_ENABLE_REQ = 1, BFI_IOC_H2I_DISABLE_REQ = 2, @@ -251,8 +204,8 @@ enum bfi_ioc_i2h_msgs { BFI_IOC_I2H_ENABLE_REPLY = BFA_I2HM(1), BFI_IOC_I2H_DISABLE_REPLY = BFA_I2HM(2), BFI_IOC_I2H_GETATTR_REPLY = BFA_I2HM(3), - BFI_IOC_I2H_HBEAT = BFA_I2HM(4), - BFI_IOC_I2H_ACQ_ADDR_REPLY = BFA_I2HM(5), + BFI_IOC_I2H_READY_EVENT = BFA_I2HM(4), + BFI_IOC_I2H_HBEAT = BFA_I2HM(5), }; /* @@ -267,8 +220,7 @@ struct bfi_ioc_attr_s { wwn_t mfg_pwwn; /* Mfg port wwn */ wwn_t mfg_nwwn; /* Mfg node wwn */ mac_t mfg_mac; /* Mfg mac */ - u8 port_mode; /* bfi_port_mode */ - u8 rsvd_a; + u16 rsvd_a; wwn_t pwwn; wwn_t nwwn; mac_t mac; /* PBC or Mfg mac */ @@ -320,33 +272,21 @@ struct bfi_ioc_getattr_reply_s { #define BFI_IOC_FW_SIGNATURE (0xbfadbfad) #define BFI_IOC_MD5SUM_SZ 4 struct bfi_ioc_image_hdr_s { - u32 signature; /* constant signature */ - u8 asic_gen; /* asic generation */ - u8 asic_mode; - u8 port0_mode; /* device mode for port 0 */ - u8 port1_mode; /* device mode for port 1 */ - u32 exec; /* exec vector */ - u32 bootenv; /* fimware boot env */ + u32 signature; /* constant signature */ + u32 rsvd_a; + u32 exec; /* exec vector */ + u32 param; /* parameters */ u32 rsvd_b[4]; u32 md5sum[BFI_IOC_MD5SUM_SZ]; }; -#define BFI_FWBOOT_DEVMODE_OFF 4 -#define BFI_FWBOOT_TYPE_OFF 8 -#define BFI_FWBOOT_ENV_OFF 12 -#define BFI_FWBOOT_DEVMODE(__asic_gen, __asic_mode, __p0_mode, __p1_mode) \ - (((u32)(__asic_gen)) << 24 | \ - ((u32)(__asic_mode)) << 16 | \ - ((u32)(__p0_mode)) << 8 | \ - ((u32)(__p1_mode))) - -#define BFI_FWBOOT_TYPE_NORMAL 0 -#define BFI_FWBOOT_TYPE_MEMTEST 2 -#define BFI_FWBOOT_ENV_OS 0 - -enum bfi_port_mode { - BFI_PORT_MODE_FC = 1, - BFI_PORT_MODE_ETH = 2, +/* + * BFI_IOC_I2H_READY_EVENT message + */ +struct bfi_ioc_rdy_event_s { + struct bfi_mhdr_s mh; /* common msg header */ + u8 init_status; /* init event status */ + u8 rsvd[3]; }; struct bfi_ioc_hbeat_s { @@ -405,8 +345,8 @@ enum { */ struct bfi_ioc_ctrl_req_s { struct bfi_mhdr_s mh; - u16 clscode; - u16 rsvd; + u8 ioc_class; + u8 rsvd[3]; u32 tv_sec; }; #define bfi_ioc_enable_req_t struct bfi_ioc_ctrl_req_s; @@ -418,9 +358,7 @@ struct bfi_ioc_ctrl_req_s { struct bfi_ioc_ctrl_reply_s { struct bfi_mhdr_s mh; /* Common msg header */ u8 status; /* enable/disable status */ - u8 port_mode; /* bfa_mode_s */ - u8 cap_bm; /* capability bit mask */ - u8 rsvd; + u8 rsvd[3]; }; #define bfi_ioc_enable_reply_t struct bfi_ioc_ctrl_reply_s; #define bfi_ioc_disable_reply_t struct bfi_ioc_ctrl_reply_s; @@ -442,7 +380,7 @@ union bfi_ioc_h2i_msg_u { */ union bfi_ioc_i2h_msg_u { struct bfi_mhdr_s mh; - struct bfi_ioc_ctrl_reply_s fw_event; + struct bfi_ioc_rdy_event_s rdy_event; u32 mboxmsg[BFI_IOC_MSGSZ]; }; @@ -455,7 +393,6 @@ union bfi_ioc_i2h_msg_u { #define BFI_PBC_MAX_BLUNS 8 #define BFI_PBC_MAX_VPORTS 16 -#define BFI_PBC_PORT_DISABLED 2 /* * PBC boot lun configuration @@ -637,496 +574,6 @@ union bfi_port_i2h_msg_u { struct bfi_port_generic_rsp_s clearstats_rsp; }; -/* - *---------------------------------------------------------------------- - * ABLK - *---------------------------------------------------------------------- - */ -enum bfi_ablk_h2i_msgs_e { - BFI_ABLK_H2I_QUERY = 1, - BFI_ABLK_H2I_ADPT_CONFIG = 2, - BFI_ABLK_H2I_PORT_CONFIG = 3, - BFI_ABLK_H2I_PF_CREATE = 4, - BFI_ABLK_H2I_PF_DELETE = 5, - BFI_ABLK_H2I_PF_UPDATE = 6, - BFI_ABLK_H2I_OPTROM_ENABLE = 7, - BFI_ABLK_H2I_OPTROM_DISABLE = 8, -}; - -enum bfi_ablk_i2h_msgs_e { - BFI_ABLK_I2H_QUERY = BFA_I2HM(BFI_ABLK_H2I_QUERY), - BFI_ABLK_I2H_ADPT_CONFIG = BFA_I2HM(BFI_ABLK_H2I_ADPT_CONFIG), - BFI_ABLK_I2H_PORT_CONFIG = BFA_I2HM(BFI_ABLK_H2I_PORT_CONFIG), - BFI_ABLK_I2H_PF_CREATE = BFA_I2HM(BFI_ABLK_H2I_PF_CREATE), - BFI_ABLK_I2H_PF_DELETE = BFA_I2HM(BFI_ABLK_H2I_PF_DELETE), - BFI_ABLK_I2H_PF_UPDATE = BFA_I2HM(BFI_ABLK_H2I_PF_UPDATE), - BFI_ABLK_I2H_OPTROM_ENABLE = BFA_I2HM(BFI_ABLK_H2I_OPTROM_ENABLE), - BFI_ABLK_I2H_OPTROM_DISABLE = BFA_I2HM(BFI_ABLK_H2I_OPTROM_DISABLE), -}; - -/* BFI_ABLK_H2I_QUERY */ -struct bfi_ablk_h2i_query_s { - struct bfi_mhdr_s mh; - union bfi_addr_u addr; -}; - -/* BFI_ABL_H2I_ADPT_CONFIG, BFI_ABLK_H2I_PORT_CONFIG */ -struct bfi_ablk_h2i_cfg_req_s { - struct bfi_mhdr_s mh; - u8 mode; - u8 port; - u8 max_pf; - u8 max_vf; -}; - -/* - * BFI_ABLK_H2I_PF_CREATE, BFI_ABLK_H2I_PF_DELETE, - */ -struct bfi_ablk_h2i_pf_req_s { - struct bfi_mhdr_s mh; - u8 pcifn; - u8 port; - u16 pers; - u32 bw; -}; - -/* BFI_ABLK_H2I_OPTROM_ENABLE, BFI_ABLK_H2I_OPTROM_DISABLE */ -struct bfi_ablk_h2i_optrom_s { - struct bfi_mhdr_s mh; -}; - -/* - * BFI_ABLK_I2H_QUERY - * BFI_ABLK_I2H_PORT_CONFIG - * BFI_ABLK_I2H_PF_CREATE - * BFI_ABLK_I2H_PF_DELETE - * BFI_ABLK_I2H_PF_UPDATE - * BFI_ABLK_I2H_OPTROM_ENABLE - * BFI_ABLK_I2H_OPTROM_DISABLE - */ -struct bfi_ablk_i2h_rsp_s { - struct bfi_mhdr_s mh; - u8 status; - u8 pcifn; - u8 port_mode; -}; - - -/* - * CEE module specific messages - */ - -/* Mailbox commands from host to firmware */ -enum bfi_cee_h2i_msgs_e { - BFI_CEE_H2I_GET_CFG_REQ = 1, - BFI_CEE_H2I_RESET_STATS = 2, - BFI_CEE_H2I_GET_STATS_REQ = 3, -}; - -enum bfi_cee_i2h_msgs_e { - BFI_CEE_I2H_GET_CFG_RSP = BFA_I2HM(1), - BFI_CEE_I2H_RESET_STATS_RSP = BFA_I2HM(2), - BFI_CEE_I2H_GET_STATS_RSP = BFA_I2HM(3), -}; - -/* - * H2I command structure for resetting the stats - */ -struct bfi_cee_reset_stats_s { - struct bfi_mhdr_s mh; -}; - -/* - * Get configuration command from host - */ -struct bfi_cee_get_req_s { - struct bfi_mhdr_s mh; - union bfi_addr_u dma_addr; -}; - -/* - * Reply message from firmware - */ -struct bfi_cee_get_rsp_s { - struct bfi_mhdr_s mh; - u8 cmd_status; - u8 rsvd[3]; -}; - -/* - * Reply message from firmware - */ -struct bfi_cee_stats_rsp_s { - struct bfi_mhdr_s mh; - u8 cmd_status; - u8 rsvd[3]; -}; - -/* Mailbox message structures from firmware to host */ -union bfi_cee_i2h_msg_u { - struct bfi_mhdr_s mh; - struct bfi_cee_get_rsp_s get_rsp; - struct bfi_cee_stats_rsp_s stats_rsp; -}; - -/* - * SFP related - */ - -enum bfi_sfp_h2i_e { - BFI_SFP_H2I_SHOW = 1, - BFI_SFP_H2I_SCN = 2, -}; - -enum bfi_sfp_i2h_e { - BFI_SFP_I2H_SHOW = BFA_I2HM(BFI_SFP_H2I_SHOW), - BFI_SFP_I2H_SCN = BFA_I2HM(BFI_SFP_H2I_SCN), -}; - -/* - * SFP state - */ -enum bfa_sfp_stat_e { - BFA_SFP_STATE_INIT = 0, /* SFP state is uninit */ - BFA_SFP_STATE_REMOVED = 1, /* SFP is removed */ - BFA_SFP_STATE_INSERTED = 2, /* SFP is inserted */ - BFA_SFP_STATE_VALID = 3, /* SFP is valid */ - BFA_SFP_STATE_UNSUPPORT = 4, /* SFP is unsupport */ - BFA_SFP_STATE_FAILED = 5, /* SFP i2c read fail */ -}; - -/* - * SFP memory access type - */ -enum bfi_sfp_mem_e { - BFI_SFP_MEM_ALL = 0x1, /* access all data field */ - BFI_SFP_MEM_DIAGEXT = 0x2, /* access diag ext data field only */ -}; - -struct bfi_sfp_req_s { - struct bfi_mhdr_s mh; - u8 memtype; - u8 rsvd[3]; - struct bfi_alen_s alen; -}; - -struct bfi_sfp_rsp_s { - struct bfi_mhdr_s mh; - u8 status; - u8 state; - u8 rsvd[2]; -}; - -/* - * FLASH module specific - */ -enum bfi_flash_h2i_msgs { - BFI_FLASH_H2I_QUERY_REQ = 1, - BFI_FLASH_H2I_ERASE_REQ = 2, - BFI_FLASH_H2I_WRITE_REQ = 3, - BFI_FLASH_H2I_READ_REQ = 4, - BFI_FLASH_H2I_BOOT_VER_REQ = 5, -}; - -enum bfi_flash_i2h_msgs { - BFI_FLASH_I2H_QUERY_RSP = BFA_I2HM(1), - BFI_FLASH_I2H_ERASE_RSP = BFA_I2HM(2), - BFI_FLASH_I2H_WRITE_RSP = BFA_I2HM(3), - BFI_FLASH_I2H_READ_RSP = BFA_I2HM(4), - BFI_FLASH_I2H_BOOT_VER_RSP = BFA_I2HM(5), - BFI_FLASH_I2H_EVENT = BFA_I2HM(127), -}; - -/* - * Flash query request - */ -struct bfi_flash_query_req_s { - struct bfi_mhdr_s mh; /* Common msg header */ - struct bfi_alen_s alen; -}; - -/* - * Flash erase request - */ -struct bfi_flash_erase_req_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u32 type; /* partition type */ - u8 instance; /* partition instance */ - u8 rsv[3]; -}; - -/* - * Flash write request - */ -struct bfi_flash_write_req_s { - struct bfi_mhdr_s mh; /* Common msg header */ - struct bfi_alen_s alen; - u32 type; /* partition type */ - u8 instance; /* partition instance */ - u8 last; - u8 rsv[2]; - u32 offset; - u32 length; -}; - -/* - * Flash read request - */ -struct bfi_flash_read_req_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u32 type; /* partition type */ - u8 instance; /* partition instance */ - u8 rsv[3]; - u32 offset; - u32 length; - struct bfi_alen_s alen; -}; - -/* - * Flash query response - */ -struct bfi_flash_query_rsp_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u32 status; -}; - -/* - * Flash read response - */ -struct bfi_flash_read_rsp_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u32 type; /* partition type */ - u8 instance; /* partition instance */ - u8 rsv[3]; - u32 status; - u32 length; -}; - -/* - * Flash write response - */ -struct bfi_flash_write_rsp_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u32 type; /* partition type */ - u8 instance; /* partition instance */ - u8 rsv[3]; - u32 status; - u32 length; -}; - -/* - * Flash erase response - */ -struct bfi_flash_erase_rsp_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u32 type; /* partition type */ - u8 instance; /* partition instance */ - u8 rsv[3]; - u32 status; -}; - -/* - *---------------------------------------------------------------------- - * DIAG - *---------------------------------------------------------------------- - */ -enum bfi_diag_h2i { - BFI_DIAG_H2I_PORTBEACON = 1, - BFI_DIAG_H2I_LOOPBACK = 2, - BFI_DIAG_H2I_FWPING = 3, - BFI_DIAG_H2I_TEMPSENSOR = 4, - BFI_DIAG_H2I_LEDTEST = 5, - BFI_DIAG_H2I_QTEST = 6, -}; - -enum bfi_diag_i2h { - BFI_DIAG_I2H_PORTBEACON = BFA_I2HM(BFI_DIAG_H2I_PORTBEACON), - BFI_DIAG_I2H_LOOPBACK = BFA_I2HM(BFI_DIAG_H2I_LOOPBACK), - BFI_DIAG_I2H_FWPING = BFA_I2HM(BFI_DIAG_H2I_FWPING), - BFI_DIAG_I2H_TEMPSENSOR = BFA_I2HM(BFI_DIAG_H2I_TEMPSENSOR), - BFI_DIAG_I2H_LEDTEST = BFA_I2HM(BFI_DIAG_H2I_LEDTEST), - BFI_DIAG_I2H_QTEST = BFA_I2HM(BFI_DIAG_H2I_QTEST), -}; - -#define BFI_DIAG_MAX_SGES 2 -#define BFI_DIAG_DMA_BUF_SZ (2 * 1024) -#define BFI_BOOT_MEMTEST_RES_ADDR 0x900 -#define BFI_BOOT_MEMTEST_RES_SIG 0xA0A1A2A3 - -struct bfi_diag_lb_req_s { - struct bfi_mhdr_s mh; - u32 loopcnt; - u32 pattern; - u8 lb_mode; /*!< bfa_port_opmode_t */ - u8 speed; /*!< bfa_port_speed_t */ - u8 rsvd[2]; -}; - -struct bfi_diag_lb_rsp_s { - struct bfi_mhdr_s mh; /* 4 bytes */ - struct bfa_diag_loopback_result_s res; /* 16 bytes */ -}; - -struct bfi_diag_fwping_req_s { - struct bfi_mhdr_s mh; /* 4 bytes */ - struct bfi_alen_s alen; /* 12 bytes */ - u32 data; /* user input data pattern */ - u32 count; /* user input dma count */ - u8 qtag; /* track CPE vc */ - u8 rsv[3]; -}; - -struct bfi_diag_fwping_rsp_s { - struct bfi_mhdr_s mh; /* 4 bytes */ - u32 data; /* user input data pattern */ - u8 qtag; /* track CPE vc */ - u8 dma_status; /* dma status */ - u8 rsv[2]; -}; - -/* - * Temperature Sensor - */ -struct bfi_diag_ts_req_s { - struct bfi_mhdr_s mh; /* 4 bytes */ - u16 temp; /* 10-bit A/D value */ - u16 brd_temp; /* 9-bit board temp */ - u8 status; - u8 ts_junc; /* show junction tempsensor */ - u8 ts_brd; /* show board tempsensor */ - u8 rsv; -}; -#define bfi_diag_ts_rsp_t struct bfi_diag_ts_req_s - -struct bfi_diag_ledtest_req_s { - struct bfi_mhdr_s mh; /* 4 bytes */ - u8 cmd; - u8 color; - u8 portid; - u8 led; /* bitmap of LEDs to be tested */ - u16 freq; /* no. of blinks every 10 secs */ - u8 rsv[2]; -}; - -/* notify host led operation is done */ -struct bfi_diag_ledtest_rsp_s { - struct bfi_mhdr_s mh; /* 4 bytes */ -}; - -struct bfi_diag_portbeacon_req_s { - struct bfi_mhdr_s mh; /* 4 bytes */ - u32 period; /* beaconing period */ - u8 beacon; /* 1: beacon on */ - u8 rsvd[3]; -}; - -/* notify host the beacon is off */ -struct bfi_diag_portbeacon_rsp_s { - struct bfi_mhdr_s mh; /* 4 bytes */ -}; - -struct bfi_diag_qtest_req_s { - struct bfi_mhdr_s mh; /* 4 bytes */ - u32 data[BFI_LMSG_PL_WSZ]; /* fill up tcm prefetch area */ -}; -#define bfi_diag_qtest_rsp_t struct bfi_diag_qtest_req_s - -/* - * PHY module specific - */ -enum bfi_phy_h2i_msgs_e { - BFI_PHY_H2I_QUERY_REQ = 1, - BFI_PHY_H2I_STATS_REQ = 2, - BFI_PHY_H2I_WRITE_REQ = 3, - BFI_PHY_H2I_READ_REQ = 4, -}; - -enum bfi_phy_i2h_msgs_e { - BFI_PHY_I2H_QUERY_RSP = BFA_I2HM(1), - BFI_PHY_I2H_STATS_RSP = BFA_I2HM(2), - BFI_PHY_I2H_WRITE_RSP = BFA_I2HM(3), - BFI_PHY_I2H_READ_RSP = BFA_I2HM(4), -}; - -/* - * External PHY query request - */ -struct bfi_phy_query_req_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u8 instance; - u8 rsv[3]; - struct bfi_alen_s alen; -}; - -/* - * External PHY stats request - */ -struct bfi_phy_stats_req_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u8 instance; - u8 rsv[3]; - struct bfi_alen_s alen; -}; - -/* - * External PHY write request - */ -struct bfi_phy_write_req_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u8 instance; - u8 last; - u8 rsv[2]; - u32 offset; - u32 length; - struct bfi_alen_s alen; -}; - -/* - * External PHY read request - */ -struct bfi_phy_read_req_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u8 instance; - u8 rsv[3]; - u32 offset; - u32 length; - struct bfi_alen_s alen; -}; - -/* - * External PHY query response - */ -struct bfi_phy_query_rsp_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u32 status; -}; - -/* - * External PHY stats response - */ -struct bfi_phy_stats_rsp_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u32 status; -}; - -/* - * External PHY read response - */ -struct bfi_phy_read_rsp_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u32 status; - u32 length; -}; - -/* - * External PHY write response - */ -struct bfi_phy_write_rsp_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u32 status; - u32 length; -}; - #pragma pack() #endif /* __BFI_H__ */ diff --git a/trunk/drivers/scsi/bfa/bfi_cbreg.h b/trunk/drivers/scsi/bfa/bfi_cbreg.h new file mode 100644 index 000000000000..39ad42b66b5b --- /dev/null +++ b/trunk/drivers/scsi/bfa/bfi_cbreg.h @@ -0,0 +1,305 @@ + +/* + * bfi_cbreg.h crossbow host block register definitions + * + * !!! Do not edit. Auto generated. !!! + */ + +#ifndef __BFI_CBREG_H__ +#define __BFI_CBREG_H__ + + +#define HOSTFN0_INT_STATUS 0x00014000 +#define __HOSTFN0_INT_STATUS_LVL_MK 0x00f00000 +#define __HOSTFN0_INT_STATUS_LVL_SH 20 +#define __HOSTFN0_INT_STATUS_LVL(_v) ((_v) << __HOSTFN0_INT_STATUS_LVL_SH) +#define __HOSTFN0_INT_STATUS_P 0x000fffff +#define HOSTFN0_INT_MSK 0x00014004 +#define HOST_PAGE_NUM_FN0 0x00014008 +#define __HOST_PAGE_NUM_FN 0x000001ff +#define HOSTFN1_INT_STATUS 0x00014100 +#define __HOSTFN1_INT_STAT_LVL_MK 0x00f00000 +#define __HOSTFN1_INT_STAT_LVL_SH 20 +#define __HOSTFN1_INT_STAT_LVL(_v) ((_v) << __HOSTFN1_INT_STAT_LVL_SH) +#define __HOSTFN1_INT_STAT_P 0x000fffff +#define HOSTFN1_INT_MSK 0x00014104 +#define HOST_PAGE_NUM_FN1 0x00014108 +#define APP_PLL_400_CTL_REG 0x00014204 +#define __P_400_PLL_LOCK 0x80000000 +#define __APP_PLL_400_SRAM_USE_100MHZ 0x00100000 +#define __APP_PLL_400_RESET_TIMER_MK 0x000e0000 +#define __APP_PLL_400_RESET_TIMER_SH 17 +#define __APP_PLL_400_RESET_TIMER(_v) ((_v) << __APP_PLL_400_RESET_TIMER_SH) +#define __APP_PLL_400_LOGIC_SOFT_RESET 0x00010000 +#define __APP_PLL_400_CNTLMT0_1_MK 0x0000c000 +#define __APP_PLL_400_CNTLMT0_1_SH 14 +#define __APP_PLL_400_CNTLMT0_1(_v) ((_v) << __APP_PLL_400_CNTLMT0_1_SH) +#define __APP_PLL_400_JITLMT0_1_MK 0x00003000 +#define __APP_PLL_400_JITLMT0_1_SH 12 +#define __APP_PLL_400_JITLMT0_1(_v) ((_v) << __APP_PLL_400_JITLMT0_1_SH) +#define __APP_PLL_400_HREF 0x00000800 +#define __APP_PLL_400_HDIV 0x00000400 +#define __APP_PLL_400_P0_1_MK 0x00000300 +#define __APP_PLL_400_P0_1_SH 8 +#define __APP_PLL_400_P0_1(_v) ((_v) << __APP_PLL_400_P0_1_SH) +#define __APP_PLL_400_Z0_2_MK 0x000000e0 +#define __APP_PLL_400_Z0_2_SH 5 +#define __APP_PLL_400_Z0_2(_v) ((_v) << __APP_PLL_400_Z0_2_SH) +#define __APP_PLL_400_RSEL200500 0x00000010 +#define __APP_PLL_400_ENARST 0x00000008 +#define __APP_PLL_400_BYPASS 0x00000004 +#define __APP_PLL_400_LRESETN 0x00000002 +#define __APP_PLL_400_ENABLE 0x00000001 +#define APP_PLL_212_CTL_REG 0x00014208 +#define __P_212_PLL_LOCK 0x80000000 +#define __APP_PLL_212_RESET_TIMER_MK 0x000e0000 +#define __APP_PLL_212_RESET_TIMER_SH 17 +#define __APP_PLL_212_RESET_TIMER(_v) ((_v) << __APP_PLL_212_RESET_TIMER_SH) +#define __APP_PLL_212_LOGIC_SOFT_RESET 0x00010000 +#define __APP_PLL_212_CNTLMT0_1_MK 0x0000c000 +#define __APP_PLL_212_CNTLMT0_1_SH 14 +#define __APP_PLL_212_CNTLMT0_1(_v) ((_v) << __APP_PLL_212_CNTLMT0_1_SH) +#define __APP_PLL_212_JITLMT0_1_MK 0x00003000 +#define __APP_PLL_212_JITLMT0_1_SH 12 +#define __APP_PLL_212_JITLMT0_1(_v) ((_v) << __APP_PLL_212_JITLMT0_1_SH) +#define __APP_PLL_212_HREF 0x00000800 +#define __APP_PLL_212_HDIV 0x00000400 +#define __APP_PLL_212_P0_1_MK 0x00000300 +#define __APP_PLL_212_P0_1_SH 8 +#define __APP_PLL_212_P0_1(_v) ((_v) << __APP_PLL_212_P0_1_SH) +#define __APP_PLL_212_Z0_2_MK 0x000000e0 +#define __APP_PLL_212_Z0_2_SH 5 +#define __APP_PLL_212_Z0_2(_v) ((_v) << __APP_PLL_212_Z0_2_SH) +#define __APP_PLL_212_RSEL200500 0x00000010 +#define __APP_PLL_212_ENARST 0x00000008 +#define __APP_PLL_212_BYPASS 0x00000004 +#define __APP_PLL_212_LRESETN 0x00000002 +#define __APP_PLL_212_ENABLE 0x00000001 +#define HOST_SEM0_REG 0x00014230 +#define __HOST_SEMAPHORE 0x00000001 +#define HOST_SEM1_REG 0x00014234 +#define HOST_SEM2_REG 0x00014238 +#define HOST_SEM3_REG 0x0001423c +#define HOST_SEM0_INFO_REG 0x00014240 +#define HOST_SEM1_INFO_REG 0x00014244 +#define HOST_SEM2_INFO_REG 0x00014248 +#define HOST_SEM3_INFO_REG 0x0001424c +#define HOSTFN0_LPU0_CMD_STAT 0x00019000 +#define __HOSTFN0_LPU0_MBOX_INFO_MK 0xfffffffe +#define __HOSTFN0_LPU0_MBOX_INFO_SH 1 +#define __HOSTFN0_LPU0_MBOX_INFO(_v) ((_v) << __HOSTFN0_LPU0_MBOX_INFO_SH) +#define __HOSTFN0_LPU0_MBOX_CMD_STATUS 0x00000001 +#define LPU0_HOSTFN0_CMD_STAT 0x00019008 +#define __LPU0_HOSTFN0_MBOX_INFO_MK 0xfffffffe +#define __LPU0_HOSTFN0_MBOX_INFO_SH 1 +#define __LPU0_HOSTFN0_MBOX_INFO(_v) ((_v) << __LPU0_HOSTFN0_MBOX_INFO_SH) +#define __LPU0_HOSTFN0_MBOX_CMD_STATUS 0x00000001 +#define HOSTFN1_LPU1_CMD_STAT 0x00019014 +#define __HOSTFN1_LPU1_MBOX_INFO_MK 0xfffffffe +#define __HOSTFN1_LPU1_MBOX_INFO_SH 1 +#define __HOSTFN1_LPU1_MBOX_INFO(_v) ((_v) << __HOSTFN1_LPU1_MBOX_INFO_SH) +#define __HOSTFN1_LPU1_MBOX_CMD_STATUS 0x00000001 +#define LPU1_HOSTFN1_CMD_STAT 0x0001901c +#define __LPU1_HOSTFN1_MBOX_INFO_MK 0xfffffffe +#define __LPU1_HOSTFN1_MBOX_INFO_SH 1 +#define __LPU1_HOSTFN1_MBOX_INFO(_v) ((_v) << __LPU1_HOSTFN1_MBOX_INFO_SH) +#define __LPU1_HOSTFN1_MBOX_CMD_STATUS 0x00000001 +#define CPE_Q0_DEPTH 0x00010014 +#define CPE_Q0_PI 0x0001001c +#define CPE_Q0_CI 0x00010020 +#define CPE_Q1_DEPTH 0x00010034 +#define CPE_Q1_PI 0x0001003c +#define CPE_Q1_CI 0x00010040 +#define CPE_Q2_DEPTH 0x00010054 +#define CPE_Q2_PI 0x0001005c +#define CPE_Q2_CI 0x00010060 +#define CPE_Q3_DEPTH 0x00010074 +#define CPE_Q3_PI 0x0001007c +#define CPE_Q3_CI 0x00010080 +#define CPE_Q4_DEPTH 0x00010094 +#define CPE_Q4_PI 0x0001009c +#define CPE_Q4_CI 0x000100a0 +#define CPE_Q5_DEPTH 0x000100b4 +#define CPE_Q5_PI 0x000100bc +#define CPE_Q5_CI 0x000100c0 +#define CPE_Q6_DEPTH 0x000100d4 +#define CPE_Q6_PI 0x000100dc +#define CPE_Q6_CI 0x000100e0 +#define CPE_Q7_DEPTH 0x000100f4 +#define CPE_Q7_PI 0x000100fc +#define CPE_Q7_CI 0x00010100 +#define RME_Q0_DEPTH 0x00011014 +#define RME_Q0_PI 0x0001101c +#define RME_Q0_CI 0x00011020 +#define RME_Q1_DEPTH 0x00011034 +#define RME_Q1_PI 0x0001103c +#define RME_Q1_CI 0x00011040 +#define RME_Q2_DEPTH 0x00011054 +#define RME_Q2_PI 0x0001105c +#define RME_Q2_CI 0x00011060 +#define RME_Q3_DEPTH 0x00011074 +#define RME_Q3_PI 0x0001107c +#define RME_Q3_CI 0x00011080 +#define RME_Q4_DEPTH 0x00011094 +#define RME_Q4_PI 0x0001109c +#define RME_Q4_CI 0x000110a0 +#define RME_Q5_DEPTH 0x000110b4 +#define RME_Q5_PI 0x000110bc +#define RME_Q5_CI 0x000110c0 +#define RME_Q6_DEPTH 0x000110d4 +#define RME_Q6_PI 0x000110dc +#define RME_Q6_CI 0x000110e0 +#define RME_Q7_DEPTH 0x000110f4 +#define RME_Q7_PI 0x000110fc +#define RME_Q7_CI 0x00011100 +#define PSS_CTL_REG 0x00018800 +#define __PSS_I2C_CLK_DIV_MK 0x00030000 +#define __PSS_I2C_CLK_DIV_SH 16 +#define __PSS_I2C_CLK_DIV(_v) ((_v) << __PSS_I2C_CLK_DIV_SH) +#define __PSS_LMEM_INIT_DONE 0x00001000 +#define __PSS_LMEM_RESET 0x00000200 +#define __PSS_LMEM_INIT_EN 0x00000100 +#define __PSS_LPU1_RESET 0x00000002 +#define __PSS_LPU0_RESET 0x00000001 +#define PSS_ERR_STATUS_REG 0x00018810 +#define __PSS_LMEM1_CORR_ERR 0x00000800 +#define __PSS_LMEM0_CORR_ERR 0x00000400 +#define __PSS_LMEM1_UNCORR_ERR 0x00000200 +#define __PSS_LMEM0_UNCORR_ERR 0x00000100 +#define __PSS_BAL_PERR 0x00000080 +#define __PSS_DIP_IF_ERR 0x00000040 +#define __PSS_IOH_IF_ERR 0x00000020 +#define __PSS_TDS_IF_ERR 0x00000010 +#define __PSS_RDS_IF_ERR 0x00000008 +#define __PSS_SGM_IF_ERR 0x00000004 +#define __PSS_LPU1_RAM_ERR 0x00000002 +#define __PSS_LPU0_RAM_ERR 0x00000001 +#define ERR_SET_REG 0x00018818 +#define __PSS_ERR_STATUS_SET 0x00000fff + + +/* + * These definitions are either in error/missing in spec. Its auto-generated + * from hard coded values in regparse.pl. + */ +#define __EMPHPOST_AT_4G_MK_FIX 0x0000001c +#define __EMPHPOST_AT_4G_SH_FIX 0x00000002 +#define __EMPHPRE_AT_4G_FIX 0x00000003 +#define __SFP_TXRATE_EN_FIX 0x00000100 +#define __SFP_RXRATE_EN_FIX 0x00000080 + + +/* + * These register definitions are auto-generated from hard coded values + * in regparse.pl. + */ +#define HOSTFN0_LPU_MBOX0_0 0x00019200 +#define HOSTFN1_LPU_MBOX0_8 0x00019260 +#define LPU_HOSTFN0_MBOX0_0 0x00019280 +#define LPU_HOSTFN1_MBOX0_8 0x000192e0 + + +/* + * These register mapping definitions are auto-generated from mapping tables + * in regparse.pl. + */ +#define BFA_IOC0_HBEAT_REG HOST_SEM0_INFO_REG +#define BFA_IOC0_STATE_REG HOST_SEM1_INFO_REG +#define BFA_IOC1_HBEAT_REG HOST_SEM2_INFO_REG +#define BFA_IOC1_STATE_REG HOST_SEM3_INFO_REG +#define BFA_FW_USE_COUNT HOST_SEM4_INFO_REG +#define BFA_IOC_FAIL_SYNC HOST_SEM5_INFO_REG + +#define CPE_Q_DEPTH(__n) \ + (CPE_Q0_DEPTH + (__n) * (CPE_Q1_DEPTH - CPE_Q0_DEPTH)) +#define CPE_Q_PI(__n) \ + (CPE_Q0_PI + (__n) * (CPE_Q1_PI - CPE_Q0_PI)) +#define CPE_Q_CI(__n) \ + (CPE_Q0_CI + (__n) * (CPE_Q1_CI - CPE_Q0_CI)) +#define RME_Q_DEPTH(__n) \ + (RME_Q0_DEPTH + (__n) * (RME_Q1_DEPTH - RME_Q0_DEPTH)) +#define RME_Q_PI(__n) \ + (RME_Q0_PI + (__n) * (RME_Q1_PI - RME_Q0_PI)) +#define RME_Q_CI(__n) \ + (RME_Q0_CI + (__n) * (RME_Q1_CI - RME_Q0_CI)) + +#define CPE_Q_NUM(__fn, __q) (((__fn) << 2) + (__q)) +#define RME_Q_NUM(__fn, __q) (((__fn) << 2) + (__q)) +#define CPE_Q_MASK(__q) ((__q) & 0x3) +#define RME_Q_MASK(__q) ((__q) & 0x3) + + +/* + * PCI MSI-X vector defines + */ +enum { + BFA_MSIX_CPE_Q0 = 0, + BFA_MSIX_CPE_Q1 = 1, + BFA_MSIX_CPE_Q2 = 2, + BFA_MSIX_CPE_Q3 = 3, + BFA_MSIX_CPE_Q4 = 4, + BFA_MSIX_CPE_Q5 = 5, + BFA_MSIX_CPE_Q6 = 6, + BFA_MSIX_CPE_Q7 = 7, + BFA_MSIX_RME_Q0 = 8, + BFA_MSIX_RME_Q1 = 9, + BFA_MSIX_RME_Q2 = 10, + BFA_MSIX_RME_Q3 = 11, + BFA_MSIX_RME_Q4 = 12, + BFA_MSIX_RME_Q5 = 13, + BFA_MSIX_RME_Q6 = 14, + BFA_MSIX_RME_Q7 = 15, + BFA_MSIX_ERR_EMC = 16, + BFA_MSIX_ERR_LPU0 = 17, + BFA_MSIX_ERR_LPU1 = 18, + BFA_MSIX_ERR_PSS = 19, + BFA_MSIX_MBOX_LPU0 = 20, + BFA_MSIX_MBOX_LPU1 = 21, + BFA_MSIX_CB_MAX = 22, +}; + +/* + * And corresponding host interrupt status bit field defines + */ +#define __HFN_INT_CPE_Q0 0x00000001U +#define __HFN_INT_CPE_Q1 0x00000002U +#define __HFN_INT_CPE_Q2 0x00000004U +#define __HFN_INT_CPE_Q3 0x00000008U +#define __HFN_INT_CPE_Q4 0x00000010U +#define __HFN_INT_CPE_Q5 0x00000020U +#define __HFN_INT_CPE_Q6 0x00000040U +#define __HFN_INT_CPE_Q7 0x00000080U +#define __HFN_INT_RME_Q0 0x00000100U +#define __HFN_INT_RME_Q1 0x00000200U +#define __HFN_INT_RME_Q2 0x00000400U +#define __HFN_INT_RME_Q3 0x00000800U +#define __HFN_INT_RME_Q4 0x00001000U +#define __HFN_INT_RME_Q5 0x00002000U +#define __HFN_INT_RME_Q6 0x00004000U +#define __HFN_INT_RME_Q7 0x00008000U +#define __HFN_INT_ERR_EMC 0x00010000U +#define __HFN_INT_ERR_LPU0 0x00020000U +#define __HFN_INT_ERR_LPU1 0x00040000U +#define __HFN_INT_ERR_PSS 0x00080000U +#define __HFN_INT_MBOX_LPU0 0x00100000U +#define __HFN_INT_MBOX_LPU1 0x00200000U +#define __HFN_INT_MBOX1_LPU0 0x00400000U +#define __HFN_INT_MBOX1_LPU1 0x00800000U +#define __HFN_INT_CPE_MASK 0x000000ffU +#define __HFN_INT_RME_MASK 0x0000ff00U + + +/* + * crossbow memory map. + */ +#define PSS_SMEM_PAGE_START 0x8000 +#define PSS_SMEM_PGNUM(_pg0, _ma) ((_pg0) + ((_ma) >> 15)) +#define PSS_SMEM_PGOFF(_ma) ((_ma) & 0x7fff) + +/* + * End of crossbow memory map + */ + + +#endif /* __BFI_CBREG_H__ */ + diff --git a/trunk/drivers/scsi/bfa/bfi_ctreg.h b/trunk/drivers/scsi/bfa/bfi_ctreg.h new file mode 100644 index 000000000000..fc4ce4a5a183 --- /dev/null +++ b/trunk/drivers/scsi/bfa/bfi_ctreg.h @@ -0,0 +1,636 @@ + +/* + * bfi_ctreg.h catapult host block register definitions + * + * !!! Do not edit. Auto generated. !!! + */ + +#ifndef __BFI_CTREG_H__ +#define __BFI_CTREG_H__ + + +#define HOSTFN0_LPU_MBOX0_0 0x00019200 +#define HOSTFN1_LPU_MBOX0_8 0x00019260 +#define LPU_HOSTFN0_MBOX0_0 0x00019280 +#define LPU_HOSTFN1_MBOX0_8 0x000192e0 +#define HOSTFN2_LPU_MBOX0_0 0x00019400 +#define HOSTFN3_LPU_MBOX0_8 0x00019460 +#define LPU_HOSTFN2_MBOX0_0 0x00019480 +#define LPU_HOSTFN3_MBOX0_8 0x000194e0 +#define HOSTFN0_INT_STATUS 0x00014000 +#define __HOSTFN0_HALT_OCCURRED 0x01000000 +#define __HOSTFN0_INT_STATUS_LVL_MK 0x00f00000 +#define __HOSTFN0_INT_STATUS_LVL_SH 20 +#define __HOSTFN0_INT_STATUS_LVL(_v) ((_v) << __HOSTFN0_INT_STATUS_LVL_SH) +#define __HOSTFN0_INT_STATUS_P_MK 0x000f0000 +#define __HOSTFN0_INT_STATUS_P_SH 16 +#define __HOSTFN0_INT_STATUS_P(_v) ((_v) << __HOSTFN0_INT_STATUS_P_SH) +#define __HOSTFN0_INT_STATUS_F 0x0000ffff +#define HOSTFN0_INT_MSK 0x00014004 +#define HOST_PAGE_NUM_FN0 0x00014008 +#define __HOST_PAGE_NUM_FN 0x000001ff +#define HOST_MSIX_ERR_INDEX_FN0 0x0001400c +#define __MSIX_ERR_INDEX_FN 0x000001ff +#define HOSTFN1_INT_STATUS 0x00014100 +#define __HOSTFN1_HALT_OCCURRED 0x01000000 +#define __HOSTFN1_INT_STATUS_LVL_MK 0x00f00000 +#define __HOSTFN1_INT_STATUS_LVL_SH 20 +#define __HOSTFN1_INT_STATUS_LVL(_v) ((_v) << __HOSTFN1_INT_STATUS_LVL_SH) +#define __HOSTFN1_INT_STATUS_P_MK 0x000f0000 +#define __HOSTFN1_INT_STATUS_P_SH 16 +#define __HOSTFN1_INT_STATUS_P(_v) ((_v) << __HOSTFN1_INT_STATUS_P_SH) +#define __HOSTFN1_INT_STATUS_F 0x0000ffff +#define HOSTFN1_INT_MSK 0x00014104 +#define HOST_PAGE_NUM_FN1 0x00014108 +#define HOST_MSIX_ERR_INDEX_FN1 0x0001410c +#define APP_PLL_425_CTL_REG 0x00014204 +#define __P_425_PLL_LOCK 0x80000000 +#define __APP_PLL_425_SRAM_USE_100MHZ 0x00100000 +#define __APP_PLL_425_RESET_TIMER_MK 0x000e0000 +#define __APP_PLL_425_RESET_TIMER_SH 17 +#define __APP_PLL_425_RESET_TIMER(_v) ((_v) << __APP_PLL_425_RESET_TIMER_SH) +#define __APP_PLL_425_LOGIC_SOFT_RESET 0x00010000 +#define __APP_PLL_425_CNTLMT0_1_MK 0x0000c000 +#define __APP_PLL_425_CNTLMT0_1_SH 14 +#define __APP_PLL_425_CNTLMT0_1(_v) ((_v) << __APP_PLL_425_CNTLMT0_1_SH) +#define __APP_PLL_425_JITLMT0_1_MK 0x00003000 +#define __APP_PLL_425_JITLMT0_1_SH 12 +#define __APP_PLL_425_JITLMT0_1(_v) ((_v) << __APP_PLL_425_JITLMT0_1_SH) +#define __APP_PLL_425_HREF 0x00000800 +#define __APP_PLL_425_HDIV 0x00000400 +#define __APP_PLL_425_P0_1_MK 0x00000300 +#define __APP_PLL_425_P0_1_SH 8 +#define __APP_PLL_425_P0_1(_v) ((_v) << __APP_PLL_425_P0_1_SH) +#define __APP_PLL_425_Z0_2_MK 0x000000e0 +#define __APP_PLL_425_Z0_2_SH 5 +#define __APP_PLL_425_Z0_2(_v) ((_v) << __APP_PLL_425_Z0_2_SH) +#define __APP_PLL_425_RSEL200500 0x00000010 +#define __APP_PLL_425_ENARST 0x00000008 +#define __APP_PLL_425_BYPASS 0x00000004 +#define __APP_PLL_425_LRESETN 0x00000002 +#define __APP_PLL_425_ENABLE 0x00000001 +#define APP_PLL_312_CTL_REG 0x00014208 +#define __P_312_PLL_LOCK 0x80000000 +#define __ENABLE_MAC_AHB_1 0x00800000 +#define __ENABLE_MAC_AHB_0 0x00400000 +#define __ENABLE_MAC_1 0x00200000 +#define __ENABLE_MAC_0 0x00100000 +#define __APP_PLL_312_RESET_TIMER_MK 0x000e0000 +#define __APP_PLL_312_RESET_TIMER_SH 17 +#define __APP_PLL_312_RESET_TIMER(_v) ((_v) << __APP_PLL_312_RESET_TIMER_SH) +#define __APP_PLL_312_LOGIC_SOFT_RESET 0x00010000 +#define __APP_PLL_312_CNTLMT0_1_MK 0x0000c000 +#define __APP_PLL_312_CNTLMT0_1_SH 14 +#define __APP_PLL_312_CNTLMT0_1(_v) ((_v) << __APP_PLL_312_CNTLMT0_1_SH) +#define __APP_PLL_312_JITLMT0_1_MK 0x00003000 +#define __APP_PLL_312_JITLMT0_1_SH 12 +#define __APP_PLL_312_JITLMT0_1(_v) ((_v) << __APP_PLL_312_JITLMT0_1_SH) +#define __APP_PLL_312_HREF 0x00000800 +#define __APP_PLL_312_HDIV 0x00000400 +#define __APP_PLL_312_P0_1_MK 0x00000300 +#define __APP_PLL_312_P0_1_SH 8 +#define __APP_PLL_312_P0_1(_v) ((_v) << __APP_PLL_312_P0_1_SH) +#define __APP_PLL_312_Z0_2_MK 0x000000e0 +#define __APP_PLL_312_Z0_2_SH 5 +#define __APP_PLL_312_Z0_2(_v) ((_v) << __APP_PLL_312_Z0_2_SH) +#define __APP_PLL_312_RSEL200500 0x00000010 +#define __APP_PLL_312_ENARST 0x00000008 +#define __APP_PLL_312_BYPASS 0x00000004 +#define __APP_PLL_312_LRESETN 0x00000002 +#define __APP_PLL_312_ENABLE 0x00000001 +#define MBIST_CTL_REG 0x00014220 +#define __EDRAM_BISTR_START 0x00000004 +#define __MBIST_RESET 0x00000002 +#define __MBIST_START 0x00000001 +#define MBIST_STAT_REG 0x00014224 +#define __EDRAM_BISTR_STATUS 0x00000008 +#define __EDRAM_BISTR_DONE 0x00000004 +#define __MEM_BIT_STATUS 0x00000002 +#define __MBIST_DONE 0x00000001 +#define HOST_SEM0_REG 0x00014230 +#define __HOST_SEMAPHORE 0x00000001 +#define HOST_SEM1_REG 0x00014234 +#define HOST_SEM2_REG 0x00014238 +#define HOST_SEM3_REG 0x0001423c +#define HOST_SEM0_INFO_REG 0x00014240 +#define HOST_SEM1_INFO_REG 0x00014244 +#define HOST_SEM2_INFO_REG 0x00014248 +#define HOST_SEM3_INFO_REG 0x0001424c +#define ETH_MAC_SER_REG 0x00014288 +#define __APP_EMS_CKBUFAMPIN 0x00000020 +#define __APP_EMS_REFCLKSEL 0x00000010 +#define __APP_EMS_CMLCKSEL 0x00000008 +#define __APP_EMS_REFCKBUFEN2 0x00000004 +#define __APP_EMS_REFCKBUFEN1 0x00000002 +#define __APP_EMS_CHANNEL_SEL 0x00000001 +#define HOSTFN2_INT_STATUS 0x00014300 +#define __HOSTFN2_HALT_OCCURRED 0x01000000 +#define __HOSTFN2_INT_STATUS_LVL_MK 0x00f00000 +#define __HOSTFN2_INT_STATUS_LVL_SH 20 +#define __HOSTFN2_INT_STATUS_LVL(_v) ((_v) << __HOSTFN2_INT_STATUS_LVL_SH) +#define __HOSTFN2_INT_STATUS_P_MK 0x000f0000 +#define __HOSTFN2_INT_STATUS_P_SH 16 +#define __HOSTFN2_INT_STATUS_P(_v) ((_v) << __HOSTFN2_INT_STATUS_P_SH) +#define __HOSTFN2_INT_STATUS_F 0x0000ffff +#define HOSTFN2_INT_MSK 0x00014304 +#define HOST_PAGE_NUM_FN2 0x00014308 +#define HOST_MSIX_ERR_INDEX_FN2 0x0001430c +#define HOSTFN3_INT_STATUS 0x00014400 +#define __HALT_OCCURRED 0x01000000 +#define __HOSTFN3_INT_STATUS_LVL_MK 0x00f00000 +#define __HOSTFN3_INT_STATUS_LVL_SH 20 +#define __HOSTFN3_INT_STATUS_LVL(_v) ((_v) << __HOSTFN3_INT_STATUS_LVL_SH) +#define __HOSTFN3_INT_STATUS_P_MK 0x000f0000 +#define __HOSTFN3_INT_STATUS_P_SH 16 +#define __HOSTFN3_INT_STATUS_P(_v) ((_v) << __HOSTFN3_INT_STATUS_P_SH) +#define __HOSTFN3_INT_STATUS_F 0x0000ffff +#define HOSTFN3_INT_MSK 0x00014404 +#define HOST_PAGE_NUM_FN3 0x00014408 +#define HOST_MSIX_ERR_INDEX_FN3 0x0001440c +#define FNC_ID_REG 0x00014600 +#define __FUNCTION_NUMBER 0x00000007 +#define FNC_PERS_REG 0x00014604 +#define __F3_FUNCTION_ACTIVE 0x80000000 +#define __F3_FUNCTION_MODE 0x40000000 +#define __F3_PORT_MAP_MK 0x30000000 +#define __F3_PORT_MAP_SH 28 +#define __F3_PORT_MAP(_v) ((_v) << __F3_PORT_MAP_SH) +#define __F3_VM_MODE 0x08000000 +#define __F3_INTX_STATUS_MK 0x07000000 +#define __F3_INTX_STATUS_SH 24 +#define __F3_INTX_STATUS(_v) ((_v) << __F3_INTX_STATUS_SH) +#define __F2_FUNCTION_ACTIVE 0x00800000 +#define __F2_FUNCTION_MODE 0x00400000 +#define __F2_PORT_MAP_MK 0x00300000 +#define __F2_PORT_MAP_SH 20 +#define __F2_PORT_MAP(_v) ((_v) << __F2_PORT_MAP_SH) +#define __F2_VM_MODE 0x00080000 +#define __F2_INTX_STATUS_MK 0x00070000 +#define __F2_INTX_STATUS_SH 16 +#define __F2_INTX_STATUS(_v) ((_v) << __F2_INTX_STATUS_SH) +#define __F1_FUNCTION_ACTIVE 0x00008000 +#define __F1_FUNCTION_MODE 0x00004000 +#define __F1_PORT_MAP_MK 0x00003000 +#define __F1_PORT_MAP_SH 12 +#define __F1_PORT_MAP(_v) ((_v) << __F1_PORT_MAP_SH) +#define __F1_VM_MODE 0x00000800 +#define __F1_INTX_STATUS_MK 0x00000700 +#define __F1_INTX_STATUS_SH 8 +#define __F1_INTX_STATUS(_v) ((_v) << __F1_INTX_STATUS_SH) +#define __F0_FUNCTION_ACTIVE 0x00000080 +#define __F0_FUNCTION_MODE 0x00000040 +#define __F0_PORT_MAP_MK 0x00000030 +#define __F0_PORT_MAP_SH 4 +#define __F0_PORT_MAP(_v) ((_v) << __F0_PORT_MAP_SH) +#define __F0_VM_MODE 0x00000008 +#define __F0_INTX_STATUS 0x00000007 +enum { + __F0_INTX_STATUS_MSIX = 0x0, + __F0_INTX_STATUS_INTA = 0x1, + __F0_INTX_STATUS_INTB = 0x2, + __F0_INTX_STATUS_INTC = 0x3, + __F0_INTX_STATUS_INTD = 0x4, +}; +#define OP_MODE 0x0001460c +#define __APP_ETH_CLK_LOWSPEED 0x00000004 +#define __GLOBAL_CORECLK_HALFSPEED 0x00000002 +#define __GLOBAL_FCOE_MODE 0x00000001 +#define HOST_SEM4_REG 0x00014610 +#define HOST_SEM5_REG 0x00014614 +#define HOST_SEM6_REG 0x00014618 +#define HOST_SEM7_REG 0x0001461c +#define HOST_SEM4_INFO_REG 0x00014620 +#define HOST_SEM5_INFO_REG 0x00014624 +#define HOST_SEM6_INFO_REG 0x00014628 +#define HOST_SEM7_INFO_REG 0x0001462c +#define HOSTFN0_LPU0_MBOX0_CMD_STAT 0x00019000 +#define __HOSTFN0_LPU0_MBOX0_INFO_MK 0xfffffffe +#define __HOSTFN0_LPU0_MBOX0_INFO_SH 1 +#define __HOSTFN0_LPU0_MBOX0_INFO(_v) ((_v) << __HOSTFN0_LPU0_MBOX0_INFO_SH) +#define __HOSTFN0_LPU0_MBOX0_CMD_STATUS 0x00000001 +#define HOSTFN0_LPU1_MBOX0_CMD_STAT 0x00019004 +#define __HOSTFN0_LPU1_MBOX0_INFO_MK 0xfffffffe +#define __HOSTFN0_LPU1_MBOX0_INFO_SH 1 +#define __HOSTFN0_LPU1_MBOX0_INFO(_v) ((_v) << __HOSTFN0_LPU1_MBOX0_INFO_SH) +#define __HOSTFN0_LPU1_MBOX0_CMD_STATUS 0x00000001 +#define LPU0_HOSTFN0_MBOX0_CMD_STAT 0x00019008 +#define __LPU0_HOSTFN0_MBOX0_INFO_MK 0xfffffffe +#define __LPU0_HOSTFN0_MBOX0_INFO_SH 1 +#define __LPU0_HOSTFN0_MBOX0_INFO(_v) ((_v) << __LPU0_HOSTFN0_MBOX0_INFO_SH) +#define __LPU0_HOSTFN0_MBOX0_CMD_STATUS 0x00000001 +#define LPU1_HOSTFN0_MBOX0_CMD_STAT 0x0001900c +#define __LPU1_HOSTFN0_MBOX0_INFO_MK 0xfffffffe +#define __LPU1_HOSTFN0_MBOX0_INFO_SH 1 +#define __LPU1_HOSTFN0_MBOX0_INFO(_v) ((_v) << __LPU1_HOSTFN0_MBOX0_INFO_SH) +#define __LPU1_HOSTFN0_MBOX0_CMD_STATUS 0x00000001 +#define HOSTFN1_LPU0_MBOX0_CMD_STAT 0x00019010 +#define __HOSTFN1_LPU0_MBOX0_INFO_MK 0xfffffffe +#define __HOSTFN1_LPU0_MBOX0_INFO_SH 1 +#define __HOSTFN1_LPU0_MBOX0_INFO(_v) ((_v) << __HOSTFN1_LPU0_MBOX0_INFO_SH) +#define __HOSTFN1_LPU0_MBOX0_CMD_STATUS 0x00000001 +#define HOSTFN1_LPU1_MBOX0_CMD_STAT 0x00019014 +#define __HOSTFN1_LPU1_MBOX0_INFO_MK 0xfffffffe +#define __HOSTFN1_LPU1_MBOX0_INFO_SH 1 +#define __HOSTFN1_LPU1_MBOX0_INFO(_v) ((_v) << __HOSTFN1_LPU1_MBOX0_INFO_SH) +#define __HOSTFN1_LPU1_MBOX0_CMD_STATUS 0x00000001 +#define LPU0_HOSTFN1_MBOX0_CMD_STAT 0x00019018 +#define __LPU0_HOSTFN1_MBOX0_INFO_MK 0xfffffffe +#define __LPU0_HOSTFN1_MBOX0_INFO_SH 1 +#define __LPU0_HOSTFN1_MBOX0_INFO(_v) ((_v) << __LPU0_HOSTFN1_MBOX0_INFO_SH) +#define __LPU0_HOSTFN1_MBOX0_CMD_STATUS 0x00000001 +#define LPU1_HOSTFN1_MBOX0_CMD_STAT 0x0001901c +#define __LPU1_HOSTFN1_MBOX0_INFO_MK 0xfffffffe +#define __LPU1_HOSTFN1_MBOX0_INFO_SH 1 +#define __LPU1_HOSTFN1_MBOX0_INFO(_v) ((_v) << __LPU1_HOSTFN1_MBOX0_INFO_SH) +#define __LPU1_HOSTFN1_MBOX0_CMD_STATUS 0x00000001 +#define HOSTFN2_LPU0_MBOX0_CMD_STAT 0x00019150 +#define __HOSTFN2_LPU0_MBOX0_INFO_MK 0xfffffffe +#define __HOSTFN2_LPU0_MBOX0_INFO_SH 1 +#define __HOSTFN2_LPU0_MBOX0_INFO(_v) ((_v) << __HOSTFN2_LPU0_MBOX0_INFO_SH) +#define __HOSTFN2_LPU0_MBOX0_CMD_STATUS 0x00000001 +#define HOSTFN2_LPU1_MBOX0_CMD_STAT 0x00019154 +#define __HOSTFN2_LPU1_MBOX0_INFO_MK 0xfffffffe +#define __HOSTFN2_LPU1_MBOX0_INFO_SH 1 +#define __HOSTFN2_LPU1_MBOX0_INFO(_v) ((_v) << __HOSTFN2_LPU1_MBOX0_INFO_SH) +#define __HOSTFN2_LPU1_MBOX0BOX0_CMD_STATUS 0x00000001 +#define LPU0_HOSTFN2_MBOX0_CMD_STAT 0x00019158 +#define __LPU0_HOSTFN2_MBOX0_INFO_MK 0xfffffffe +#define __LPU0_HOSTFN2_MBOX0_INFO_SH 1 +#define __LPU0_HOSTFN2_MBOX0_INFO(_v) ((_v) << __LPU0_HOSTFN2_MBOX0_INFO_SH) +#define __LPU0_HOSTFN2_MBOX0_CMD_STATUS 0x00000001 +#define LPU1_HOSTFN2_MBOX0_CMD_STAT 0x0001915c +#define __LPU1_HOSTFN2_MBOX0_INFO_MK 0xfffffffe +#define __LPU1_HOSTFN2_MBOX0_INFO_SH 1 +#define __LPU1_HOSTFN2_MBOX0_INFO(_v) ((_v) << __LPU1_HOSTFN2_MBOX0_INFO_SH) +#define __LPU1_HOSTFN2_MBOX0_CMD_STATUS 0x00000001 +#define HOSTFN3_LPU0_MBOX0_CMD_STAT 0x00019160 +#define __HOSTFN3_LPU0_MBOX0_INFO_MK 0xfffffffe +#define __HOSTFN3_LPU0_MBOX0_INFO_SH 1 +#define __HOSTFN3_LPU0_MBOX0_INFO(_v) ((_v) << __HOSTFN3_LPU0_MBOX0_INFO_SH) +#define __HOSTFN3_LPU0_MBOX0_CMD_STATUS 0x00000001 +#define HOSTFN3_LPU1_MBOX0_CMD_STAT 0x00019164 +#define __HOSTFN3_LPU1_MBOX0_INFO_MK 0xfffffffe +#define __HOSTFN3_LPU1_MBOX0_INFO_SH 1 +#define __HOSTFN3_LPU1_MBOX0_INFO(_v) ((_v) << __HOSTFN3_LPU1_MBOX0_INFO_SH) +#define __HOSTFN3_LPU1_MBOX0_CMD_STATUS 0x00000001 +#define LPU0_HOSTFN3_MBOX0_CMD_STAT 0x00019168 +#define __LPU0_HOSTFN3_MBOX0_INFO_MK 0xfffffffe +#define __LPU0_HOSTFN3_MBOX0_INFO_SH 1 +#define __LPU0_HOSTFN3_MBOX0_INFO(_v) ((_v) << __LPU0_HOSTFN3_MBOX0_INFO_SH) +#define __LPU0_HOSTFN3_MBOX0_CMD_STATUS 0x00000001 +#define LPU1_HOSTFN3_MBOX0_CMD_STAT 0x0001916c +#define __LPU1_HOSTFN3_MBOX0_INFO_MK 0xfffffffe +#define __LPU1_HOSTFN3_MBOX0_INFO_SH 1 +#define __LPU1_HOSTFN3_MBOX0_INFO(_v) ((_v) << __LPU1_HOSTFN3_MBOX0_INFO_SH) +#define __LPU1_HOSTFN3_MBOX0_CMD_STATUS 0x00000001 +#define FW_INIT_HALT_P0 0x000191ac +#define __FW_INIT_HALT_P 0x00000001 +#define FW_INIT_HALT_P1 0x000191bc +#define CPE_PI_PTR_Q0 0x00038000 +#define __CPE_PI_UNUSED_MK 0xffff0000 +#define __CPE_PI_UNUSED_SH 16 +#define __CPE_PI_UNUSED(_v) ((_v) << __CPE_PI_UNUSED_SH) +#define __CPE_PI_PTR 0x0000ffff +#define CPE_PI_PTR_Q1 0x00038040 +#define CPE_CI_PTR_Q0 0x00038004 +#define __CPE_CI_UNUSED_MK 0xffff0000 +#define __CPE_CI_UNUSED_SH 16 +#define __CPE_CI_UNUSED(_v) ((_v) << __CPE_CI_UNUSED_SH) +#define __CPE_CI_PTR 0x0000ffff +#define CPE_CI_PTR_Q1 0x00038044 +#define CPE_DEPTH_Q0 0x00038008 +#define __CPE_DEPTH_UNUSED_MK 0xf8000000 +#define __CPE_DEPTH_UNUSED_SH 27 +#define __CPE_DEPTH_UNUSED(_v) ((_v) << __CPE_DEPTH_UNUSED_SH) +#define __CPE_MSIX_VEC_INDEX_MK 0x07ff0000 +#define __CPE_MSIX_VEC_INDEX_SH 16 +#define __CPE_MSIX_VEC_INDEX(_v) ((_v) << __CPE_MSIX_VEC_INDEX_SH) +#define __CPE_DEPTH 0x0000ffff +#define CPE_DEPTH_Q1 0x00038048 +#define CPE_QCTRL_Q0 0x0003800c +#define __CPE_CTRL_UNUSED30_MK 0xfc000000 +#define __CPE_CTRL_UNUSED30_SH 26 +#define __CPE_CTRL_UNUSED30(_v) ((_v) << __CPE_CTRL_UNUSED30_SH) +#define __CPE_FUNC_INT_CTRL_MK 0x03000000 +#define __CPE_FUNC_INT_CTRL_SH 24 +#define __CPE_FUNC_INT_CTRL(_v) ((_v) << __CPE_FUNC_INT_CTRL_SH) +enum { + __CPE_FUNC_INT_CTRL_DISABLE = 0x0, + __CPE_FUNC_INT_CTRL_F2NF = 0x1, + __CPE_FUNC_INT_CTRL_3QUART = 0x2, + __CPE_FUNC_INT_CTRL_HALF = 0x3, +}; +#define __CPE_CTRL_UNUSED20_MK 0x00f00000 +#define __CPE_CTRL_UNUSED20_SH 20 +#define __CPE_CTRL_UNUSED20(_v) ((_v) << __CPE_CTRL_UNUSED20_SH) +#define __CPE_SCI_TH_MK 0x000f0000 +#define __CPE_SCI_TH_SH 16 +#define __CPE_SCI_TH(_v) ((_v) << __CPE_SCI_TH_SH) +#define __CPE_CTRL_UNUSED10_MK 0x0000c000 +#define __CPE_CTRL_UNUSED10_SH 14 +#define __CPE_CTRL_UNUSED10(_v) ((_v) << __CPE_CTRL_UNUSED10_SH) +#define __CPE_ACK_PENDING 0x00002000 +#define __CPE_CTRL_UNUSED40_MK 0x00001c00 +#define __CPE_CTRL_UNUSED40_SH 10 +#define __CPE_CTRL_UNUSED40(_v) ((_v) << __CPE_CTRL_UNUSED40_SH) +#define __CPE_PCIEID_MK 0x00000300 +#define __CPE_PCIEID_SH 8 +#define __CPE_PCIEID(_v) ((_v) << __CPE_PCIEID_SH) +#define __CPE_CTRL_UNUSED00_MK 0x000000fe +#define __CPE_CTRL_UNUSED00_SH 1 +#define __CPE_CTRL_UNUSED00(_v) ((_v) << __CPE_CTRL_UNUSED00_SH) +#define __CPE_ESIZE 0x00000001 +#define CPE_QCTRL_Q1 0x0003804c +#define __CPE_CTRL_UNUSED31_MK 0xfc000000 +#define __CPE_CTRL_UNUSED31_SH 26 +#define __CPE_CTRL_UNUSED31(_v) ((_v) << __CPE_CTRL_UNUSED31_SH) +#define __CPE_CTRL_UNUSED21_MK 0x00f00000 +#define __CPE_CTRL_UNUSED21_SH 20 +#define __CPE_CTRL_UNUSED21(_v) ((_v) << __CPE_CTRL_UNUSED21_SH) +#define __CPE_CTRL_UNUSED11_MK 0x0000c000 +#define __CPE_CTRL_UNUSED11_SH 14 +#define __CPE_CTRL_UNUSED11(_v) ((_v) << __CPE_CTRL_UNUSED11_SH) +#define __CPE_CTRL_UNUSED41_MK 0x00001c00 +#define __CPE_CTRL_UNUSED41_SH 10 +#define __CPE_CTRL_UNUSED41(_v) ((_v) << __CPE_CTRL_UNUSED41_SH) +#define __CPE_CTRL_UNUSED01_MK 0x000000fe +#define __CPE_CTRL_UNUSED01_SH 1 +#define __CPE_CTRL_UNUSED01(_v) ((_v) << __CPE_CTRL_UNUSED01_SH) +#define RME_PI_PTR_Q0 0x00038020 +#define __LATENCY_TIME_STAMP_MK 0xffff0000 +#define __LATENCY_TIME_STAMP_SH 16 +#define __LATENCY_TIME_STAMP(_v) ((_v) << __LATENCY_TIME_STAMP_SH) +#define __RME_PI_PTR 0x0000ffff +#define RME_PI_PTR_Q1 0x00038060 +#define RME_CI_PTR_Q0 0x00038024 +#define __DELAY_TIME_STAMP_MK 0xffff0000 +#define __DELAY_TIME_STAMP_SH 16 +#define __DELAY_TIME_STAMP(_v) ((_v) << __DELAY_TIME_STAMP_SH) +#define __RME_CI_PTR 0x0000ffff +#define RME_CI_PTR_Q1 0x00038064 +#define RME_DEPTH_Q0 0x00038028 +#define __RME_DEPTH_UNUSED_MK 0xf8000000 +#define __RME_DEPTH_UNUSED_SH 27 +#define __RME_DEPTH_UNUSED(_v) ((_v) << __RME_DEPTH_UNUSED_SH) +#define __RME_MSIX_VEC_INDEX_MK 0x07ff0000 +#define __RME_MSIX_VEC_INDEX_SH 16 +#define __RME_MSIX_VEC_INDEX(_v) ((_v) << __RME_MSIX_VEC_INDEX_SH) +#define __RME_DEPTH 0x0000ffff +#define RME_DEPTH_Q1 0x00038068 +#define RME_QCTRL_Q0 0x0003802c +#define __RME_INT_LATENCY_TIMER_MK 0xff000000 +#define __RME_INT_LATENCY_TIMER_SH 24 +#define __RME_INT_LATENCY_TIMER(_v) ((_v) << __RME_INT_LATENCY_TIMER_SH) +#define __RME_INT_DELAY_TIMER_MK 0x00ff0000 +#define __RME_INT_DELAY_TIMER_SH 16 +#define __RME_INT_DELAY_TIMER(_v) ((_v) << __RME_INT_DELAY_TIMER_SH) +#define __RME_INT_DELAY_DISABLE 0x00008000 +#define __RME_DLY_DELAY_DISABLE 0x00004000 +#define __RME_ACK_PENDING 0x00002000 +#define __RME_FULL_INTERRUPT_DISABLE 0x00001000 +#define __RME_CTRL_UNUSED10_MK 0x00000c00 +#define __RME_CTRL_UNUSED10_SH 10 +#define __RME_CTRL_UNUSED10(_v) ((_v) << __RME_CTRL_UNUSED10_SH) +#define __RME_PCIEID_MK 0x00000300 +#define __RME_PCIEID_SH 8 +#define __RME_PCIEID(_v) ((_v) << __RME_PCIEID_SH) +#define __RME_CTRL_UNUSED00_MK 0x000000fe +#define __RME_CTRL_UNUSED00_SH 1 +#define __RME_CTRL_UNUSED00(_v) ((_v) << __RME_CTRL_UNUSED00_SH) +#define __RME_ESIZE 0x00000001 +#define RME_QCTRL_Q1 0x0003806c +#define __RME_CTRL_UNUSED11_MK 0x00000c00 +#define __RME_CTRL_UNUSED11_SH 10 +#define __RME_CTRL_UNUSED11(_v) ((_v) << __RME_CTRL_UNUSED11_SH) +#define __RME_CTRL_UNUSED01_MK 0x000000fe +#define __RME_CTRL_UNUSED01_SH 1 +#define __RME_CTRL_UNUSED01(_v) ((_v) << __RME_CTRL_UNUSED01_SH) +#define PSS_CTL_REG 0x00018800 +#define __PSS_I2C_CLK_DIV_MK 0x007f0000 +#define __PSS_I2C_CLK_DIV_SH 16 +#define __PSS_I2C_CLK_DIV(_v) ((_v) << __PSS_I2C_CLK_DIV_SH) +#define __PSS_LMEM_INIT_DONE 0x00001000 +#define __PSS_LMEM_RESET 0x00000200 +#define __PSS_LMEM_INIT_EN 0x00000100 +#define __PSS_LPU1_RESET 0x00000002 +#define __PSS_LPU0_RESET 0x00000001 +#define PSS_ERR_STATUS_REG 0x00018810 +#define __PSS_LPU1_TCM_READ_ERR 0x00200000 +#define __PSS_LPU0_TCM_READ_ERR 0x00100000 +#define __PSS_LMEM5_CORR_ERR 0x00080000 +#define __PSS_LMEM4_CORR_ERR 0x00040000 +#define __PSS_LMEM3_CORR_ERR 0x00020000 +#define __PSS_LMEM2_CORR_ERR 0x00010000 +#define __PSS_LMEM1_CORR_ERR 0x00008000 +#define __PSS_LMEM0_CORR_ERR 0x00004000 +#define __PSS_LMEM5_UNCORR_ERR 0x00002000 +#define __PSS_LMEM4_UNCORR_ERR 0x00001000 +#define __PSS_LMEM3_UNCORR_ERR 0x00000800 +#define __PSS_LMEM2_UNCORR_ERR 0x00000400 +#define __PSS_LMEM1_UNCORR_ERR 0x00000200 +#define __PSS_LMEM0_UNCORR_ERR 0x00000100 +#define __PSS_BAL_PERR 0x00000080 +#define __PSS_DIP_IF_ERR 0x00000040 +#define __PSS_IOH_IF_ERR 0x00000020 +#define __PSS_TDS_IF_ERR 0x00000010 +#define __PSS_RDS_IF_ERR 0x00000008 +#define __PSS_SGM_IF_ERR 0x00000004 +#define __PSS_LPU1_RAM_ERR 0x00000002 +#define __PSS_LPU0_RAM_ERR 0x00000001 +#define ERR_SET_REG 0x00018818 +#define __PSS_ERR_STATUS_SET 0x003fffff +#define PMM_1T_RESET_REG_P0 0x0002381c +#define __PMM_1T_RESET_P 0x00000001 +#define PMM_1T_RESET_REG_P1 0x00023c1c +#define HQM_QSET0_RXQ_DRBL_P0 0x00038000 +#define __RXQ0_ADD_VECTORS_P 0x80000000 +#define __RXQ0_STOP_P 0x40000000 +#define __RXQ0_PRD_PTR_P 0x0000ffff +#define HQM_QSET1_RXQ_DRBL_P0 0x00038080 +#define __RXQ1_ADD_VECTORS_P 0x80000000 +#define __RXQ1_STOP_P 0x40000000 +#define __RXQ1_PRD_PTR_P 0x0000ffff +#define HQM_QSET0_RXQ_DRBL_P1 0x0003c000 +#define HQM_QSET1_RXQ_DRBL_P1 0x0003c080 +#define HQM_QSET0_TXQ_DRBL_P0 0x00038020 +#define __TXQ0_ADD_VECTORS_P 0x80000000 +#define __TXQ0_STOP_P 0x40000000 +#define __TXQ0_PRD_PTR_P 0x0000ffff +#define HQM_QSET1_TXQ_DRBL_P0 0x000380a0 +#define __TXQ1_ADD_VECTORS_P 0x80000000 +#define __TXQ1_STOP_P 0x40000000 +#define __TXQ1_PRD_PTR_P 0x0000ffff +#define HQM_QSET0_TXQ_DRBL_P1 0x0003c020 +#define HQM_QSET1_TXQ_DRBL_P1 0x0003c0a0 +#define HQM_QSET0_IB_DRBL_1_P0 0x00038040 +#define __IB1_0_ACK_P 0x80000000 +#define __IB1_0_DISABLE_P 0x40000000 +#define __IB1_0_COALESCING_CFG_P_MK 0x00ff0000 +#define __IB1_0_COALESCING_CFG_P_SH 16 +#define __IB1_0_COALESCING_CFG_P(_v) ((_v) << __IB1_0_COALESCING_CFG_P_SH) +#define __IB1_0_NUM_OF_ACKED_EVENTS_P 0x0000ffff +#define HQM_QSET1_IB_DRBL_1_P0 0x000380c0 +#define __IB1_1_ACK_P 0x80000000 +#define __IB1_1_DISABLE_P 0x40000000 +#define __IB1_1_COALESCING_CFG_P_MK 0x00ff0000 +#define __IB1_1_COALESCING_CFG_P_SH 16 +#define __IB1_1_COALESCING_CFG_P(_v) ((_v) << __IB1_1_COALESCING_CFG_P_SH) +#define __IB1_1_NUM_OF_ACKED_EVENTS_P 0x0000ffff +#define HQM_QSET0_IB_DRBL_1_P1 0x0003c040 +#define HQM_QSET1_IB_DRBL_1_P1 0x0003c0c0 +#define HQM_QSET0_IB_DRBL_2_P0 0x00038060 +#define __IB2_0_ACK_P 0x80000000 +#define __IB2_0_DISABLE_P 0x40000000 +#define __IB2_0_COALESCING_CFG_P_MK 0x00ff0000 +#define __IB2_0_COALESCING_CFG_P_SH 16 +#define __IB2_0_COALESCING_CFG_P(_v) ((_v) << __IB2_0_COALESCING_CFG_P_SH) +#define __IB2_0_NUM_OF_ACKED_EVENTS_P 0x0000ffff +#define HQM_QSET1_IB_DRBL_2_P0 0x000380e0 +#define __IB2_1_ACK_P 0x80000000 +#define __IB2_1_DISABLE_P 0x40000000 +#define __IB2_1_COALESCING_CFG_P_MK 0x00ff0000 +#define __IB2_1_COALESCING_CFG_P_SH 16 +#define __IB2_1_COALESCING_CFG_P(_v) ((_v) << __IB2_1_COALESCING_CFG_P_SH) +#define __IB2_1_NUM_OF_ACKED_EVENTS_P 0x0000ffff +#define HQM_QSET0_IB_DRBL_2_P1 0x0003c060 +#define HQM_QSET1_IB_DRBL_2_P1 0x0003c0e0 + + +/* + * These definitions are either in error/missing in spec. Its auto-generated + * from hard coded values in regparse.pl. + */ +#define __EMPHPOST_AT_4G_MK_FIX 0x0000001c +#define __EMPHPOST_AT_4G_SH_FIX 0x00000002 +#define __EMPHPRE_AT_4G_FIX 0x00000003 +#define __SFP_TXRATE_EN_FIX 0x00000100 +#define __SFP_RXRATE_EN_FIX 0x00000080 + + +/* + * These register definitions are auto-generated from hard coded values + * in regparse.pl. + */ + + +/* + * These register mapping definitions are auto-generated from mapping tables + * in regparse.pl. + */ +#define BFA_IOC0_HBEAT_REG HOST_SEM0_INFO_REG +#define BFA_IOC0_STATE_REG HOST_SEM1_INFO_REG +#define BFA_IOC1_HBEAT_REG HOST_SEM2_INFO_REG +#define BFA_IOC1_STATE_REG HOST_SEM3_INFO_REG +#define BFA_FW_USE_COUNT HOST_SEM4_INFO_REG +#define BFA_IOC_FAIL_SYNC HOST_SEM5_INFO_REG + +#define CPE_DEPTH_Q(__n) \ + (CPE_DEPTH_Q0 + (__n) * (CPE_DEPTH_Q1 - CPE_DEPTH_Q0)) +#define CPE_QCTRL_Q(__n) \ + (CPE_QCTRL_Q0 + (__n) * (CPE_QCTRL_Q1 - CPE_QCTRL_Q0)) +#define CPE_PI_PTR_Q(__n) \ + (CPE_PI_PTR_Q0 + (__n) * (CPE_PI_PTR_Q1 - CPE_PI_PTR_Q0)) +#define CPE_CI_PTR_Q(__n) \ + (CPE_CI_PTR_Q0 + (__n) * (CPE_CI_PTR_Q1 - CPE_CI_PTR_Q0)) +#define RME_DEPTH_Q(__n) \ + (RME_DEPTH_Q0 + (__n) * (RME_DEPTH_Q1 - RME_DEPTH_Q0)) +#define RME_QCTRL_Q(__n) \ + (RME_QCTRL_Q0 + (__n) * (RME_QCTRL_Q1 - RME_QCTRL_Q0)) +#define RME_PI_PTR_Q(__n) \ + (RME_PI_PTR_Q0 + (__n) * (RME_PI_PTR_Q1 - RME_PI_PTR_Q0)) +#define RME_CI_PTR_Q(__n) \ + (RME_CI_PTR_Q0 + (__n) * (RME_CI_PTR_Q1 - RME_CI_PTR_Q0)) +#define HQM_QSET_RXQ_DRBL_P0(__n) \ + (HQM_QSET0_RXQ_DRBL_P0 + (__n) * \ + (HQM_QSET1_RXQ_DRBL_P0 - HQM_QSET0_RXQ_DRBL_P0)) +#define HQM_QSET_TXQ_DRBL_P0(__n) \ + (HQM_QSET0_TXQ_DRBL_P0 + (__n) * \ + (HQM_QSET1_TXQ_DRBL_P0 - HQM_QSET0_TXQ_DRBL_P0)) +#define HQM_QSET_IB_DRBL_1_P0(__n) \ + (HQM_QSET0_IB_DRBL_1_P0 + (__n) * \ + (HQM_QSET1_IB_DRBL_1_P0 - HQM_QSET0_IB_DRBL_1_P0)) +#define HQM_QSET_IB_DRBL_2_P0(__n) \ + (HQM_QSET0_IB_DRBL_2_P0 + (__n) * \ + (HQM_QSET1_IB_DRBL_2_P0 - HQM_QSET0_IB_DRBL_2_P0)) +#define HQM_QSET_RXQ_DRBL_P1(__n) \ + (HQM_QSET0_RXQ_DRBL_P1 + (__n) * \ + (HQM_QSET1_RXQ_DRBL_P1 - HQM_QSET0_RXQ_DRBL_P1)) +#define HQM_QSET_TXQ_DRBL_P1(__n) \ + (HQM_QSET0_TXQ_DRBL_P1 + (__n) * \ + (HQM_QSET1_TXQ_DRBL_P1 - HQM_QSET0_TXQ_DRBL_P1)) +#define HQM_QSET_IB_DRBL_1_P1(__n) \ + (HQM_QSET0_IB_DRBL_1_P1 + (__n) * \ + (HQM_QSET1_IB_DRBL_1_P1 - HQM_QSET0_IB_DRBL_1_P1)) +#define HQM_QSET_IB_DRBL_2_P1(__n) \ + (HQM_QSET0_IB_DRBL_2_P1 + (__n) * \ + (HQM_QSET1_IB_DRBL_2_P1 - HQM_QSET0_IB_DRBL_2_P1)) + +#define CPE_Q_NUM(__fn, __q) (((__fn) << 2) + (__q)) +#define RME_Q_NUM(__fn, __q) (((__fn) << 2) + (__q)) +#define CPE_Q_MASK(__q) ((__q) & 0x3) +#define RME_Q_MASK(__q) ((__q) & 0x3) + + +/* + * PCI MSI-X vector defines + */ +enum { + BFA_MSIX_CPE_Q0 = 0, + BFA_MSIX_CPE_Q1 = 1, + BFA_MSIX_CPE_Q2 = 2, + BFA_MSIX_CPE_Q3 = 3, + BFA_MSIX_RME_Q0 = 4, + BFA_MSIX_RME_Q1 = 5, + BFA_MSIX_RME_Q2 = 6, + BFA_MSIX_RME_Q3 = 7, + BFA_MSIX_LPU_ERR = 8, + BFA_MSIX_CT_MAX = 9, +}; + +/* + * And corresponding host interrupt status bit field defines + */ +#define __HFN_INT_CPE_Q0 0x00000001U +#define __HFN_INT_CPE_Q1 0x00000002U +#define __HFN_INT_CPE_Q2 0x00000004U +#define __HFN_INT_CPE_Q3 0x00000008U +#define __HFN_INT_CPE_Q4 0x00000010U +#define __HFN_INT_CPE_Q5 0x00000020U +#define __HFN_INT_CPE_Q6 0x00000040U +#define __HFN_INT_CPE_Q7 0x00000080U +#define __HFN_INT_RME_Q0 0x00000100U +#define __HFN_INT_RME_Q1 0x00000200U +#define __HFN_INT_RME_Q2 0x00000400U +#define __HFN_INT_RME_Q3 0x00000800U +#define __HFN_INT_RME_Q4 0x00001000U +#define __HFN_INT_RME_Q5 0x00002000U +#define __HFN_INT_RME_Q6 0x00004000U +#define __HFN_INT_RME_Q7 0x00008000U +#define __HFN_INT_ERR_EMC 0x00010000U +#define __HFN_INT_ERR_LPU0 0x00020000U +#define __HFN_INT_ERR_LPU1 0x00040000U +#define __HFN_INT_ERR_PSS 0x00080000U +#define __HFN_INT_MBOX_LPU0 0x00100000U +#define __HFN_INT_MBOX_LPU1 0x00200000U +#define __HFN_INT_MBOX1_LPU0 0x00400000U +#define __HFN_INT_MBOX1_LPU1 0x00800000U +#define __HFN_INT_LL_HALT 0x01000000U +#define __HFN_INT_CPE_MASK 0x000000ffU +#define __HFN_INT_RME_MASK 0x0000ff00U + + +/* + * catapult memory map. + */ +#define LL_PGN_HQM0 0x0096 +#define LL_PGN_HQM1 0x0097 +#define PSS_SMEM_PAGE_START 0x8000 +#define PSS_SMEM_PGNUM(_pg0, _ma) ((_pg0) + ((_ma) >> 15)) +#define PSS_SMEM_PGOFF(_ma) ((_ma) & 0x7fff) + +/* + * End of catapult memory map + */ + + +#endif /* __BFI_CTREG_H__ */ diff --git a/trunk/drivers/scsi/bfa/bfi_ms.h b/trunk/drivers/scsi/bfa/bfi_ms.h index 0d9f1fb50db0..19e888a57555 100644 --- a/trunk/drivers/scsi/bfa/bfi_ms.h +++ b/trunk/drivers/scsi/bfa/bfi_ms.h @@ -28,17 +28,11 @@ enum bfi_iocfc_h2i_msgs { BFI_IOCFC_H2I_CFG_REQ = 1, BFI_IOCFC_H2I_SET_INTR_REQ = 2, BFI_IOCFC_H2I_UPDATEQ_REQ = 3, - BFI_IOCFC_H2I_FAA_ENABLE_REQ = 4, - BFI_IOCFC_H2I_FAA_DISABLE_REQ = 5, - BFI_IOCFC_H2I_FAA_QUERY_REQ = 6, }; enum bfi_iocfc_i2h_msgs { BFI_IOCFC_I2H_CFG_REPLY = BFA_I2HM(1), BFI_IOCFC_I2H_UPDATEQ_RSP = BFA_I2HM(3), - BFI_IOCFC_I2H_FAA_ENABLE_RSP = BFA_I2HM(4), - BFI_IOCFC_I2H_FAA_DISABLE_RSP = BFA_I2HM(5), - BFI_IOCFC_I2H_FAA_QUERY_RSP = BFA_I2HM(6), }; struct bfi_iocfc_cfg_s { @@ -46,12 +40,6 @@ struct bfi_iocfc_cfg_s { u8 sense_buf_len; /* SCSI sense length */ u16 rsvd_1; u32 endian_sig; /* endian signature of host */ - u8 rsvd_2; - u8 single_msix_vec; - u8 rsvd[2]; - __be16 num_ioim_reqs; - __be16 num_fwtio_reqs; - /* * Request and response circular queue base addresses, size and @@ -66,8 +54,7 @@ struct bfi_iocfc_cfg_s { union bfi_addr_u stats_addr; /* DMA-able address for stats */ union bfi_addr_u cfgrsp_addr; /* config response dma address */ - union bfi_addr_u ioim_snsbase[BFI_IOIM_SNSBUF_SEGS]; - /* IO sense buf base addr segments */ + union bfi_addr_u ioim_snsbase; /* IO sense buffer base address */ struct bfa_iocfc_intr_attr_s intr_attr; /* IOC interrupt attributes */ }; @@ -81,25 +68,11 @@ struct bfi_iocfc_bootwwns { u8 rsvd[7]; }; -/** - * Queue configuration response from firmware - */ -struct bfi_iocfc_qreg_s { - u32 cpe_q_ci_off[BFI_IOC_MAX_CQS]; - u32 cpe_q_pi_off[BFI_IOC_MAX_CQS]; - u32 cpe_qctl_off[BFI_IOC_MAX_CQS]; - u32 rme_q_ci_off[BFI_IOC_MAX_CQS]; - u32 rme_q_pi_off[BFI_IOC_MAX_CQS]; - u32 rme_qctl_off[BFI_IOC_MAX_CQS]; - u8 hw_qid[BFI_IOC_MAX_CQS]; -}; - struct bfi_iocfc_cfgrsp_s { struct bfa_iocfc_fwcfg_s fwcfg; struct bfa_iocfc_intr_attr_s intr_attr; struct bfi_iocfc_bootwwns bootwwns; struct bfi_pbc_s pbc_cfg; - struct bfi_iocfc_qreg_s qreg; }; /* @@ -177,37 +150,6 @@ union bfi_iocfc_i2h_msg_u { u32 mboxmsg[BFI_IOC_MSGSZ]; }; -/* - * BFI_IOCFC_H2I_FAA_ENABLE_REQ BFI_IOCFC_H2I_FAA_DISABLE_REQ message - */ -struct bfi_faa_en_dis_s { - struct bfi_mhdr_s mh; /* common msg header */ -}; - -/* - * BFI_IOCFC_H2I_FAA_QUERY_REQ message - */ -struct bfi_faa_query_s { - struct bfi_mhdr_s mh; /* common msg header */ - u8 faa_status; /* FAA status */ - u8 addr_source; /* PWWN source */ - u8 rsvd[2]; - wwn_t faa; /* Fabric acquired PWWN */ -}; - -/* - * BFI_IOCFC_I2H_FAA_ENABLE_RSP, BFI_IOCFC_I2H_FAA_DISABLE_RSP message - */ -struct bfi_faa_en_dis_rsp_s { - struct bfi_mhdr_s mh; /* common msg header */ - u8 status; /* updateq status */ - u8 rsvd[3]; -}; - -/* - * BFI_IOCFC_I2H_FAA_QUERY_RSP message - */ -#define bfi_faa_query_rsp_t struct bfi_faa_query_s enum bfi_fcport_h2i { BFI_FCPORT_H2I_ENABLE_REQ = (1), @@ -271,8 +213,7 @@ struct bfi_fcport_enable_req_s { struct bfi_fcport_set_svc_params_req_s { struct bfi_mhdr_s mh; /* msg header */ __be16 tx_bbcredit; /* Tx credits */ - u8 bb_scn; /* BB_SC FC credit recovery */ - u8 rsvd; + u16 rsvd; }; /* @@ -352,12 +293,12 @@ struct bfi_fcxp_send_req_s { u8 class; /* FC class used for req/rsp */ u8 rsp_timeout; /* timeout in secs, 0-no response */ u8 cts; /* continue sequence */ - u8 lp_fwtag; /* lport tag */ + u8 lp_tag; /* lport tag */ struct fchs_s fchs; /* request FC header structure */ __be32 req_len; /* request payload length */ __be32 rsp_maxlen; /* max response length expected */ - struct bfi_alen_s req_alen; /* request buffer */ - struct bfi_alen_s rsp_alen; /* response buffer */ + struct bfi_sge_s req_sge[BFA_FCXP_MAX_SGES]; /* request buf */ + struct bfi_sge_s rsp_sge[BFA_FCXP_MAX_SGES]; /* response buf */ }; /* @@ -387,7 +328,7 @@ struct bfi_uf_buf_post_s { struct bfi_mhdr_s mh; /* Common msg header */ u16 buf_tag; /* buffer tag */ __be16 buf_len; /* total buffer length */ - struct bfi_alen_s alen; /* buffer address/len pair */ + struct bfi_sge_s sge[BFA_UF_MAX_SGES]; /* buffer DMA SGEs */ }; struct bfi_uf_frm_rcvd_s { @@ -405,27 +346,26 @@ enum bfi_lps_h2i_msgs { }; enum bfi_lps_i2h_msgs { - BFI_LPS_I2H_LOGIN_RSP = BFA_I2HM(1), - BFI_LPS_I2H_LOGOUT_RSP = BFA_I2HM(2), - BFI_LPS_I2H_CVL_EVENT = BFA_I2HM(3), + BFI_LPS_H2I_LOGIN_RSP = BFA_I2HM(1), + BFI_LPS_H2I_LOGOUT_RSP = BFA_I2HM(2), + BFI_LPS_H2I_CVL_EVENT = BFA_I2HM(3), }; struct bfi_lps_login_req_s { struct bfi_mhdr_s mh; /* common msg header */ - u8 bfa_tag; + u8 lp_tag; u8 alpa; __be16 pdu_size; wwn_t pwwn; wwn_t nwwn; u8 fdisc; u8 auth_en; - u8 lps_role; - u8 bb_scn; + u8 rsvd[2]; }; struct bfi_lps_login_rsp_s { struct bfi_mhdr_s mh; /* common msg header */ - u8 fw_tag; + u8 lp_tag; u8 status; u8 lsrjt_rsn; u8 lsrjt_expl; @@ -440,33 +380,31 @@ struct bfi_lps_login_rsp_s { mac_t fcf_mac; u8 ext_status; u8 brcd_switch; /* attached peer is brcd switch */ - u8 bb_scn; /* atatched port's bb_scn */ - u8 bfa_tag; }; struct bfi_lps_logout_req_s { struct bfi_mhdr_s mh; /* common msg header */ - u8 fw_tag; + u8 lp_tag; u8 rsvd[3]; wwn_t port_name; }; struct bfi_lps_logout_rsp_s { struct bfi_mhdr_s mh; /* common msg header */ - u8 bfa_tag; + u8 lp_tag; u8 status; u8 rsvd[2]; }; struct bfi_lps_cvl_event_s { struct bfi_mhdr_s mh; /* common msg header */ - u8 bfa_tag; + u8 lp_tag; u8 rsvd[3]; }; struct bfi_lps_n2n_pid_req_s { struct bfi_mhdr_s mh; /* common msg header */ - u8 fw_tag; + u8 lp_tag; u32 lp_pid:24; }; @@ -501,7 +439,7 @@ struct bfi_rport_create_req_s { u16 bfa_handle; /* host rport handle */ __be16 max_frmsz; /* max rcv pdu size */ u32 pid:24, /* remote port ID */ - lp_fwtag:8; /* local port tag */ + lp_tag:8; /* local port tag */ u32 local_pid:24, /* local port ID */ cisc:8; u8 fc_class; /* supported FC classes */ @@ -564,63 +502,62 @@ union bfi_rport_i2h_msg_u { * Initiator mode I-T nexus interface defines. */ -enum bfi_itn_h2i { - BFI_ITN_H2I_CREATE_REQ = 1, /* i-t nexus creation */ - BFI_ITN_H2I_DELETE_REQ = 2, /* i-t nexus deletion */ +enum bfi_itnim_h2i { + BFI_ITNIM_H2I_CREATE_REQ = 1, /* i-t nexus creation */ + BFI_ITNIM_H2I_DELETE_REQ = 2, /* i-t nexus deletion */ }; -enum bfi_itn_i2h { - BFI_ITN_I2H_CREATE_RSP = BFA_I2HM(1), - BFI_ITN_I2H_DELETE_RSP = BFA_I2HM(2), - BFI_ITN_I2H_SLER_EVENT = BFA_I2HM(3), +enum bfi_itnim_i2h { + BFI_ITNIM_I2H_CREATE_RSP = BFA_I2HM(1), + BFI_ITNIM_I2H_DELETE_RSP = BFA_I2HM(2), + BFI_ITNIM_I2H_SLER_EVENT = BFA_I2HM(3), }; -struct bfi_itn_create_req_s { +struct bfi_itnim_create_req_s { struct bfi_mhdr_s mh; /* common msg header */ u16 fw_handle; /* f/w handle for itnim */ u8 class; /* FC class for IO */ u8 seq_rec; /* sequence recovery support */ u8 msg_no; /* seq id of the msg */ - u8 role; }; -struct bfi_itn_create_rsp_s { +struct bfi_itnim_create_rsp_s { struct bfi_mhdr_s mh; /* common msg header */ u16 bfa_handle; /* bfa handle for itnim */ u8 status; /* fcp request status */ u8 seq_id; /* seq id of the msg */ }; -struct bfi_itn_delete_req_s { +struct bfi_itnim_delete_req_s { struct bfi_mhdr_s mh; /* common msg header */ u16 fw_handle; /* f/w itnim handle */ u8 seq_id; /* seq id of the msg */ u8 rsvd; }; -struct bfi_itn_delete_rsp_s { +struct bfi_itnim_delete_rsp_s { struct bfi_mhdr_s mh; /* common msg header */ u16 bfa_handle; /* bfa handle for itnim */ u8 status; /* fcp request status */ u8 seq_id; /* seq id of the msg */ }; -struct bfi_itn_sler_event_s { +struct bfi_itnim_sler_event_s { struct bfi_mhdr_s mh; /* common msg header */ u16 bfa_handle; /* bfa handle for itnim */ u16 rsvd; }; -union bfi_itn_h2i_msg_u { - struct bfi_itn_create_req_s *create_req; - struct bfi_itn_delete_req_s *delete_req; +union bfi_itnim_h2i_msg_u { + struct bfi_itnim_create_req_s *create_req; + struct bfi_itnim_delete_req_s *delete_req; struct bfi_msg_s *msg; }; -union bfi_itn_i2h_msg_u { - struct bfi_itn_create_rsp_s *create_rsp; - struct bfi_itn_delete_rsp_s *delete_rsp; - struct bfi_itn_sler_event_s *sler_event; +union bfi_itnim_i2h_msg_u { + struct bfi_itnim_create_rsp_s *create_rsp; + struct bfi_itnim_delete_rsp_s *delete_rsp; + struct bfi_itnim_sler_event_s *sler_event; struct bfi_msg_s *msg; }; @@ -756,6 +693,7 @@ enum bfi_ioim_status { BFI_IOIM_STS_PATHTOV = 8, }; +#define BFI_IOIM_SNSLEN (256) /* * I/O response message */ @@ -834,27 +772,4 @@ struct bfi_tskim_rsp_s { #pragma pack() -/* - * Crossbow PCI MSI-X vector defines - */ -enum { - BFI_MSIX_CPE_QMIN_CB = 0, - BFI_MSIX_CPE_QMAX_CB = 7, - BFI_MSIX_RME_QMIN_CB = 8, - BFI_MSIX_RME_QMAX_CB = 15, - BFI_MSIX_CB_MAX = 22, -}; - -/* - * Catapult FC PCI MSI-X vector defines - */ -enum { - BFI_MSIX_LPU_ERR_CT = 0, - BFI_MSIX_CPE_QMIN_CT = 1, - BFI_MSIX_CPE_QMAX_CT = 4, - BFI_MSIX_RME_QMIN_CT = 5, - BFI_MSIX_RME_QMAX_CT = 8, - BFI_MSIX_CT_MAX = 9, -}; - #endif /* __BFI_MS_H__ */ diff --git a/trunk/drivers/scsi/bfa/bfi_reg.h b/trunk/drivers/scsi/bfa/bfi_reg.h deleted file mode 100644 index d892064b64a8..000000000000 --- a/trunk/drivers/scsi/bfa/bfi_reg.h +++ /dev/null @@ -1,450 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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. - */ - -/* - * bfi_reg.h ASIC register defines for all Brocade adapter ASICs - */ - -#ifndef __BFI_REG_H__ -#define __BFI_REG_H__ - -#define HOSTFN0_INT_STATUS 0x00014000 /* cb/ct */ -#define HOSTFN1_INT_STATUS 0x00014100 /* cb/ct */ -#define HOSTFN2_INT_STATUS 0x00014300 /* ct */ -#define HOSTFN3_INT_STATUS 0x00014400 /* ct */ -#define HOSTFN0_INT_MSK 0x00014004 /* cb/ct */ -#define HOSTFN1_INT_MSK 0x00014104 /* cb/ct */ -#define HOSTFN2_INT_MSK 0x00014304 /* ct */ -#define HOSTFN3_INT_MSK 0x00014404 /* ct */ - -#define HOST_PAGE_NUM_FN0 0x00014008 /* cb/ct */ -#define HOST_PAGE_NUM_FN1 0x00014108 /* cb/ct */ -#define HOST_PAGE_NUM_FN2 0x00014308 /* ct */ -#define HOST_PAGE_NUM_FN3 0x00014408 /* ct */ - -#define APP_PLL_LCLK_CTL_REG 0x00014204 /* cb/ct */ -#define __P_LCLK_PLL_LOCK 0x80000000 -#define __APP_PLL_LCLK_SRAM_USE_100MHZ 0x00100000 -#define __APP_PLL_LCLK_RESET_TIMER_MK 0x000e0000 -#define __APP_PLL_LCLK_RESET_TIMER_SH 17 -#define __APP_PLL_LCLK_RESET_TIMER(_v) ((_v) << __APP_PLL_LCLK_RESET_TIMER_SH) -#define __APP_PLL_LCLK_LOGIC_SOFT_RESET 0x00010000 -#define __APP_PLL_LCLK_CNTLMT0_1_MK 0x0000c000 -#define __APP_PLL_LCLK_CNTLMT0_1_SH 14 -#define __APP_PLL_LCLK_CNTLMT0_1(_v) ((_v) << __APP_PLL_LCLK_CNTLMT0_1_SH) -#define __APP_PLL_LCLK_JITLMT0_1_MK 0x00003000 -#define __APP_PLL_LCLK_JITLMT0_1_SH 12 -#define __APP_PLL_LCLK_JITLMT0_1(_v) ((_v) << __APP_PLL_LCLK_JITLMT0_1_SH) -#define __APP_PLL_LCLK_HREF 0x00000800 -#define __APP_PLL_LCLK_HDIV 0x00000400 -#define __APP_PLL_LCLK_P0_1_MK 0x00000300 -#define __APP_PLL_LCLK_P0_1_SH 8 -#define __APP_PLL_LCLK_P0_1(_v) ((_v) << __APP_PLL_LCLK_P0_1_SH) -#define __APP_PLL_LCLK_Z0_2_MK 0x000000e0 -#define __APP_PLL_LCLK_Z0_2_SH 5 -#define __APP_PLL_LCLK_Z0_2(_v) ((_v) << __APP_PLL_LCLK_Z0_2_SH) -#define __APP_PLL_LCLK_RSEL200500 0x00000010 -#define __APP_PLL_LCLK_ENARST 0x00000008 -#define __APP_PLL_LCLK_BYPASS 0x00000004 -#define __APP_PLL_LCLK_LRESETN 0x00000002 -#define __APP_PLL_LCLK_ENABLE 0x00000001 -#define APP_PLL_SCLK_CTL_REG 0x00014208 /* cb/ct */ -#define __P_SCLK_PLL_LOCK 0x80000000 -#define __APP_PLL_SCLK_RESET_TIMER_MK 0x000e0000 -#define __APP_PLL_SCLK_RESET_TIMER_SH 17 -#define __APP_PLL_SCLK_RESET_TIMER(_v) ((_v) << __APP_PLL_SCLK_RESET_TIMER_SH) -#define __APP_PLL_SCLK_LOGIC_SOFT_RESET 0x00010000 -#define __APP_PLL_SCLK_CNTLMT0_1_MK 0x0000c000 -#define __APP_PLL_SCLK_CNTLMT0_1_SH 14 -#define __APP_PLL_SCLK_CNTLMT0_1(_v) ((_v) << __APP_PLL_SCLK_CNTLMT0_1_SH) -#define __APP_PLL_SCLK_JITLMT0_1_MK 0x00003000 -#define __APP_PLL_SCLK_JITLMT0_1_SH 12 -#define __APP_PLL_SCLK_JITLMT0_1(_v) ((_v) << __APP_PLL_SCLK_JITLMT0_1_SH) -#define __APP_PLL_SCLK_HREF 0x00000800 -#define __APP_PLL_SCLK_HDIV 0x00000400 -#define __APP_PLL_SCLK_P0_1_MK 0x00000300 -#define __APP_PLL_SCLK_P0_1_SH 8 -#define __APP_PLL_SCLK_P0_1(_v) ((_v) << __APP_PLL_SCLK_P0_1_SH) -#define __APP_PLL_SCLK_Z0_2_MK 0x000000e0 -#define __APP_PLL_SCLK_Z0_2_SH 5 -#define __APP_PLL_SCLK_Z0_2(_v) ((_v) << __APP_PLL_SCLK_Z0_2_SH) -#define __APP_PLL_SCLK_RSEL200500 0x00000010 -#define __APP_PLL_SCLK_ENARST 0x00000008 -#define __APP_PLL_SCLK_BYPASS 0x00000004 -#define __APP_PLL_SCLK_LRESETN 0x00000002 -#define __APP_PLL_SCLK_ENABLE 0x00000001 -#define __ENABLE_MAC_AHB_1 0x00800000 /* ct */ -#define __ENABLE_MAC_AHB_0 0x00400000 /* ct */ -#define __ENABLE_MAC_1 0x00200000 /* ct */ -#define __ENABLE_MAC_0 0x00100000 /* ct */ - -#define HOST_SEM0_REG 0x00014230 /* cb/ct */ -#define HOST_SEM1_REG 0x00014234 /* cb/ct */ -#define HOST_SEM2_REG 0x00014238 /* cb/ct */ -#define HOST_SEM3_REG 0x0001423c /* cb/ct */ -#define HOST_SEM4_REG 0x00014610 /* cb/ct */ -#define HOST_SEM5_REG 0x00014614 /* cb/ct */ -#define HOST_SEM6_REG 0x00014618 /* cb/ct */ -#define HOST_SEM7_REG 0x0001461c /* cb/ct */ -#define HOST_SEM0_INFO_REG 0x00014240 /* cb/ct */ -#define HOST_SEM1_INFO_REG 0x00014244 /* cb/ct */ -#define HOST_SEM2_INFO_REG 0x00014248 /* cb/ct */ -#define HOST_SEM3_INFO_REG 0x0001424c /* cb/ct */ -#define HOST_SEM4_INFO_REG 0x00014620 /* cb/ct */ -#define HOST_SEM5_INFO_REG 0x00014624 /* cb/ct */ -#define HOST_SEM6_INFO_REG 0x00014628 /* cb/ct */ -#define HOST_SEM7_INFO_REG 0x0001462c /* cb/ct */ - -#define HOSTFN0_LPU0_CMD_STAT 0x00019000 /* cb/ct */ -#define HOSTFN0_LPU1_CMD_STAT 0x00019004 /* cb/ct */ -#define HOSTFN1_LPU0_CMD_STAT 0x00019010 /* cb/ct */ -#define HOSTFN1_LPU1_CMD_STAT 0x00019014 /* cb/ct */ -#define HOSTFN2_LPU0_CMD_STAT 0x00019150 /* ct */ -#define HOSTFN2_LPU1_CMD_STAT 0x00019154 /* ct */ -#define HOSTFN3_LPU0_CMD_STAT 0x00019160 /* ct */ -#define HOSTFN3_LPU1_CMD_STAT 0x00019164 /* ct */ -#define LPU0_HOSTFN0_CMD_STAT 0x00019008 /* cb/ct */ -#define LPU1_HOSTFN0_CMD_STAT 0x0001900c /* cb/ct */ -#define LPU0_HOSTFN1_CMD_STAT 0x00019018 /* cb/ct */ -#define LPU1_HOSTFN1_CMD_STAT 0x0001901c /* cb/ct */ -#define LPU0_HOSTFN2_CMD_STAT 0x00019158 /* ct */ -#define LPU1_HOSTFN2_CMD_STAT 0x0001915c /* ct */ -#define LPU0_HOSTFN3_CMD_STAT 0x00019168 /* ct */ -#define LPU1_HOSTFN3_CMD_STAT 0x0001916c /* ct */ - -#define PSS_CTL_REG 0x00018800 /* cb/ct */ -#define __PSS_I2C_CLK_DIV_MK 0x007f0000 -#define __PSS_I2C_CLK_DIV_SH 16 -#define __PSS_I2C_CLK_DIV(_v) ((_v) << __PSS_I2C_CLK_DIV_SH) -#define __PSS_LMEM_INIT_DONE 0x00001000 -#define __PSS_LMEM_RESET 0x00000200 -#define __PSS_LMEM_INIT_EN 0x00000100 -#define __PSS_LPU1_RESET 0x00000002 -#define __PSS_LPU0_RESET 0x00000001 -#define PSS_ERR_STATUS_REG 0x00018810 /* cb/ct */ -#define ERR_SET_REG 0x00018818 /* cb/ct */ -#define PSS_GPIO_OUT_REG 0x000188c0 /* cb/ct */ -#define __PSS_GPIO_OUT_REG 0x00000fff -#define PSS_GPIO_OE_REG 0x000188c8 /* cb/ct */ -#define __PSS_GPIO_OE_REG 0x000000ff - -#define HOSTFN0_LPU_MBOX0_0 0x00019200 /* cb/ct */ -#define HOSTFN1_LPU_MBOX0_8 0x00019260 /* cb/ct */ -#define LPU_HOSTFN0_MBOX0_0 0x00019280 /* cb/ct */ -#define LPU_HOSTFN1_MBOX0_8 0x000192e0 /* cb/ct */ -#define HOSTFN2_LPU_MBOX0_0 0x00019400 /* ct */ -#define HOSTFN3_LPU_MBOX0_8 0x00019460 /* ct */ -#define LPU_HOSTFN2_MBOX0_0 0x00019480 /* ct */ -#define LPU_HOSTFN3_MBOX0_8 0x000194e0 /* ct */ - -#define HOST_MSIX_ERR_INDEX_FN0 0x0001400c /* ct */ -#define HOST_MSIX_ERR_INDEX_FN1 0x0001410c /* ct */ -#define HOST_MSIX_ERR_INDEX_FN2 0x0001430c /* ct */ -#define HOST_MSIX_ERR_INDEX_FN3 0x0001440c /* ct */ - -#define MBIST_CTL_REG 0x00014220 /* ct */ -#define __EDRAM_BISTR_START 0x00000004 -#define MBIST_STAT_REG 0x00014224 /* ct */ -#define ETH_MAC_SER_REG 0x00014288 /* ct */ -#define __APP_EMS_CKBUFAMPIN 0x00000020 -#define __APP_EMS_REFCLKSEL 0x00000010 -#define __APP_EMS_CMLCKSEL 0x00000008 -#define __APP_EMS_REFCKBUFEN2 0x00000004 -#define __APP_EMS_REFCKBUFEN1 0x00000002 -#define __APP_EMS_CHANNEL_SEL 0x00000001 -#define FNC_PERS_REG 0x00014604 /* ct */ -#define __F3_FUNCTION_ACTIVE 0x80000000 -#define __F3_FUNCTION_MODE 0x40000000 -#define __F3_PORT_MAP_MK 0x30000000 -#define __F3_PORT_MAP_SH 28 -#define __F3_PORT_MAP(_v) ((_v) << __F3_PORT_MAP_SH) -#define __F3_VM_MODE 0x08000000 -#define __F3_INTX_STATUS_MK 0x07000000 -#define __F3_INTX_STATUS_SH 24 -#define __F3_INTX_STATUS(_v) ((_v) << __F3_INTX_STATUS_SH) -#define __F2_FUNCTION_ACTIVE 0x00800000 -#define __F2_FUNCTION_MODE 0x00400000 -#define __F2_PORT_MAP_MK 0x00300000 -#define __F2_PORT_MAP_SH 20 -#define __F2_PORT_MAP(_v) ((_v) << __F2_PORT_MAP_SH) -#define __F2_VM_MODE 0x00080000 -#define __F2_INTX_STATUS_MK 0x00070000 -#define __F2_INTX_STATUS_SH 16 -#define __F2_INTX_STATUS(_v) ((_v) << __F2_INTX_STATUS_SH) -#define __F1_FUNCTION_ACTIVE 0x00008000 -#define __F1_FUNCTION_MODE 0x00004000 -#define __F1_PORT_MAP_MK 0x00003000 -#define __F1_PORT_MAP_SH 12 -#define __F1_PORT_MAP(_v) ((_v) << __F1_PORT_MAP_SH) -#define __F1_VM_MODE 0x00000800 -#define __F1_INTX_STATUS_MK 0x00000700 -#define __F1_INTX_STATUS_SH 8 -#define __F1_INTX_STATUS(_v) ((_v) << __F1_INTX_STATUS_SH) -#define __F0_FUNCTION_ACTIVE 0x00000080 -#define __F0_FUNCTION_MODE 0x00000040 -#define __F0_PORT_MAP_MK 0x00000030 -#define __F0_PORT_MAP_SH 4 -#define __F0_PORT_MAP(_v) ((_v) << __F0_PORT_MAP_SH) -#define __F0_VM_MODE 0x00000008 -#define __F0_INTX_STATUS 0x00000007 -enum { - __F0_INTX_STATUS_MSIX = 0x0, - __F0_INTX_STATUS_INTA = 0x1, - __F0_INTX_STATUS_INTB = 0x2, - __F0_INTX_STATUS_INTC = 0x3, - __F0_INTX_STATUS_INTD = 0x4, -}; - -#define OP_MODE 0x0001460c /* ct */ -#define __APP_ETH_CLK_LOWSPEED 0x00000004 -#define __GLOBAL_CORECLK_HALFSPEED 0x00000002 -#define __GLOBAL_FCOE_MODE 0x00000001 -#define FW_INIT_HALT_P0 0x000191ac /* ct */ -#define __FW_INIT_HALT_P 0x00000001 -#define FW_INIT_HALT_P1 0x000191bc /* ct */ -#define PMM_1T_RESET_REG_P0 0x0002381c /* ct */ -#define __PMM_1T_RESET_P 0x00000001 -#define PMM_1T_RESET_REG_P1 0x00023c1c /* ct */ - -/** - * Catapult-2 specific defines - */ -#define CT2_PCI_CPQ_BASE 0x00030000 -#define CT2_PCI_APP_BASE 0x00030100 -#define CT2_PCI_ETH_BASE 0x00030400 - -/* - * APP block registers - */ -#define CT2_HOSTFN_INT_STATUS (CT2_PCI_APP_BASE + 0x00) -#define CT2_HOSTFN_INTR_MASK (CT2_PCI_APP_BASE + 0x04) -#define CT2_HOSTFN_PERSONALITY0 (CT2_PCI_APP_BASE + 0x08) -#define __PME_STATUS_ 0x00200000 -#define __PF_VF_BAR_SIZE_MODE__MK 0x00180000 -#define __PF_VF_BAR_SIZE_MODE__SH 19 -#define __PF_VF_BAR_SIZE_MODE_(_v) ((_v) << __PF_VF_BAR_SIZE_MODE__SH) -#define __FC_LL_PORT_MAP__MK 0x00060000 -#define __FC_LL_PORT_MAP__SH 17 -#define __FC_LL_PORT_MAP_(_v) ((_v) << __FC_LL_PORT_MAP__SH) -#define __PF_VF_ACTIVE_ 0x00010000 -#define __PF_VF_CFG_RDY_ 0x00008000 -#define __PF_VF_ENABLE_ 0x00004000 -#define __PF_DRIVER_ACTIVE_ 0x00002000 -#define __PF_PME_SEND_ENABLE_ 0x00001000 -#define __PF_EXROM_OFFSET__MK 0x00000ff0 -#define __PF_EXROM_OFFSET__SH 4 -#define __PF_EXROM_OFFSET_(_v) ((_v) << __PF_EXROM_OFFSET__SH) -#define __FC_LL_MODE_ 0x00000008 -#define __PF_INTX_PIN_ 0x00000007 -#define CT2_HOSTFN_PERSONALITY1 (CT2_PCI_APP_BASE + 0x0C) -#define __PF_NUM_QUEUES1__MK 0xff000000 -#define __PF_NUM_QUEUES1__SH 24 -#define __PF_NUM_QUEUES1_(_v) ((_v) << __PF_NUM_QUEUES1__SH) -#define __PF_VF_QUE_OFFSET1__MK 0x00ff0000 -#define __PF_VF_QUE_OFFSET1__SH 16 -#define __PF_VF_QUE_OFFSET1_(_v) ((_v) << __PF_VF_QUE_OFFSET1__SH) -#define __PF_VF_NUM_QUEUES__MK 0x0000ff00 -#define __PF_VF_NUM_QUEUES__SH 8 -#define __PF_VF_NUM_QUEUES_(_v) ((_v) << __PF_VF_NUM_QUEUES__SH) -#define __PF_VF_QUE_OFFSET_ 0x000000ff -#define CT2_HOSTFN_PAGE_NUM (CT2_PCI_APP_BASE + 0x18) -#define CT2_HOSTFN_MSIX_VT_INDEX_MBOX_ERR (CT2_PCI_APP_BASE + 0x38) - -/* - * Catapult-2 CPQ block registers - */ -#define CT2_HOSTFN_LPU0_MBOX0 (CT2_PCI_CPQ_BASE + 0x00) -#define CT2_HOSTFN_LPU1_MBOX0 (CT2_PCI_CPQ_BASE + 0x20) -#define CT2_LPU0_HOSTFN_MBOX0 (CT2_PCI_CPQ_BASE + 0x40) -#define CT2_LPU1_HOSTFN_MBOX0 (CT2_PCI_CPQ_BASE + 0x60) -#define CT2_HOSTFN_LPU0_CMD_STAT (CT2_PCI_CPQ_BASE + 0x80) -#define CT2_HOSTFN_LPU1_CMD_STAT (CT2_PCI_CPQ_BASE + 0x84) -#define CT2_LPU0_HOSTFN_CMD_STAT (CT2_PCI_CPQ_BASE + 0x88) -#define CT2_LPU1_HOSTFN_CMD_STAT (CT2_PCI_CPQ_BASE + 0x8c) -#define CT2_HOSTFN_LPU0_READ_STAT (CT2_PCI_CPQ_BASE + 0x90) -#define CT2_HOSTFN_LPU1_READ_STAT (CT2_PCI_CPQ_BASE + 0x94) -#define CT2_LPU0_HOSTFN_MBOX0_MSK (CT2_PCI_CPQ_BASE + 0x98) -#define CT2_LPU1_HOSTFN_MBOX0_MSK (CT2_PCI_CPQ_BASE + 0x9C) -#define CT2_HOST_SEM0_REG 0x000148f0 -#define CT2_HOST_SEM1_REG 0x000148f4 -#define CT2_HOST_SEM2_REG 0x000148f8 -#define CT2_HOST_SEM3_REG 0x000148fc -#define CT2_HOST_SEM4_REG 0x00014900 -#define CT2_HOST_SEM5_REG 0x00014904 -#define CT2_HOST_SEM6_REG 0x00014908 -#define CT2_HOST_SEM7_REG 0x0001490c -#define CT2_HOST_SEM0_INFO_REG 0x000148b0 -#define CT2_HOST_SEM1_INFO_REG 0x000148b4 -#define CT2_HOST_SEM2_INFO_REG 0x000148b8 -#define CT2_HOST_SEM3_INFO_REG 0x000148bc -#define CT2_HOST_SEM4_INFO_REG 0x000148c0 -#define CT2_HOST_SEM5_INFO_REG 0x000148c4 -#define CT2_HOST_SEM6_INFO_REG 0x000148c8 -#define CT2_HOST_SEM7_INFO_REG 0x000148cc - -#define CT2_APP_PLL_LCLK_CTL_REG 0x00014808 -#define __APP_LPUCLK_HALFSPEED 0x40000000 -#define __APP_PLL_LCLK_LOAD 0x20000000 -#define __APP_PLL_LCLK_FBCNT_MK 0x1fe00000 -#define __APP_PLL_LCLK_FBCNT_SH 21 -#define __APP_PLL_LCLK_FBCNT(_v) ((_v) << __APP_PLL_SCLK_FBCNT_SH) -enum { - __APP_PLL_LCLK_FBCNT_425_MHZ = 6, - __APP_PLL_LCLK_FBCNT_468_MHZ = 4, -}; -#define __APP_PLL_LCLK_EXTFB 0x00000800 -#define __APP_PLL_LCLK_ENOUTS 0x00000400 -#define __APP_PLL_LCLK_RATE 0x00000010 -#define CT2_APP_PLL_SCLK_CTL_REG 0x0001480c -#define __P_SCLK_PLL_LOCK 0x80000000 -#define __APP_PLL_SCLK_REFCLK_SEL 0x40000000 -#define __APP_PLL_SCLK_CLK_DIV2 0x20000000 -#define __APP_PLL_SCLK_LOAD 0x10000000 -#define __APP_PLL_SCLK_FBCNT_MK 0x0ff00000 -#define __APP_PLL_SCLK_FBCNT_SH 20 -#define __APP_PLL_SCLK_FBCNT(_v) ((_v) << __APP_PLL_SCLK_FBCNT_SH) -enum { - __APP_PLL_SCLK_FBCNT_NORM = 6, - __APP_PLL_SCLK_FBCNT_10G_FC = 10, -}; -#define __APP_PLL_SCLK_EXTFB 0x00000800 -#define __APP_PLL_SCLK_ENOUTS 0x00000400 -#define __APP_PLL_SCLK_RATE 0x00000010 -#define CT2_PCIE_MISC_REG 0x00014804 -#define __ETH_CLK_ENABLE_PORT1 0x00000010 -#define CT2_CHIP_MISC_PRG 0x000148a4 -#define __ETH_CLK_ENABLE_PORT0 0x00004000 -#define __APP_LPU_SPEED 0x00000002 -#define CT2_MBIST_STAT_REG 0x00014818 -#define CT2_MBIST_CTL_REG 0x0001481c -#define CT2_PMM_1T_CONTROL_REG_P0 0x0002381c -#define __PMM_1T_PNDB_P 0x00000002 -#define CT2_PMM_1T_CONTROL_REG_P1 0x00023c1c -#define CT2_WGN_STATUS 0x00014990 -#define __WGN_READY 0x00000400 -#define __GLBL_PF_VF_CFG_RDY 0x00000200 -#define CT2_NFC_CSR_SET_REG 0x00027424 -#define __HALT_NFC_CONTROLLER 0x00000002 -#define __NFC_CONTROLLER_HALTED 0x00001000 - -#define CT2_CSI_MAC0_CONTROL_REG 0x000270d0 -#define __CSI_MAC_RESET 0x00000010 -#define __CSI_MAC_AHB_RESET 0x00000008 -#define CT2_CSI_MAC1_CONTROL_REG 0x000270d4 -#define CT2_CSI_MAC_CONTROL_REG(__n) \ - (CT2_CSI_MAC0_CONTROL_REG + \ - (__n) * (CT2_CSI_MAC1_CONTROL_REG - CT2_CSI_MAC0_CONTROL_REG)) - -/* - * Name semaphore registers based on usage - */ -#define BFA_IOC0_HBEAT_REG HOST_SEM0_INFO_REG -#define BFA_IOC0_STATE_REG HOST_SEM1_INFO_REG -#define BFA_IOC1_HBEAT_REG HOST_SEM2_INFO_REG -#define BFA_IOC1_STATE_REG HOST_SEM3_INFO_REG -#define BFA_FW_USE_COUNT HOST_SEM4_INFO_REG -#define BFA_IOC_FAIL_SYNC HOST_SEM5_INFO_REG - -/* - * CT2 semaphore register locations changed - */ -#define CT2_BFA_IOC0_HBEAT_REG CT2_HOST_SEM0_INFO_REG -#define CT2_BFA_IOC0_STATE_REG CT2_HOST_SEM1_INFO_REG -#define CT2_BFA_IOC1_HBEAT_REG CT2_HOST_SEM2_INFO_REG -#define CT2_BFA_IOC1_STATE_REG CT2_HOST_SEM3_INFO_REG -#define CT2_BFA_FW_USE_COUNT CT2_HOST_SEM4_INFO_REG -#define CT2_BFA_IOC_FAIL_SYNC CT2_HOST_SEM5_INFO_REG - -#define CPE_Q_NUM(__fn, __q) (((__fn) << 2) + (__q)) -#define RME_Q_NUM(__fn, __q) (((__fn) << 2) + (__q)) - -/* - * And corresponding host interrupt status bit field defines - */ -#define __HFN_INT_CPE_Q0 0x00000001U -#define __HFN_INT_CPE_Q1 0x00000002U -#define __HFN_INT_CPE_Q2 0x00000004U -#define __HFN_INT_CPE_Q3 0x00000008U -#define __HFN_INT_CPE_Q4 0x00000010U -#define __HFN_INT_CPE_Q5 0x00000020U -#define __HFN_INT_CPE_Q6 0x00000040U -#define __HFN_INT_CPE_Q7 0x00000080U -#define __HFN_INT_RME_Q0 0x00000100U -#define __HFN_INT_RME_Q1 0x00000200U -#define __HFN_INT_RME_Q2 0x00000400U -#define __HFN_INT_RME_Q3 0x00000800U -#define __HFN_INT_RME_Q4 0x00001000U -#define __HFN_INT_RME_Q5 0x00002000U -#define __HFN_INT_RME_Q6 0x00004000U -#define __HFN_INT_RME_Q7 0x00008000U -#define __HFN_INT_ERR_EMC 0x00010000U -#define __HFN_INT_ERR_LPU0 0x00020000U -#define __HFN_INT_ERR_LPU1 0x00040000U -#define __HFN_INT_ERR_PSS 0x00080000U -#define __HFN_INT_MBOX_LPU0 0x00100000U -#define __HFN_INT_MBOX_LPU1 0x00200000U -#define __HFN_INT_MBOX1_LPU0 0x00400000U -#define __HFN_INT_MBOX1_LPU1 0x00800000U -#define __HFN_INT_LL_HALT 0x01000000U -#define __HFN_INT_CPE_MASK 0x000000ffU -#define __HFN_INT_RME_MASK 0x0000ff00U -#define __HFN_INT_ERR_MASK \ - (__HFN_INT_ERR_EMC | __HFN_INT_ERR_LPU0 | __HFN_INT_ERR_LPU1 | \ - __HFN_INT_ERR_PSS | __HFN_INT_LL_HALT) -#define __HFN_INT_FN0_MASK \ - (__HFN_INT_CPE_Q0 | __HFN_INT_CPE_Q1 | __HFN_INT_CPE_Q2 | \ - __HFN_INT_CPE_Q3 | __HFN_INT_RME_Q0 | __HFN_INT_RME_Q1 | \ - __HFN_INT_RME_Q2 | __HFN_INT_RME_Q3 | __HFN_INT_MBOX_LPU0) -#define __HFN_INT_FN1_MASK \ - (__HFN_INT_CPE_Q4 | __HFN_INT_CPE_Q5 | __HFN_INT_CPE_Q6 | \ - __HFN_INT_CPE_Q7 | __HFN_INT_RME_Q4 | __HFN_INT_RME_Q5 | \ - __HFN_INT_RME_Q6 | __HFN_INT_RME_Q7 | __HFN_INT_MBOX_LPU1) - -/* - * Host interrupt status defines for catapult-2 - */ -#define __HFN_INT_MBOX_LPU0_CT2 0x00010000U -#define __HFN_INT_MBOX_LPU1_CT2 0x00020000U -#define __HFN_INT_ERR_PSS_CT2 0x00040000U -#define __HFN_INT_ERR_LPU0_CT2 0x00080000U -#define __HFN_INT_ERR_LPU1_CT2 0x00100000U -#define __HFN_INT_CPQ_HALT_CT2 0x00200000U -#define __HFN_INT_ERR_WGN_CT2 0x00400000U -#define __HFN_INT_ERR_LEHRX_CT2 0x00800000U -#define __HFN_INT_ERR_LEHTX_CT2 0x01000000U -#define __HFN_INT_ERR_MASK_CT2 \ - (__HFN_INT_ERR_PSS_CT2 | __HFN_INT_ERR_LPU0_CT2 | \ - __HFN_INT_ERR_LPU1_CT2 | __HFN_INT_CPQ_HALT_CT2 | \ - __HFN_INT_ERR_WGN_CT2 | __HFN_INT_ERR_LEHRX_CT2 | \ - __HFN_INT_ERR_LEHTX_CT2) -#define __HFN_INT_FN0_MASK_CT2 \ - (__HFN_INT_CPE_Q0 | __HFN_INT_CPE_Q1 | __HFN_INT_CPE_Q2 | \ - __HFN_INT_CPE_Q3 | __HFN_INT_RME_Q0 | __HFN_INT_RME_Q1 | \ - __HFN_INT_RME_Q2 | __HFN_INT_RME_Q3 | __HFN_INT_MBOX_LPU0_CT2) -#define __HFN_INT_FN1_MASK_CT2 \ - (__HFN_INT_CPE_Q4 | __HFN_INT_CPE_Q5 | __HFN_INT_CPE_Q6 | \ - __HFN_INT_CPE_Q7 | __HFN_INT_RME_Q4 | __HFN_INT_RME_Q5 | \ - __HFN_INT_RME_Q6 | __HFN_INT_RME_Q7 | __HFN_INT_MBOX_LPU1_CT2) - -/* - * asic memory map. - */ -#define PSS_SMEM_PAGE_START 0x8000 -#define PSS_SMEM_PGNUM(_pg0, _ma) ((_pg0) + ((_ma) >> 15)) -#define PSS_SMEM_PGOFF(_ma) ((_ma) & 0x7fff) - -#endif /* __BFI_REG_H__ */ diff --git a/trunk/drivers/scsi/bnx2fc/bnx2fc.h b/trunk/drivers/scsi/bnx2fc/bnx2fc.h index d924236e1b91..907672e86063 100644 --- a/trunk/drivers/scsi/bnx2fc/bnx2fc.h +++ b/trunk/drivers/scsi/bnx2fc/bnx2fc.h @@ -152,6 +152,7 @@ struct bnx2fc_percpu_s { spinlock_t fp_work_lock; }; + struct bnx2fc_hba { struct list_head link; struct cnic_dev *cnic; @@ -178,7 +179,6 @@ struct bnx2fc_hba { #define BNX2FC_CTLR_INIT_DONE 1 #define BNX2FC_CREATE_DONE 2 struct fcoe_ctlr ctlr; - struct list_head vports; u8 vlan_enabled; int vlan_id; u32 next_conn_id; @@ -232,11 +232,6 @@ struct bnx2fc_hba { #define bnx2fc_from_ctlr(fip) container_of(fip, struct bnx2fc_hba, ctlr) -struct bnx2fc_lport { - struct list_head list; - struct fc_lport *lport; -}; - struct bnx2fc_cmd_mgr { struct bnx2fc_hba *hba; u16 next_idx; @@ -433,7 +428,6 @@ struct bnx2fc_work { struct bnx2fc_unsol_els { struct fc_lport *lport; struct fc_frame *fp; - struct bnx2fc_hba *hba; struct work_struct unsol_els_work; }; diff --git a/trunk/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/trunk/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index a97aff3a0662..9eebaebdaa78 100644 --- a/trunk/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/trunk/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -679,9 +679,6 @@ static void bnx2fc_link_speed_update(struct fc_lport *lport) case SPEED_1000: lport->link_speed = FC_PORTSPEED_1GBIT; break; - case SPEED_2500: - lport->link_speed = FC_PORTSPEED_2GBIT; - break; case SPEED_10000: lport->link_speed = FC_PORTSPEED_10GBIT; break; @@ -1234,7 +1231,6 @@ static int bnx2fc_interface_setup(struct bnx2fc_hba *hba, hba->ctlr.get_src_addr = bnx2fc_get_src_mac; set_bit(BNX2FC_CTLR_INIT_DONE, &hba->init_done); - INIT_LIST_HEAD(&hba->vports); rc = bnx2fc_netdev_setup(hba); if (rc) goto setup_err; @@ -1271,15 +1267,8 @@ static struct fc_lport *bnx2fc_if_create(struct bnx2fc_hba *hba, struct fcoe_port *port; struct Scsi_Host *shost; struct fc_vport *vport = dev_to_vport(parent); - struct bnx2fc_lport *blport; int rc = 0; - blport = kzalloc(sizeof(struct bnx2fc_lport), GFP_KERNEL); - if (!blport) { - BNX2FC_HBA_DBG(hba->ctlr.lp, "Unable to alloc bnx2fc_lport\n"); - return NULL; - } - /* Allocate Scsi_Host structure */ if (!npiv) lport = libfc_host_alloc(&bnx2fc_shost_template, sizeof(*port)); @@ -1288,7 +1277,7 @@ static struct fc_lport *bnx2fc_if_create(struct bnx2fc_hba *hba, if (!lport) { printk(KERN_ERR PFX "could not allocate scsi host structure\n"); - goto free_blport; + return NULL; } shost = lport->host; port = lport_priv(lport); @@ -1344,20 +1333,12 @@ static struct fc_lport *bnx2fc_if_create(struct bnx2fc_hba *hba, } bnx2fc_interface_get(hba); - - spin_lock_bh(&hba->hba_lock); - blport->lport = lport; - list_add_tail(&blport->list, &hba->vports); - spin_unlock_bh(&hba->hba_lock); - return lport; shost_err: scsi_remove_host(shost); lp_config_err: scsi_host_put(lport->host); -free_blport: - kfree(blport); return NULL; } @@ -1373,7 +1354,6 @@ static void bnx2fc_if_destroy(struct fc_lport *lport) { struct fcoe_port *port = lport_priv(lport); struct bnx2fc_hba *hba = port->priv; - struct bnx2fc_lport *blport, *tmp; BNX2FC_HBA_DBG(hba->ctlr.lp, "ENTERED bnx2fc_if_destroy\n"); /* Stop the transmit retry timer */ @@ -1398,15 +1378,6 @@ static void bnx2fc_if_destroy(struct fc_lport *lport) /* Free memory used by statistical counters */ fc_lport_free_stats(lport); - spin_lock_bh(&hba->hba_lock); - list_for_each_entry_safe(blport, tmp, &hba->vports, list) { - if (blport->lport == lport) { - list_del(&blport->list); - kfree(blport); - } - } - spin_unlock_bh(&hba->hba_lock); - /* Release Scsi_Host */ scsi_host_put(lport->host); diff --git a/trunk/drivers/scsi/bnx2fc/bnx2fc_hwi.c b/trunk/drivers/scsi/bnx2fc/bnx2fc_hwi.c index 09bdd9b88d1a..d8e8a825560d 100644 --- a/trunk/drivers/scsi/bnx2fc/bnx2fc_hwi.c +++ b/trunk/drivers/scsi/bnx2fc/bnx2fc_hwi.c @@ -486,36 +486,16 @@ int bnx2fc_send_session_destroy_req(struct bnx2fc_hba *hba, return rc; } -static bool is_valid_lport(struct bnx2fc_hba *hba, struct fc_lport *lport) -{ - struct bnx2fc_lport *blport; - - spin_lock_bh(&hba->hba_lock); - list_for_each_entry(blport, &hba->vports, list) { - if (blport->lport == lport) { - spin_unlock_bh(&hba->hba_lock); - return true; - } - } - spin_unlock_bh(&hba->hba_lock); - return false; - -} - - static void bnx2fc_unsol_els_work(struct work_struct *work) { struct bnx2fc_unsol_els *unsol_els; struct fc_lport *lport; - struct bnx2fc_hba *hba; struct fc_frame *fp; unsol_els = container_of(work, struct bnx2fc_unsol_els, unsol_els_work); lport = unsol_els->lport; fp = unsol_els->fp; - hba = unsol_els->hba; - if (is_valid_lport(hba, lport)) - fc_exch_recv(lport, fp); + fc_exch_recv(lport, fp); kfree(unsol_els); } @@ -525,7 +505,6 @@ void bnx2fc_process_l2_frame_compl(struct bnx2fc_rport *tgt, { struct fcoe_port *port = tgt->port; struct fc_lport *lport = port->lport; - struct bnx2fc_hba *hba = port->priv; struct bnx2fc_unsol_els *unsol_els; struct fc_frame_header *fh; struct fc_frame *fp; @@ -586,7 +565,6 @@ void bnx2fc_process_l2_frame_compl(struct bnx2fc_rport *tgt, fr_eof(fp) = FC_EOF_T; fr_crc(fp) = cpu_to_le32(~crc); unsol_els->lport = lport; - unsol_els->hba = hba; unsol_els->fp = fp; INIT_WORK(&unsol_els->unsol_els_work, bnx2fc_unsol_els_work); queue_work(bnx2fc_wq, &unsol_els->unsol_els_work); diff --git a/trunk/drivers/scsi/bnx2fc/bnx2fc_io.c b/trunk/drivers/scsi/bnx2fc/bnx2fc_io.c index 45eba6d609c9..5dc4205ed8af 100644 --- a/trunk/drivers/scsi/bnx2fc/bnx2fc_io.c +++ b/trunk/drivers/scsi/bnx2fc/bnx2fc_io.c @@ -1743,6 +1743,7 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req, printk(KERN_ERR PFX "SCp.ptr is NULL\n"); return; } + io_req->sc_cmd = NULL; if (io_req->on_active_queue) { list_del_init(&io_req->link); @@ -1762,7 +1763,6 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req, } bnx2fc_unmap_sg_list(io_req); - io_req->sc_cmd = NULL; switch (io_req->fcp_status) { case FC_GOOD: diff --git a/trunk/drivers/scsi/bnx2i/57xx_iscsi_constants.h b/trunk/drivers/scsi/bnx2i/57xx_iscsi_constants.h index 57515f1f1690..15673cc786ff 100644 --- a/trunk/drivers/scsi/bnx2i/57xx_iscsi_constants.h +++ b/trunk/drivers/scsi/bnx2i/57xx_iscsi_constants.h @@ -1,6 +1,6 @@ /* 57xx_iscsi_constants.h: Broadcom NetXtreme II iSCSI HSI * - * Copyright (c) 2006 - 2011 Broadcom Corporation + * Copyright (c) 2006 - 2010 Broadcom 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 diff --git a/trunk/drivers/scsi/bnx2i/57xx_iscsi_hsi.h b/trunk/drivers/scsi/bnx2i/57xx_iscsi_hsi.h index 72118db89a20..71890a063cd3 100644 --- a/trunk/drivers/scsi/bnx2i/57xx_iscsi_hsi.h +++ b/trunk/drivers/scsi/bnx2i/57xx_iscsi_hsi.h @@ -1,6 +1,6 @@ /* 57xx_iscsi_hsi.h: Broadcom NetXtreme II iSCSI HSI. * - * Copyright (c) 2006 - 2011 Broadcom Corporation + * Copyright (c) 2006 - 2010 Broadcom 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 diff --git a/trunk/drivers/scsi/bnx2i/bnx2i.h b/trunk/drivers/scsi/bnx2i/bnx2i.h index dc5700765db4..e7cb7ecf6847 100644 --- a/trunk/drivers/scsi/bnx2i/bnx2i.h +++ b/trunk/drivers/scsi/bnx2i/bnx2i.h @@ -1,6 +1,6 @@ /* bnx2i.h: Broadcom NetXtreme II iSCSI driver. * - * Copyright (c) 2006 - 2011 Broadcom Corporation + * Copyright (c) 2006 - 2010 Broadcom Corporation * Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved. * Copyright (c) 2007, 2008 Mike Christie * @@ -22,14 +22,11 @@ #include #include #include -#include #include #include #include #include #include -#include -#include #include #include @@ -205,13 +202,10 @@ struct io_bdt { /** * bnx2i_cmd - iscsi command structure * - * @hdr: iSCSI header - * @conn: iscsi_conn pointer * @scsi_cmd: SCSI-ML task pointer corresponding to this iscsi cmd * @sg: SG list * @io_tbl: buffer descriptor (BD) table * @bd_tbl_dma: buffer descriptor (BD) table's dma address - * @req: bnx2i specific command request struct */ struct bnx2i_cmd { struct iscsi_hdr hdr; @@ -235,7 +229,6 @@ struct bnx2i_cmd { * @gen_pdu: login/nopout/logout pdu resources * @violation_notified: bit mask used to track iscsi error/warning messages * already printed out - * @work_cnt: keeps track of the number of outstanding work * * iSCSI connection structure */ @@ -259,8 +252,6 @@ struct bnx2i_conn { */ struct generic_pdu_resc gen_pdu; u64 violation_notified; - - atomic_t work_cnt; }; @@ -670,6 +661,7 @@ enum { * @hba: adapter to which this connection belongs * @conn: iscsi connection this EP is linked to * @cls_ep: associated iSCSI endpoint pointer + * @sess: iscsi session this EP is linked to * @cm_sk: cnic sock struct * @hba_age: age to detect if 'iscsid' issues ep_disconnect() * after HBA reset is completed by bnx2i/cnic/bnx2 @@ -695,7 +687,7 @@ struct bnx2i_endpoint { u32 hba_age; u32 state; unsigned long timestamp; - atomic_t num_active_cmds; + int num_active_cmds; u32 ec_shift; struct qp_info qp; @@ -708,19 +700,6 @@ struct bnx2i_endpoint { }; -struct bnx2i_work { - struct list_head list; - struct iscsi_session *session; - struct bnx2i_conn *bnx2i_conn; - struct cqe cqe; -}; - -struct bnx2i_percpu_s { - struct task_struct *iothread; - struct list_head work_list; - spinlock_t p_work_lock; -}; - /* Global variables */ extern unsigned int error_mask1, error_mask2; @@ -804,7 +783,7 @@ extern struct bnx2i_endpoint *bnx2i_find_ep_in_destroy_list( struct bnx2i_hba *hba, u32 iscsi_cid); extern int bnx2i_map_ep_dbell_regs(struct bnx2i_endpoint *ep); -extern int bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action); +extern void bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action); extern int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep); @@ -814,8 +793,4 @@ extern void bnx2i_print_active_cmd_queue(struct bnx2i_conn *conn); extern void bnx2i_print_xmit_pdu_queue(struct bnx2i_conn *conn); extern void bnx2i_print_recv_state(struct bnx2i_conn *conn); -extern int bnx2i_percpu_io_thread(void *arg); -extern int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session, - struct bnx2i_conn *bnx2i_conn, - struct cqe *cqe); #endif diff --git a/trunk/drivers/scsi/bnx2i/bnx2i_hwi.c b/trunk/drivers/scsi/bnx2i/bnx2i_hwi.c index 030a96c646c3..372d30c099cc 100644 --- a/trunk/drivers/scsi/bnx2i/bnx2i_hwi.c +++ b/trunk/drivers/scsi/bnx2i/bnx2i_hwi.c @@ -1,6 +1,6 @@ /* bnx2i_hwi.c: Broadcom NetXtreme II iSCSI driver. * - * Copyright (c) 2006 - 2011 Broadcom Corporation + * Copyright (c) 2006 - 2010 Broadcom Corporation * Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved. * Copyright (c) 2007, 2008 Mike Christie * @@ -17,8 +17,6 @@ #include #include "bnx2i.h" -DECLARE_PER_CPU(struct bnx2i_percpu_s, bnx2i_percpu); - /** * bnx2i_get_cid_num - get cid from ep * @ep: endpoint pointer @@ -133,16 +131,16 @@ static void bnx2i_iscsi_license_error(struct bnx2i_hba *hba, u32 error_code) * the driver. EQ event is generated CQ index is hit or at least 1 CQ is * outstanding and on chip timer expires */ -int bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action) +void bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action) { struct bnx2i_5771x_cq_db *cq_db; u16 cq_index; - u16 next_index = 0; + u16 next_index; u32 num_active_cmds; /* Coalesce CQ entries only on 10G devices */ if (!test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) - return 0; + return; /* Do not update CQ DB multiple times before firmware writes * '0xFFFF' to CQDB->SQN field. Deviation may cause spurious @@ -152,17 +150,16 @@ int bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action) if (action != CNIC_ARM_CQE_FP) if (cq_db->sqn[0] && cq_db->sqn[0] != 0xFFFF) - return 0; + return; if (action == CNIC_ARM_CQE || action == CNIC_ARM_CQE_FP) { - num_active_cmds = atomic_read(&ep->num_active_cmds); + num_active_cmds = ep->num_active_cmds; if (num_active_cmds <= event_coal_min) next_index = 1; - else { - next_index = num_active_cmds >> ep->ec_shift; - if (next_index > num_active_cmds - event_coal_min) - next_index = num_active_cmds - event_coal_min; - } + else + next_index = event_coal_min + + ((num_active_cmds - event_coal_min) >> + ep->ec_shift); if (!next_index) next_index = 1; cq_index = ep->qp.cqe_exp_seq_sn + next_index - 1; @@ -173,7 +170,6 @@ int bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action) cq_db->sqn[0] = cq_index; } - return next_index; } @@ -269,7 +265,7 @@ static void bnx2i_ring_sq_dbell(struct bnx2i_conn *bnx2i_conn, int count) struct bnx2i_5771x_sq_rq_db *sq_db; struct bnx2i_endpoint *ep = bnx2i_conn->ep; - atomic_inc(&ep->num_active_cmds); + ep->num_active_cmds++; wmb(); /* flush SQ WQE memory before the doorbell is rung */ if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) { sq_db = (struct bnx2i_5771x_sq_rq_db *) ep->qp.sq_pgtbl_virt; @@ -434,7 +430,7 @@ int bnx2i_send_iscsi_tmf(struct bnx2i_conn *bnx2i_conn, default: tmfabort_wqe->ref_itt = RESERVED_ITT; } - memcpy(scsi_lun, &tmfabort_hdr->lun, sizeof(struct scsi_lun)); + memcpy(scsi_lun, tmfabort_hdr->lun, sizeof(struct scsi_lun)); tmfabort_wqe->lun[0] = be32_to_cpu(scsi_lun[0]); tmfabort_wqe->lun[1] = be32_to_cpu(scsi_lun[1]); @@ -551,7 +547,7 @@ int bnx2i_send_iscsi_nopout(struct bnx2i_conn *bnx2i_conn, nopout_wqe->op_code = nopout_hdr->opcode; nopout_wqe->op_attr = ISCSI_FLAG_CMD_FINAL; - memcpy(nopout_wqe->lun, &nopout_hdr->lun, 8); + memcpy(nopout_wqe->lun, nopout_hdr->lun, 8); if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) { u32 tmp = nopout_wqe->lun[0]; @@ -1335,15 +1331,14 @@ int bnx2i_send_fw_iscsi_init_msg(struct bnx2i_hba *hba) /** * bnx2i_process_scsi_cmd_resp - this function handles scsi cmd completion. - * @session: iscsi session - * @bnx2i_conn: bnx2i connection + * @conn: iscsi connection * @cqe: pointer to newly DMA'ed CQE entry for processing * * process SCSI CMD Response CQE & complete the request to SCSI-ML */ -int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session, - struct bnx2i_conn *bnx2i_conn, - struct cqe *cqe) +static int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session, + struct bnx2i_conn *bnx2i_conn, + struct cqe *cqe) { struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data; struct bnx2i_cmd_response *resp_cqe; @@ -1353,7 +1348,7 @@ int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session, u32 datalen = 0; resp_cqe = (struct bnx2i_cmd_response *)cqe; - spin_lock_bh(&session->lock); + spin_lock(&session->lock); task = iscsi_itt_to_task(conn, resp_cqe->itt & ISCSI_CMD_RESPONSE_INDEX); if (!task) @@ -1414,7 +1409,7 @@ int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session, __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, conn->data, datalen); fail: - spin_unlock_bh(&session->lock); + spin_unlock(&session->lock); return 0; } @@ -1716,7 +1711,7 @@ static int bnx2i_process_nopin_mesg(struct iscsi_session *session, hdr->flags = ISCSI_FLAG_CMD_FINAL; hdr->itt = task->hdr->itt; hdr->ttt = cpu_to_be32(nop_in->ttt); - memcpy(&hdr->lun, nop_in->lun, 8); + memcpy(hdr->lun, nop_in->lun, 8); } done: __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0); @@ -1759,7 +1754,7 @@ static void bnx2i_process_async_mesg(struct iscsi_session *session, resp_hdr->opcode = async_cqe->op_code; resp_hdr->flags = 0x80; - memcpy(&resp_hdr->lun, async_cqe->lun, 8); + memcpy(resp_hdr->lun, async_cqe->lun, 8); resp_hdr->exp_cmdsn = cpu_to_be32(async_cqe->exp_cmd_sn); resp_hdr->max_cmdsn = cpu_to_be32(async_cqe->max_cmd_sn); @@ -1841,136 +1836,21 @@ static void bnx2i_process_cmd_cleanup_resp(struct iscsi_session *session, } -/** - * bnx2i_percpu_io_thread - thread per cpu for ios - * - * @arg: ptr to bnx2i_percpu_info structure - */ -int bnx2i_percpu_io_thread(void *arg) -{ - struct bnx2i_percpu_s *p = arg; - struct bnx2i_work *work, *tmp; - LIST_HEAD(work_list); - - set_user_nice(current, -20); - - while (!kthread_should_stop()) { - spin_lock_bh(&p->p_work_lock); - while (!list_empty(&p->work_list)) { - list_splice_init(&p->work_list, &work_list); - spin_unlock_bh(&p->p_work_lock); - - list_for_each_entry_safe(work, tmp, &work_list, list) { - list_del_init(&work->list); - /* work allocated in the bh, freed here */ - bnx2i_process_scsi_cmd_resp(work->session, - work->bnx2i_conn, - &work->cqe); - atomic_dec(&work->bnx2i_conn->work_cnt); - kfree(work); - } - spin_lock_bh(&p->p_work_lock); - } - set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_bh(&p->p_work_lock); - schedule(); - } - __set_current_state(TASK_RUNNING); - - return 0; -} - - -/** - * bnx2i_queue_scsi_cmd_resp - queue cmd completion to the percpu thread - * @bnx2i_conn: bnx2i connection - * - * this function is called by generic KCQ handler to queue all pending cmd - * completion CQEs - * - * The implementation is to queue the cmd response based on the - * last recorded command for the given connection. The - * cpu_id gets recorded upon task_xmit. No out-of-order completion! - */ -static int bnx2i_queue_scsi_cmd_resp(struct iscsi_session *session, - struct bnx2i_conn *bnx2i_conn, - struct bnx2i_nop_in_msg *cqe) -{ - struct bnx2i_work *bnx2i_work = NULL; - struct bnx2i_percpu_s *p = NULL; - struct iscsi_task *task; - struct scsi_cmnd *sc; - int rc = 0; - int cpu; - - spin_lock(&session->lock); - task = iscsi_itt_to_task(bnx2i_conn->cls_conn->dd_data, - cqe->itt & ISCSI_CMD_RESPONSE_INDEX); - if (!task) { - spin_unlock(&session->lock); - return -EINVAL; - } - sc = task->sc; - spin_unlock(&session->lock); - - if (!blk_rq_cpu_valid(sc->request)) - cpu = smp_processor_id(); - else - cpu = sc->request->cpu; - - p = &per_cpu(bnx2i_percpu, cpu); - spin_lock(&p->p_work_lock); - if (unlikely(!p->iothread)) { - rc = -EINVAL; - goto err; - } - /* Alloc and copy to the cqe */ - bnx2i_work = kzalloc(sizeof(struct bnx2i_work), GFP_ATOMIC); - if (bnx2i_work) { - INIT_LIST_HEAD(&bnx2i_work->list); - bnx2i_work->session = session; - bnx2i_work->bnx2i_conn = bnx2i_conn; - memcpy(&bnx2i_work->cqe, cqe, sizeof(struct cqe)); - list_add_tail(&bnx2i_work->list, &p->work_list); - atomic_inc(&bnx2i_conn->work_cnt); - wake_up_process(p->iothread); - spin_unlock(&p->p_work_lock); - goto done; - } else - rc = -ENOMEM; -err: - spin_unlock(&p->p_work_lock); - bnx2i_process_scsi_cmd_resp(session, bnx2i_conn, (struct cqe *)cqe); -done: - return rc; -} - /** * bnx2i_process_new_cqes - process newly DMA'ed CQE's - * @bnx2i_conn: bnx2i connection + * @bnx2i_conn: iscsi connection * * this function is called by generic KCQ handler to process all pending CQE's */ -static int bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn) +static void bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn) { struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data; struct iscsi_session *session = conn->session; - struct qp_info *qp; + struct qp_info *qp = &bnx2i_conn->ep->qp; struct bnx2i_nop_in_msg *nopin; int tgt_async_msg; - int cqe_cnt = 0; - if (bnx2i_conn->ep == NULL) - return 0; - - qp = &bnx2i_conn->ep->qp; - - if (!qp->cq_virt) { - printk(KERN_ALERT "bnx2i (%s): cq resr freed in bh execution!", - bnx2i_conn->hba->netdev->name); - goto out; - } while (1) { nopin = (struct bnx2i_nop_in_msg *) qp->cq_cons_qe; if (nopin->cq_req_sn != qp->cqe_exp_seq_sn) @@ -1993,9 +1873,8 @@ static int bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn) switch (nopin->op_code) { case ISCSI_OP_SCSI_CMD_RSP: case ISCSI_OP_SCSI_DATA_IN: - /* Run the kthread engine only for data cmds - All other cmds will be completed in this bh! */ - bnx2i_queue_scsi_cmd_resp(session, bnx2i_conn, nopin); + bnx2i_process_scsi_cmd_resp(session, bnx2i_conn, + qp->cq_cons_qe); break; case ISCSI_OP_LOGIN_RSP: bnx2i_process_login_resp(session, bnx2i_conn, @@ -2039,21 +1918,13 @@ static int bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn) printk(KERN_ALERT "bnx2i: unknown opcode 0x%x\n", nopin->op_code); } - if (!tgt_async_msg) { - if (!atomic_read(&bnx2i_conn->ep->num_active_cmds)) - printk(KERN_ALERT "bnx2i (%s): no active cmd! " - "op 0x%x\n", - bnx2i_conn->hba->netdev->name, - nopin->op_code); - else - atomic_dec(&bnx2i_conn->ep->num_active_cmds); - } + if (!tgt_async_msg) + bnx2i_conn->ep->num_active_cmds--; cqe_out: /* clear out in production version only, till beta keep opcode * field intact, will be helpful in debugging (context dump) * nopin->op_code = 0; */ - cqe_cnt++; qp->cqe_exp_seq_sn++; if (qp->cqe_exp_seq_sn == (qp->cqe_size * 2 + 1)) qp->cqe_exp_seq_sn = ISCSI_INITIAL_SN; @@ -2066,8 +1937,6 @@ static int bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn) qp->cq_cons_idx++; } } -out: - return cqe_cnt; } /** @@ -2083,7 +1952,6 @@ static void bnx2i_fastpath_notification(struct bnx2i_hba *hba, { struct bnx2i_conn *bnx2i_conn; u32 iscsi_cid; - int nxt_idx; iscsi_cid = new_cqe_kcqe->iscsi_conn_id; bnx2i_conn = bnx2i_get_conn_from_id(hba, iscsi_cid); @@ -2096,12 +1964,9 @@ static void bnx2i_fastpath_notification(struct bnx2i_hba *hba, printk(KERN_ALERT "cid #%x - ep not bound\n", iscsi_cid); return; } - bnx2i_process_new_cqes(bnx2i_conn); - nxt_idx = bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep, - CNIC_ARM_CQE_FP); - if (nxt_idx && nxt_idx == bnx2i_process_new_cqes(bnx2i_conn)) - bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep, CNIC_ARM_CQE_FP); + bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep, CNIC_ARM_CQE_FP); + bnx2i_process_new_cqes(bnx2i_conn); } @@ -2447,7 +2312,7 @@ static void bnx2i_process_ofld_cmpl(struct bnx2i_hba *hba, printk(KERN_ALERT "bnx2i (%s): ofld1 cmpl - invalid " "opcode\n", hba->netdev->name); else if (ofld_kcqe->completion_status == - ISCSI_KCQE_COMPLETION_STATUS_CID_BUSY) + ISCSI_KCQE_COMPLETION_STATUS_CID_BUSY) /* error status code valid only for 5771x chipset */ ep->state = EP_STATE_OFLD_FAILED_CID_BUSY; else @@ -2652,7 +2517,7 @@ static void bnx2i_cm_remote_abort(struct cnic_sock *cm_sk) static int bnx2i_send_nl_mesg(void *context, u32 msg_type, - char *buf, u16 buflen) + char *buf, u16 buflen) { struct bnx2i_hba *hba = context; int rc; diff --git a/trunk/drivers/scsi/bnx2i/bnx2i_init.c b/trunk/drivers/scsi/bnx2i/bnx2i_init.c index 1a947f1b9729..6973413e91ec 100644 --- a/trunk/drivers/scsi/bnx2i/bnx2i_init.c +++ b/trunk/drivers/scsi/bnx2i/bnx2i_init.c @@ -1,6 +1,6 @@ /* bnx2i.c: Broadcom NetXtreme II iSCSI driver. * - * Copyright (c) 2006 - 2011 Broadcom Corporation + * Copyright (c) 2006 - 2010 Broadcom Corporation * Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved. * Copyright (c) 2007, 2008 Mike Christie * @@ -18,8 +18,8 @@ static struct list_head adapter_list = LIST_HEAD_INIT(adapter_list); static u32 adapter_count; #define DRV_MODULE_NAME "bnx2i" -#define DRV_MODULE_VERSION "2.7.0.3" -#define DRV_MODULE_RELDATE "Jun 15, 2011" +#define DRV_MODULE_VERSION "2.6.2.3" +#define DRV_MODULE_RELDATE "Dec 31, 2010" static char version[] __devinitdata = "Broadcom NetXtreme II iSCSI Driver " DRV_MODULE_NAME \ @@ -40,7 +40,7 @@ unsigned int event_coal_min = 24; module_param(event_coal_min, int, 0664); MODULE_PARM_DESC(event_coal_min, "Event Coalescing Minimum Commands"); -unsigned int event_coal_div = 2; +unsigned int event_coal_div = 1; module_param(event_coal_div, int, 0664); MODULE_PARM_DESC(event_coal_div, "Event Coalescing Divide Factor"); @@ -66,15 +66,6 @@ MODULE_PARM_DESC(rq_size, "Configure RQ size"); u64 iscsi_error_mask = 0x00; -DEFINE_PER_CPU(struct bnx2i_percpu_s, bnx2i_percpu); - -static int bnx2i_cpu_callback(struct notifier_block *nfb, - unsigned long action, void *hcpu); -/* notification function for CPU hotplug events */ -static struct notifier_block bnx2i_cpu_notifier = { - .notifier_call = bnx2i_cpu_callback, -}; - /** * bnx2i_identify_device - identifies NetXtreme II device type @@ -181,14 +172,21 @@ void bnx2i_start(void *handle) struct bnx2i_hba *hba = handle; int i = HZ; - /* - * We should never register devices that don't support iSCSI - * (see bnx2i_init_one), so something is wrong if we try to - * start a iSCSI adapter on hardware with 0 supported iSCSI - * connections - */ - BUG_ON(!hba->cnic->max_iscsi_conn); + if (!hba->cnic->max_iscsi_conn) { + printk(KERN_ALERT "bnx2i: dev %s does not support " + "iSCSI\n", hba->netdev->name); + if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) { + mutex_lock(&bnx2i_dev_lock); + list_del_init(&hba->link); + adapter_count--; + hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI); + clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic); + mutex_unlock(&bnx2i_dev_lock); + bnx2i_free_hba(hba); + } + return; + } bnx2i_send_fw_iscsi_init_msg(hba); while (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state) && i--) msleep(BNX2I_INIT_POLL_TIME); @@ -292,13 +290,6 @@ static int bnx2i_init_one(struct bnx2i_hba *hba, struct cnic_dev *cnic) int rc; mutex_lock(&bnx2i_dev_lock); - if (!cnic->max_iscsi_conn) { - printk(KERN_ALERT "bnx2i: dev %s does not support " - "iSCSI\n", hba->netdev->name); - rc = -EOPNOTSUPP; - goto out; - } - hba->cnic = cnic; rc = cnic->register_device(cnic, CNIC_ULP_ISCSI, hba); if (!rc) { @@ -316,7 +307,6 @@ static int bnx2i_init_one(struct bnx2i_hba *hba, struct cnic_dev *cnic) else printk(KERN_ERR "bnx2i dev reg, unknown error, %d\n", rc); -out: mutex_unlock(&bnx2i_dev_lock); return rc; @@ -380,91 +370,6 @@ void bnx2i_ulp_exit(struct cnic_dev *dev) } -/** - * bnx2i_percpu_thread_create - Create a receive thread for an - * online CPU - * - * @cpu: cpu index for the online cpu - */ -static void bnx2i_percpu_thread_create(unsigned int cpu) -{ - struct bnx2i_percpu_s *p; - struct task_struct *thread; - - p = &per_cpu(bnx2i_percpu, cpu); - - thread = kthread_create(bnx2i_percpu_io_thread, (void *)p, - "bnx2i_thread/%d", cpu); - /* bind thread to the cpu */ - if (likely(!IS_ERR(thread))) { - kthread_bind(thread, cpu); - p->iothread = thread; - wake_up_process(thread); - } -} - - -static void bnx2i_percpu_thread_destroy(unsigned int cpu) -{ - struct bnx2i_percpu_s *p; - struct task_struct *thread; - struct bnx2i_work *work, *tmp; - - /* Prevent any new work from being queued for this CPU */ - p = &per_cpu(bnx2i_percpu, cpu); - spin_lock_bh(&p->p_work_lock); - thread = p->iothread; - p->iothread = NULL; - - /* Free all work in the list */ - list_for_each_entry_safe(work, tmp, &p->work_list, list) { - list_del_init(&work->list); - bnx2i_process_scsi_cmd_resp(work->session, - work->bnx2i_conn, &work->cqe); - kfree(work); - } - - spin_unlock_bh(&p->p_work_lock); - if (thread) - kthread_stop(thread); -} - - -/** - * bnx2i_cpu_callback - Handler for CPU hotplug events - * - * @nfb: The callback data block - * @action: The event triggering the callback - * @hcpu: The index of the CPU that the event is for - * - * This creates or destroys per-CPU data for iSCSI - * - * Returns NOTIFY_OK always. - */ -static int bnx2i_cpu_callback(struct notifier_block *nfb, - unsigned long action, void *hcpu) -{ - unsigned cpu = (unsigned long)hcpu; - - switch (action) { - case CPU_ONLINE: - case CPU_ONLINE_FROZEN: - printk(KERN_INFO "bnx2i: CPU %x online: Create Rx thread\n", - cpu); - bnx2i_percpu_thread_create(cpu); - break; - case CPU_DEAD: - case CPU_DEAD_FROZEN: - printk(KERN_INFO "CPU %x offline: Remove Rx thread\n", cpu); - bnx2i_percpu_thread_destroy(cpu); - break; - default: - break; - } - return NOTIFY_OK; -} - - /** * bnx2i_mod_init - module init entry point * @@ -475,8 +380,6 @@ static int bnx2i_cpu_callback(struct notifier_block *nfb, static int __init bnx2i_mod_init(void) { int err; - unsigned cpu = 0; - struct bnx2i_percpu_s *p; printk(KERN_INFO "%s", version); @@ -499,20 +402,6 @@ static int __init bnx2i_mod_init(void) goto unreg_xport; } - /* Create percpu kernel threads to handle iSCSI I/O completions */ - for_each_possible_cpu(cpu) { - p = &per_cpu(bnx2i_percpu, cpu); - INIT_LIST_HEAD(&p->work_list); - spin_lock_init(&p->p_work_lock); - p->iothread = NULL; - } - - for_each_online_cpu(cpu) - bnx2i_percpu_thread_create(cpu); - - /* Initialize per CPU interrupt thread */ - register_hotcpu_notifier(&bnx2i_cpu_notifier); - return 0; unreg_xport: @@ -533,7 +422,6 @@ static int __init bnx2i_mod_init(void) static void __exit bnx2i_mod_exit(void) { struct bnx2i_hba *hba; - unsigned cpu = 0; mutex_lock(&bnx2i_dev_lock); while (!list_empty(&adapter_list)) { @@ -551,11 +439,6 @@ static void __exit bnx2i_mod_exit(void) } mutex_unlock(&bnx2i_dev_lock); - unregister_hotcpu_notifier(&bnx2i_cpu_notifier); - - for_each_online_cpu(cpu) - bnx2i_percpu_thread_destroy(cpu); - iscsi_unregister_transport(&bnx2i_iscsi_transport); cnic_unregister_driver(CNIC_ULP_ISCSI); } diff --git a/trunk/drivers/scsi/bnx2i/bnx2i_iscsi.c b/trunk/drivers/scsi/bnx2i/bnx2i_iscsi.c index 5c55a75ae597..041928b23cb0 100644 --- a/trunk/drivers/scsi/bnx2i/bnx2i_iscsi.c +++ b/trunk/drivers/scsi/bnx2i/bnx2i_iscsi.c @@ -1,7 +1,7 @@ /* * bnx2i_iscsi.c: Broadcom NetXtreme II iSCSI driver. * - * Copyright (c) 2006 - 2011 Broadcom Corporation + * Copyright (c) 2006 - 2010 Broadcom Corporation * Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved. * Copyright (c) 2007, 2008 Mike Christie * @@ -27,7 +27,6 @@ static struct scsi_host_template bnx2i_host_template; */ static DEFINE_SPINLOCK(bnx2i_resc_lock); /* protects global resources */ -DECLARE_PER_CPU(struct bnx2i_percpu_s, bnx2i_percpu); static int bnx2i_adapter_ready(struct bnx2i_hba *hba) { @@ -1215,8 +1214,7 @@ static int bnx2i_task_xmit(struct iscsi_task *task) struct bnx2i_cmd *cmd = task->dd_data; struct iscsi_cmd *hdr = (struct iscsi_cmd *) task->hdr; - if (atomic_read(&bnx2i_conn->ep->num_active_cmds) + 1 > - hba->max_sqes) + if (bnx2i_conn->ep->num_active_cmds + 1 > hba->max_sqes) return -ENOMEM; /* @@ -1356,9 +1354,6 @@ bnx2i_conn_create(struct iscsi_cls_session *cls_session, uint32_t cid) bnx2i_conn = conn->dd_data; bnx2i_conn->cls_conn = cls_conn; bnx2i_conn->hba = hba; - - atomic_set(&bnx2i_conn->work_cnt, 0); - /* 'ep' ptr will be assigned in bind() call */ bnx2i_conn->ep = NULL; init_completion(&bnx2i_conn->cmd_cleanup_cmpl); @@ -1462,34 +1457,11 @@ static void bnx2i_conn_destroy(struct iscsi_cls_conn *cls_conn) struct bnx2i_conn *bnx2i_conn = conn->dd_data; struct Scsi_Host *shost; struct bnx2i_hba *hba; - struct bnx2i_work *work, *tmp; - unsigned cpu = 0; - struct bnx2i_percpu_s *p; shost = iscsi_session_to_shost(iscsi_conn_to_session(cls_conn)); hba = iscsi_host_priv(shost); bnx2i_conn_free_login_resources(hba, bnx2i_conn); - - if (atomic_read(&bnx2i_conn->work_cnt)) { - for_each_online_cpu(cpu) { - p = &per_cpu(bnx2i_percpu, cpu); - spin_lock_bh(&p->p_work_lock); - list_for_each_entry_safe(work, tmp, - &p->work_list, list) { - if (work->session == conn->session && - work->bnx2i_conn == bnx2i_conn) { - list_del_init(&work->list); - kfree(work); - if (!atomic_dec_and_test( - &bnx2i_conn->work_cnt)) - break; - } - } - spin_unlock_bh(&p->p_work_lock); - } - } - iscsi_conn_teardown(cls_conn); } @@ -1797,7 +1769,7 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost, } bnx2i_ep = ep->dd_data; - atomic_set(&bnx2i_ep->num_active_cmds, 0); + bnx2i_ep->num_active_cmds = 0; iscsi_cid = bnx2i_alloc_iscsi_cid(hba); if (iscsi_cid == -1) { printk(KERN_ALERT "bnx2i (%s): alloc_ep - unable to allocate " @@ -2191,9 +2163,9 @@ static struct scsi_host_template bnx2i_host_template = { .eh_device_reset_handler = iscsi_eh_device_reset, .eh_target_reset_handler = iscsi_eh_recover_target, .change_queue_depth = iscsi_change_queue_depth, - .can_queue = 2048, + .can_queue = 1024, .max_sectors = 127, - .cmd_per_lun = 128, + .cmd_per_lun = 24, .this_id = -1, .use_clustering = ENABLE_CLUSTERING, .sg_tablesize = ISCSI_MAX_BDS_PER_CMD, diff --git a/trunk/drivers/scsi/bnx2i/bnx2i_sysfs.c b/trunk/drivers/scsi/bnx2i/bnx2i_sysfs.c index 83a77f7244d2..9174196d9033 100644 --- a/trunk/drivers/scsi/bnx2i/bnx2i_sysfs.c +++ b/trunk/drivers/scsi/bnx2i/bnx2i_sysfs.c @@ -1,6 +1,6 @@ /* bnx2i_sysfs.c: Broadcom NetXtreme II iSCSI driver. * - * Copyright (c) 2004 - 2011 Broadcom Corporation + * Copyright (c) 2004 - 2010 Broadcom 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 diff --git a/trunk/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c b/trunk/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c index bd22041e2789..abc7b122e050 100644 --- a/trunk/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c +++ b/trunk/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c @@ -1245,7 +1245,7 @@ static int cxgb3i_ddp_init(struct cxgbi_device *cdev) struct cxgbi_ddp_info *ddp = tdev->ulp_iscsi; struct ulp_iscsi_info uinfo; unsigned int pgsz_factor[4]; - int i, err; + int err; if (ddp) { kref_get(&ddp->refcnt); @@ -1271,8 +1271,6 @@ static int cxgb3i_ddp_init(struct cxgbi_device *cdev) uinfo.tagmask = ddp->idx_mask << PPOD_IDX_SHIFT; cxgbi_ddp_page_size_factor(pgsz_factor); - for (i = 0; i < 4; i++) - uinfo.pgsz_factor[i] = pgsz_factor[i]; uinfo.ulimit = uinfo.llimit + (ddp->nppods << PPOD_SIZE_SHIFT); err = tdev->ctl(tdev, ULP_ISCSI_SET_PARAMS, &uinfo); diff --git a/trunk/drivers/scsi/fcoe/fcoe.c b/trunk/drivers/scsi/fcoe/fcoe.c index 204fa8d4b4ab..155d7b9bdeae 100644 --- a/trunk/drivers/scsi/fcoe/fcoe.c +++ b/trunk/drivers/scsi/fcoe/fcoe.c @@ -99,8 +99,7 @@ static void fcoe_destroy_work(struct work_struct *); static int fcoe_ddp_setup(struct fc_lport *, u16, struct scatterlist *, unsigned int); static int fcoe_ddp_done(struct fc_lport *, u16); -static int fcoe_ddp_target(struct fc_lport *, u16, struct scatterlist *, - unsigned int); + static int fcoe_cpu_callback(struct notifier_block *, unsigned long, void *); static bool fcoe_match(struct net_device *netdev); @@ -144,7 +143,6 @@ static struct libfc_function_template fcoe_libfc_fcn_templ = { .frame_send = fcoe_xmit, .ddp_setup = fcoe_ddp_setup, .ddp_done = fcoe_ddp_done, - .ddp_target = fcoe_ddp_target, .elsct_send = fcoe_elsct_send, .get_lesb = fcoe_get_lesb, .lport_set_port_id = fcoe_set_port_id, @@ -431,6 +429,21 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe) struct fcoe_ctlr *fip = &fcoe->ctlr; u8 flogi_maddr[ETH_ALEN]; const struct net_device_ops *ops; + struct fcoe_port *port = lport_priv(fcoe->ctlr.lp); + + FCOE_NETDEV_DBG(netdev, "Destroying interface\n"); + + /* Logout of the fabric */ + fc_fabric_logoff(fcoe->ctlr.lp); + + /* Cleanup the fc_lport */ + fc_lport_destroy(fcoe->ctlr.lp); + + /* Stop the transmit retry timer */ + del_timer_sync(&port->timer); + + /* Free existing transmit skbs */ + fcoe_clean_pending_queue(fcoe->ctlr.lp); /* * Don't listen for Ethernet packets anymore. @@ -453,6 +466,9 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe) } else dev_mc_del(netdev, FIP_ALL_ENODE_MACS); + if (!is_zero_ether_addr(port->data_src_addr)) + dev_uc_del(netdev, port->data_src_addr); + /* Tell the LLD we are done w/ FCoE */ ops = netdev->netdev_ops; if (ops->ndo_fcoe_disable) { @@ -460,8 +476,6 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe) FCOE_NETDEV_DBG(netdev, "Failed to disable FCoE" " specific feature for LLD.\n"); } - - /* Release the self-reference taken during fcoe_interface_create() */ fcoe_interface_put(fcoe); } @@ -735,27 +749,12 @@ static int fcoe_shost_config(struct fc_lport *lport, struct device *dev) * The offload EM that this routine is associated with will handle any * packets that are for SCSI read requests. * - * This has been enhanced to work when FCoE stack is operating in target - * mode. - * * Returns: True for read types I/O, otherwise returns false. */ bool fcoe_oem_match(struct fc_frame *fp) { - struct fc_frame_header *fh = fc_frame_header_get(fp); - struct fcp_cmnd *fcp; - - if (fc_fcp_is_read(fr_fsp(fp)) && - (fr_fsp(fp)->data_len > fcoe_ddp_min)) - return true; - else if (!(ntoh24(fh->fh_f_ctl) & FC_FC_EX_CTX)) { - fcp = fc_frame_payload_get(fp, sizeof(*fcp)); - if (ntohs(fh->fh_rx_id) == FC_XID_UNKNOWN && - fcp && (ntohl(fcp->fc_dl) > fcoe_ddp_min) && - (fcp->fc_flags & FCP_CFL_WRDATA)) - return true; - } - return false; + return fc_fcp_is_read(fr_fsp(fp)) && + (fr_fsp(fp)->data_len > fcoe_ddp_min); } /** @@ -845,32 +844,6 @@ static inline int fcoe_em_config(struct fc_lport *lport) */ static void fcoe_if_destroy(struct fc_lport *lport) { - struct fcoe_port *port = lport_priv(lport); - struct fcoe_interface *fcoe = port->priv; - struct net_device *netdev = fcoe->netdev; - - FCOE_NETDEV_DBG(netdev, "Destroying interface\n"); - - /* Logout of the fabric */ - fc_fabric_logoff(lport); - - /* Cleanup the fc_lport */ - fc_lport_destroy(lport); - - /* Stop the transmit retry timer */ - del_timer_sync(&port->timer); - - /* Free existing transmit skbs */ - fcoe_clean_pending_queue(lport); - - rtnl_lock(); - if (!is_zero_ether_addr(port->data_src_addr)) - dev_uc_del(netdev, port->data_src_addr); - rtnl_unlock(); - - /* Release reference held in fcoe_if_create() */ - fcoe_interface_put(fcoe); - /* Free queued packets for the per-CPU receive threads */ fcoe_percpu_clean(lport); @@ -913,28 +886,6 @@ static int fcoe_ddp_setup(struct fc_lport *lport, u16 xid, return 0; } -/** - * fcoe_ddp_target() - Call a LLD's ddp_target through the net device - * @lport: The local port to setup DDP for - * @xid: The exchange ID for this DDP transfer - * @sgl: The scatterlist describing this transfer - * @sgc: The number of sg items - * - * Returns: 0 if the DDP context was not configured - */ -static int fcoe_ddp_target(struct fc_lport *lport, u16 xid, - struct scatterlist *sgl, unsigned int sgc) -{ - struct net_device *netdev = fcoe_netdev(lport); - - if (netdev->netdev_ops->ndo_fcoe_ddp_target) - return netdev->netdev_ops->ndo_fcoe_ddp_target(netdev, xid, - sgl, sgc); - - return 0; -} - - /** * fcoe_ddp_done() - Call a LLD's ddp_done through the net device * @lport: The local port to complete DDP on @@ -1254,36 +1205,6 @@ static int fcoe_cpu_callback(struct notifier_block *nfb, return NOTIFY_OK; } -/** - * fcoe_select_cpu() - Selects CPU to handle post-processing of incoming - * command. - * @curr_cpu: CPU which received request - * - * This routine selects next CPU based on cpumask. - * - * Returns: int (CPU number). Caller to verify if returned CPU is online or not. - */ -static unsigned int fcoe_select_cpu(unsigned int curr_cpu) -{ - static unsigned int selected_cpu; - - if (num_online_cpus() == 1) - return curr_cpu; - /* - * Doing following check, to skip "curr_cpu (smp_processor_id)" - * from selection of CPU is intentional. This is to avoid same CPU - * doing post-processing of command. "curr_cpu" to just receive - * incoming request in case where rx_id is UNKNOWN and all other - * CPU to actually process the command(s) - */ - do { - selected_cpu = cpumask_next(selected_cpu, cpu_online_mask); - if (selected_cpu >= nr_cpu_ids) - selected_cpu = cpumask_first(cpu_online_mask); - } while (selected_cpu == curr_cpu); - return selected_cpu; -} - /** * fcoe_rcv() - Receive packets from a net device * @skb: The received packet @@ -1360,20 +1281,9 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev, */ if (ntoh24(fh->fh_f_ctl) & FC_FC_EX_CTX) cpu = ntohs(fh->fh_ox_id) & fc_cpu_mask; - else { + else cpu = smp_processor_id(); - if ((fh->fh_type == FC_TYPE_FCP) && - (ntohs(fh->fh_rx_id) == FC_XID_UNKNOWN)) { - do { - cpu = fcoe_select_cpu(cpu); - } while (!cpu_online(cpu)); - } else if ((fh->fh_type == FC_TYPE_FCP) && - (ntohs(fh->fh_rx_id) != FC_XID_UNKNOWN)) { - cpu = ntohs(fh->fh_rx_id) & fc_cpu_mask; - } else - cpu = smp_processor_id(); - } fps = &per_cpu(fcoe_percpu, cpu); spin_lock_bh(&fps->fcoe_rx_list.lock); if (unlikely(!fps->thread)) { @@ -1823,6 +1733,7 @@ static int fcoe_device_notification(struct notifier_block *notifier, case NETDEV_UNREGISTER: list_del(&fcoe->list); port = lport_priv(fcoe->ctlr.lp); + fcoe_interface_cleanup(fcoe); queue_work(fcoe_wq, &port->destroy_work); goto out; break; @@ -1916,22 +1827,22 @@ static int fcoe_destroy(struct net_device *netdev) { struct fcoe_interface *fcoe; struct fc_lport *lport; - struct fcoe_port *port; int rc = 0; mutex_lock(&fcoe_config_mutex); rtnl_lock(); fcoe = fcoe_hostlist_lookup_port(netdev); if (!fcoe) { + rtnl_unlock(); rc = -ENODEV; goto out_nodev; } lport = fcoe->ctlr.lp; - port = lport_priv(lport); list_del(&fcoe->list); - queue_work(fcoe_wq, &port->destroy_work); -out_nodev: + fcoe_interface_cleanup(fcoe); rtnl_unlock(); + fcoe_if_destroy(lport); +out_nodev: mutex_unlock(&fcoe_config_mutex); return rc; } @@ -1943,25 +1854,10 @@ static int fcoe_destroy(struct net_device *netdev) static void fcoe_destroy_work(struct work_struct *work) { struct fcoe_port *port; - struct fcoe_interface *fcoe; - int npiv = 0; port = container_of(work, struct fcoe_port, destroy_work); mutex_lock(&fcoe_config_mutex); - - /* set if this is an NPIV port */ - npiv = port->lport->vport ? 1 : 0; - - fcoe = port->priv; fcoe_if_destroy(port->lport); - - /* Do not tear down the fcoe interface for NPIV port */ - if (!npiv) { - rtnl_lock(); - fcoe_interface_cleanup(fcoe); - rtnl_unlock(); - } - mutex_unlock(&fcoe_config_mutex); } @@ -1990,7 +1886,7 @@ static bool fcoe_match(struct net_device *netdev) */ static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode) { - int rc = 0; + int rc; struct fcoe_interface *fcoe; struct fc_lport *lport; @@ -2015,7 +1911,7 @@ static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode) netdev->name); rc = -EIO; fcoe_interface_cleanup(fcoe); - goto out_nodev; + goto out_free; } /* Make this the "master" N_Port */ @@ -2030,6 +1926,17 @@ static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode) if (!fcoe_link_ok(lport)) fcoe_ctlr_link_up(&fcoe->ctlr); + /* + * Release from init in fcoe_interface_create(), on success lport + * should be holding a reference taken in fcoe_if_create(). + */ + fcoe_interface_put(fcoe); + rtnl_unlock(); + mutex_unlock(&fcoe_config_mutex); + + return 0; +out_free: + fcoe_interface_put(fcoe); out_nodev: rtnl_unlock(); mutex_unlock(&fcoe_config_mutex); @@ -2311,6 +2218,7 @@ static void __exit fcoe_exit(void) list_for_each_entry_safe(fcoe, tmp, &fcoe_hostlist, list) { list_del(&fcoe->list); port = lport_priv(fcoe->ctlr.lp); + fcoe_interface_cleanup(fcoe); queue_work(fcoe_wq, &port->destroy_work); } rtnl_unlock(); diff --git a/trunk/drivers/scsi/fnic/fnic.h b/trunk/drivers/scsi/fnic/fnic.h index 95a5ba29320d..671cde9d4060 100644 --- a/trunk/drivers/scsi/fnic/fnic.h +++ b/trunk/drivers/scsi/fnic/fnic.h @@ -37,7 +37,7 @@ #define DRV_NAME "fnic" #define DRV_DESCRIPTION "Cisco FCoE HBA Driver" -#define DRV_VERSION "1.5.0.2" +#define DRV_VERSION "1.5.0.1" #define PFX DRV_NAME ": " #define DFX DRV_NAME "%d: " diff --git a/trunk/drivers/scsi/fnic/fnic_main.c b/trunk/drivers/scsi/fnic/fnic_main.c index fc98eb61e760..bb63f1a1f808 100644 --- a/trunk/drivers/scsi/fnic/fnic_main.c +++ b/trunk/drivers/scsi/fnic/fnic_main.c @@ -388,6 +388,17 @@ static void fnic_iounmap(struct fnic *fnic) iounmap(fnic->bar0.vaddr); } +/* + * Allocate element for mempools requiring GFP_DMA flag. + * Otherwise, checks in kmem_flagcheck() hit BUG_ON(). + */ +static void *fnic_alloc_slab_dma(gfp_t gfp_mask, void *pool_data) +{ + struct kmem_cache *mem = pool_data; + + return kmem_cache_alloc(mem, gfp_mask | GFP_ATOMIC | GFP_DMA); +} + /** * fnic_get_mac() - get assigned data MAC address for FIP code. * @lport: local port. @@ -592,12 +603,14 @@ static int __devinit fnic_probe(struct pci_dev *pdev, if (!fnic->io_req_pool) goto err_out_free_resources; - pool = mempool_create_slab_pool(2, fnic_sgl_cache[FNIC_SGL_CACHE_DFLT]); + pool = mempool_create(2, fnic_alloc_slab_dma, mempool_free_slab, + fnic_sgl_cache[FNIC_SGL_CACHE_DFLT]); if (!pool) goto err_out_free_ioreq_pool; fnic->io_sgl_pool[FNIC_SGL_CACHE_DFLT] = pool; - pool = mempool_create_slab_pool(2, fnic_sgl_cache[FNIC_SGL_CACHE_MAX]); + pool = mempool_create(2, fnic_alloc_slab_dma, mempool_free_slab, + fnic_sgl_cache[FNIC_SGL_CACHE_MAX]); if (!pool) goto err_out_free_dflt_pool; fnic->io_sgl_pool[FNIC_SGL_CACHE_MAX] = pool; @@ -863,7 +876,7 @@ static int __init fnic_init_module(void) len = sizeof(struct fnic_dflt_sgl_list); fnic_sgl_cache[FNIC_SGL_CACHE_DFLT] = kmem_cache_create ("fnic_sgl_dflt", len + FNIC_SG_DESC_ALIGN, FNIC_SG_DESC_ALIGN, - SLAB_HWCACHE_ALIGN, + SLAB_HWCACHE_ALIGN | SLAB_CACHE_DMA, NULL); if (!fnic_sgl_cache[FNIC_SGL_CACHE_DFLT]) { printk(KERN_ERR PFX "failed to create fnic dflt sgl slab\n"); @@ -875,7 +888,7 @@ static int __init fnic_init_module(void) len = sizeof(struct fnic_sgl_list); fnic_sgl_cache[FNIC_SGL_CACHE_MAX] = kmem_cache_create ("fnic_sgl_max", len + FNIC_SG_DESC_ALIGN, FNIC_SG_DESC_ALIGN, - SLAB_HWCACHE_ALIGN, + SLAB_HWCACHE_ALIGN | SLAB_CACHE_DMA, NULL); if (!fnic_sgl_cache[FNIC_SGL_CACHE_MAX]) { printk(KERN_ERR PFX "failed to create fnic max sgl slab\n"); diff --git a/trunk/drivers/scsi/fnic/fnic_scsi.c b/trunk/drivers/scsi/fnic/fnic_scsi.c index c40ce52ed7c6..538b31c2cf58 100644 --- a/trunk/drivers/scsi/fnic/fnic_scsi.c +++ b/trunk/drivers/scsi/fnic/fnic_scsi.c @@ -406,7 +406,7 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_ if (sg_count) { io_req->sgl_list = mempool_alloc(fnic->io_sgl_pool[io_req->sgl_type], - GFP_ATOMIC); + GFP_ATOMIC | GFP_DMA); if (!io_req->sgl_list) { ret = SCSI_MLQUEUE_HOST_BUSY; scsi_dma_unmap(sc); diff --git a/trunk/drivers/scsi/iscsi_boot_sysfs.c b/trunk/drivers/scsi/iscsi_boot_sysfs.c index 89700cbca16e..df6bff7366cf 100644 --- a/trunk/drivers/scsi/iscsi_boot_sysfs.c +++ b/trunk/drivers/scsi/iscsi_boot_sysfs.c @@ -64,8 +64,7 @@ static void iscsi_boot_kobj_release(struct kobject *kobj) struct iscsi_boot_kobj *boot_kobj = container_of(kobj, struct iscsi_boot_kobj, kobj); - if (boot_kobj->release) - boot_kobj->release(boot_kobj->data); + kfree(boot_kobj->data); kfree(boot_kobj); } @@ -306,8 +305,7 @@ iscsi_boot_create_kobj(struct iscsi_boot_kset *boot_kset, struct attribute_group *attr_group, const char *name, int index, void *data, ssize_t (*show) (void *data, int type, char *buf), - mode_t (*is_visible) (void *data, int type), - void (*release) (void *data)) + mode_t (*is_visible) (void *data, int type)) { struct iscsi_boot_kobj *boot_kobj; @@ -325,7 +323,6 @@ iscsi_boot_create_kobj(struct iscsi_boot_kset *boot_kset, boot_kobj->data = data; boot_kobj->show = show; boot_kobj->is_visible = is_visible; - boot_kobj->release = release; if (sysfs_create_group(&boot_kobj->kobj, attr_group)) { /* @@ -334,7 +331,7 @@ iscsi_boot_create_kobj(struct iscsi_boot_kset *boot_kset, * the boot kobj was not setup and the normal release * path is not being run. */ - boot_kobj->release = NULL; + boot_kobj->data = NULL; kobject_put(&boot_kobj->kobj); return NULL; } @@ -360,7 +357,6 @@ static void iscsi_boot_remove_kobj(struct iscsi_boot_kobj *boot_kobj) * @data: driver specific data for target * @show: attr show function * @is_visible: attr visibility function - * @release: release function * * Note: The boot sysfs lib will free the data passed in for the caller * when all refs to the target kobject have been released. @@ -369,12 +365,10 @@ struct iscsi_boot_kobj * iscsi_boot_create_target(struct iscsi_boot_kset *boot_kset, int index, void *data, ssize_t (*show) (void *data, int type, char *buf), - mode_t (*is_visible) (void *data, int type), - void (*release) (void *data)) + mode_t (*is_visible) (void *data, int type)) { return iscsi_boot_create_kobj(boot_kset, &iscsi_boot_target_attr_group, - "target%d", index, data, show, is_visible, - release); + "target%d", index, data, show, is_visible); } EXPORT_SYMBOL_GPL(iscsi_boot_create_target); @@ -385,7 +379,6 @@ EXPORT_SYMBOL_GPL(iscsi_boot_create_target); * @data: driver specific data * @show: attr show function * @is_visible: attr visibility function - * @release: release function * * Note: The boot sysfs lib will free the data passed in for the caller * when all refs to the initiator kobject have been released. @@ -394,13 +387,12 @@ struct iscsi_boot_kobj * iscsi_boot_create_initiator(struct iscsi_boot_kset *boot_kset, int index, void *data, ssize_t (*show) (void *data, int type, char *buf), - mode_t (*is_visible) (void *data, int type), - void (*release) (void *data)) + mode_t (*is_visible) (void *data, int type)) { return iscsi_boot_create_kobj(boot_kset, &iscsi_boot_initiator_attr_group, "initiator", index, data, show, - is_visible, release); + is_visible); } EXPORT_SYMBOL_GPL(iscsi_boot_create_initiator); @@ -411,7 +403,6 @@ EXPORT_SYMBOL_GPL(iscsi_boot_create_initiator); * @data: driver specific data * @show: attr show function * @is_visible: attr visibility function - * @release: release function * * Note: The boot sysfs lib will free the data passed in for the caller * when all refs to the ethernet kobject have been released. @@ -420,13 +411,12 @@ struct iscsi_boot_kobj * iscsi_boot_create_ethernet(struct iscsi_boot_kset *boot_kset, int index, void *data, ssize_t (*show) (void *data, int type, char *buf), - mode_t (*is_visible) (void *data, int type), - void (*release) (void *data)) + mode_t (*is_visible) (void *data, int type)) { return iscsi_boot_create_kobj(boot_kset, &iscsi_boot_ethernet_attr_group, "ethernet%d", index, data, show, - is_visible, release); + is_visible); } EXPORT_SYMBOL_GPL(iscsi_boot_create_ethernet); @@ -482,9 +472,6 @@ void iscsi_boot_destroy_kset(struct iscsi_boot_kset *boot_kset) { struct iscsi_boot_kobj *boot_kobj, *tmp_kobj; - if (!boot_kset) - return; - list_for_each_entry_safe(boot_kobj, tmp_kobj, &boot_kset->kobj_list, list) iscsi_boot_remove_kobj(boot_kobj); diff --git a/trunk/drivers/scsi/iscsi_tcp.c b/trunk/drivers/scsi/iscsi_tcp.c index 7724414588fa..3df985305f69 100644 --- a/trunk/drivers/scsi/iscsi_tcp.c +++ b/trunk/drivers/scsi/iscsi_tcp.c @@ -107,12 +107,10 @@ static int iscsi_sw_tcp_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, * If the socket is in CLOSE or CLOSE_WAIT we should * not close the connection if there is still some * data pending. - * - * Must be called with sk_callback_lock. */ static inline int iscsi_sw_sk_state_check(struct sock *sk) { - struct iscsi_conn *conn = sk->sk_user_data; + struct iscsi_conn *conn = (struct iscsi_conn*)sk->sk_user_data; if ((sk->sk_state == TCP_CLOSE_WAIT || sk->sk_state == TCP_CLOSE) && !atomic_read(&sk->sk_rmem_alloc)) { @@ -125,17 +123,11 @@ static inline int iscsi_sw_sk_state_check(struct sock *sk) static void iscsi_sw_tcp_data_ready(struct sock *sk, int flag) { - struct iscsi_conn *conn; - struct iscsi_tcp_conn *tcp_conn; + struct iscsi_conn *conn = sk->sk_user_data; + struct iscsi_tcp_conn *tcp_conn = conn->dd_data; read_descriptor_t rd_desc; read_lock(&sk->sk_callback_lock); - conn = sk->sk_user_data; - if (!conn) { - read_unlock(&sk->sk_callback_lock); - return; - } - tcp_conn = conn->dd_data; /* * Use rd_desc to pass 'conn' to iscsi_tcp_recv. @@ -149,10 +141,11 @@ static void iscsi_sw_tcp_data_ready(struct sock *sk, int flag) iscsi_sw_sk_state_check(sk); + read_unlock(&sk->sk_callback_lock); + /* If we had to (atomically) map a highmem page, * unmap it now. */ iscsi_tcp_segment_unmap(&tcp_conn->in.segment); - read_unlock(&sk->sk_callback_lock); } static void iscsi_sw_tcp_state_change(struct sock *sk) @@ -164,11 +157,8 @@ static void iscsi_sw_tcp_state_change(struct sock *sk) void (*old_state_change)(struct sock *); read_lock(&sk->sk_callback_lock); - conn = sk->sk_user_data; - if (!conn) { - read_unlock(&sk->sk_callback_lock); - return; - } + + conn = (struct iscsi_conn*)sk->sk_user_data; session = conn->session; iscsi_sw_sk_state_check(sk); @@ -188,25 +178,11 @@ static void iscsi_sw_tcp_state_change(struct sock *sk) **/ static void iscsi_sw_tcp_write_space(struct sock *sk) { - struct iscsi_conn *conn; - struct iscsi_tcp_conn *tcp_conn; - struct iscsi_sw_tcp_conn *tcp_sw_conn; - void (*old_write_space)(struct sock *); - - read_lock_bh(&sk->sk_callback_lock); - conn = sk->sk_user_data; - if (!conn) { - read_unlock_bh(&sk->sk_callback_lock); - return; - } - - tcp_conn = conn->dd_data; - tcp_sw_conn = tcp_conn->dd_data; - old_write_space = tcp_sw_conn->old_write_space; - read_unlock_bh(&sk->sk_callback_lock); - - old_write_space(sk); + struct iscsi_conn *conn = (struct iscsi_conn*)sk->sk_user_data; + struct iscsi_tcp_conn *tcp_conn = conn->dd_data; + struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; + tcp_sw_conn->old_write_space(sk); ISCSI_SW_TCP_DBG(conn, "iscsi_write_space\n"); iscsi_conn_queue_work(conn); } @@ -616,17 +592,20 @@ static void iscsi_sw_tcp_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) /* userspace may have goofed up and not bound us */ if (!sock) return; + /* + * Make sure our recv side is stopped. + * Older tools called conn stop before ep_disconnect + * so IO could still be coming in. + */ + write_lock_bh(&tcp_sw_conn->sock->sk->sk_callback_lock); + set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); + write_unlock_bh(&tcp_sw_conn->sock->sk->sk_callback_lock); sock->sk->sk_err = EIO; wake_up_interruptible(sk_sleep(sock->sk)); - /* stop xmit side */ - iscsi_suspend_tx(conn); - - /* stop recv side and release socket */ - iscsi_sw_tcp_release_conn(conn); - iscsi_conn_stop(cls_conn, flag); + iscsi_sw_tcp_release_conn(conn); } static int diff --git a/trunk/drivers/scsi/libfc/fc_exch.c b/trunk/drivers/scsi/libfc/fc_exch.c index f5a0665b6773..3b8a6451ea28 100644 --- a/trunk/drivers/scsi/libfc/fc_exch.c +++ b/trunk/drivers/scsi/libfc/fc_exch.c @@ -965,30 +965,8 @@ static enum fc_pf_rjt_reason fc_seq_lookup_recip(struct fc_lport *lport, sp = &ep->seq; if (sp->id != fh->fh_seq_id) { atomic_inc(&mp->stats.seq_not_found); - if (f_ctl & FC_FC_END_SEQ) { - /* - * Update sequence_id based on incoming last - * frame of sequence exchange. This is needed - * for FCoE target where DDP has been used - * on target where, stack is indicated only - * about last frame's (payload _header) header. - * Whereas "seq_id" which is part of - * frame_header is allocated by initiator - * which is totally different from "seq_id" - * allocated when XFER_RDY was sent by target. - * To avoid false -ve which results into not - * sending RSP, hence write request on other - * end never finishes. - */ - spin_lock_bh(&ep->ex_lock); - sp->ssb_stat |= SSB_ST_RESP; - sp->id = fh->fh_seq_id; - spin_unlock_bh(&ep->ex_lock); - } else { - /* sequence/exch should exist */ - reject = FC_RJT_SEQ_ID; - goto rel; - } + reject = FC_RJT_SEQ_ID; /* sequence/exch should exist */ + goto rel; } } WARN_ON(ep != fc_seq_exch(sp)); diff --git a/trunk/drivers/scsi/libfc/fc_lport.c b/trunk/drivers/scsi/libfc/fc_lport.c index e008b1673507..389ab80aef0a 100644 --- a/trunk/drivers/scsi/libfc/fc_lport.c +++ b/trunk/drivers/scsi/libfc/fc_lport.c @@ -1025,8 +1025,6 @@ static void fc_lport_enter_reset(struct fc_lport *lport) fc_vport_set_state(lport->vport, FC_VPORT_LINKDOWN); } fc_lport_state_enter(lport, LPORT_ST_RESET); - fc_host_post_event(lport->host, fc_get_event_number(), - FCH_EVT_LIPRESET, 0); fc_vports_linkchange(lport); fc_lport_reset_locked(lport); if (lport->link_up) diff --git a/trunk/drivers/scsi/libfc/fc_rport.c b/trunk/drivers/scsi/libfc/fc_rport.c index 760db7619446..49e1ccca09d5 100644 --- a/trunk/drivers/scsi/libfc/fc_rport.c +++ b/trunk/drivers/scsi/libfc/fc_rport.c @@ -152,6 +152,18 @@ static struct fc_rport_priv *fc_rport_create(struct fc_lport *lport, return rdata; } +/** + * fc_rport_free_rcu() - Free a remote port + * @rcu: The rcu_head structure inside the remote port + */ +static void fc_rport_free_rcu(struct rcu_head *rcu) +{ + struct fc_rport_priv *rdata; + + rdata = container_of(rcu, struct fc_rport_priv, rcu); + kfree(rdata); +} + /** * fc_rport_destroy() - Free a remote port after last reference is released * @kref: The remote port's kref @@ -161,7 +173,7 @@ static void fc_rport_destroy(struct kref *kref) struct fc_rport_priv *rdata; rdata = container_of(kref, struct fc_rport_priv, kref); - kfree_rcu(rdata, rcu); + call_rcu(&rdata->rcu, fc_rport_free_rcu); } /** @@ -789,20 +801,6 @@ static void fc_rport_recv_flogi_req(struct fc_lport *lport, switch (rdata->rp_state) { case RPORT_ST_INIT: - /* - * If received the FLOGI request on RPORT which is INIT state - * (means not transition to FLOGI either fc_rport timeout - * function didn;t trigger or this end hasn;t received - * beacon yet from other end. In that case only, allow RPORT - * state machine to continue, otherwise fall through which - * causes the code to send reject response. - * NOTE; Not checking for FIP->state such as VNMP_UP or - * VNMP_CLAIM because if FIP state is not one of those, - * RPORT wouldn;t have created and 'rport_lookup' would have - * failed anyway in that case. - */ - if (lport->point_to_multipoint) - break; case RPORT_ST_DELETE: mutex_unlock(&rdata->rp_mutex); rjt_data.reason = ELS_RJT_FIP; diff --git a/trunk/drivers/scsi/libiscsi.c b/trunk/drivers/scsi/libiscsi.c index d7a4120034a2..0c550d5b9133 100644 --- a/trunk/drivers/scsi/libiscsi.c +++ b/trunk/drivers/scsi/libiscsi.c @@ -169,7 +169,7 @@ void iscsi_prep_data_out_pdu(struct iscsi_task *task, struct iscsi_r2t_info *r2t hdr->datasn = cpu_to_be32(r2t->datasn); r2t->datasn++; hdr->opcode = ISCSI_OP_SCSI_DATA_OUT; - hdr->lun = task->lun; + memcpy(hdr->lun, task->lun, sizeof(hdr->lun)); hdr->itt = task->hdr_itt; hdr->exp_statsn = r2t->exp_statsn; hdr->offset = cpu_to_be32(r2t->data_offset + r2t->sent); @@ -296,7 +296,7 @@ static int iscsi_check_tmf_restrictions(struct iscsi_task *task, int opcode) /* * Allow PDUs for unrelated LUNs */ - hdr_lun = scsilun_to_int(&tmf->lun); + hdr_lun = scsilun_to_int((struct scsi_lun *)tmf->lun); if (hdr_lun != task->sc->device->lun) return 0; /* fall through */ @@ -389,8 +389,8 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task) return rc; hdr->opcode = ISCSI_OP_SCSI_CMD; hdr->flags = ISCSI_ATTR_SIMPLE; - int_to_scsilun(sc->device->lun, &hdr->lun); - task->lun = hdr->lun; + int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); + memcpy(task->lun, hdr->lun, sizeof(task->lun)); hdr->exp_statsn = cpu_to_be32(conn->exp_statsn); cmd_len = sc->cmd_len; if (cmd_len < ISCSI_CDB_SIZE) @@ -968,7 +968,7 @@ static void iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr) hdr.flags = ISCSI_FLAG_CMD_FINAL; if (rhdr) { - hdr.lun = rhdr->lun; + memcpy(hdr.lun, rhdr->lun, 8); hdr.ttt = rhdr->ttt; hdr.itt = RESERVED_ITT; } else @@ -2092,7 +2092,7 @@ static void iscsi_prep_abort_task_pdu(struct iscsi_task *task, hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE; hdr->flags = ISCSI_TM_FUNC_ABORT_TASK & ISCSI_FLAG_TM_FUNC_MASK; hdr->flags |= ISCSI_FLAG_CMD_FINAL; - hdr->lun = task->lun; + memcpy(hdr->lun, task->lun, sizeof(hdr->lun)); hdr->rtt = task->hdr_itt; hdr->refcmdsn = task->cmdsn; } @@ -2233,7 +2233,7 @@ static void iscsi_prep_lun_reset_pdu(struct scsi_cmnd *sc, struct iscsi_tm *hdr) hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE; hdr->flags = ISCSI_TM_FUNC_LOGICAL_UNIT_RESET & ISCSI_FLAG_TM_FUNC_MASK; hdr->flags |= ISCSI_FLAG_CMD_FINAL; - int_to_scsilun(sc->device->lun, &hdr->lun); + int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); hdr->rtt = RESERVED_ITT; } diff --git a/trunk/drivers/scsi/libiscsi_tcp.c b/trunk/drivers/scsi/libiscsi_tcp.c index 09b232fd9a1b..e98ae33f1295 100644 --- a/trunk/drivers/scsi/libiscsi_tcp.c +++ b/trunk/drivers/scsi/libiscsi_tcp.c @@ -1084,8 +1084,7 @@ iscsi_tcp_conn_setup(struct iscsi_cls_session *cls_session, int dd_data_size, struct iscsi_cls_conn *cls_conn; struct iscsi_tcp_conn *tcp_conn; - cls_conn = iscsi_conn_setup(cls_session, - sizeof(*tcp_conn) + dd_data_size, conn_idx); + cls_conn = iscsi_conn_setup(cls_session, sizeof(*tcp_conn), conn_idx); if (!cls_conn) return NULL; conn = cls_conn->dd_data; @@ -1097,13 +1096,22 @@ iscsi_tcp_conn_setup(struct iscsi_cls_session *cls_session, int dd_data_size, tcp_conn = conn->dd_data; tcp_conn->iscsi_conn = conn; - tcp_conn->dd_data = conn->dd_data + sizeof(*tcp_conn); + + tcp_conn->dd_data = kzalloc(dd_data_size, GFP_KERNEL); + if (!tcp_conn->dd_data) { + iscsi_conn_teardown(cls_conn); + return NULL; + } return cls_conn; } EXPORT_SYMBOL_GPL(iscsi_tcp_conn_setup); void iscsi_tcp_conn_teardown(struct iscsi_cls_conn *cls_conn) { + struct iscsi_conn *conn = cls_conn->dd_data; + struct iscsi_tcp_conn *tcp_conn = conn->dd_data; + + kfree(tcp_conn->dd_data); iscsi_conn_teardown(cls_conn); } EXPORT_SYMBOL_GPL(iscsi_tcp_conn_teardown); diff --git a/trunk/drivers/scsi/lpfc/lpfc_debugfs.c b/trunk/drivers/scsi/lpfc/lpfc_debugfs.c index 30b25c5fdd7e..ffe82d169b40 100644 --- a/trunk/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/trunk/drivers/scsi/lpfc/lpfc_debugfs.c @@ -1147,8 +1147,7 @@ static int lpfc_idiag_cmd_get(const char __user *buf, size_t nbytes, { char mybuf[64]; char *pbuf, *step_str; - int i; - size_t bsize; + int bsize, i; /* Protect copy from user */ if (!access_ok(VERIFY_READ, buf, nbytes)) diff --git a/trunk/drivers/scsi/mac_scsi.c b/trunk/drivers/scsi/mac_scsi.c index af3a6af97cc7..bf2a1c516293 100644 --- a/trunk/drivers/scsi/mac_scsi.c +++ b/trunk/drivers/scsi/mac_scsi.c @@ -214,6 +214,13 @@ static int __init mac_scsi_setup(char *str) { __setup("mac5380=", mac_scsi_setup); +/* + * If you want to find the instance with (k)gdb ... + */ +#if NDEBUG +static struct Scsi_Host *default_instance; +#endif + /* * Function : int macscsi_detect(struct scsi_host_template * tpnt) * @@ -226,7 +233,7 @@ __setup("mac5380=", mac_scsi_setup); * */ -int __init macscsi_detect(struct scsi_host_template * tpnt) +int macscsi_detect(struct scsi_host_template * tpnt) { static int called = 0; int flags = 0; @@ -261,7 +268,10 @@ int __init macscsi_detect(struct scsi_host_template * tpnt) /* Once we support multiple 5380s (e.g. DuoDock) we'll do something different here */ instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); - +#if NDEBUG + default_instance = instance; +#endif + if (macintosh_config->ident == MAC_MODEL_IIFX) { mac_scsi_regp = via1+0x8000; mac_scsi_drq = via1+0xE000; diff --git a/trunk/drivers/scsi/mpt2sas/mpi/mpi2.h b/trunk/drivers/scsi/mpt2sas/mpi/mpi2.h index 3105d5e8d908..a3e60385787f 100644 --- a/trunk/drivers/scsi/mpt2sas/mpi/mpi2.h +++ b/trunk/drivers/scsi/mpt2sas/mpi/mpi2.h @@ -8,7 +8,7 @@ * scatter/gather formats. * Creation Date: June 21, 2006 * - * mpi2.h Version: 02.00.18 + * mpi2.h Version: 02.00.17 * * Version History * --------------- @@ -64,8 +64,6 @@ * 05-12-10 02.00.16 Bumped MPI2_HEADER_VERSION_UNIT. * Added alternative defines for the SGE Direction bit. * 08-11-10 02.00.17 Bumped MPI2_HEADER_VERSION_UNIT. - * 11-10-10 02.00.18 Bumped MPI2_HEADER_VERSION_UNIT. - * Added MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR define. * -------------------------------------------------------------------------- */ @@ -91,7 +89,7 @@ #define MPI2_VERSION_02_00 (0x0200) /* versioning for this MPI header set */ -#define MPI2_HEADER_VERSION_UNIT (0x12) +#define MPI2_HEADER_VERSION_UNIT (0x11) #define MPI2_HEADER_VERSION_DEV (0x00) #define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00) #define MPI2_HEADER_VERSION_UNIT_SHIFT (8) @@ -1062,14 +1060,10 @@ typedef struct _MPI2_IEEE_SGE_UNION #define MPI2_IEEE_SGE_FLAGS_ADDR_MASK (0x03) #define MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR (0x00) - /* IEEE Simple Element only */ #define MPI2_IEEE_SGE_FLAGS_IOCDDR_ADDR (0x01) - /* IEEE Simple Element only */ #define MPI2_IEEE_SGE_FLAGS_IOCPLB_ADDR (0x02) #define MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR (0x03) - /* IEEE Simple Element only */ -#define MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR (0x03) - /* IEEE Chain Element only */ + /**************************************************************************** * IEEE SGE operation Macros diff --git a/trunk/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/trunk/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h index 61475a6480e3..f5b9c766e28f 100644 --- a/trunk/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h +++ b/trunk/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h @@ -6,7 +6,7 @@ * Title: MPI Configuration messages and pages * Creation Date: November 10, 2006 * - * mpi2_cnfg.h Version: 02.00.17 + * mpi2_cnfg.h Version: 02.00.16 * * Version History * --------------- @@ -127,13 +127,6 @@ * Added MPI2_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY define. * 08-11-10 02.00.16 Removed IO Unit Page 1 device path (multi-pathing) * defines. - * 11-10-10 02.00.17 Added ReceptacleID field (replacing Reserved1) to - * MPI2_MANPAGE7_CONNECTOR_INFO and reworked defines for - * the Pinout field. - * Added BoardTemperature and BoardTemperatureUnits fields - * to MPI2_CONFIG_PAGE_IO_UNIT_7. - * Added MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING define - * and MPI2_CONFIG_PAGE_EXT_MAN_PS structure. * -------------------------------------------------------------------------- */ @@ -217,7 +210,6 @@ typedef union _MPI2_CONFIG_EXT_PAGE_HEADER_UNION #define MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING (0x17) #define MPI2_CONFIG_EXTPAGETYPE_SAS_PORT (0x18) #define MPI2_CONFIG_EXTPAGETYPE_ETHERNET (0x19) -#define MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING (0x1A) /***************************************************************************** @@ -620,31 +612,23 @@ typedef struct _MPI2_MANPAGE7_CONNECTOR_INFO U32 Pinout; /* 0x00 */ U8 Connector[16]; /* 0x04 */ U8 Location; /* 0x14 */ - U8 ReceptacleID; /* 0x15 */ + U8 Reserved1; /* 0x15 */ U16 Slot; /* 0x16 */ U32 Reserved2; /* 0x18 */ } MPI2_MANPAGE7_CONNECTOR_INFO, MPI2_POINTER PTR_MPI2_MANPAGE7_CONNECTOR_INFO, Mpi2ManPage7ConnectorInfo_t, MPI2_POINTER pMpi2ManPage7ConnectorInfo_t; /* defines for the Pinout field */ -#define MPI2_MANPAGE7_PINOUT_LANE_MASK (0x0000FF00) -#define MPI2_MANPAGE7_PINOUT_LANE_SHIFT (8) - -#define MPI2_MANPAGE7_PINOUT_TYPE_MASK (0x000000FF) -#define MPI2_MANPAGE7_PINOUT_TYPE_UNKNOWN (0x00) -#define MPI2_MANPAGE7_PINOUT_SATA_SINGLE (0x01) -#define MPI2_MANPAGE7_PINOUT_SFF_8482 (0x02) -#define MPI2_MANPAGE7_PINOUT_SFF_8486 (0x03) -#define MPI2_MANPAGE7_PINOUT_SFF_8484 (0x04) -#define MPI2_MANPAGE7_PINOUT_SFF_8087 (0x05) -#define MPI2_MANPAGE7_PINOUT_SFF_8643_4I (0x06) -#define MPI2_MANPAGE7_PINOUT_SFF_8643_8I (0x07) -#define MPI2_MANPAGE7_PINOUT_SFF_8470 (0x08) -#define MPI2_MANPAGE7_PINOUT_SFF_8088 (0x09) -#define MPI2_MANPAGE7_PINOUT_SFF_8644_4X (0x0A) -#define MPI2_MANPAGE7_PINOUT_SFF_8644_8X (0x0B) -#define MPI2_MANPAGE7_PINOUT_SFF_8644_16X (0x0C) -#define MPI2_MANPAGE7_PINOUT_SFF_8436 (0x0D) +#define MPI2_MANPAGE7_PINOUT_SFF_8484_L4 (0x00080000) +#define MPI2_MANPAGE7_PINOUT_SFF_8484_L3 (0x00040000) +#define MPI2_MANPAGE7_PINOUT_SFF_8484_L2 (0x00020000) +#define MPI2_MANPAGE7_PINOUT_SFF_8484_L1 (0x00010000) +#define MPI2_MANPAGE7_PINOUT_SFF_8470_L4 (0x00000800) +#define MPI2_MANPAGE7_PINOUT_SFF_8470_L3 (0x00000400) +#define MPI2_MANPAGE7_PINOUT_SFF_8470_L2 (0x00000200) +#define MPI2_MANPAGE7_PINOUT_SFF_8470_L1 (0x00000100) +#define MPI2_MANPAGE7_PINOUT_SFF_8482 (0x00000002) +#define MPI2_MANPAGE7_PINOUT_CONNECTION_UNKNOWN (0x00000001) /* defines for the Location field */ #define MPI2_MANPAGE7_LOCATION_UNKNOWN (0x01) @@ -678,7 +662,7 @@ typedef struct _MPI2_CONFIG_PAGE_MAN_7 MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_7, Mpi2ManufacturingPage7_t, MPI2_POINTER pMpi2ManufacturingPage7_t; -#define MPI2_MANUFACTURING7_PAGEVERSION (0x01) +#define MPI2_MANUFACTURING7_PAGEVERSION (0x00) /* defines for the Flags field */ #define MPI2_MANPAGE7_FLAG_USE_SLOT_INFO (0x00000001) @@ -865,13 +849,11 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7 { U16 IOCTemperature; /* 0x10 */ U8 IOCTemperatureUnits; /* 0x12 */ U8 IOCSpeed; /* 0x13 */ - U16 BoardTemperature; /* 0x14 */ - U8 BoardTemperatureUnits; /* 0x16 */ - U8 Reserved3; /* 0x17 */ + U32 Reserved3; /* 0x14 */ } MPI2_CONFIG_PAGE_IO_UNIT_7, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_7, Mpi2IOUnitPage7_t, MPI2_POINTER pMpi2IOUnitPage7_t; -#define MPI2_IOUNITPAGE7_PAGEVERSION (0x02) +#define MPI2_IOUNITPAGE7_PAGEVERSION (0x01) /* defines for IO Unit Page 7 PCIeWidth field */ #define MPI2_IOUNITPAGE7_PCIE_WIDTH_X1 (0x01) @@ -899,6 +881,7 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7 { #define MPI2_IOUNITPAGE7_PMCAP_PCIE_WIDTH_CHANGE (0x00000008) #define MPI2_IOUNITPAGE7_PMCAP_PCIE_SPEED_CHANGE (0x00000004) + /* defines for IO Unit Page 7 IOCTemperatureUnits field */ #define MPI2_IOUNITPAGE7_IOC_TEMP_NOT_PRESENT (0x00) #define MPI2_IOUNITPAGE7_IOC_TEMP_FAHRENHEIT (0x01) @@ -910,11 +893,6 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7 { #define MPI2_IOUNITPAGE7_IOC_SPEED_QUARTER (0x04) #define MPI2_IOUNITPAGE7_IOC_SPEED_EIGHTH (0x08) -/* defines for IO Unit Page 7 BoardTemperatureUnits field */ -#define MPI2_IOUNITPAGE7_BOARD_TEMP_NOT_PRESENT (0x00) -#define MPI2_IOUNITPAGE7_BOARD_TEMP_FAHRENHEIT (0x01) -#define MPI2_IOUNITPAGE7_BOARD_TEMP_CELSIUS (0x02) - /**************************************************************************** @@ -2821,25 +2799,5 @@ typedef struct _MPI2_CONFIG_PAGE_ETHERNET_1 { #define MPI2_ETHPG1_MS_DATA_RATE_1GBIT (0x03) -/**************************************************************************** -* Extended Manufacturing Config Pages -****************************************************************************/ - -/* - * Generic structure to use for product-specific extended manufacturing pages - * (currently Extended Manufacturing Page 40 through Extended Manufacturing - * Page 60). - */ - -typedef struct _MPI2_CONFIG_PAGE_EXT_MAN_PS { - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U32 ProductSpecificInfo; /* 0x08 */ -} MPI2_CONFIG_PAGE_EXT_MAN_PS, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_EXT_MAN_PS, - Mpi2ExtManufacturingPagePS_t, - MPI2_POINTER pMpi2ExtManufacturingPagePS_t; - -/* PageVersion should be provided by product-specific code */ - #endif diff --git a/trunk/drivers/scsi/mpt2sas/mpi/mpi2_init.h b/trunk/drivers/scsi/mpt2sas/mpi/mpi2_init.h index de90162413c2..165454d52591 100644 --- a/trunk/drivers/scsi/mpt2sas/mpi/mpi2_init.h +++ b/trunk/drivers/scsi/mpt2sas/mpi/mpi2_init.h @@ -6,7 +6,7 @@ * Title: MPI SCSI initiator mode messages and structures * Creation Date: June 23, 2006 * - * mpi2_init.h Version: 02.00.11 + * mpi2_init.h Version: 02.00.10 * * Version History * --------------- @@ -33,7 +33,6 @@ * Added MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG define. * 02-10-10 02.00.09 Removed unused structure that had "#if 0" around it. * 05-12-10 02.00.10 Added optional vendor-unique region to SCSI IO Request. - * 11-10-10 02.00.11 Added MPI2_SCSIIO_NUM_SGLOFFSETS define. * -------------------------------------------------------------------------- */ @@ -140,9 +139,6 @@ typedef struct _MPI2_SCSI_IO_REQUEST #define MPI2_SCSIIO_SGLFLAGS_SGL1_SHIFT (4) #define MPI2_SCSIIO_SGLFLAGS_SGL0_SHIFT (0) -/* number of SGLOffset fields */ -#define MPI2_SCSIIO_NUM_SGLOFFSETS (4) - /* SCSI IO IoFlags bits */ /* Large CDB Address Space */ diff --git a/trunk/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h b/trunk/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h index 1f0c190d336e..761cbdb8a033 100644 --- a/trunk/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h +++ b/trunk/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h @@ -6,7 +6,7 @@ * Title: MPI IOC, Port, Event, FW Download, and FW Upload messages * Creation Date: October 11, 2006 * - * mpi2_ioc.h Version: 02.00.16 + * mpi2_ioc.h Version: 02.00.15 * * Version History * --------------- @@ -103,7 +103,6 @@ * defines. * 05-12-10 02.00.15 Marked Task Set Full Event as obsolete. * Added MPI2_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY define. - * 11-10-10 02.00.16 Added MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC. * -------------------------------------------------------------------------- */ @@ -1033,7 +1032,6 @@ typedef struct _MPI2_FW_DOWNLOAD_REQUEST #define MPI2_FW_DOWNLOAD_ITYPE_MEGARAID (0x09) #define MPI2_FW_DOWNLOAD_ITYPE_COMPLETE (0x0A) #define MPI2_FW_DOWNLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B) -#define MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC (0xF0) /* FWDownload TransactionContext Element */ typedef struct _MPI2_FW_DOWNLOAD_TCSGE diff --git a/trunk/drivers/scsi/mpt2sas/mpt2sas_base.c b/trunk/drivers/scsi/mpt2sas/mpt2sas_base.c index 83035bd1c489..efa0255491c2 100644 --- a/trunk/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/trunk/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -94,7 +94,7 @@ module_param(diag_buffer_enable, int, 0); MODULE_PARM_DESC(diag_buffer_enable, " post diag buffers " "(TRACE=1/SNAPSHOT=2/EXTENDED=4/default=0)"); -static int mpt2sas_fwfault_debug; +int mpt2sas_fwfault_debug; MODULE_PARM_DESC(mpt2sas_fwfault_debug, " enable detection of firmware fault " "and halt firmware - (default=0)"); @@ -857,7 +857,7 @@ _base_interrupt(int irq, void *bus_id) completed_cmds = 0; cb_idx = 0xFF; do { - rd.word = le64_to_cpu(rpf->Words); + rd.word = rpf->Words; if (rd.u.low == UINT_MAX || rd.u.high == UINT_MAX) goto out; reply = 0; @@ -906,7 +906,7 @@ _base_interrupt(int irq, void *bus_id) next: - rpf->Words = cpu_to_le64(ULLONG_MAX); + rpf->Words = ULLONG_MAX; ioc->reply_post_host_index = (ioc->reply_post_host_index == (ioc->reply_post_queue_depth - 1)) ? 0 : ioc->reply_post_host_index + 1; @@ -1740,11 +1740,9 @@ _base_display_dell_branding(struct MPT2SAS_ADAPTER *ioc) static void _base_display_intel_branding(struct MPT2SAS_ADAPTER *ioc) { - if (ioc->pdev->subsystem_vendor != PCI_VENDOR_ID_INTEL) - return; + if (ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_INTEL && + ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008) { - switch (ioc->pdev->device) { - case MPI2_MFGPAGE_DEVID_SAS2008: switch (ioc->pdev->subsystem_device) { case MPT2SAS_INTEL_RMS2LL080_SSDID: printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, @@ -1754,20 +1752,7 @@ _base_display_intel_branding(struct MPT2SAS_ADAPTER *ioc) printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, MPT2SAS_INTEL_RMS2LL040_BRANDING); break; - default: - break; - } - case MPI2_MFGPAGE_DEVID_SAS2308_2: - switch (ioc->pdev->subsystem_device) { - case MPT2SAS_INTEL_RS25GB008_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_RS25GB008_BRANDING); - break; - default: - break; } - default: - break; } } @@ -1832,9 +1817,7 @@ _base_display_ioc_capabilities(struct MPT2SAS_ADAPTER *ioc) char desc[16]; u8 revision; u32 iounit_pg1_flags; - u32 bios_version; - bios_version = le32_to_cpu(ioc->bios_pg3.BiosVersion); pci_read_config_byte(ioc->pdev, PCI_CLASS_REVISION, &revision); strncpy(desc, ioc->manu_pg0.ChipName, 16); printk(MPT2SAS_INFO_FMT "%s: FWVersion(%02d.%02d.%02d.%02d), " @@ -1845,10 +1828,10 @@ _base_display_ioc_capabilities(struct MPT2SAS_ADAPTER *ioc) (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8, ioc->facts.FWVersion.Word & 0x000000FF, revision, - (bios_version & 0xFF000000) >> 24, - (bios_version & 0x00FF0000) >> 16, - (bios_version & 0x0000FF00) >> 8, - bios_version & 0x000000FF); + (ioc->bios_pg3.BiosVersion & 0xFF000000) >> 24, + (ioc->bios_pg3.BiosVersion & 0x00FF0000) >> 16, + (ioc->bios_pg3.BiosVersion & 0x0000FF00) >> 8, + ioc->bios_pg3.BiosVersion & 0x000000FF); _base_display_dell_branding(ioc); _base_display_intel_branding(ioc); @@ -2167,7 +2150,7 @@ _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc) static int _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) { - struct mpt2sas_facts *facts; + Mpi2IOCFactsReply_t *facts; u32 queue_size, queue_diff; u16 max_sge_elements; u16 num_of_reply_frames; @@ -2800,7 +2783,7 @@ _base_handshake_req_reply_wait(struct MPT2SAS_ADAPTER *ioc, int request_bytes, int i; u8 failed; u16 dummy; - __le32 *mfp; + u32 *mfp; /* make sure doorbell is not in use */ if ((readl(&ioc->chip->Doorbell) & MPI2_DOORBELL_USED)) { @@ -2888,7 +2871,7 @@ _base_handshake_req_reply_wait(struct MPT2SAS_ADAPTER *ioc, int request_bytes, writel(0, &ioc->chip->HostInterruptStatus); if (ioc->logging_level & MPT_DEBUG_INIT) { - mfp = (__le32 *)reply; + mfp = (u32 *)reply; printk(KERN_INFO "\toffset:data\n"); for (i = 0; i < reply_bytes/4; i++) printk(KERN_INFO "\t[0x%02x]:%08x\n", i*4, @@ -3114,8 +3097,7 @@ static int _base_get_port_facts(struct MPT2SAS_ADAPTER *ioc, int port, int sleep_flag) { Mpi2PortFactsRequest_t mpi_request; - Mpi2PortFactsReply_t mpi_reply; - struct mpt2sas_port_facts *pfacts; + Mpi2PortFactsReply_t mpi_reply, *pfacts; int mpi_reply_sz, mpi_request_sz, r; dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, @@ -3157,8 +3139,7 @@ static int _base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) { Mpi2IOCFactsRequest_t mpi_request; - Mpi2IOCFactsReply_t mpi_reply; - struct mpt2sas_facts *facts; + Mpi2IOCFactsReply_t mpi_reply, *facts; int mpi_reply_sz, mpi_request_sz, r; dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, @@ -3244,6 +3225,17 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) mpi_request.MsgVersion = cpu_to_le16(MPI2_VERSION); mpi_request.HeaderVersion = cpu_to_le16(MPI2_HEADER_VERSION); + /* In MPI Revision I (0xA), the SystemReplyFrameSize(offset 0x18) was + * removed and made reserved. For those with older firmware will need + * this fix. It was decided that the Reply and Request frame sizes are + * the same. + */ + if ((ioc->facts.HeaderVersion >> 8) < 0xA) { + mpi_request.Reserved7 = cpu_to_le16(ioc->reply_sz); +/* mpi_request.SystemReplyFrameSize = + * cpu_to_le16(ioc->reply_sz); + */ + } mpi_request.SystemRequestFrameSize = cpu_to_le16(ioc->request_sz/4); mpi_request.ReplyDescriptorPostQueueDepth = @@ -3251,17 +3243,25 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) mpi_request.ReplyFreeQueueDepth = cpu_to_le16(ioc->reply_free_queue_depth); +#if BITS_PER_LONG > 32 mpi_request.SenseBufferAddressHigh = - cpu_to_le32((u64)ioc->sense_dma >> 32); + cpu_to_le32(ioc->sense_dma >> 32); mpi_request.SystemReplyAddressHigh = - cpu_to_le32((u64)ioc->reply_dma >> 32); + cpu_to_le32(ioc->reply_dma >> 32); mpi_request.SystemRequestFrameBaseAddress = - cpu_to_le64((u64)ioc->request_dma); + cpu_to_le64(ioc->request_dma); mpi_request.ReplyFreeQueueAddress = - cpu_to_le64((u64)ioc->reply_free_dma); + cpu_to_le64(ioc->reply_free_dma); mpi_request.ReplyDescriptorPostQueueAddress = - cpu_to_le64((u64)ioc->reply_post_free_dma); - + cpu_to_le64(ioc->reply_post_free_dma); +#else + mpi_request.SystemRequestFrameBaseAddress = + cpu_to_le32(ioc->request_dma); + mpi_request.ReplyFreeQueueAddress = + cpu_to_le32(ioc->reply_free_dma); + mpi_request.ReplyDescriptorPostQueueAddress = + cpu_to_le32(ioc->reply_post_free_dma); +#endif /* This time stamp specifies number of milliseconds * since epoch ~ midnight January 1, 1970. @@ -3271,10 +3271,10 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) (current_time.tv_usec / 1000)); if (ioc->logging_level & MPT_DEBUG_INIT) { - __le32 *mfp; + u32 *mfp; int i; - mfp = (__le32 *)&mpi_request; + mfp = (u32 *)&mpi_request; printk(KERN_INFO "\toffset:data\n"); for (i = 0; i < sizeof(Mpi2IOCInitRequest_t)/4; i++) printk(KERN_INFO "\t[0x%02x]:%08x\n", i*4, @@ -3759,7 +3759,7 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) /* initialize Reply Post Free Queue */ for (i = 0; i < ioc->reply_post_queue_depth; i++) - ioc->reply_post_free[i].Words = cpu_to_le64(ULLONG_MAX); + ioc->reply_post_free[i].Words = ULLONG_MAX; r = _base_send_ioc_init(ioc, sleep_flag); if (r) diff --git a/trunk/drivers/scsi/mpt2sas/mpt2sas_base.h b/trunk/drivers/scsi/mpt2sas/mpt2sas_base.h index 8d5be2120c63..dcc289c25459 100644 --- a/trunk/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/trunk/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -69,11 +69,11 @@ #define MPT2SAS_DRIVER_NAME "mpt2sas" #define MPT2SAS_AUTHOR "LSI Corporation " #define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver" -#define MPT2SAS_DRIVER_VERSION "09.100.00.00" -#define MPT2SAS_MAJOR_VERSION 09 +#define MPT2SAS_DRIVER_VERSION "08.100.00.02" +#define MPT2SAS_MAJOR_VERSION 08 #define MPT2SAS_MINOR_VERSION 100 #define MPT2SAS_BUILD_VERSION 00 -#define MPT2SAS_RELEASE_VERSION 00 +#define MPT2SAS_RELEASE_VERSION 02 /* * Set MPT2SAS_SG_DEPTH value based on user input. @@ -161,15 +161,12 @@ "Intel Integrated RAID Module RMS2LL080" #define MPT2SAS_INTEL_RMS2LL040_BRANDING \ "Intel Integrated RAID Module RMS2LL040" -#define MPT2SAS_INTEL_RS25GB008_BRANDING \ - "Intel(R) RAID Controller RS25GB008" /* * Intel HBA SSDIDs */ #define MPT2SAS_INTEL_RMS2LL080_SSDID 0x350E #define MPT2SAS_INTEL_RMS2LL040_SSDID 0x350F -#define MPT2SAS_INTEL_RS25GB008_SSDID 0x3000 /* @@ -544,63 +541,6 @@ struct _tr_list { typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr); -/* IOC Facts and Port Facts converted from little endian to cpu */ -union mpi2_version_union { - MPI2_VERSION_STRUCT Struct; - u32 Word; -}; - -struct mpt2sas_facts { - u16 MsgVersion; - u16 HeaderVersion; - u8 IOCNumber; - u8 VP_ID; - u8 VF_ID; - u16 IOCExceptions; - u16 IOCStatus; - u32 IOCLogInfo; - u8 MaxChainDepth; - u8 WhoInit; - u8 NumberOfPorts; - u8 MaxMSIxVectors; - u16 RequestCredit; - u16 ProductID; - u32 IOCCapabilities; - union mpi2_version_union FWVersion; - u16 IOCRequestFrameSize; - u16 Reserved3; - u16 MaxInitiators; - u16 MaxTargets; - u16 MaxSasExpanders; - u16 MaxEnclosures; - u16 ProtocolFlags; - u16 HighPriorityCredit; - u16 MaxReplyDescriptorPostQueueDepth; - u8 ReplyFrameSize; - u8 MaxVolumes; - u16 MaxDevHandle; - u16 MaxPersistentEntries; - u16 MinDevHandle; -}; - -struct mpt2sas_port_facts { - u8 PortNumber; - u8 VP_ID; - u8 VF_ID; - u8 PortType; - u16 MaxPostedCmdBuffers; -}; - -/** - * enum mutex_type - task management mutex type - * @TM_MUTEX_OFF: mutex is not required becuase calling function is acquiring it - * @TM_MUTEX_ON: mutex is required - */ -enum mutex_type { - TM_MUTEX_OFF = 0, - TM_MUTEX_ON = 1, -}; - /** * struct MPT2SAS_ADAPTER - per adapter struct * @list: ioc_list @@ -763,7 +703,6 @@ struct MPT2SAS_ADAPTER { /* misc flags */ int aen_event_read_flag; u8 broadcast_aen_busy; - u16 broadcast_aen_pending; u8 shost_recovery; struct mutex reset_in_progress_mutex; @@ -810,8 +749,8 @@ struct MPT2SAS_ADAPTER { u32 event_masks[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS]; /* static config pages */ - struct mpt2sas_facts facts; - struct mpt2sas_port_facts *pfacts; + Mpi2IOCFactsReply_t facts; + Mpi2PortFactsReply_t *pfacts; Mpi2ManufacturingPage0_t manu_pg0; Mpi2BiosPage2_t bios_pg2; Mpi2BiosPage3_t bios_pg3; @@ -901,7 +840,7 @@ struct MPT2SAS_ADAPTER { /* reply free queue */ u16 reply_free_queue_depth; - __le32 *reply_free; + u32 *reply_free; dma_addr_t reply_free_dma; struct dma_pool *reply_free_dma_pool; u32 reply_free_host_index; @@ -993,8 +932,8 @@ void mpt2sas_halt_firmware(struct MPT2SAS_ADAPTER *ioc); u8 mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, u32 reply); int mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, - uint channel, uint id, uint lun, u8 type, u16 smid_task, - ulong timeout, unsigned long serial_number, enum mutex_type m_type); + uint channel, uint id, uint lun, u8 type, u16 smid_task, + ulong timeout, struct scsi_cmnd *scmd); void mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle); void mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle); void mpt2sas_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address); diff --git a/trunk/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/trunk/drivers/scsi/mpt2sas/mpt2sas_ctl.c index 38ed0260959d..437c2d94c45a 100644 --- a/trunk/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/trunk/drivers/scsi/mpt2sas/mpt2sas_ctl.c @@ -994,7 +994,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, mpt2sas_scsih_issue_tm(ioc, le16_to_cpu(mpi_request->FunctionDependent1), 0, 0, 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10, - 0, TM_MUTEX_ON); + NULL); ioc->tm_cmds.status = MPT2_CMD_NOT_USED; } else mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, @@ -2706,13 +2706,13 @@ static DEVICE_ATTR(ioc_reset_count, S_IRUGO, _ctl_ioc_reset_count_show, NULL); struct DIAG_BUFFER_START { - __le32 Size; - __le32 DiagVersion; + u32 Size; + u32 DiagVersion; u8 BufferType; u8 Reserved[3]; - __le32 Reserved1; - __le32 Reserved2; - __le32 Reserved3; + u32 Reserved1; + u32 Reserved2; + u32 Reserved3; }; /** * _ctl_host_trace_buffer_size_show - host buffer size (trace only) diff --git a/trunk/drivers/scsi/mpt2sas/mpt2sas_debug.h b/trunk/drivers/scsi/mpt2sas/mpt2sas_debug.h index 9731f8e661bf..3dcddfeb6f4c 100644 --- a/trunk/drivers/scsi/mpt2sas/mpt2sas_debug.h +++ b/trunk/drivers/scsi/mpt2sas/mpt2sas_debug.h @@ -164,7 +164,7 @@ static inline void _debug_dump_mf(void *mpi_request, int sz) { int i; - __le32 *mfp = (__le32 *)mpi_request; + u32 *mfp = (u32 *)mpi_request; printk(KERN_INFO "mf:\n\t"); for (i = 0; i < sz; i++) { diff --git a/trunk/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/trunk/drivers/scsi/mpt2sas/mpt2sas_scsih.c index 939f283d0c28..a7dbc6825f5f 100644 --- a/trunk/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/trunk/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -94,10 +94,6 @@ static u32 logging_level; MODULE_PARM_DESC(logging_level, " bits for enabling additional logging info " "(default=0)"); -static ushort max_sectors = 0xFFFF; -module_param(max_sectors, ushort, 0); -MODULE_PARM_DESC(max_sectors, "max sectors, range 64 to 8192 default=8192"); - /* scsi-mid layer global parmeter is max_report_luns, which is 511 */ #define MPT2SAS_MAX_LUN (16895) static int max_lun = MPT2SAS_MAX_LUN; @@ -1960,7 +1956,7 @@ _scsih_slave_configure(struct scsi_device *sdev) case MPI2_RAID_VOL_TYPE_RAID1E: qdepth = MPT2SAS_RAID_QUEUE_DEPTH; if (ioc->manu_pg10.OEMIdentifier && - (le32_to_cpu(ioc->manu_pg10.GenericFlags0) & + (ioc->manu_pg10.GenericFlags0 & MFG10_GF0_R10_DISPLAY) && !(raid_device->num_pds % 2)) r_level = "RAID10"; @@ -2240,8 +2236,6 @@ mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle) * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in mpi2_init.h) * @smid_task: smid assigned to the task * @timeout: timeout in seconds - * @serial_number: the serial_number from scmd - * @m_type: TM_MUTEX_ON or TM_MUTEX_OFF * Context: user * * A generic API for sending task management requests to firmware. @@ -2253,18 +2247,17 @@ mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle) int mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel, uint id, uint lun, u8 type, u16 smid_task, ulong timeout, - unsigned long serial_number, enum mutex_type m_type) + struct scsi_cmnd *scmd) { Mpi2SCSITaskManagementRequest_t *mpi_request; Mpi2SCSITaskManagementReply_t *mpi_reply; u16 smid = 0; u32 ioc_state; unsigned long timeleft; - struct scsiio_tracker *scsi_lookup = NULL; + struct scsi_cmnd *scmd_lookup; int rc; - if (m_type == TM_MUTEX_ON) - mutex_lock(&ioc->tm_cmds.mutex); + mutex_lock(&ioc->tm_cmds.mutex); if (ioc->tm_cmds.status != MPT2_CMD_NOT_USED) { printk(MPT2SAS_INFO_FMT "%s: tm_cmd busy!!!\n", __func__, ioc->name); @@ -2284,18 +2277,18 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel, if (ioc_state & MPI2_DOORBELL_USED) { dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "unexpected doorbell " "active!\n", ioc->name)); - rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, + mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, FORCE_BIG_HAMMER); - rc = (!rc) ? SUCCESS : FAILED; + rc = SUCCESS; goto err_out; } if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { mpt2sas_base_fault_info(ioc, ioc_state & MPI2_DOORBELL_DATA_MASK); - rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, + mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, FORCE_BIG_HAMMER); - rc = (!rc) ? SUCCESS : FAILED; + rc = SUCCESS; goto err_out; } @@ -2307,9 +2300,6 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel, goto err_out; } - if (type == MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK) - scsi_lookup = &ioc->scsi_lookup[smid_task - 1]; - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "sending tm: handle(0x%04x)," " task_type(0x%02x), smid(%d)\n", ioc->name, handle, type, smid_task)); @@ -2317,7 +2307,6 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel, mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); ioc->tm_cmds.smid = smid; memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t)); - memset(ioc->tm_cmds.reply, 0, sizeof(Mpi2SCSITaskManagementReply_t)); mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; mpi_request->DevHandle = cpu_to_le16(handle); mpi_request->TaskType = type; @@ -2333,9 +2322,9 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel, _debug_dump_mf(mpi_request, sizeof(Mpi2SCSITaskManagementRequest_t)/4); if (!(ioc->tm_cmds.status & MPT2_CMD_RESET)) { - rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, + mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, FORCE_BIG_HAMMER); - rc = (!rc) ? SUCCESS : FAILED; + rc = SUCCESS; ioc->tm_cmds.status = MPT2_CMD_NOT_USED; mpt2sas_scsih_clear_tm_flag(ioc, handle); goto err_out; @@ -2357,12 +2346,20 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel, } } + /* sanity check: + * Check to see the commands were terminated. + * This is only needed for eh callbacks, hence the scmd check. + */ + rc = FAILED; + if (scmd == NULL) + goto bypass_sanity_checks; switch (type) { case MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK: - rc = SUCCESS; - if (scsi_lookup->scmd == NULL) - break; - rc = FAILED; + scmd_lookup = _scsih_scsi_lookup_get(ioc, smid_task); + if (scmd_lookup) + rc = FAILED; + else + rc = SUCCESS; break; case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET: @@ -2372,31 +2369,24 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel, rc = SUCCESS; break; - case MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET: case MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET: if (_scsih_scsi_lookup_find_by_lun(ioc, id, lun, channel)) rc = FAILED; else rc = SUCCESS; break; - case MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK: - rc = SUCCESS; - break; - default: - rc = FAILED; - break; } + bypass_sanity_checks: + mpt2sas_scsih_clear_tm_flag(ioc, handle); ioc->tm_cmds.status = MPT2_CMD_NOT_USED; - if (m_type == TM_MUTEX_ON) - mutex_unlock(&ioc->tm_cmds.mutex); + mutex_unlock(&ioc->tm_cmds.mutex); return rc; err_out: - if (m_type == TM_MUTEX_ON) - mutex_unlock(&ioc->tm_cmds.mutex); + mutex_unlock(&ioc->tm_cmds.mutex); return rc; } @@ -2506,8 +2496,7 @@ _scsih_abort(struct scsi_cmnd *scmd) handle = sas_device_priv_data->sas_target->handle; r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel, scmd->device->id, scmd->device->lun, - MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30, - scmd->serial_number, TM_MUTEX_ON); + MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30, scmd); out: sdev_printk(KERN_INFO, scmd->device, "task abort: %s scmd(%p)\n", @@ -2568,8 +2557,7 @@ _scsih_dev_reset(struct scsi_cmnd *scmd) r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel, scmd->device->id, scmd->device->lun, - MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, 0, 30, 0, - TM_MUTEX_ON); + MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, 0, 30, scmd); out: sdev_printk(KERN_INFO, scmd->device, "device reset: %s scmd(%p)\n", @@ -2629,7 +2617,7 @@ _scsih_target_reset(struct scsi_cmnd *scmd) r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel, scmd->device->id, 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, - 30, 0, TM_MUTEX_ON); + 30, scmd); out: starget_printk(KERN_INFO, starget, "target reset: %s scmd(%p)\n", @@ -2761,31 +2749,6 @@ _scsih_fw_event_cleanup_queue(struct MPT2SAS_ADAPTER *ioc) } } -/** - * _scsih_ublock_io_all_device - unblock every device - * @ioc: per adapter object - * - * change the device state from block to running - */ -static void -_scsih_ublock_io_all_device(struct MPT2SAS_ADAPTER *ioc) -{ - struct MPT2SAS_DEVICE *sas_device_priv_data; - struct scsi_device *sdev; - - shost_for_each_device(sdev, ioc->shost) { - sas_device_priv_data = sdev->hostdata; - if (!sas_device_priv_data) - continue; - if (!sas_device_priv_data->block) - continue; - sas_device_priv_data->block = 0; - dewtprintk(ioc, sdev_printk(KERN_INFO, sdev, "device_running, " - "handle(0x%04x)\n", - sas_device_priv_data->sas_target->handle)); - scsi_internal_device_unblock(sdev); - } -} /** * _scsih_ublock_io_device - set the device state to SDEV_RUNNING * @ioc: per adapter object @@ -2815,34 +2778,6 @@ _scsih_ublock_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle) } } -/** - * _scsih_block_io_all_device - set the device state to SDEV_BLOCK - * @ioc: per adapter object - * @handle: device handle - * - * During device pull we need to appropiately set the sdev state. - */ -static void -_scsih_block_io_all_device(struct MPT2SAS_ADAPTER *ioc) -{ - struct MPT2SAS_DEVICE *sas_device_priv_data; - struct scsi_device *sdev; - - shost_for_each_device(sdev, ioc->shost) { - sas_device_priv_data = sdev->hostdata; - if (!sas_device_priv_data) - continue; - if (sas_device_priv_data->block) - continue; - sas_device_priv_data->block = 1; - dewtprintk(ioc, sdev_printk(KERN_INFO, sdev, "device_blocked, " - "handle(0x%04x)\n", - sas_device_priv_data->sas_target->handle)); - scsi_internal_device_block(sdev); - } -} - - /** * _scsih_block_io_device - set the device state to SDEV_BLOCK * @ioc: per adapter object @@ -3763,7 +3698,7 @@ _scsih_qcmd_lck(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *)) return 0; } - if (ioc->pci_error_recovery || ioc->remove_host) { + if (ioc->pci_error_recovery) { scmd->result = DID_NO_CONNECT << 16; scmd->scsi_done(scmd); return 0; @@ -4663,7 +4598,7 @@ _scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle) Mpi2SasEnclosurePage0_t enclosure_pg0; u32 ioc_status; u16 parent_handle; - u64 sas_address, sas_address_parent = 0; + __le64 sas_address, sas_address_parent = 0; int i; unsigned long flags; struct _sas_port *mpt2sas_port = NULL; @@ -5445,10 +5380,9 @@ _scsih_sas_device_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc, break; } printk(MPT2SAS_INFO_FMT "device status change: (%s)\n" - "\thandle(0x%04x), sas address(0x%016llx), tag(%d)", - ioc->name, reason_str, le16_to_cpu(event_data->DevHandle), - (unsigned long long)le64_to_cpu(event_data->SASAddress), - le16_to_cpu(event_data->TaskTag)); + "\thandle(0x%04x), sas address(0x%016llx)", ioc->name, + reason_str, le16_to_cpu(event_data->DevHandle), + (unsigned long long)le64_to_cpu(event_data->SASAddress)); if (event_data->ReasonCode == MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA) printk(MPT2SAS_INFO_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name, event_data->ASC, event_data->ASCQ); @@ -5470,7 +5404,7 @@ _scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc, { struct MPT2SAS_TARGET *target_priv_data; struct _sas_device *sas_device; - u64 sas_address; + __le64 sas_address; unsigned long flags; Mpi2EventDataSasDeviceStatusChange_t *event_data = fw_event->event_data; @@ -5588,38 +5522,25 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, u32 termination_count; u32 query_count; Mpi2SCSITaskManagementReply_t *mpi_reply; +#ifdef CONFIG_SCSI_MPT2SAS_LOGGING Mpi2EventDataSasBroadcastPrimitive_t *event_data = fw_event->event_data; +#endif u16 ioc_status; unsigned long flags; int r; - u8 max_retries = 0; - u8 task_abort_retries; - mutex_lock(&ioc->tm_cmds.mutex); - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: phy number(%d), " - "width(%d)\n", ioc->name, __func__, event_data->PhyNum, - event_data->PortWidth)); - - _scsih_block_io_all_device(ioc); + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "broadcast primitive: " + "phy number(%d), width(%d)\n", ioc->name, event_data->PhyNum, + event_data->PortWidth)); + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, + __func__)); spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - mpi_reply = ioc->tm_cmds.reply; -broadcast_aen_retry: - - /* sanity checks for retrying this loop */ - if (max_retries++ == 5) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: giving up\n", - ioc->name, __func__)); - goto out; - } else if (max_retries > 1) - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: %d retry\n", - ioc->name, __func__, max_retries - 1)); - + ioc->broadcast_aen_busy = 0; termination_count = 0; query_count = 0; + mpi_reply = ioc->tm_cmds.reply; for (smid = 1; smid <= ioc->scsiio_depth; smid++) { - if (ioc->ioc_reset_in_progress_status) - goto out; scmd = _scsih_scsi_lookup_get(ioc, smid); if (!scmd) continue; @@ -5640,90 +5561,34 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, lun = sas_device_priv_data->lun; query_count++; - if (ioc->ioc_reset_in_progress_status) - goto out; - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - r = mpt2sas_scsih_issue_tm(ioc, handle, 0, 0, lun, - MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30, 0, - TM_MUTEX_OFF); - if (r == FAILED) { - sdev_printk(KERN_WARNING, sdev, - "mpt2sas_scsih_issue_tm: FAILED when sending " - "QUERY_TASK: scmd(%p)\n", scmd); - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - goto broadcast_aen_retry; - } + mpt2sas_scsih_issue_tm(ioc, handle, 0, 0, lun, + MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30, NULL); + ioc->tm_cmds.status = MPT2_CMD_NOT_USED; ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - sdev_printk(KERN_WARNING, sdev, "query task: FAILED " - "with IOCSTATUS(0x%04x), scmd(%p)\n", ioc_status, - scmd); - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - goto broadcast_aen_retry; - } - - /* see if IO is still owned by IOC and target */ - if (mpi_reply->ResponseCode == + if ((ioc_status == MPI2_IOCSTATUS_SUCCESS) && + (mpi_reply->ResponseCode == MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED || mpi_reply->ResponseCode == - MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC) { + MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC)) { spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); continue; } - task_abort_retries = 0; - tm_retry: - if (task_abort_retries++ == 60) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT - "%s: ABORT_TASK: giving up\n", ioc->name, - __func__)); - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - goto broadcast_aen_retry; - } - - if (ioc->ioc_reset_in_progress_status) - goto out_no_lock; - r = mpt2sas_scsih_issue_tm(ioc, handle, sdev->channel, sdev->id, sdev->lun, MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30, - scmd->serial_number, TM_MUTEX_OFF); - if (r == FAILED) { - sdev_printk(KERN_WARNING, sdev, - "mpt2sas_scsih_issue_tm: ABORT_TASK: FAILED : " + scmd); + if (r == FAILED) + sdev_printk(KERN_WARNING, sdev, "task abort: FAILED " "scmd(%p)\n", scmd); - goto tm_retry; - } - - if (task_abort_retries > 1) - sdev_printk(KERN_WARNING, sdev, - "mpt2sas_scsih_issue_tm: ABORT_TASK: RETRIES (%d):" - " scmd(%p)\n", - task_abort_retries - 1, scmd); - termination_count += le32_to_cpu(mpi_reply->TerminationCount); spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); } - - if (ioc->broadcast_aen_pending) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: loop back due to" - " pending AEN\n", ioc->name, __func__)); - ioc->broadcast_aen_pending = 0; - goto broadcast_aen_retry; - } - - out: spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - out_no_lock: - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s - exit, query_count = %d termination_count = %d\n", ioc->name, __func__, query_count, termination_count)); - - ioc->broadcast_aen_busy = 0; - if (!ioc->ioc_reset_in_progress_status) - _scsih_ublock_io_all_device(ioc); - mutex_unlock(&ioc->tm_cmds.mutex); } /** @@ -6701,7 +6566,7 @@ _scsih_search_responding_expanders(struct MPT2SAS_ADAPTER *ioc) Mpi2ExpanderPage0_t expander_pg0; Mpi2ConfigReply_t mpi_reply; u16 ioc_status; - u64 sas_address; + __le64 sas_address; u16 handle; printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__); @@ -6997,14 +6862,10 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, mpi_reply->EventData; if (baen_data->Primitive != - MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT) + MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT || + ioc->broadcast_aen_busy) return 1; - - if (ioc->broadcast_aen_busy) { - ioc->broadcast_aen_pending++; - return 1; - } else - ioc->broadcast_aen_busy = 1; + ioc->broadcast_aen_busy = 1; break; } @@ -7350,6 +7211,7 @@ _scsih_remove(struct pci_dev *pdev) } sas_remove_host(shost); + _scsih_shutdown(pdev); list_del(&ioc->list); scsi_remove_host(shost); scsi_host_put(shost); @@ -7574,25 +7436,6 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) shost->transportt = mpt2sas_transport_template; shost->unique_id = ioc->id; - if (max_sectors != 0xFFFF) { - if (max_sectors < 64) { - shost->max_sectors = 64; - printk(MPT2SAS_WARN_FMT "Invalid value %d passed " - "for max_sectors, range is 64 to 8192. Assigning " - "value of 64.\n", ioc->name, max_sectors); - } else if (max_sectors > 8192) { - shost->max_sectors = 8192; - printk(MPT2SAS_WARN_FMT "Invalid value %d passed " - "for max_sectors, range is 64 to 8192. Assigning " - "default value of 8192.\n", ioc->name, - max_sectors); - } else { - shost->max_sectors = max_sectors & 0xFFFE; - printk(MPT2SAS_INFO_FMT "The max_sectors value is " - "set to %d\n", ioc->name, shost->max_sectors); - } - } - if ((scsi_add_host(shost, &pdev->dev))) { printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); @@ -7662,7 +7505,7 @@ _scsih_suspend(struct pci_dev *pdev, pm_message_t state) { struct Scsi_Host *shost = pci_get_drvdata(pdev); struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - pci_power_t device_state; + u32 device_state; mpt2sas_base_stop_watchdog(ioc); scsi_block_requests(shost); @@ -7689,7 +7532,7 @@ _scsih_resume(struct pci_dev *pdev) { struct Scsi_Host *shost = pci_get_drvdata(pdev); struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - pci_power_t device_state = pdev->current_state; + u32 device_state = pdev->current_state; int r; printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, previous " diff --git a/trunk/drivers/scsi/mpt2sas/mpt2sas_transport.c b/trunk/drivers/scsi/mpt2sas/mpt2sas_transport.c index 15c798026217..cb1cdecbe0f8 100644 --- a/trunk/drivers/scsi/mpt2sas/mpt2sas_transport.c +++ b/trunk/drivers/scsi/mpt2sas/mpt2sas_transport.c @@ -299,6 +299,7 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc, void *data_out = NULL; dma_addr_t data_out_dma; u32 sz; + u64 *sas_address_le; u16 wait_state_count; if (ioc->shost_recovery || ioc->pci_error_recovery) { @@ -371,7 +372,8 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc, mpi_request->PhysicalPort = 0xFF; mpi_request->VF_ID = 0; /* TODO */ mpi_request->VP_ID = 0; - mpi_request->SASAddress = cpu_to_le64(sas_address); + sas_address_le = (u64 *)&mpi_request->SASAddress; + *sas_address_le = cpu_to_le64(sas_address); mpi_request->RequestDataLength = cpu_to_le16(sizeof(struct rep_manu_request)); psge = &mpi_request->SGL; @@ -1047,14 +1049,14 @@ struct phy_error_log_reply{ u8 function; /* 0x11 */ u8 function_result; u8 response_length; - __be16 expander_change_count; + u16 expander_change_count; u8 reserved_1[3]; u8 phy_identifier; u8 reserved_2[2]; - __be32 invalid_dword; - __be32 running_disparity_error; - __be32 loss_of_dword_sync; - __be32 phy_reset_problem; + u32 invalid_dword; + u32 running_disparity_error; + u32 loss_of_dword_sync; + u32 phy_reset_problem; }; /** @@ -1083,6 +1085,7 @@ _transport_get_expander_phy_error_log(struct MPT2SAS_ADAPTER *ioc, void *data_out = NULL; dma_addr_t data_out_dma; u32 sz; + u64 *sas_address_le; u16 wait_state_count; if (ioc->shost_recovery || ioc->pci_error_recovery) { @@ -1157,7 +1160,8 @@ _transport_get_expander_phy_error_log(struct MPT2SAS_ADAPTER *ioc, mpi_request->PhysicalPort = 0xFF; mpi_request->VF_ID = 0; /* TODO */ mpi_request->VP_ID = 0; - mpi_request->SASAddress = cpu_to_le64(phy->identify.sas_address); + sas_address_le = (u64 *)&mpi_request->SASAddress; + *sas_address_le = cpu_to_le64(phy->identify.sas_address); mpi_request->RequestDataLength = cpu_to_le16(sizeof(struct phy_error_log_request)); psge = &mpi_request->SGL; @@ -1402,6 +1406,7 @@ _transport_expander_phy_control(struct MPT2SAS_ADAPTER *ioc, void *data_out = NULL; dma_addr_t data_out_dma; u32 sz; + u64 *sas_address_le; u16 wait_state_count; if (ioc->shost_recovery) { @@ -1481,7 +1486,8 @@ _transport_expander_phy_control(struct MPT2SAS_ADAPTER *ioc, mpi_request->PhysicalPort = 0xFF; mpi_request->VF_ID = 0; /* TODO */ mpi_request->VP_ID = 0; - mpi_request->SASAddress = cpu_to_le64(phy->identify.sas_address); + sas_address_le = (u64 *)&mpi_request->SASAddress; + *sas_address_le = cpu_to_le64(phy->identify.sas_address); mpi_request->RequestDataLength = cpu_to_le16(sizeof(struct phy_error_log_request)); psge = &mpi_request->SGL; @@ -1908,7 +1914,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, mpi_request->PhysicalPort = 0xFF; mpi_request->VF_ID = 0; /* TODO */ mpi_request->VP_ID = 0; - mpi_request->SASAddress = (rphy) ? + *((u64 *)&mpi_request->SASAddress) = (rphy) ? cpu_to_le64(rphy->identify.sas_address) : cpu_to_le64(ioc->sas_hba.sas_address); mpi_request->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4); diff --git a/trunk/drivers/scsi/scsi_devinfo.c b/trunk/drivers/scsi/scsi_devinfo.c index cf8dfab9489f..82e9e5c0476e 100644 --- a/trunk/drivers/scsi/scsi_devinfo.c +++ b/trunk/drivers/scsi/scsi_devinfo.c @@ -197,7 +197,6 @@ static struct { {"IBM", "ProFibre 4000R", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, {"IBM", "2105", NULL, BLIST_RETRY_HWERROR}, {"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN}, - {"IOMEGA", "ZIP", NULL, BLIST_NOTQ | BLIST_NOLUN}, {"IOMEGA", "Io20S *F", NULL, BLIST_KEY}, {"INSITE", "Floptical F*8I", NULL, BLIST_KEY}, {"INSITE", "I325VM", NULL, BLIST_KEY}, @@ -244,7 +243,6 @@ static struct { {"Tornado-", "F4", "*", BLIST_NOREPORTLUN}, {"TOSHIBA", "CDROM", NULL, BLIST_ISROM}, {"TOSHIBA", "CD-ROM", NULL, BLIST_ISROM}, - {"Traxdata", "CDR4120", NULL, BLIST_NOLUN}, /* locks up */ {"USB2.0", "SMARTMEDIA/XD", NULL, BLIST_FORCELUN | BLIST_INQUIRY_36}, {"WangDAT", "Model 2600", "01.7", BLIST_SELECT_NO_ATN}, {"WangDAT", "Model 3200", "02.2", BLIST_SELECT_NO_ATN}, diff --git a/trunk/drivers/scsi/scsi_lib.c b/trunk/drivers/scsi/scsi_lib.c index 28d9c9d6b4b4..ec1803a48723 100644 --- a/trunk/drivers/scsi/scsi_lib.c +++ b/trunk/drivers/scsi/scsi_lib.c @@ -213,8 +213,6 @@ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, int ret = DRIVER_ERROR << 24; req = blk_get_request(sdev->request_queue, write, __GFP_WAIT); - if (!req) - return ret; if (bufflen && blk_rq_map_kern(sdev->request_queue, req, buffer, bufflen, __GFP_WAIT)) diff --git a/trunk/drivers/scsi/ses.c b/trunk/drivers/scsi/ses.c index eba183c428cf..eb7a3e85304f 100644 --- a/trunk/drivers/scsi/ses.c +++ b/trunk/drivers/scsi/ses.c @@ -160,10 +160,6 @@ static unsigned char *ses_get_page2_descriptor(struct enclosure_device *edev, return NULL; } -/* For device slot and array device slot elements, byte 3 bit 6 - * is "fault sensed" while byte 3 bit 5 is "fault reqstd". As this - * code stands these bits are shifted 4 positions right so in - * sysfs they will appear as bits 2 and 1 respectively. Strange. */ static void ses_get_fault(struct enclosure_device *edev, struct enclosure_component *ecomp) { @@ -185,7 +181,7 @@ static int ses_set_fault(struct enclosure_device *edev, /* zero is disabled */ break; case ENCLOSURE_SETTING_ENABLED: - desc[3] = 0x20; + desc[2] = 0x02; break; default: /* SES doesn't do the SGPIO blink settings */ diff --git a/trunk/drivers/scsi/sr.c b/trunk/drivers/scsi/sr.c index 5fc97d2ba2fd..4778e2707168 100644 --- a/trunk/drivers/scsi/sr.c +++ b/trunk/drivers/scsi/sr.c @@ -221,33 +221,14 @@ static unsigned int sr_check_events(struct cdrom_device_info *cdi, return 0; events = sr_get_events(cd->device); - cd->get_event_changed |= events & DISK_EVENT_MEDIA_CHANGE; - - /* - * If earlier GET_EVENT_STATUS_NOTIFICATION and TUR did not agree - * for several times in a row. We rely on TUR only for this likely - * broken device, to prevent generating incorrect media changed - * events for every open(). - */ - if (cd->ignore_get_event) { - events &= ~DISK_EVENT_MEDIA_CHANGE; - goto do_tur; - } - /* * GET_EVENT_STATUS_NOTIFICATION is enough unless MEDIA_CHANGE * is being cleared. Note that there are devices which hang * if asked to execute TUR repeatedly. */ - if (cd->device->changed) { - events |= DISK_EVENT_MEDIA_CHANGE; - cd->device->changed = 0; - cd->tur_changed = true; - } - if (!(clearing & DISK_EVENT_MEDIA_CHANGE)) - return events; -do_tur: + goto skip_tur; + /* let's see whether the media is there with TUR */ last_present = cd->media_present; ret = scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr); @@ -261,31 +242,12 @@ static unsigned int sr_check_events(struct cdrom_device_info *cdi, (scsi_sense_valid(&sshdr) && sshdr.asc != 0x3a); if (last_present != cd->media_present) - cd->device->changed = 1; - + events |= DISK_EVENT_MEDIA_CHANGE; +skip_tur: if (cd->device->changed) { events |= DISK_EVENT_MEDIA_CHANGE; cd->device->changed = 0; - cd->tur_changed = true; - } - - if (cd->ignore_get_event) - return events; - - /* check whether GET_EVENT is reporting spurious MEDIA_CHANGE */ - if (!cd->tur_changed) { - if (cd->get_event_changed) { - if (cd->tur_mismatch++ > 8) { - sdev_printk(KERN_WARNING, cd->device, - "GET_EVENT and TUR disagree continuously, suppress GET_EVENT events\n"); - cd->ignore_get_event = true; - } - } else { - cd->tur_mismatch = 0; - } } - cd->tur_changed = false; - cd->get_event_changed = false; return events; } diff --git a/trunk/drivers/scsi/sr.h b/trunk/drivers/scsi/sr.h index 37c8f6b17510..e036f1dc83c8 100644 --- a/trunk/drivers/scsi/sr.h +++ b/trunk/drivers/scsi/sr.h @@ -41,13 +41,6 @@ typedef struct scsi_cd { unsigned readcd_known:1; /* drive supports READ_CD (0xbe) */ unsigned readcd_cdda:1; /* reading audio data using READ_CD */ unsigned media_present:1; /* media is present */ - - /* GET_EVENT spurious event handling, blk layer guarantees exclusion */ - int tur_mismatch; /* nr of get_event TUR mismatches */ - bool tur_changed:1; /* changed according to TUR */ - bool get_event_changed:1; /* changed according to GET_EVENT */ - bool ignore_get_event:1; /* GET_EVENT is unreliable, use TUR */ - struct cdrom_device_info cdi; /* We hold gendisk and scsi_device references on probe and use * the refs on this kref to decide when to release them */ diff --git a/trunk/drivers/scsi/sun3_NCR5380.c b/trunk/drivers/scsi/sun3_NCR5380.c index 7e12a2e4e0a3..07eaef1c722b 100644 --- a/trunk/drivers/scsi/sun3_NCR5380.c +++ b/trunk/drivers/scsi/sun3_NCR5380.c @@ -49,6 +49,13 @@ * inside the execution of NCR5380_intr(), leading to recursive * calls. * + * - I've added a function merge_contiguous_buffers() that tries to + * merge scatter-gather buffers that are located at contiguous + * physical addresses and can be processed with the same DMA setup. + * Since most scatter-gather operations work on a page (4K) of + * 4 buffers (1K), in more than 90% of all cases three interrupts and + * DMA setup actions are saved. + * * - I've deleted all the stuff for AUTOPROBE_IRQ, REAL_DMA_POLL, PSEUDO_DMA * and USLEEP, because these were messing up readability and will never be * needed for Atari SCSI. @@ -259,9 +266,8 @@ static struct scsi_host_template *the_template = NULL; (struct NCR5380_hostdata *)(in)->hostdata #define HOSTDATA(in) ((struct NCR5380_hostdata *)(in)->hostdata) -#define NEXT(cmd) ((struct scsi_cmnd *)(cmd)->host_scribble) -#define SET_NEXT(cmd, next) ((cmd)->host_scribble = (void *)(next)) -#define NEXTADDR(cmd) ((struct scsi_cmnd **)&((cmd)->host_scribble)) +#define NEXT(cmd) (*(struct scsi_cmnd **)&((cmd)->host_scribble)) +#define NEXTADDR(cmd) ((struct scsi_cmnd **)&((cmd)->host_scribble)) #define HOSTNO instance->host_no #define H_NO(cmd) (cmd)->device->host->host_no @@ -452,6 +458,47 @@ static void free_all_tags( void ) #endif /* SUPPORT_TAGS */ +/* + * Function: void merge_contiguous_buffers(struct scsi_cmnd *cmd) + * + * Purpose: Try to merge several scatter-gather requests into one DMA + * transfer. This is possible if the scatter buffers lie on + * physical contiguous addresses. + * + * Parameters: struct scsi_cmnd *cmd + * The command to work on. The first scatter buffer's data are + * assumed to be already transferred into ptr/this_residual. + */ + +static void merge_contiguous_buffers(struct scsi_cmnd *cmd) +{ + unsigned long endaddr; +#if (NDEBUG & NDEBUG_MERGING) + unsigned long oldlen = cmd->SCp.this_residual; + int cnt = 1; +#endif + + for (endaddr = virt_to_phys(cmd->SCp.ptr + cmd->SCp.this_residual - 1) + 1; + cmd->SCp.buffers_residual && + virt_to_phys(SGADDR(&(cmd->SCp.buffer[1]))) == endaddr; ) { + + MER_PRINTK("VTOP(%p) == %08lx -> merging\n", + SGADDR(&(cmd->SCp.buffer[1])), endaddr); +#if (NDEBUG & NDEBUG_MERGING) + ++cnt; +#endif + ++cmd->SCp.buffer; + --cmd->SCp.buffers_residual; + cmd->SCp.this_residual += cmd->SCp.buffer->length; + endaddr += cmd->SCp.buffer->length; + } +#if (NDEBUG & NDEBUG_MERGING) + if (oldlen != cmd->SCp.this_residual) + MER_PRINTK("merged %d buffers from %p, new length %08x\n", + cnt, cmd->SCp.ptr, cmd->SCp.this_residual); +#endif +} + /* * Function : void initialize_SCp(struct scsi_cmnd *cmd) * @@ -473,6 +520,11 @@ static __inline__ void initialize_SCp(struct scsi_cmnd *cmd) cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1; cmd->SCp.ptr = (char *) SGADDR(cmd->SCp.buffer); cmd->SCp.this_residual = cmd->SCp.buffer->length; + + /* ++roman: Try to merge some scatter-buffers if they are at + * contiguous physical addresses. + */ +// merge_contiguous_buffers( cmd ); } else { cmd->SCp.buffer = NULL; cmd->SCp.buffers_residual = 0; @@ -789,7 +841,7 @@ static char *lprint_Scsi_Cmnd(struct scsi_cmnd *cmd, char *pos, char *buffer, * */ -static int __init NCR5380_init(struct Scsi_Host *instance, int flags) +static int NCR5380_init (struct Scsi_Host *instance, int flags) { int i; SETUP_HOSTDATA(instance); @@ -837,11 +889,6 @@ static int __init NCR5380_init(struct Scsi_Host *instance, int flags) return 0; } -static void NCR5380_exit(struct Scsi_Host *instance) -{ - /* Empty, as we didn't schedule any delayed work */ -} - /* * Function : int NCR5380_queue_command (struct scsi_cmnd *cmd, * void (*done)(struct scsi_cmnd *)) @@ -915,7 +962,7 @@ static int NCR5380_queue_command_lck(struct scsi_cmnd *cmd, * in a queue */ - SET_NEXT(cmd, NULL); + NEXT(cmd) = NULL; cmd->scsi_done = done; cmd->result = 0; @@ -943,14 +990,14 @@ static int NCR5380_queue_command_lck(struct scsi_cmnd *cmd, */ if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) { LIST(cmd, hostdata->issue_queue); - SET_NEXT(cmd, hostdata->issue_queue); + NEXT(cmd) = hostdata->issue_queue; hostdata->issue_queue = cmd; } else { for (tmp = (struct scsi_cmnd *)hostdata->issue_queue; NEXT(tmp); tmp = NEXT(tmp)) ; LIST(cmd, tmp); - SET_NEXT(tmp, cmd); + NEXT(tmp) = cmd; } local_irq_restore(flags); @@ -1058,12 +1105,12 @@ static void NCR5380_main (struct work_struct *bl) local_irq_disable(); if (prev) { REMOVE(prev, NEXT(prev), tmp, NEXT(tmp)); - SET_NEXT(prev, NEXT(tmp)); + NEXT(prev) = NEXT(tmp); } else { REMOVE(-1, hostdata->issue_queue, tmp, NEXT(tmp)); hostdata->issue_queue = NEXT(tmp); } - SET_NEXT(tmp, NULL); + NEXT(tmp) = NULL; /* reenable interrupts after finding one */ local_irq_restore(flags); @@ -1097,7 +1144,7 @@ static void NCR5380_main (struct work_struct *bl) } else { local_irq_disable(); LIST(tmp, hostdata->issue_queue); - SET_NEXT(tmp, hostdata->issue_queue); + NEXT(tmp) = hostdata->issue_queue; hostdata->issue_queue = tmp; #ifdef SUPPORT_TAGS cmd_free_tag( tmp ); @@ -1392,7 +1439,7 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd, local_irq_restore(flags); /* Wait for arbitration logic to complete */ -#ifdef NCR_TIMEOUT +#if NCR_TIMEOUT { unsigned long timeout = jiffies + 2*NCR_TIMEOUT; @@ -2023,6 +2070,11 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) --cmd->SCp.buffers_residual; cmd->SCp.this_residual = cmd->SCp.buffer->length; cmd->SCp.ptr = SGADDR(cmd->SCp.buffer); + + /* ++roman: Try to merge some scatter-buffers if + * they are at contiguous physical addresses. + */ +// merge_contiguous_buffers( cmd ); INF_PRINTK("scsi%d: %d bytes and %d buffers left\n", HOSTNO, cmd->SCp.this_residual, cmd->SCp.buffers_residual); @@ -2222,7 +2274,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) local_irq_save(flags); LIST(cmd,hostdata->issue_queue); - SET_NEXT(cmd, hostdata->issue_queue); + NEXT(cmd) = hostdata->issue_queue; hostdata->issue_queue = (struct scsi_cmnd *) cmd; local_irq_restore(flags); QU_PRINTK("scsi%d: REQUEST SENSE added to head of " @@ -2278,7 +2330,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) local_irq_save(flags); cmd->device->disconnect = 1; LIST(cmd,hostdata->disconnected_queue); - SET_NEXT(cmd, hostdata->disconnected_queue); + NEXT(cmd) = hostdata->disconnected_queue; hostdata->connected = NULL; hostdata->disconnected_queue = cmd; local_irq_restore(flags); @@ -2537,12 +2589,12 @@ static void NCR5380_reselect (struct Scsi_Host *instance) ) { if (prev) { REMOVE(prev, NEXT(prev), tmp, NEXT(tmp)); - SET_NEXT(prev, NEXT(tmp)); + NEXT(prev) = NEXT(tmp); } else { REMOVE(-1, hostdata->disconnected_queue, tmp, NEXT(tmp)); hostdata->disconnected_queue = NEXT(tmp); } - SET_NEXT(tmp, NULL); + NEXT(tmp) = NULL; break; } } @@ -2710,7 +2762,7 @@ static int NCR5380_abort(struct scsi_cmnd *cmd) if (cmd == tmp) { REMOVE(5, *prev, tmp, NEXT(tmp)); (*prev) = NEXT(tmp); - SET_NEXT(tmp, NULL); + NEXT(tmp) = NULL; tmp->result = DID_ABORT << 16; local_irq_restore(flags); ABRT_PRINTK("scsi%d: abort removed command from issue queue.\n", @@ -2783,7 +2835,7 @@ static int NCR5380_abort(struct scsi_cmnd *cmd) if (cmd == tmp) { REMOVE(5, *prev, tmp, NEXT(tmp)); *prev = NEXT(tmp); - SET_NEXT(tmp, NULL); + NEXT(tmp) = NULL; tmp->result = DID_ABORT << 16; /* We must unlock the tag/LUN immediately here, since the * target goes to BUS FREE and doesn't send us another @@ -2891,7 +2943,7 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd) for (i = 0; (cmd = disconnected_queue); ++i) { disconnected_queue = NEXT(cmd); - SET_NEXT(cmd, NULL); + NEXT(cmd) = NULL; cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16); cmd->scsi_done( cmd ); } diff --git a/trunk/drivers/scsi/sun3_scsi.c b/trunk/drivers/scsi/sun3_scsi.c index baf7328de956..613f5880d135 100644 --- a/trunk/drivers/scsi/sun3_scsi.c +++ b/trunk/drivers/scsi/sun3_scsi.c @@ -70,12 +70,6 @@ #include #include -#define NDEBUG 0 - -#define NDEBUG_ABORT 0x00100000 -#define NDEBUG_TAGS 0x00200000 -#define NDEBUG_MERGING 0x00400000 - /* dma on! */ #define REAL_DMA @@ -92,6 +86,8 @@ static void NCR5380_print(struct Scsi_Host *instance); /*#define RESET_BOOT */ #define DRIVER_SETUP +#define NDEBUG 0 + /* * BUG can be used to trigger a strange code-size related hang on 2.1 kernels */ @@ -199,7 +195,7 @@ static struct Scsi_Host *default_instance; * */ -int __init sun3scsi_detect(struct scsi_host_template * tpnt) +int sun3scsi_detect(struct scsi_host_template * tpnt) { unsigned long ioaddr; static int called = 0; @@ -318,7 +314,6 @@ int sun3scsi_release (struct Scsi_Host *shpnt) iounmap((void *)sun3_scsi_regp); - NCR5380_exit(shpnt); return 0; } diff --git a/trunk/drivers/scsi/sun3_scsi_vme.c b/trunk/drivers/scsi/sun3_scsi_vme.c index fbba78e5722e..7c526b8e30ac 100644 --- a/trunk/drivers/scsi/sun3_scsi_vme.c +++ b/trunk/drivers/scsi/sun3_scsi_vme.c @@ -39,12 +39,6 @@ /* dma on! */ #define REAL_DMA -#define NDEBUG 0 - -#define NDEBUG_ABORT 0x00100000 -#define NDEBUG_TAGS 0x00200000 -#define NDEBUG_MERGING 0x00400000 - #include "scsi.h" #include "initio.h" #include @@ -56,6 +50,8 @@ extern int sun3_map_test(unsigned long, char *); /*#define RESET_BOOT */ #define DRIVER_SETUP +#define NDEBUG 0 + /* * BUG can be used to trigger a strange code-size related hang on 2.1 kernels */ @@ -141,7 +137,7 @@ static struct Scsi_Host *default_instance; * */ -static int __init sun3scsi_detect(struct scsi_host_template * tpnt) +static int sun3scsi_detect(struct scsi_host_template * tpnt) { unsigned long ioaddr, irq = 0; static int called = 0; @@ -287,7 +283,6 @@ int sun3scsi_release (struct Scsi_Host *shpnt) iounmap((void *)sun3_scsi_regp); - NCR5380_exit(shpnt); return 0; } diff --git a/trunk/drivers/sh/clk/core.c b/trunk/drivers/sh/clk/core.c index d6702e57d428..7e9c39951ecb 100644 --- a/trunk/drivers/sh/clk/core.c +++ b/trunk/drivers/sh/clk/core.c @@ -670,7 +670,7 @@ static struct dentry *clk_debugfs_root; static int clk_debugfs_register_one(struct clk *c) { int err; - struct dentry *d; + struct dentry *d, *child, *child_tmp; struct clk *pa = c->parent; char s[255]; char *p = s; @@ -699,7 +699,10 @@ static int clk_debugfs_register_one(struct clk *c) return 0; err_out: - debugfs_remove_recursive(c->dentry); + d = c->dentry; + list_for_each_entry_safe(child, child_tmp, &d->d_subdirs, d_u.d_child) + debugfs_remove(child); + debugfs_remove(c->dentry); return err; } diff --git a/trunk/drivers/staging/gma500/psb_intel_display.c b/trunk/drivers/staging/gma500/psb_intel_display.c index 09e378d5ddcb..4f47d09d65de 100644 --- a/trunk/drivers/staging/gma500/psb_intel_display.c +++ b/trunk/drivers/staging/gma500/psb_intel_display.c @@ -331,7 +331,7 @@ static bool psb_intel_find_best_PLL(struct drm_crtc *crtc, int target, void psb_intel_wait_for_vblank(struct drm_device *dev) { /* Wait for 20ms, i.e. one cycle at 50hz. */ - mdelay(20); + udelay(20000); } int psb_intel_pipe_set_base(struct drm_crtc *crtc, diff --git a/trunk/drivers/staging/pohmelfs/dir.c b/trunk/drivers/staging/pohmelfs/dir.c index 7598e77672a5..9732a9666cc4 100644 --- a/trunk/drivers/staging/pohmelfs/dir.c +++ b/trunk/drivers/staging/pohmelfs/dir.c @@ -512,7 +512,7 @@ struct dentry *pohmelfs_lookup(struct inode *dir, struct dentry *dentry, struct int err, lock_type = POHMELFS_READ_LOCK, need_lock = 1; struct qstr str = dentry->d_name; - if ((nd->intent.open.flags & O_ACCMODE) != O_RDONLY) + if ((nd->intent.open.flags & O_ACCMODE) > 1) lock_type = POHMELFS_WRITE_LOCK; if (test_bit(NETFS_INODE_OWNED, &parent->state)) { diff --git a/trunk/drivers/staging/pohmelfs/inode.c b/trunk/drivers/staging/pohmelfs/inode.c index f3c6060c96b8..c0f0ac7c1cdb 100644 --- a/trunk/drivers/staging/pohmelfs/inode.c +++ b/trunk/drivers/staging/pohmelfs/inode.c @@ -887,16 +887,11 @@ static struct inode *pohmelfs_alloc_inode(struct super_block *sb) /* * We want fsync() to work on POHMELFS. */ -static int pohmelfs_fsync(struct file *file, loff_t start, loff_t end, int datasync) +static int pohmelfs_fsync(struct file *file, int datasync) { struct inode *inode = file->f_mapping->host; - int err = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (!err) { - mutex_lock(&inode->i_mutex); - err = sync_inode_metadata(inode, 1); - mutex_unlock(&inode->i_mutex); - } - return err; + + return sync_inode_metadata(inode, 1); } ssize_t pohmelfs_write(struct file *file, const char __user *buf, diff --git a/trunk/drivers/target/tcm_fc/tfc_cmd.c b/trunk/drivers/target/tcm_fc/tfc_cmd.c index a6bfb6deba94..a9e9a31da11d 100644 --- a/trunk/drivers/target/tcm_fc/tfc_cmd.c +++ b/trunk/drivers/target/tcm_fc/tfc_cmd.c @@ -264,9 +264,8 @@ int ft_write_pending(struct se_cmd *se_cmd) cmd->sg_cnt = se_cmd->t_tasks_sg_chained_no; } - if (cmd->sg && lport->tt.ddp_target(lport, ep->xid, - cmd->sg, - cmd->sg_cnt)) + if (cmd->sg && lport->tt.ddp_setup(lport, ep->xid, + cmd->sg, cmd->sg_cnt)) cmd->was_ddp_setup = 1; } } @@ -372,23 +371,12 @@ static void ft_send_resp_status(struct fc_lport *lport, /* * Send error or task management response. + * Always frees the cmd and associated state. */ -static void ft_send_resp_code(struct ft_cmd *cmd, - enum fcp_resp_rsp_codes code) +static void ft_send_resp_code(struct ft_cmd *cmd, enum fcp_resp_rsp_codes code) { ft_send_resp_status(cmd->sess->tport->lport, cmd->req_frame, SAM_STAT_GOOD, code); -} - - -/* - * Send error or task management response. - * Always frees the cmd and associated state. - */ -static void ft_send_resp_code_and_free(struct ft_cmd *cmd, - enum fcp_resp_rsp_codes code) -{ - ft_send_resp_code(cmd, code); ft_free_cmd(cmd); } @@ -426,7 +414,7 @@ static void ft_send_tm(struct ft_cmd *cmd) * tm_flags set is invalid. */ pr_debug("invalid FCP tm_flags %x\n", fcp->fc_tm_flags); - ft_send_resp_code_and_free(cmd, FCP_CMND_FIELDS_INVALID); + ft_send_resp_code(cmd, FCP_CMND_FIELDS_INVALID); return; } @@ -434,7 +422,7 @@ static void ft_send_tm(struct ft_cmd *cmd) tmr = core_tmr_alloc_req(&cmd->se_cmd, cmd, tm_func); if (!tmr) { pr_debug("alloc failed\n"); - ft_send_resp_code_and_free(cmd, FCP_TMF_FAILED); + ft_send_resp_code(cmd, FCP_TMF_FAILED); return; } cmd->se_cmd.se_tmr_req = tmr; @@ -673,7 +661,7 @@ static void ft_send_cmd(struct ft_cmd *cmd) return; err: - ft_send_resp_code_and_free(cmd, FCP_CMND_FIELDS_INVALID); + ft_send_resp_code(cmd, FCP_CMND_FIELDS_INVALID); } /* diff --git a/trunk/drivers/usb/gadget/printer.c b/trunk/drivers/usb/gadget/printer.c index 978e6a101bf2..271ef94668e7 100644 --- a/trunk/drivers/usb/gadget/printer.c +++ b/trunk/drivers/usb/gadget/printer.c @@ -795,14 +795,12 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr) } static int -printer_fsync(struct file *fd, loff_t start, loff_t end, int datasync) +printer_fsync(struct file *fd, int datasync) { struct printer_dev *dev = fd->private_data; - struct inode *inode = fd->f_path.dentry->d_inode; unsigned long flags; int tx_list_empty; - mutex_lock(&inode->i_mutex); spin_lock_irqsave(&dev->lock, flags); tx_list_empty = (likely(list_empty(&dev->tx_reqs))); spin_unlock_irqrestore(&dev->lock, flags); @@ -812,7 +810,6 @@ printer_fsync(struct file *fd, loff_t start, loff_t end, int datasync) wait_event_interruptible(dev->tx_flush_wait, (likely(list_empty(&dev->tx_reqs_active)))); } - mutex_unlock(&inode->i_mutex); return 0; } diff --git a/trunk/drivers/video/fb_defio.c b/trunk/drivers/video/fb_defio.c index 32814e8800e0..804000183c5e 100644 --- a/trunk/drivers/video/fb_defio.c +++ b/trunk/drivers/video/fb_defio.c @@ -66,26 +66,19 @@ static int fb_deferred_io_fault(struct vm_area_struct *vma, return 0; } -int fb_deferred_io_fsync(struct file *file, loff_t start, loff_t end, int datasync) +int fb_deferred_io_fsync(struct file *file, int datasync) { struct fb_info *info = file->private_data; - struct inode *inode = file->f_path.dentry->d_inode; - int err = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (err) - return err; /* Skip if deferred io is compiled-in but disabled on this fbdev */ if (!info->fbdefio) return 0; - mutex_lock(&inode->i_mutex); /* Kill off the delayed work */ cancel_delayed_work_sync(&info->deferred_work); /* Run it immediately */ - err = schedule_delayed_work(&info->deferred_work, 0); - mutex_unlock(&inode->i_mutex); - return err; + return schedule_delayed_work(&info->deferred_work, 0); } EXPORT_SYMBOL_GPL(fb_deferred_io_fsync); diff --git a/trunk/drivers/virtio/Kconfig b/trunk/drivers/virtio/Kconfig index 57e493b1bd20..3dd6294d10b6 100644 --- a/trunk/drivers/virtio/Kconfig +++ b/trunk/drivers/virtio/Kconfig @@ -7,8 +7,6 @@ config VIRTIO_RING tristate depends on VIRTIO -menu "Virtio drivers" - config VIRTIO_PCI tristate "PCI driver for virtio devices (EXPERIMENTAL)" depends on PCI && EXPERIMENTAL @@ -35,4 +33,3 @@ config VIRTIO_BALLOON If unsure, say M. -endmenu diff --git a/trunk/fs/9p/acl.c b/trunk/fs/9p/acl.c index e98f56d3787d..535ab6eccb1a 100644 --- a/trunk/fs/9p/acl.c +++ b/trunk/fs/9p/acl.c @@ -96,12 +96,12 @@ static struct posix_acl *v9fs_get_cached_acl(struct inode *inode, int type) return acl; } -int v9fs_check_acl(struct inode *inode, int mask) +int v9fs_check_acl(struct inode *inode, int mask, unsigned int flags) { struct posix_acl *acl; struct v9fs_session_info *v9ses; - if (mask & MAY_NOT_BLOCK) + if (flags & IPERM_FLAG_RCU) return -ECHILD; v9ses = v9fs_inode2v9ses(inode); diff --git a/trunk/fs/9p/acl.h b/trunk/fs/9p/acl.h index 59e18c2e8c7e..7ef3ac9f6d95 100644 --- a/trunk/fs/9p/acl.h +++ b/trunk/fs/9p/acl.h @@ -16,7 +16,7 @@ #ifdef CONFIG_9P_FS_POSIX_ACL extern int v9fs_get_acl(struct inode *, struct p9_fid *); -extern int v9fs_check_acl(struct inode *inode, int mask); +extern int v9fs_check_acl(struct inode *inode, int mask, unsigned int flags); extern int v9fs_acl_chmod(struct dentry *); extern int v9fs_set_create_acl(struct dentry *, struct posix_acl *, struct posix_acl *); diff --git a/trunk/fs/9p/cache.c b/trunk/fs/9p/cache.c index 945aa5f02f9b..5b335c5086a1 100644 --- a/trunk/fs/9p/cache.c +++ b/trunk/fs/9p/cache.c @@ -108,10 +108,11 @@ static uint16_t v9fs_cache_inode_get_key(const void *cookie_netfs_data, void *buffer, uint16_t bufmax) { const struct v9fs_inode *v9inode = cookie_netfs_data; - memcpy(buffer, &v9inode->qid.path, sizeof(v9inode->qid.path)); + memcpy(buffer, &v9inode->fscache_key->path, + sizeof(v9inode->fscache_key->path)); P9_DPRINTK(P9_DEBUG_FSC, "inode %p get key %llu", &v9inode->vfs_inode, - v9inode->qid.path); - return sizeof(v9inode->qid.path); + v9inode->fscache_key->path); + return sizeof(v9inode->fscache_key->path); } static void v9fs_cache_inode_get_attr(const void *cookie_netfs_data, @@ -128,10 +129,11 @@ static uint16_t v9fs_cache_inode_get_aux(const void *cookie_netfs_data, void *buffer, uint16_t buflen) { const struct v9fs_inode *v9inode = cookie_netfs_data; - memcpy(buffer, &v9inode->qid.version, sizeof(v9inode->qid.version)); + memcpy(buffer, &v9inode->fscache_key->version, + sizeof(v9inode->fscache_key->version)); P9_DPRINTK(P9_DEBUG_FSC, "inode %p get aux %u", &v9inode->vfs_inode, - v9inode->qid.version); - return sizeof(v9inode->qid.version); + v9inode->fscache_key->version); + return sizeof(v9inode->fscache_key->version); } static enum @@ -141,11 +143,11 @@ fscache_checkaux v9fs_cache_inode_check_aux(void *cookie_netfs_data, { const struct v9fs_inode *v9inode = cookie_netfs_data; - if (buflen != sizeof(v9inode->qid.version)) + if (buflen != sizeof(v9inode->fscache_key->version)) return FSCACHE_CHECKAUX_OBSOLETE; - if (memcmp(buffer, &v9inode->qid.version, - sizeof(v9inode->qid.version))) + if (memcmp(buffer, &v9inode->fscache_key->version, + sizeof(v9inode->fscache_key->version))) return FSCACHE_CHECKAUX_OBSOLETE; return FSCACHE_CHECKAUX_OKAY; diff --git a/trunk/fs/9p/cache.h b/trunk/fs/9p/cache.h index 40cc54ced5d9..049507a5b01c 100644 --- a/trunk/fs/9p/cache.h +++ b/trunk/fs/9p/cache.h @@ -93,6 +93,15 @@ static inline void v9fs_uncache_page(struct inode *inode, struct page *page) BUG_ON(PageFsCache(page)); } +static inline void v9fs_fscache_set_key(struct inode *inode, + struct p9_qid *qid) +{ + struct v9fs_inode *v9inode = V9FS_I(inode); + spin_lock(&v9inode->fscache_lock); + v9inode->fscache_key = qid; + spin_unlock(&v9inode->fscache_lock); +} + static inline void v9fs_fscache_wait_on_page_write(struct inode *inode, struct page *page) { diff --git a/trunk/fs/9p/v9fs.c b/trunk/fs/9p/v9fs.c index ef9661886112..c82b017f51f3 100644 --- a/trunk/fs/9p/v9fs.c +++ b/trunk/fs/9p/v9fs.c @@ -78,25 +78,6 @@ static const match_table_t tokens = { {Opt_err, NULL} }; -/* Interpret mount options for cache mode */ -static int get_cache_mode(char *s) -{ - int version = -EINVAL; - - if (!strcmp(s, "loose")) { - version = CACHE_LOOSE; - P9_DPRINTK(P9_DEBUG_9P, "Cache mode: loose\n"); - } else if (!strcmp(s, "fscache")) { - version = CACHE_FSCACHE; - P9_DPRINTK(P9_DEBUG_9P, "Cache mode: fscache\n"); - } else if (!strcmp(s, "none")) { - version = CACHE_NONE; - P9_DPRINTK(P9_DEBUG_9P, "Cache mode: none\n"); - } else - printk(KERN_INFO "9p: Unknown Cache mode %s.\n", s); - return version; -} - /** * v9fs_parse_options - parse mount options into session structure * @v9ses: existing v9fs session information @@ -116,7 +97,7 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts) /* setup defaults */ v9ses->afid = ~0; v9ses->debug = 0; - v9ses->cache = CACHE_NONE; + v9ses->cache = 0; #ifdef CONFIG_9P_FSCACHE v9ses->cachetag = NULL; #endif @@ -190,13 +171,13 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts) "problem allocating copy of cache arg\n"); goto free_and_return; } - ret = get_cache_mode(s); - if (ret == -EINVAL) { - kfree(s); - goto free_and_return; - } - v9ses->cache = ret; + if (strcmp(s, "loose") == 0) + v9ses->cache = CACHE_LOOSE; + else if (strcmp(s, "fscache") == 0) + v9ses->cache = CACHE_FSCACHE; + else + v9ses->cache = CACHE_NONE; kfree(s); break; @@ -219,15 +200,9 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts) } else { v9ses->flags |= V9FS_ACCESS_SINGLE; v9ses->uid = simple_strtoul(s, &e, 10); - if (*e != '\0') { - ret = -EINVAL; - printk(KERN_INFO "9p: Unknown access " - "argument %s.\n", s); - kfree(s); - goto free_and_return; - } + if (*e != '\0') + v9ses->uid = ~0; } - kfree(s); break; @@ -512,8 +487,8 @@ static void v9fs_inode_init_once(void *foo) struct v9fs_inode *v9inode = (struct v9fs_inode *)foo; #ifdef CONFIG_9P_FSCACHE v9inode->fscache = NULL; + v9inode->fscache_key = NULL; #endif - memset(&v9inode->qid, 0, sizeof(v9inode->qid)); inode_init_once(&v9inode->vfs_inode); } diff --git a/trunk/fs/9p/v9fs.h b/trunk/fs/9p/v9fs.h index e78956cbd702..e5ebedfc5ed8 100644 --- a/trunk/fs/9p/v9fs.h +++ b/trunk/fs/9p/v9fs.h @@ -125,8 +125,8 @@ struct v9fs_inode { #ifdef CONFIG_9P_FSCACHE spinlock_t fscache_lock; struct fscache_cookie *fscache; + struct p9_qid *fscache_key; #endif - struct p9_qid qid; unsigned int cache_validity; struct p9_fid *writeback_fid; struct mutex v_mutex; @@ -153,13 +153,13 @@ extern void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void *p); extern struct inode *v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid, - struct super_block *sb, int new); + struct super_block *sb); extern const struct inode_operations v9fs_dir_inode_operations_dotl; extern const struct inode_operations v9fs_file_inode_operations_dotl; extern const struct inode_operations v9fs_symlink_inode_operations_dotl; extern struct inode *v9fs_inode_from_fid_dotl(struct v9fs_session_info *v9ses, struct p9_fid *fid, - struct super_block *sb, int new); + struct super_block *sb); /* other default globals */ #define V9FS_PORT 564 @@ -201,27 +201,8 @@ v9fs_get_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid, struct super_block *sb) { if (v9fs_proto_dotl(v9ses)) - return v9fs_inode_from_fid_dotl(v9ses, fid, sb, 0); + return v9fs_inode_from_fid_dotl(v9ses, fid, sb); else - return v9fs_inode_from_fid(v9ses, fid, sb, 0); + return v9fs_inode_from_fid(v9ses, fid, sb); } - -/** - * v9fs_get_new_inode_from_fid - Helper routine to populate an inode by - * issuing a attribute request - * @v9ses: session information - * @fid: fid to issue attribute request for - * @sb: superblock on which to create inode - * - */ -static inline struct inode * -v9fs_get_new_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid, - struct super_block *sb) -{ - if (v9fs_proto_dotl(v9ses)) - return v9fs_inode_from_fid_dotl(v9ses, fid, sb, 1); - else - return v9fs_inode_from_fid(v9ses, fid, sb, 1); -} - #endif diff --git a/trunk/fs/9p/v9fs_vfs.h b/trunk/fs/9p/v9fs_vfs.h index 46ce357ca1ab..4014160903a9 100644 --- a/trunk/fs/9p/v9fs_vfs.h +++ b/trunk/fs/9p/v9fs_vfs.h @@ -70,8 +70,7 @@ ssize_t v9fs_file_readn(struct file *, char *, char __user *, u32, u64); ssize_t v9fs_fid_readn(struct p9_fid *, char *, char __user *, u32, u64); void v9fs_blank_wstat(struct p9_wstat *wstat); int v9fs_vfs_setattr_dotl(struct dentry *, struct iattr *); -int v9fs_file_fsync_dotl(struct file *filp, loff_t start, loff_t end, - int datasync); +int v9fs_file_fsync_dotl(struct file *filp, int datasync); ssize_t v9fs_file_write_internal(struct inode *, struct p9_fid *, const char __user *, size_t, loff_t *, int); int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode); diff --git a/trunk/fs/9p/vfs_file.c b/trunk/fs/9p/vfs_file.c index 3c173fcc2c5a..ffed55817f0c 100644 --- a/trunk/fs/9p/vfs_file.c +++ b/trunk/fs/9p/vfs_file.c @@ -519,50 +519,32 @@ v9fs_file_write(struct file *filp, const char __user * data, } -static int v9fs_file_fsync(struct file *filp, loff_t start, loff_t end, - int datasync) +static int v9fs_file_fsync(struct file *filp, int datasync) { struct p9_fid *fid; - struct inode *inode = filp->f_mapping->host; struct p9_wstat wstat; int retval; - retval = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (retval) - return retval; - - mutex_lock(&inode->i_mutex); P9_DPRINTK(P9_DEBUG_VFS, "filp %p datasync %x\n", filp, datasync); fid = filp->private_data; v9fs_blank_wstat(&wstat); retval = p9_client_wstat(fid, &wstat); - mutex_unlock(&inode->i_mutex); - return retval; } -int v9fs_file_fsync_dotl(struct file *filp, loff_t start, loff_t end, - int datasync) +int v9fs_file_fsync_dotl(struct file *filp, int datasync) { struct p9_fid *fid; - struct inode *inode = filp->f_mapping->host; int retval; - retval = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (retval) - return retval; - - mutex_lock(&inode->i_mutex); P9_DPRINTK(P9_DEBUG_VFS, "v9fs_file_fsync_dotl: filp %p datasync %x\n", filp, datasync); fid = filp->private_data; retval = p9_client_fsync(fid, datasync); - mutex_unlock(&inode->i_mutex); - return retval; } diff --git a/trunk/fs/9p/vfs_inode.c b/trunk/fs/9p/vfs_inode.c index 8bb5507e822f..7f6c67703195 100644 --- a/trunk/fs/9p/vfs_inode.c +++ b/trunk/fs/9p/vfs_inode.c @@ -216,6 +216,7 @@ struct inode *v9fs_alloc_inode(struct super_block *sb) return NULL; #ifdef CONFIG_9P_FSCACHE v9inode->fscache = NULL; + v9inode->fscache_key = NULL; spin_lock_init(&v9inode->fscache_lock); #endif v9inode->writeback_fid = NULL; @@ -432,60 +433,17 @@ void v9fs_evict_inode(struct inode *inode) } } -static int v9fs_test_inode(struct inode *inode, void *data) -{ - int umode; - struct v9fs_inode *v9inode = V9FS_I(inode); - struct p9_wstat *st = (struct p9_wstat *)data; - struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); - - umode = p9mode2unixmode(v9ses, st->mode); - /* don't match inode of different type */ - if ((inode->i_mode & S_IFMT) != (umode & S_IFMT)) - return 0; - - /* compare qid details */ - if (memcmp(&v9inode->qid.version, - &st->qid.version, sizeof(v9inode->qid.version))) - return 0; - - if (v9inode->qid.type != st->qid.type) - return 0; - return 1; -} - -static int v9fs_test_new_inode(struct inode *inode, void *data) -{ - return 0; -} - -static int v9fs_set_inode(struct inode *inode, void *data) -{ - struct v9fs_inode *v9inode = V9FS_I(inode); - struct p9_wstat *st = (struct p9_wstat *)data; - - memcpy(&v9inode->qid, &st->qid, sizeof(st->qid)); - return 0; -} - static struct inode *v9fs_qid_iget(struct super_block *sb, struct p9_qid *qid, - struct p9_wstat *st, - int new) + struct p9_wstat *st) { int retval, umode; unsigned long i_ino; struct inode *inode; struct v9fs_session_info *v9ses = sb->s_fs_info; - int (*test)(struct inode *, void *); - - if (new) - test = v9fs_test_new_inode; - else - test = v9fs_test_inode; i_ino = v9fs_qid2ino(qid); - inode = iget5_locked(sb, i_ino, test, v9fs_set_inode, st); + inode = iget_locked(sb, i_ino); if (!inode) return ERR_PTR(-ENOMEM); if (!(inode->i_state & I_NEW)) @@ -495,7 +453,6 @@ static struct inode *v9fs_qid_iget(struct super_block *sb, * FIXME!! we may need support for stale inodes * later. */ - inode->i_ino = i_ino; umode = p9mode2unixmode(v9ses, st->mode); retval = v9fs_init_inode(v9ses, inode, umode); if (retval) @@ -503,6 +460,7 @@ static struct inode *v9fs_qid_iget(struct super_block *sb, v9fs_stat2inode(st, inode, sb); #ifdef CONFIG_9P_FSCACHE + v9fs_fscache_set_key(inode, &st->qid); v9fs_cache_inode_get_cookie(inode); #endif unlock_new_inode(inode); @@ -516,7 +474,7 @@ static struct inode *v9fs_qid_iget(struct super_block *sb, struct inode * v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid, - struct super_block *sb, int new) + struct super_block *sb) { struct p9_wstat *st; struct inode *inode = NULL; @@ -525,7 +483,7 @@ v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid, if (IS_ERR(st)) return ERR_CAST(st); - inode = v9fs_qid_iget(sb, &st->qid, st, new); + inode = v9fs_qid_iget(sb, &st->qid, st); p9stat_free(st); kfree(st); return inode; @@ -534,50 +492,38 @@ v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid, /** * v9fs_remove - helper function to remove files and directories * @dir: directory inode that is being deleted - * @dentry: dentry that is being deleted + * @file: dentry that is being deleted * @rmdir: removing a directory * */ -static int v9fs_remove(struct inode *dir, struct dentry *dentry, int flags) +static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir) { - struct inode *inode; - int retval = -EOPNOTSUPP; - struct p9_fid *v9fid, *dfid; - struct v9fs_session_info *v9ses; + int retval; + struct p9_fid *v9fid; + struct inode *file_inode; - P9_DPRINTK(P9_DEBUG_VFS, "inode: %p dentry: %p rmdir: %x\n", - dir, dentry, flags); + P9_DPRINTK(P9_DEBUG_VFS, "inode: %p dentry: %p rmdir: %d\n", dir, file, + rmdir); - v9ses = v9fs_inode2v9ses(dir); - inode = dentry->d_inode; - dfid = v9fs_fid_lookup(dentry->d_parent); - if (IS_ERR(dfid)) { - retval = PTR_ERR(dfid); - P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", retval); - return retval; - } - if (v9fs_proto_dotl(v9ses)) - retval = p9_client_unlinkat(dfid, dentry->d_name.name, flags); - if (retval == -EOPNOTSUPP) { - /* Try the one based on path */ - v9fid = v9fs_fid_clone(dentry); - if (IS_ERR(v9fid)) - return PTR_ERR(v9fid); - retval = p9_client_remove(v9fid); - } + file_inode = file->d_inode; + v9fid = v9fs_fid_clone(file); + if (IS_ERR(v9fid)) + return PTR_ERR(v9fid); + + retval = p9_client_remove(v9fid); if (!retval) { /* * directories on unlink should have zero * link count */ - if (flags & AT_REMOVEDIR) { - clear_nlink(inode); + if (rmdir) { + clear_nlink(file_inode); drop_nlink(dir); } else - drop_nlink(inode); + drop_nlink(file_inode); - v9fs_invalidate_inode_attr(inode); + v9fs_invalidate_inode_attr(file_inode); v9fs_invalidate_inode_attr(dir); } return retval; @@ -639,7 +585,7 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir, } /* instantiate inode and assign the unopened fid to the dentry */ - inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb); + inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb); if (IS_ERR(inode)) { err = PTR_ERR(inode); P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err); @@ -687,8 +633,8 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode, fid = NULL; v9ses = v9fs_inode2v9ses(dir); perm = unixmode2p9mode(v9ses, mode); - if (nd) - flags = nd->intent.open.flags; + if (nd && nd->flags & LOOKUP_OPEN) + flags = nd->intent.open.flags - 1; else flags = O_RDWR; @@ -703,7 +649,7 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode, v9fs_invalidate_inode_attr(dir); /* if we are opening a file, assign the open fid to the file */ - if (nd) { + if (nd && nd->flags & LOOKUP_OPEN) { v9inode = V9FS_I(dentry->d_inode); mutex_lock(&v9inode->v_mutex); if (v9ses->cache && !v9inode->writeback_fid && @@ -868,7 +814,7 @@ int v9fs_vfs_unlink(struct inode *i, struct dentry *d) int v9fs_vfs_rmdir(struct inode *i, struct dentry *d) { - return v9fs_remove(i, d, AT_REMOVEDIR); + return v9fs_remove(i, d, 1); } /** @@ -916,12 +862,9 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, down_write(&v9ses->rename_sem); if (v9fs_proto_dotl(v9ses)) { - retval = p9_client_renameat(olddirfid, old_dentry->d_name.name, - newdirfid, new_dentry->d_name.name); - if (retval == -EOPNOTSUPP) - retval = p9_client_rename(oldfid, newdirfid, - new_dentry->d_name.name); - if (retval != -EOPNOTSUPP) + retval = p9_client_rename(oldfid, newdirfid, + (char *) new_dentry->d_name.name); + if (retval != -ENOSYS) goto clunk_newdir; } if (old_dentry->d_parent != new_dentry->d_parent) { @@ -946,6 +889,11 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, clear_nlink(new_inode); else drop_nlink(new_inode); + /* + * Work around vfs rename rehash bug with + * FS_RENAME_DOES_D_MOVE + */ + v9fs_invalidate_inode_attr(new_inode); } if (S_ISDIR(old_inode->i_mode)) { if (!new_inode) diff --git a/trunk/fs/9p/vfs_inode_dotl.c b/trunk/fs/9p/vfs_inode_dotl.c index 276f4a69ecd4..691c78f58bef 100644 --- a/trunk/fs/9p/vfs_inode_dotl.c +++ b/trunk/fs/9p/vfs_inode_dotl.c @@ -86,63 +86,18 @@ static struct dentry *v9fs_dentry_from_dir_inode(struct inode *inode) return dentry; } -static int v9fs_test_inode_dotl(struct inode *inode, void *data) -{ - struct v9fs_inode *v9inode = V9FS_I(inode); - struct p9_stat_dotl *st = (struct p9_stat_dotl *)data; - - /* don't match inode of different type */ - if ((inode->i_mode & S_IFMT) != (st->st_mode & S_IFMT)) - return 0; - - if (inode->i_generation != st->st_gen) - return 0; - - /* compare qid details */ - if (memcmp(&v9inode->qid.version, - &st->qid.version, sizeof(v9inode->qid.version))) - return 0; - - if (v9inode->qid.type != st->qid.type) - return 0; - return 1; -} - -/* Always get a new inode */ -static int v9fs_test_new_inode_dotl(struct inode *inode, void *data) -{ - return 0; -} - -static int v9fs_set_inode_dotl(struct inode *inode, void *data) -{ - struct v9fs_inode *v9inode = V9FS_I(inode); - struct p9_stat_dotl *st = (struct p9_stat_dotl *)data; - - memcpy(&v9inode->qid, &st->qid, sizeof(st->qid)); - inode->i_generation = st->st_gen; - return 0; -} - static struct inode *v9fs_qid_iget_dotl(struct super_block *sb, struct p9_qid *qid, struct p9_fid *fid, - struct p9_stat_dotl *st, - int new) + struct p9_stat_dotl *st) { int retval; unsigned long i_ino; struct inode *inode; struct v9fs_session_info *v9ses = sb->s_fs_info; - int (*test)(struct inode *, void *); - - if (new) - test = v9fs_test_new_inode_dotl; - else - test = v9fs_test_inode_dotl; i_ino = v9fs_qid2ino(qid); - inode = iget5_locked(sb, i_ino, test, v9fs_set_inode_dotl, st); + inode = iget_locked(sb, i_ino); if (!inode) return ERR_PTR(-ENOMEM); if (!(inode->i_state & I_NEW)) @@ -152,13 +107,13 @@ static struct inode *v9fs_qid_iget_dotl(struct super_block *sb, * FIXME!! we may need support for stale inodes * later. */ - inode->i_ino = i_ino; retval = v9fs_init_inode(v9ses, inode, st->st_mode); if (retval) goto error; v9fs_stat2inode_dotl(st, inode); #ifdef CONFIG_9P_FSCACHE + v9fs_fscache_set_key(inode, &st->qid); v9fs_cache_inode_get_cookie(inode); #endif retval = v9fs_get_acl(inode, fid); @@ -176,16 +131,16 @@ static struct inode *v9fs_qid_iget_dotl(struct super_block *sb, struct inode * v9fs_inode_from_fid_dotl(struct v9fs_session_info *v9ses, struct p9_fid *fid, - struct super_block *sb, int new) + struct super_block *sb) { struct p9_stat_dotl *st; struct inode *inode = NULL; - st = p9_client_getattr_dotl(fid, P9_STATS_BASIC | P9_STATS_GEN); + st = p9_client_getattr_dotl(fid, P9_STATS_BASIC); if (IS_ERR(st)) return ERR_CAST(st); - inode = v9fs_qid_iget_dotl(sb, &st->qid, fid, st, new); + inode = v9fs_qid_iget_dotl(sb, &st->qid, fid, st); kfree(st); return inode; } @@ -218,8 +173,8 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode, struct posix_acl *pacl = NULL, *dacl = NULL; v9ses = v9fs_inode2v9ses(dir); - if (nd) - flags = nd->intent.open.flags; + if (nd && nd->flags & LOOKUP_OPEN) + flags = nd->intent.open.flags - 1; else { /* * create call without LOOKUP_OPEN is due @@ -275,7 +230,7 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode, fid = NULL; goto error; } - inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb); + inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb); if (IS_ERR(inode)) { err = PTR_ERR(inode); P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err); @@ -395,7 +350,7 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir, goto error; } - inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb); + inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb); if (IS_ERR(inode)) { err = PTR_ERR(inode); P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", @@ -592,7 +547,7 @@ v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode) inode->i_blocks = stat->st_blocks; } if (stat->st_result_mask & P9_STATS_GEN) - inode->i_generation = stat->st_gen; + inode->i_generation = stat->st_gen; /* Currently we don't support P9_STATS_BTIME and P9_STATS_DATA_VERSION * because the inode structure does not have fields for them. @@ -648,7 +603,7 @@ v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry, } /* instantiate inode and assign the unopened fid to dentry */ - inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb); + inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb); if (IS_ERR(inode)) { err = PTR_ERR(inode); P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", @@ -801,7 +756,7 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int omode, goto error; } - inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb); + inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb); if (IS_ERR(inode)) { err = PTR_ERR(inode); P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", diff --git a/trunk/fs/affs/affs.h b/trunk/fs/affs/affs.h index c2b9c79eb64e..0e95f73a7023 100644 --- a/trunk/fs/affs/affs.h +++ b/trunk/fs/affs/affs.h @@ -182,7 +182,7 @@ extern int affs_add_entry(struct inode *dir, struct inode *inode, struct dent void affs_free_prealloc(struct inode *inode); extern void affs_truncate(struct inode *); -int affs_file_fsync(struct file *, loff_t, loff_t, int); +int affs_file_fsync(struct file *, int); /* dir.c */ diff --git a/trunk/fs/affs/file.c b/trunk/fs/affs/file.c index 2f4c935cb327..acf321b70fcd 100644 --- a/trunk/fs/affs/file.c +++ b/trunk/fs/affs/file.c @@ -923,20 +923,14 @@ affs_truncate(struct inode *inode) affs_free_prealloc(inode); } -int affs_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync) +int affs_file_fsync(struct file *filp, int datasync) { struct inode *inode = filp->f_mapping->host; int ret, err; - err = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (err) - return err; - - mutex_lock(&inode->i_mutex); ret = write_inode_now(inode, 0); err = sync_blockdev(inode->i_sb->s_bdev); if (!ret) ret = err; - mutex_unlock(&inode->i_mutex); return ret; } diff --git a/trunk/fs/afs/afs_vl.h b/trunk/fs/afs/afs_vl.h index 800f607ffaf5..8bbefe009ed4 100644 --- a/trunk/fs/afs/afs_vl.h +++ b/trunk/fs/afs/afs_vl.h @@ -49,7 +49,7 @@ enum AFSVL_Errors { AFSVL_BADVOLOPER = 363542, /* Bad volume operation code */ AFSVL_BADRELLOCKTYPE = 363543, /* Bad release lock type */ AFSVL_RERELEASE = 363544, /* Status report: last release was aborted */ - AFSVL_BADSERVERFLAG = 363545, /* Invalid replication site server flag */ + AFSVL_BADSERVERFLAG = 363545, /* Invalid replication site server °ag */ AFSVL_PERM = 363546, /* No permission access */ AFSVL_NOMEM = 363547, /* malloc/realloc failed to alloc enough memory */ }; diff --git a/trunk/fs/afs/internal.h b/trunk/fs/afs/internal.h index d2b0888126d4..5a9b6843bac1 100644 --- a/trunk/fs/afs/internal.h +++ b/trunk/fs/afs/internal.h @@ -627,7 +627,7 @@ extern void afs_clear_permits(struct afs_vnode *); extern void afs_cache_permit(struct afs_vnode *, struct key *, long); extern void afs_zap_permits(struct rcu_head *); extern struct key *afs_request_key(struct afs_cell *); -extern int afs_permission(struct inode *, int); +extern int afs_permission(struct inode *, int, unsigned int); /* * server.c @@ -750,7 +750,7 @@ extern void afs_pages_written_back(struct afs_vnode *, struct afs_call *); extern ssize_t afs_file_write(struct kiocb *, const struct iovec *, unsigned long, loff_t); extern int afs_writeback_all(struct afs_vnode *); -extern int afs_fsync(struct file *, loff_t, loff_t, int); +extern int afs_fsync(struct file *, int); /*****************************************************************************/ diff --git a/trunk/fs/afs/security.c b/trunk/fs/afs/security.c index 8d010422dc89..f44b9d355377 100644 --- a/trunk/fs/afs/security.c +++ b/trunk/fs/afs/security.c @@ -285,14 +285,14 @@ static int afs_check_permit(struct afs_vnode *vnode, struct key *key, * - AFS ACLs are attached to directories only, and a file is controlled by its * parent directory's ACL */ -int afs_permission(struct inode *inode, int mask) +int afs_permission(struct inode *inode, int mask, unsigned int flags) { struct afs_vnode *vnode = AFS_FS_I(inode); afs_access_t uninitialized_var(access); struct key *key; int ret; - if (mask & MAY_NOT_BLOCK) + if (flags & IPERM_FLAG_RCU) return -ECHILD; _enter("{{%x:%u},%lx},%x,", @@ -350,7 +350,7 @@ int afs_permission(struct inode *inode, int mask) } key_put(key); - ret = generic_permission(inode, mask); + ret = generic_permission(inode, mask, flags, NULL); _leave(" = %d", ret); return ret; diff --git a/trunk/fs/afs/write.c b/trunk/fs/afs/write.c index 9aa52d93c73c..b806285ff853 100644 --- a/trunk/fs/afs/write.c +++ b/trunk/fs/afs/write.c @@ -681,10 +681,9 @@ int afs_writeback_all(struct afs_vnode *vnode) * - the return status from this call provides a reliable indication of * whether any write errors occurred for this process. */ -int afs_fsync(struct file *file, loff_t start, loff_t end, int datasync) +int afs_fsync(struct file *file, int datasync) { struct dentry *dentry = file->f_path.dentry; - struct inode *inode = file->f_mapping->host; struct afs_writeback *wb, *xwb; struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode); int ret; @@ -693,19 +692,12 @@ int afs_fsync(struct file *file, loff_t start, loff_t end, int datasync) vnode->fid.vid, vnode->fid.vnode, dentry->d_name.name, datasync); - ret = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (ret) - return ret; - mutex_lock(&inode->i_mutex); - /* use a writeback record as a marker in the queue - when this reaches * the front of the queue, all the outstanding writes are either * completed or rejected */ wb = kzalloc(sizeof(*wb), GFP_KERNEL); - if (!wb) { - ret = -ENOMEM; - goto out; - } + if (!wb) + return -ENOMEM; wb->vnode = vnode; wb->first = 0; wb->last = -1; @@ -728,7 +720,7 @@ int afs_fsync(struct file *file, loff_t start, loff_t end, int datasync) if (ret < 0) { afs_put_writeback(wb); _leave(" = %d [wb]", ret); - goto out; + return ret; } /* wait for the preceding writes to actually complete */ @@ -737,8 +729,6 @@ int afs_fsync(struct file *file, loff_t start, loff_t end, int datasync) vnode->writebacks.next == &wb->link); afs_put_writeback(wb); _leave(" = %d", ret); -out: - mutex_unlock(&inode->i_mutex); return ret; } diff --git a/trunk/fs/attr.c b/trunk/fs/attr.c index 538e27959d3f..caf2aa521e2b 100644 --- a/trunk/fs/attr.c +++ b/trunk/fs/attr.c @@ -232,11 +232,17 @@ int notify_change(struct dentry * dentry, struct iattr * attr) if (error) return error; + if (ia_valid & ATTR_SIZE) + down_write(&dentry->d_inode->i_alloc_sem); + if (inode->i_op->setattr) error = inode->i_op->setattr(dentry, attr); else error = simple_setattr(dentry, attr); + if (ia_valid & ATTR_SIZE) + up_write(&dentry->d_inode->i_alloc_sem); + if (!error) fsnotify_change(dentry, ia_valid); diff --git a/trunk/fs/bad_inode.c b/trunk/fs/bad_inode.c index 9205cf25f1c6..bfcb18feb1df 100644 --- a/trunk/fs/bad_inode.c +++ b/trunk/fs/bad_inode.c @@ -87,8 +87,7 @@ static int bad_file_release(struct inode *inode, struct file *filp) return -EIO; } -static int bad_file_fsync(struct file *file, loff_t start, loff_t end, - int datasync) +static int bad_file_fsync(struct file *file, int datasync) { return -EIO; } @@ -230,7 +229,7 @@ static int bad_inode_readlink(struct dentry *dentry, char __user *buffer, return -EIO; } -static int bad_inode_permission(struct inode *inode, int mask) +static int bad_inode_permission(struct inode *inode, int mask, unsigned int flags) { return -EIO; } diff --git a/trunk/fs/binfmt_elf.c b/trunk/fs/binfmt_elf.c index dd0fdfc56d38..303983fabfd6 100644 --- a/trunk/fs/binfmt_elf.c +++ b/trunk/fs/binfmt_elf.c @@ -668,7 +668,8 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) * mm->dumpable = 0 regardless of the interpreter's * permissions. */ - would_dump(bprm, interpreter); + if (file_permission(interpreter, MAY_READ) < 0) + bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP; retval = kernel_read(interpreter, 0, bprm->buf, BINPRM_BUF_SIZE); diff --git a/trunk/fs/binfmt_elf_fdpic.c b/trunk/fs/binfmt_elf_fdpic.c index 30745f459faf..2bc5dc644b4c 100644 --- a/trunk/fs/binfmt_elf_fdpic.c +++ b/trunk/fs/binfmt_elf_fdpic.c @@ -245,7 +245,8 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm, * mm->dumpable = 0 regardless of the interpreter's * permissions. */ - would_dump(bprm, interpreter); + if (file_permission(interpreter, MAY_READ) < 0) + bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP; retval = kernel_read(interpreter, 0, bprm->buf, BINPRM_BUF_SIZE); diff --git a/trunk/fs/binfmt_misc.c b/trunk/fs/binfmt_misc.c index ba1a1ae4a18a..1befe2ec8186 100644 --- a/trunk/fs/binfmt_misc.c +++ b/trunk/fs/binfmt_misc.c @@ -149,7 +149,8 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs) /* if the binary is not readable than enforce mm->dumpable=0 regardless of the interpreter's permissions */ - would_dump(bprm, bprm->file); + if (file_permission(bprm->file, MAY_READ)) + bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP; allow_write_access(bprm->file); bprm->file = NULL; diff --git a/trunk/fs/block_dev.c b/trunk/fs/block_dev.c index 9fb0b15331d3..610e8e0b04b8 100644 --- a/trunk/fs/block_dev.c +++ b/trunk/fs/block_dev.c @@ -355,30 +355,25 @@ static loff_t block_llseek(struct file *file, loff_t offset, int origin) mutex_lock(&bd_inode->i_mutex); size = i_size_read(bd_inode); - retval = -EINVAL; switch (origin) { - case SEEK_END: + case 2: offset += size; break; - case SEEK_CUR: + case 1: offset += file->f_pos; - case SEEK_SET: - break; - default: - goto out; } + retval = -EINVAL; if (offset >= 0 && offset <= size) { if (offset != file->f_pos) { file->f_pos = offset; } retval = offset; } -out: mutex_unlock(&bd_inode->i_mutex); return retval; } -int blkdev_fsync(struct file *filp, loff_t start, loff_t end, int datasync) +int blkdev_fsync(struct file *filp, int datasync) { struct inode *bd_inode = filp->f_mapping->host; struct block_device *bdev = I_BDEV(bd_inode); @@ -389,10 +384,14 @@ int blkdev_fsync(struct file *filp, loff_t start, loff_t end, int datasync) * i_mutex and doing so causes performance issues with concurrent * O_SYNC writers to a block device. */ + mutex_unlock(&bd_inode->i_mutex); + error = blkdev_issue_flush(bdev, GFP_KERNEL, NULL); if (error == -EOPNOTSUPP) error = 0; + mutex_lock(&bd_inode->i_mutex); + return error; } EXPORT_SYMBOL(blkdev_fsync); diff --git a/trunk/fs/btrfs/acl.c b/trunk/fs/btrfs/acl.c index 9f62ab2a7282..f66fc9959733 100644 --- a/trunk/fs/btrfs/acl.c +++ b/trunk/fs/btrfs/acl.c @@ -195,13 +195,14 @@ static int btrfs_xattr_acl_set(struct dentry *dentry, const char *name, return ret; } -int btrfs_check_acl(struct inode *inode, int mask) +int btrfs_check_acl(struct inode *inode, int mask, unsigned int flags) { int error = -EAGAIN; - if (mask & MAY_NOT_BLOCK) { + if (flags & IPERM_FLAG_RCU) { if (!negative_cached_acl(inode, ACL_TYPE_ACCESS)) error = -ECHILD; + } else { struct posix_acl *acl; acl = btrfs_get_acl(inode, ACL_TYPE_ACCESS); diff --git a/trunk/fs/btrfs/ctree.h b/trunk/fs/btrfs/ctree.h index 82be74efbb26..3b859a3e6a0e 100644 --- a/trunk/fs/btrfs/ctree.h +++ b/trunk/fs/btrfs/ctree.h @@ -1219,7 +1219,7 @@ struct btrfs_root { * right now this just gets used so that a root has its own devid * for stat. It may be used for more later */ - dev_t anon_dev; + struct super_block anon_super; }; struct btrfs_ioctl_defrag_range_args { @@ -2510,9 +2510,6 @@ int btrfs_csum_truncate(struct btrfs_trans_handle *trans, int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, struct list_head *list, int search_commit); /* inode.c */ -struct extent_map *btrfs_get_extent_fiemap(struct inode *inode, struct page *page, - size_t pg_offset, u64 start, u64 len, - int create); /* RHEL and EL kernels have a patch that renames PG_checked to FsMisc */ #if defined(ClearPageFsMisc) && !defined(ClearPageChecked) @@ -2605,7 +2602,7 @@ int btrfs_defrag_file(struct inode *inode, struct file *file, int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans, struct inode *inode); int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info); -int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync); +int btrfs_sync_file(struct file *file, int datasync); int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end, int skip_pinned); extern const struct file_operations btrfs_file_operations; @@ -2645,7 +2642,7 @@ do { \ /* acl.c */ #ifdef CONFIG_BTRFS_FS_POSIX_ACL -int btrfs_check_acl(struct inode *inode, int mask); +int btrfs_check_acl(struct inode *inode, int mask, unsigned int flags); #else #define btrfs_check_acl NULL #endif diff --git a/trunk/fs/btrfs/disk-io.c b/trunk/fs/btrfs/disk-io.c index b231ae13b269..1ac8db5dc0a3 100644 --- a/trunk/fs/btrfs/disk-io.c +++ b/trunk/fs/btrfs/disk-io.c @@ -1077,7 +1077,12 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, init_completion(&root->kobj_unregister); root->defrag_running = 0; root->root_key.objectid = objectid; - root->anon_dev = 0; + root->anon_super.s_root = NULL; + root->anon_super.s_dev = 0; + INIT_LIST_HEAD(&root->anon_super.s_list); + INIT_LIST_HEAD(&root->anon_super.s_instances); + init_rwsem(&root->anon_super.s_umount); + return 0; } @@ -1306,7 +1311,7 @@ struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info, spin_lock_init(&root->cache_lock); init_waitqueue_head(&root->cache_wait); - ret = get_anon_bdev(&root->anon_dev); + ret = set_anon_super(&root->anon_super, NULL); if (ret) goto fail; @@ -2388,8 +2393,10 @@ static void free_fs_root(struct btrfs_root *root) { iput(root->cache_inode); WARN_ON(!RB_EMPTY_ROOT(&root->inode_tree)); - if (root->anon_dev) - free_anon_bdev(root->anon_dev); + if (root->anon_super.s_dev) { + down_write(&root->anon_super.s_umount); + kill_anon_super(&root->anon_super); + } free_extent_buffer(root->node); free_extent_buffer(root->commit_root); kfree(root->free_ino_ctl); diff --git a/trunk/fs/btrfs/file.c b/trunk/fs/btrfs/file.c index 59cbdb120ad0..fa4ef18b66b1 100644 --- a/trunk/fs/btrfs/file.c +++ b/trunk/fs/btrfs/file.c @@ -1452,7 +1452,7 @@ int btrfs_release_file(struct inode *inode, struct file *filp) * important optimization for directories because holding the mutex prevents * new operations on the dir while we write to disk. */ -int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) +int btrfs_sync_file(struct file *file, int datasync) { struct dentry *dentry = file->f_path.dentry; struct inode *inode = dentry->d_inode; @@ -1462,13 +1462,9 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) trace_btrfs_sync_file(file, datasync); - ret = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (ret) - return ret; - mutex_lock(&inode->i_mutex); - /* we wait first, since the writeback may change the inode */ root->log_batch++; + /* the VFS called filemap_fdatawrite for us */ btrfs_wait_ordered_range(inode, 0, (u64)-1); root->log_batch++; @@ -1476,10 +1472,8 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) * check the transaction that last modified this inode * and see if its already been committed */ - if (!BTRFS_I(inode)->last_trans) { - mutex_unlock(&inode->i_mutex); + if (!BTRFS_I(inode)->last_trans) goto out; - } /* * if the last transaction that changed this file was before @@ -1490,7 +1484,6 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) if (BTRFS_I(inode)->last_trans <= root->fs_info->last_trans_committed) { BTRFS_I(inode)->last_trans = 0; - mutex_unlock(&inode->i_mutex); goto out; } @@ -1503,15 +1496,12 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) trans = btrfs_start_transaction(root, 0); if (IS_ERR(trans)) { ret = PTR_ERR(trans); - mutex_unlock(&inode->i_mutex); goto out; } ret = btrfs_log_dentry_safe(trans, root, dentry); - if (ret < 0) { - mutex_unlock(&inode->i_mutex); + if (ret < 0) goto out; - } /* we've logged all the items and now have a consistent * version of the file in the log. It is possible that @@ -1523,7 +1513,7 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) * file again, but that will end up using the synchronization * inside btrfs_sync_log to keep things safe. */ - mutex_unlock(&inode->i_mutex); + mutex_unlock(&dentry->d_inode->i_mutex); if (ret != BTRFS_NO_LOG_SYNC) { if (ret > 0) { @@ -1538,6 +1528,7 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) } else { ret = btrfs_end_transaction(trans, root); } + mutex_lock(&dentry->d_inode->i_mutex); out: return ret > 0 ? -EIO : ret; } @@ -1673,154 +1664,8 @@ static long btrfs_fallocate(struct file *file, int mode, return ret; } -static int find_desired_extent(struct inode *inode, loff_t *offset, int origin) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - struct extent_map *em; - struct extent_state *cached_state = NULL; - u64 lockstart = *offset; - u64 lockend = i_size_read(inode); - u64 start = *offset; - u64 orig_start = *offset; - u64 len = i_size_read(inode); - u64 last_end = 0; - int ret = 0; - - lockend = max_t(u64, root->sectorsize, lockend); - if (lockend <= lockstart) - lockend = lockstart + root->sectorsize; - - len = lockend - lockstart + 1; - - len = max_t(u64, len, root->sectorsize); - if (inode->i_size == 0) - return -ENXIO; - - lock_extent_bits(&BTRFS_I(inode)->io_tree, lockstart, lockend, 0, - &cached_state, GFP_NOFS); - - /* - * Delalloc is such a pain. If we have a hole and we have pending - * delalloc for a portion of the hole we will get back a hole that - * exists for the entire range since it hasn't been actually written - * yet. So to take care of this case we need to look for an extent just - * before the position we want in case there is outstanding delalloc - * going on here. - */ - if (origin == SEEK_HOLE && start != 0) { - if (start <= root->sectorsize) - em = btrfs_get_extent_fiemap(inode, NULL, 0, 0, - root->sectorsize, 0); - else - em = btrfs_get_extent_fiemap(inode, NULL, 0, - start - root->sectorsize, - root->sectorsize, 0); - if (IS_ERR(em)) { - ret = -ENXIO; - goto out; - } - last_end = em->start + em->len; - if (em->block_start == EXTENT_MAP_DELALLOC) - last_end = min_t(u64, last_end, inode->i_size); - free_extent_map(em); - } - - while (1) { - em = btrfs_get_extent_fiemap(inode, NULL, 0, start, len, 0); - if (IS_ERR(em)) { - ret = -ENXIO; - break; - } - - if (em->block_start == EXTENT_MAP_HOLE) { - if (test_bit(EXTENT_FLAG_VACANCY, &em->flags)) { - if (last_end <= orig_start) { - free_extent_map(em); - ret = -ENXIO; - break; - } - } - - if (origin == SEEK_HOLE) { - *offset = start; - free_extent_map(em); - break; - } - } else { - if (origin == SEEK_DATA) { - if (em->block_start == EXTENT_MAP_DELALLOC) { - if (start >= inode->i_size) { - free_extent_map(em); - ret = -ENXIO; - break; - } - } - - *offset = start; - free_extent_map(em); - break; - } - } - - start = em->start + em->len; - last_end = em->start + em->len; - - if (em->block_start == EXTENT_MAP_DELALLOC) - last_end = min_t(u64, last_end, inode->i_size); - - if (test_bit(EXTENT_FLAG_VACANCY, &em->flags)) { - free_extent_map(em); - ret = -ENXIO; - break; - } - free_extent_map(em); - cond_resched(); - } - if (!ret) - *offset = min(*offset, inode->i_size); -out: - unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend, - &cached_state, GFP_NOFS); - return ret; -} - -static loff_t btrfs_file_llseek(struct file *file, loff_t offset, int origin) -{ - struct inode *inode = file->f_mapping->host; - int ret; - - mutex_lock(&inode->i_mutex); - switch (origin) { - case SEEK_END: - case SEEK_CUR: - offset = generic_file_llseek_unlocked(file, offset, origin); - goto out; - case SEEK_DATA: - case SEEK_HOLE: - ret = find_desired_extent(inode, &offset, origin); - if (ret) { - mutex_unlock(&inode->i_mutex); - return ret; - } - } - - if (offset < 0 && !(file->f_mode & FMODE_UNSIGNED_OFFSET)) - return -EINVAL; - if (offset > inode->i_sb->s_maxbytes) - return -EINVAL; - - /* Special lock needed here? */ - if (offset != file->f_pos) { - file->f_pos = offset; - file->f_version = 0; - } -out: - mutex_unlock(&inode->i_mutex); - return offset; -} - const struct file_operations btrfs_file_operations = { - .llseek = btrfs_file_llseek, + .llseek = generic_file_llseek, .read = do_sync_read, .write = do_sync_write, .aio_read = generic_file_aio_read, diff --git a/trunk/fs/btrfs/inode.c b/trunk/fs/btrfs/inode.c index 2548a04a0230..3601f0aebddf 100644 --- a/trunk/fs/btrfs/inode.c +++ b/trunk/fs/btrfs/inode.c @@ -4079,7 +4079,13 @@ static int btrfs_dentry_delete(const struct dentry *dentry) static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { - return d_splice_alias(btrfs_lookup_dentry(dir, dentry), dentry); + struct inode *inode; + + inode = btrfs_lookup_dentry(dir, dentry); + if (IS_ERR(inode)) + return ERR_CAST(inode); + + return d_splice_alias(inode, dentry); } unsigned char btrfs_filetype_table[] = { @@ -4766,10 +4772,11 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, if (err) { drop_inode = 1; } else { - struct dentry *parent = dentry->d_parent; + struct dentry *parent = dget_parent(dentry); err = btrfs_update_inode(trans, root, inode); BUG_ON(err); btrfs_log_new_name(trans, inode, NULL, parent); + dput(parent); } nr = trans->blocks_used; @@ -6893,7 +6900,7 @@ static int btrfs_getattr(struct vfsmount *mnt, { struct inode *inode = dentry->d_inode; generic_fillattr(inode, stat); - stat->dev = BTRFS_I(inode)->root->anon_dev; + stat->dev = BTRFS_I(inode)->root->anon_super.s_dev; stat->blksize = PAGE_CACHE_SIZE; stat->blocks = (inode_get_bytes(inode) + BTRFS_I(inode)->delalloc_bytes) >> 9; @@ -7061,8 +7068,9 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry, BUG_ON(ret); if (old_ino != BTRFS_FIRST_FREE_OBJECTID) { - struct dentry *parent = new_dentry->d_parent; + struct dentry *parent = dget_parent(new_dentry); btrfs_log_new_name(trans, old_inode, old_dir, parent); + dput(parent); btrfs_end_log_trans(root); } out_fail: @@ -7323,7 +7331,7 @@ static int btrfs_set_page_dirty(struct page *page) return __set_page_dirty_nobuffers(page); } -static int btrfs_permission(struct inode *inode, int mask) +static int btrfs_permission(struct inode *inode, int mask, unsigned int flags) { struct btrfs_root *root = BTRFS_I(inode)->root; @@ -7331,7 +7339,7 @@ static int btrfs_permission(struct inode *inode, int mask) return -EROFS; if ((BTRFS_I(inode)->flags & BTRFS_INODE_READONLY) && (mask & MAY_WRITE)) return -EACCES; - return generic_permission(inode, mask); + return generic_permission(inode, mask, flags, btrfs_check_acl); } static const struct inode_operations btrfs_dir_inode_operations = { @@ -7351,12 +7359,10 @@ static const struct inode_operations btrfs_dir_inode_operations = { .listxattr = btrfs_listxattr, .removexattr = btrfs_removexattr, .permission = btrfs_permission, - .check_acl = btrfs_check_acl, }; static const struct inode_operations btrfs_dir_ro_inode_operations = { .lookup = btrfs_lookup, .permission = btrfs_permission, - .check_acl = btrfs_check_acl, }; static const struct file_operations btrfs_dir_file_operations = { @@ -7425,7 +7431,6 @@ static const struct inode_operations btrfs_file_inode_operations = { .removexattr = btrfs_removexattr, .permission = btrfs_permission, .fiemap = btrfs_fiemap, - .check_acl = btrfs_check_acl, }; static const struct inode_operations btrfs_special_inode_operations = { .getattr = btrfs_getattr, @@ -7435,7 +7440,6 @@ static const struct inode_operations btrfs_special_inode_operations = { .getxattr = btrfs_getxattr, .listxattr = btrfs_listxattr, .removexattr = btrfs_removexattr, - .check_acl = btrfs_check_acl, }; static const struct inode_operations btrfs_symlink_inode_operations = { .readlink = generic_readlink, @@ -7447,7 +7451,6 @@ static const struct inode_operations btrfs_symlink_inode_operations = { .getxattr = btrfs_getxattr, .listxattr = btrfs_listxattr, .removexattr = btrfs_removexattr, - .check_acl = btrfs_check_acl, }; const struct dentry_operations btrfs_dentry_operations = { diff --git a/trunk/fs/btrfs/ioctl.c b/trunk/fs/btrfs/ioctl.c index 622543309eb2..a3c4751e07db 100644 --- a/trunk/fs/btrfs/ioctl.c +++ b/trunk/fs/btrfs/ioctl.c @@ -323,7 +323,7 @@ static noinline int create_subvol(struct btrfs_root *root, struct btrfs_inode_item *inode_item; struct extent_buffer *leaf; struct btrfs_root *new_root; - struct dentry *parent = dentry->d_parent; + struct dentry *parent = dget_parent(dentry); struct inode *dir; int ret; int err; @@ -332,8 +332,10 @@ static noinline int create_subvol(struct btrfs_root *root, u64 index = 0; ret = btrfs_find_free_objectid(root->fs_info->tree_root, &objectid); - if (ret) + if (ret) { + dput(parent); return ret; + } dir = parent->d_inode; @@ -344,8 +346,10 @@ static noinline int create_subvol(struct btrfs_root *root, * 2 - dir items */ trans = btrfs_start_transaction(root, 6); - if (IS_ERR(trans)) + if (IS_ERR(trans)) { + dput(parent); return PTR_ERR(trans); + } leaf = btrfs_alloc_free_block(trans, root, root->leafsize, 0, objectid, NULL, 0, 0, 0); @@ -435,6 +439,7 @@ static noinline int create_subvol(struct btrfs_root *root, d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry)); fail: + dput(parent); if (async_transid) { *async_transid = trans->transid; err = btrfs_commit_transaction_async(trans, root, 1); @@ -451,6 +456,7 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, bool readonly) { struct inode *inode; + struct dentry *parent; struct btrfs_pending_snapshot *pending_snapshot; struct btrfs_trans_handle *trans; int ret; @@ -498,7 +504,9 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, if (ret) goto fail; - inode = btrfs_lookup_dentry(dentry->d_parent->d_inode, dentry); + parent = dget_parent(dentry); + inode = btrfs_lookup_dentry(parent->d_inode, dentry); + dput(parent); if (IS_ERR(inode)) { ret = PTR_ERR(inode); goto fail; diff --git a/trunk/fs/cachefiles/bind.c b/trunk/fs/cachefiles/bind.c index 622f4696e484..a2603e7c0bb5 100644 --- a/trunk/fs/cachefiles/bind.c +++ b/trunk/fs/cachefiles/bind.c @@ -129,6 +129,8 @@ static int cachefiles_daemon_add_cache(struct cachefiles_cache *cache) !root->d_inode->i_op->mkdir || !root->d_inode->i_op->setxattr || !root->d_inode->i_op->getxattr || + !root->d_sb || + !root->d_sb->s_op || !root->d_sb->s_op->statfs || !root->d_sb->s_op->sync_fs) goto error_unsupported; diff --git a/trunk/fs/ceph/caps.c b/trunk/fs/ceph/caps.c index 8d74ad7ba556..f605753c8fe9 100644 --- a/trunk/fs/ceph/caps.c +++ b/trunk/fs/ceph/caps.c @@ -1811,7 +1811,7 @@ static void sync_write_wait(struct inode *inode) spin_unlock(&ci->i_unsafe_lock); } -int ceph_fsync(struct file *file, loff_t start, loff_t end, int datasync) +int ceph_fsync(struct file *file, int datasync) { struct inode *inode = file->f_mapping->host; struct ceph_inode_info *ci = ceph_inode(inode); @@ -1822,10 +1822,9 @@ int ceph_fsync(struct file *file, loff_t start, loff_t end, int datasync) dout("fsync %p%s\n", inode, datasync ? " datasync" : ""); sync_write_wait(inode); - ret = filemap_write_and_wait_range(inode->i_mapping, start, end); + ret = filemap_write_and_wait(inode->i_mapping); if (ret < 0) return ret; - mutex_lock(&inode->i_mutex); dirty = try_flush_caps(inode, NULL, &flush_tid); dout("fsync dirty caps are %s\n", ceph_cap_string(dirty)); @@ -1842,7 +1841,6 @@ int ceph_fsync(struct file *file, loff_t start, loff_t end, int datasync) } dout("fsync %p%s done\n", inode, datasync ? " datasync" : ""); - mutex_unlock(&inode->i_mutex); return ret; } diff --git a/trunk/fs/ceph/dir.c b/trunk/fs/ceph/dir.c index 1065ac779840..ef8f08c343e8 100644 --- a/trunk/fs/ceph/dir.c +++ b/trunk/fs/ceph/dir.c @@ -252,7 +252,7 @@ static int ceph_readdir(struct file *filp, void *dirent, filldir_t filldir) off = 1; } if (filp->f_pos == 1) { - ino_t ino = parent_ino(filp->f_dentry); + ino_t ino = filp->f_dentry->d_parent->d_inode->i_ino; dout("readdir off 1 -> '..'\n"); if (filldir(dirent, "..", 2, ceph_make_fpos(0, 1), ceph_translate_ino(inode->i_sb, ino), @@ -446,19 +446,14 @@ static loff_t ceph_dir_llseek(struct file *file, loff_t offset, int origin) loff_t retval; mutex_lock(&inode->i_mutex); - retval = -EINVAL; switch (origin) { case SEEK_END: offset += inode->i_size + 2; /* FIXME */ break; case SEEK_CUR: offset += file->f_pos; - case SEEK_SET: - break; - default: - goto out; } - + retval = -EINVAL; if (offset >= 0 && offset <= inode->i_sb->s_maxbytes) { if (offset != file->f_pos) { file->f_pos = offset; @@ -482,7 +477,6 @@ static loff_t ceph_dir_llseek(struct file *file, loff_t offset, int origin) if (offset > old_offset) fi->dir_release_count--; } -out: mutex_unlock(&inode->i_mutex); return retval; } @@ -572,6 +566,7 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry, /* open (but not create!) intent? */ if (nd && (nd->flags & LOOKUP_OPEN) && + (nd->flags & LOOKUP_CONTINUE) == 0 && /* only open last component */ !(nd->intent.open.flags & O_CREAT)) { int mode = nd->intent.open.create_mode & ~current->fs->umask; return ceph_lookup_open(dir, dentry, nd, mode, 1); @@ -1118,8 +1113,7 @@ static ssize_t ceph_read_dir(struct file *file, char __user *buf, size_t size, * an fsync() on a dir will wait for any uncommitted directory * operations to commit. */ -static int ceph_dir_fsync(struct file *file, loff_t start, loff_t end, - int datasync) +static int ceph_dir_fsync(struct file *file, int datasync) { struct inode *inode = file->f_path.dentry->d_inode; struct ceph_inode_info *ci = ceph_inode(inode); @@ -1129,11 +1123,6 @@ static int ceph_dir_fsync(struct file *file, loff_t start, loff_t end, int ret = 0; dout("dir_fsync %p\n", inode); - ret = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (ret) - return ret; - mutex_lock(&inode->i_mutex); - spin_lock(&ci->i_unsafe_lock); if (list_empty(head)) goto out; @@ -1167,8 +1156,6 @@ static int ceph_dir_fsync(struct file *file, loff_t start, loff_t end, } while (req->r_tid < last_tid); out: spin_unlock(&ci->i_unsafe_lock); - mutex_unlock(&inode->i_mutex); - return ret; } diff --git a/trunk/fs/ceph/file.c b/trunk/fs/ceph/file.c index 0d0eae05598f..4698a5c553dc 100644 --- a/trunk/fs/ceph/file.c +++ b/trunk/fs/ceph/file.c @@ -226,7 +226,7 @@ struct dentry *ceph_lookup_open(struct inode *dir, struct dentry *dentry, struct inode *parent_inode = get_dentry_parent_inode(file->f_dentry); struct ceph_mds_request *req; int err; - int flags = nd->intent.open.flags; + int flags = nd->intent.open.flags - 1; /* silly vfs! */ dout("ceph_lookup_open dentry %p '%.*s' flags %d mode 0%o\n", dentry, dentry->d_name.len, dentry->d_name.name, flags, mode); @@ -768,16 +768,13 @@ static loff_t ceph_llseek(struct file *file, loff_t offset, int origin) mutex_lock(&inode->i_mutex); __ceph_do_pending_vmtruncate(inode); - if (origin != SEEK_CUR || origin != SEEK_SET) { + switch (origin) { + case SEEK_END: ret = ceph_do_getattr(inode, CEPH_STAT_CAP_SIZE); if (ret < 0) { offset = ret; goto out; } - } - - switch (origin) { - case SEEK_END: offset += inode->i_size; break; case SEEK_CUR: @@ -793,19 +790,6 @@ static loff_t ceph_llseek(struct file *file, loff_t offset, int origin) } offset += file->f_pos; break; - case SEEK_DATA: - if (offset >= inode->i_size) { - ret = -ENXIO; - goto out; - } - break; - case SEEK_HOLE: - if (offset >= inode->i_size) { - ret = -ENXIO; - goto out; - } - offset = inode->i_size; - break; } if (offset < 0 || offset > inode->i_sb->s_maxbytes) { diff --git a/trunk/fs/ceph/inode.c b/trunk/fs/ceph/inode.c index dfb2831d8d85..d8858e96ab18 100644 --- a/trunk/fs/ceph/inode.c +++ b/trunk/fs/ceph/inode.c @@ -1795,17 +1795,17 @@ int ceph_do_getattr(struct inode *inode, int mask) * Check inode permissions. We verify we have a valid value for * the AUTH cap, then call the generic handler. */ -int ceph_permission(struct inode *inode, int mask) +int ceph_permission(struct inode *inode, int mask, unsigned int flags) { int err; - if (mask & MAY_NOT_BLOCK) + if (flags & IPERM_FLAG_RCU) return -ECHILD; err = ceph_do_getattr(inode, CEPH_CAP_AUTH_SHARED); if (!err) - err = generic_permission(inode, mask); + err = generic_permission(inode, mask, flags, NULL); return err; } diff --git a/trunk/fs/ceph/super.h b/trunk/fs/ceph/super.h index 30446b144e3d..f5cabefa98dc 100644 --- a/trunk/fs/ceph/super.h +++ b/trunk/fs/ceph/super.h @@ -692,7 +692,7 @@ extern void ceph_queue_invalidate(struct inode *inode); extern void ceph_queue_writeback(struct inode *inode); extern int ceph_do_getattr(struct inode *inode, int mask); -extern int ceph_permission(struct inode *inode, int mask); +extern int ceph_permission(struct inode *inode, int mask, unsigned int flags); extern int ceph_setattr(struct dentry *dentry, struct iattr *attr); extern int ceph_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); @@ -728,8 +728,7 @@ extern void ceph_put_cap(struct ceph_mds_client *mdsc, extern void ceph_queue_caps_release(struct inode *inode); extern int ceph_write_inode(struct inode *inode, struct writeback_control *wbc); -extern int ceph_fsync(struct file *file, loff_t start, loff_t end, - int datasync); +extern int ceph_fsync(struct file *file, int datasync); extern void ceph_kick_flushing_caps(struct ceph_mds_client *mdsc, struct ceph_mds_session *session); extern struct ceph_cap *ceph_get_cap_for_mds(struct ceph_inode_info *ci, diff --git a/trunk/fs/cifs/cifsfs.c b/trunk/fs/cifs/cifsfs.c index 865517470967..bc4b12ca537b 100644 --- a/trunk/fs/cifs/cifsfs.c +++ b/trunk/fs/cifs/cifsfs.c @@ -224,7 +224,7 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf) return 0; } -static int cifs_permission(struct inode *inode, int mask) +static int cifs_permission(struct inode *inode, int mask, unsigned int flags) { struct cifs_sb_info *cifs_sb; @@ -239,7 +239,7 @@ static int cifs_permission(struct inode *inode, int mask) on the client (above and beyond ACL on servers) for servers which do not support setting and viewing mode bits, so allowing client to check permissions is useful */ - return generic_permission(inode, mask); + return generic_permission(inode, mask, flags, NULL); } static struct kmem_cache *cifs_inode_cachep; @@ -704,11 +704,8 @@ static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, static loff_t cifs_llseek(struct file *file, loff_t offset, int origin) { - /* - * origin == SEEK_END || SEEK_DATA || SEEK_HOLE => we must revalidate - * the cached file length - */ - if (origin != SEEK_SET || origin != SEEK_CUR) { + /* origin == SEEK_END => we must revalidate the cached file length */ + if (origin == SEEK_END) { int rc; struct inode *inode = file->f_path.dentry->d_inode; diff --git a/trunk/fs/cifs/cifsfs.h b/trunk/fs/cifs/cifsfs.h index fbd050c8d52a..036ca83e5f46 100644 --- a/trunk/fs/cifs/cifsfs.h +++ b/trunk/fs/cifs/cifsfs.h @@ -91,8 +91,8 @@ extern ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov, extern ssize_t cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos); extern int cifs_lock(struct file *, int, struct file_lock *); -extern int cifs_fsync(struct file *, loff_t, loff_t, int); -extern int cifs_strict_fsync(struct file *, loff_t, loff_t, int); +extern int cifs_fsync(struct file *, int); +extern int cifs_strict_fsync(struct file *, int); extern int cifs_flush(struct file *, fl_owner_t id); extern int cifs_file_mmap(struct file * , struct vm_area_struct *); extern int cifs_file_strict_mmap(struct file * , struct vm_area_struct *); diff --git a/trunk/fs/cifs/connect.c b/trunk/fs/cifs/connect.c index e66297bad412..ccc1afa0bf3b 100644 --- a/trunk/fs/cifs/connect.c +++ b/trunk/fs/cifs/connect.c @@ -320,10 +320,9 @@ cifs_echo_request(struct work_struct *work) } static int -cifs_demultiplex_thread(void *p) +cifs_demultiplex_thread(struct TCP_Server_Info *server) { int length; - struct TCP_Server_Info *server = p; unsigned int pdu_length, total_read; struct smb_hdr *smb_buffer = NULL; struct smb_hdr *bigbuf = NULL; @@ -1792,7 +1791,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info) * this will succeed. No need for try_module_get(). */ __module_get(THIS_MODULE); - tcp_ses->tsk = kthread_run(cifs_demultiplex_thread, + tcp_ses->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, tcp_ses, "cifsd"); if (IS_ERR(tcp_ses->tsk)) { rc = PTR_ERR(tcp_ses->tsk); diff --git a/trunk/fs/cifs/dir.c b/trunk/fs/cifs/dir.c index 14d602f178c2..fa8c21d913bc 100644 --- a/trunk/fs/cifs/dir.c +++ b/trunk/fs/cifs/dir.c @@ -179,7 +179,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, if (oplockEnabled) oplock = REQ_OPLOCK; - if (nd) + if (nd && (nd->flags & LOOKUP_OPEN)) oflags = nd->intent.open.file->f_flags; else oflags = O_RDONLY | O_CREAT; @@ -214,7 +214,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, which should be rare for path not covered on files) */ } - if (nd) { + if (nd && (nd->flags & LOOKUP_OPEN)) { /* if the file is going to stay open, then we need to set the desired access properly */ desiredAccess = 0; @@ -328,7 +328,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, else cFYI(1, "Create worked, get_inode_info failed rc = %d", rc); - if (newinode && nd) { + if (newinode && nd && (nd->flags & LOOKUP_OPEN)) { struct cifsFileInfo *pfile_info; struct file *filp; @@ -568,7 +568,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, * reduction in network traffic in the other paths. */ if (pTcon->unix_ext) { - if (nd && !(nd->flags & LOOKUP_DIRECTORY) && + if (nd && !(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) && (nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open && (nd->intent.open.file->f_flags & O_CREAT)) { rc = cifs_posix_open(full_path, &newInode, @@ -663,8 +663,10 @@ cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd) * case sensitive name which is specified by user if this is * for creation. */ - if (nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) - return 0; + if (!(nd->flags & (LOOKUP_CONTINUE | LOOKUP_PARENT))) { + if (nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) + return 0; + } if (time_after(jiffies, direntry->d_time + HZ) || !lookupCacheEnabled) return 0; diff --git a/trunk/fs/cifs/file.c b/trunk/fs/cifs/file.c index 378acdafa356..a9b4a24f2a16 100644 --- a/trunk/fs/cifs/file.c +++ b/trunk/fs/cifs/file.c @@ -1401,8 +1401,7 @@ static int cifs_write_end(struct file *file, struct address_space *mapping, return rc; } -int cifs_strict_fsync(struct file *file, loff_t start, loff_t end, - int datasync) +int cifs_strict_fsync(struct file *file, int datasync) { int xid; int rc = 0; @@ -1411,11 +1410,6 @@ int cifs_strict_fsync(struct file *file, loff_t start, loff_t end, struct inode *inode = file->f_path.dentry->d_inode; struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); - rc = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (rc) - return rc; - mutex_lock(&inode->i_mutex); - xid = GetXid(); cFYI(1, "Sync file - name: %s datasync: 0x%x", @@ -1434,23 +1428,16 @@ int cifs_strict_fsync(struct file *file, loff_t start, loff_t end, rc = CIFSSMBFlush(xid, tcon, smbfile->netfid); FreeXid(xid); - mutex_unlock(&inode->i_mutex); return rc; } -int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync) +int cifs_fsync(struct file *file, int datasync) { int xid; int rc = 0; struct cifs_tcon *tcon; struct cifsFileInfo *smbfile = file->private_data; struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); - struct inode *inode = file->f_mapping->host; - - rc = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (rc) - return rc; - mutex_lock(&inode->i_mutex); xid = GetXid(); @@ -1462,7 +1449,6 @@ int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync) rc = CIFSSMBFlush(xid, tcon, smbfile->netfid); FreeXid(xid); - mutex_unlock(&inode->i_mutex); return rc; } diff --git a/trunk/fs/cifs/readdir.c b/trunk/fs/cifs/readdir.c index 965a3af186a1..6751e745bbc6 100644 --- a/trunk/fs/cifs/readdir.c +++ b/trunk/fs/cifs/readdir.c @@ -796,7 +796,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) file->f_pos++; case 1: if (filldir(direntry, "..", 2, file->f_pos, - parent_ino(file->f_path.dentry), DT_DIR) < 0) { + file->f_path.dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) { cERROR(1, "Filldir for parent dir failed"); rc = -ENOMEM; break; diff --git a/trunk/fs/coda/coda_int.h b/trunk/fs/coda/coda_int.h index b7143cf783ac..6b443ff43a19 100644 --- a/trunk/fs/coda/coda_int.h +++ b/trunk/fs/coda/coda_int.h @@ -11,7 +11,7 @@ extern int coda_fake_statfs; void coda_destroy_inodecache(void); int coda_init_inodecache(void); -int coda_fsync(struct file *coda_file, loff_t start, loff_t end, int datasync); +int coda_fsync(struct file *coda_file, int datasync); void coda_sysctl_init(void); void coda_sysctl_clean(void); diff --git a/trunk/fs/coda/coda_linux.h b/trunk/fs/coda/coda_linux.h index 44e17e9c21ae..9b0c5323890b 100644 --- a/trunk/fs/coda/coda_linux.h +++ b/trunk/fs/coda/coda_linux.h @@ -39,7 +39,7 @@ extern const struct file_operations coda_ioctl_operations; /* operations shared over more than one file */ int coda_open(struct inode *i, struct file *f); int coda_release(struct inode *i, struct file *f); -int coda_permission(struct inode *inode, int mask); +int coda_permission(struct inode *inode, int mask, unsigned int flags); int coda_revalidate_inode(struct dentry *); int coda_getattr(struct vfsmount *, struct dentry *, struct kstat *); int coda_setattr(struct dentry *, struct iattr *); diff --git a/trunk/fs/coda/dir.c b/trunk/fs/coda/dir.c index 0239433f50cb..2b8dae4d121e 100644 --- a/trunk/fs/coda/dir.c +++ b/trunk/fs/coda/dir.c @@ -132,11 +132,11 @@ static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, struc } -int coda_permission(struct inode *inode, int mask) +int coda_permission(struct inode *inode, int mask, unsigned int flags) { int error; - if (mask & MAY_NOT_BLOCK) + if (flags & IPERM_FLAG_RCU) return -ECHILD; mask &= MAY_READ | MAY_WRITE | MAY_EXEC; @@ -449,7 +449,8 @@ static int coda_venus_readdir(struct file *coda_file, void *buf, struct file *host_file; struct dentry *de; struct venus_dirent *vdir; - unsigned long vdir_size = offsetof(struct venus_dirent, d_name); + unsigned long vdir_size = + (unsigned long)(&((struct venus_dirent *)0)->d_name); unsigned int type; struct qstr name; ino_t ino; @@ -473,7 +474,7 @@ static int coda_venus_readdir(struct file *coda_file, void *buf, coda_file->f_pos++; } if (coda_file->f_pos == 1) { - ret = filldir(buf, "..", 2, 1, parent_ino(de), DT_DIR); + ret = filldir(buf, "..", 2, 1, de->d_parent->d_inode->i_ino, DT_DIR); if (ret < 0) goto out; result++; diff --git a/trunk/fs/coda/file.c b/trunk/fs/coda/file.c index 8edd404e6419..0433057be330 100644 --- a/trunk/fs/coda/file.c +++ b/trunk/fs/coda/file.c @@ -199,7 +199,7 @@ int coda_release(struct inode *coda_inode, struct file *coda_file) return 0; } -int coda_fsync(struct file *coda_file, loff_t start, loff_t end, int datasync) +int coda_fsync(struct file *coda_file, int datasync) { struct file *host_file; struct inode *coda_inode = coda_file->f_path.dentry->d_inode; @@ -210,11 +210,6 @@ int coda_fsync(struct file *coda_file, loff_t start, loff_t end, int datasync) S_ISLNK(coda_inode->i_mode))) return -EINVAL; - err = filemap_write_and_wait_range(coda_inode->i_mapping, start, end); - if (err) - return err; - mutex_lock(&coda_inode->i_mutex); - cfi = CODA_FTOC(coda_file); BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC); host_file = cfi->cfi_container; @@ -222,7 +217,6 @@ int coda_fsync(struct file *coda_file, loff_t start, loff_t end, int datasync) err = vfs_fsync(host_file, datasync); if (!err && !datasync) err = venus_fsync(coda_inode->i_sb, coda_i2f(coda_inode)); - mutex_unlock(&coda_inode->i_mutex); return err; } diff --git a/trunk/fs/coda/pioctl.c b/trunk/fs/coda/pioctl.c index ee0981f1375b..cb140ef293e4 100644 --- a/trunk/fs/coda/pioctl.c +++ b/trunk/fs/coda/pioctl.c @@ -24,7 +24,7 @@ #include "coda_linux.h" /* pioctl ops */ -static int coda_ioctl_permission(struct inode *inode, int mask); +static int coda_ioctl_permission(struct inode *inode, int mask, unsigned int flags); static long coda_pioctl(struct file *filp, unsigned int cmd, unsigned long user_data); @@ -41,7 +41,7 @@ const struct file_operations coda_ioctl_operations = { }; /* the coda pioctl inode ops */ -static int coda_ioctl_permission(struct inode *inode, int mask) +static int coda_ioctl_permission(struct inode *inode, int mask, unsigned int flags) { return (mask & MAY_EXEC) ? -EACCES : 0; } diff --git a/trunk/fs/dcache.c b/trunk/fs/dcache.c index be18598c7fd7..fbdcbca40725 100644 --- a/trunk/fs/dcache.c +++ b/trunk/fs/dcache.c @@ -343,24 +343,6 @@ void d_drop(struct dentry *dentry) } EXPORT_SYMBOL(d_drop); -/* - * d_clear_need_lookup - drop a dentry from cache and clear the need lookup flag - * @dentry: dentry to drop - * - * This is called when we do a lookup on a placeholder dentry that needed to be - * looked up. The dentry should have been hashed in order for it to be found by - * the lookup code, but now needs to be unhashed while we do the actual lookup - * and clear the DCACHE_NEED_LOOKUP flag. - */ -void d_clear_need_lookup(struct dentry *dentry) -{ - spin_lock(&dentry->d_lock); - __d_drop(dentry); - dentry->d_flags &= ~DCACHE_NEED_LOOKUP; - spin_unlock(&dentry->d_lock); -} -EXPORT_SYMBOL(d_clear_need_lookup); - /* * Finish off a dentry we've decided to kill. * dentry->d_lock must be held, returns with it unlocked. @@ -450,13 +432,8 @@ void dput(struct dentry *dentry) if (d_unhashed(dentry)) goto kill_it; - /* - * If this dentry needs lookup, don't set the referenced flag so that it - * is more likely to be cleaned up by the dcache shrinker in case of - * memory pressure. - */ - if (!d_need_lookup(dentry)) - dentry->d_flags |= DCACHE_REFERENCED; + /* Otherwise leave it cached and ensure it's on the LRU */ + dentry->d_flags |= DCACHE_REFERENCED; dentry_lru_add(dentry); dentry->d_count--; @@ -549,6 +526,10 @@ struct dentry *dget_parent(struct dentry *dentry) */ rcu_read_lock(); ret = dentry->d_parent; + if (!ret) { + rcu_read_unlock(); + goto out; + } spin_lock(&ret->d_lock); if (unlikely(ret != dentry->d_parent)) { spin_unlock(&ret->d_lock); @@ -559,6 +540,7 @@ struct dentry *dget_parent(struct dentry *dentry) BUG_ON(!ret->d_count); ret->d_count++; spin_unlock(&ret->d_lock); +out: return ret; } EXPORT_SYMBOL(dget_parent); @@ -738,11 +720,13 @@ static void shrink_dentry_list(struct list_head *list) * * If flags contains DCACHE_REFERENCED reference dentries will not be pruned. */ -static void __shrink_dcache_sb(struct super_block *sb, int count, int flags) +static void __shrink_dcache_sb(struct super_block *sb, int *count, int flags) { + /* called from prune_dcache() and shrink_dcache_parent() */ struct dentry *dentry; LIST_HEAD(referenced); LIST_HEAD(tmp); + int cnt = *count; relock: spin_lock(&dcache_lru_lock); @@ -770,7 +754,7 @@ static void __shrink_dcache_sb(struct super_block *sb, int count, int flags) } else { list_move_tail(&dentry->d_lru, &tmp); spin_unlock(&dentry->d_lock); - if (!--count) + if (!--cnt) break; } cond_resched_lock(&dcache_lru_lock); @@ -780,22 +764,83 @@ static void __shrink_dcache_sb(struct super_block *sb, int count, int flags) spin_unlock(&dcache_lru_lock); shrink_dentry_list(&tmp); + + *count = cnt; } /** - * prune_dcache_sb - shrink the dcache - * @nr_to_scan: number of entries to try to free + * prune_dcache - shrink the dcache + * @count: number of entries to try to free * - * Attempt to shrink the superblock dcache LRU by @nr_to_scan entries. This is - * done when we need more memory an called from the superblock shrinker - * function. + * Shrink the dcache. This is done when we need more memory, or simply when we + * need to unmount something (at which point we need to unuse all dentries). * - * This function may fail to free any resources if all the dentries are in - * use. + * This function may fail to free any resources if all the dentries are in use. */ -void prune_dcache_sb(struct super_block *sb, int nr_to_scan) +static void prune_dcache(int count) { - __shrink_dcache_sb(sb, nr_to_scan, DCACHE_REFERENCED); + struct super_block *sb, *p = NULL; + int w_count; + int unused = dentry_stat.nr_unused; + int prune_ratio; + int pruned; + + if (unused == 0 || count == 0) + return; + if (count >= unused) + prune_ratio = 1; + else + prune_ratio = unused / count; + spin_lock(&sb_lock); + list_for_each_entry(sb, &super_blocks, s_list) { + if (list_empty(&sb->s_instances)) + continue; + if (sb->s_nr_dentry_unused == 0) + continue; + sb->s_count++; + /* Now, we reclaim unused dentrins with fairness. + * We reclaim them same percentage from each superblock. + * We calculate number of dentries to scan on this sb + * as follows, but the implementation is arranged to avoid + * overflows: + * number of dentries to scan on this sb = + * count * (number of dentries on this sb / + * number of dentries in the machine) + */ + spin_unlock(&sb_lock); + if (prune_ratio != 1) + w_count = (sb->s_nr_dentry_unused / prune_ratio) + 1; + else + w_count = sb->s_nr_dentry_unused; + pruned = w_count; + /* + * We need to be sure this filesystem isn't being unmounted, + * otherwise we could race with generic_shutdown_super(), and + * end up holding a reference to an inode while the filesystem + * is unmounted. So we try to get s_umount, and make sure + * s_root isn't NULL. + */ + if (down_read_trylock(&sb->s_umount)) { + if ((sb->s_root != NULL) && + (!list_empty(&sb->s_dentry_lru))) { + __shrink_dcache_sb(sb, &w_count, + DCACHE_REFERENCED); + pruned -= w_count; + } + up_read(&sb->s_umount); + } + spin_lock(&sb_lock); + if (p) + __put_super(p); + count -= pruned; + p = sb; + /* more work left to do? */ + if (count <= 0) + break; + } + if (p) + __put_super(p); + spin_unlock(&sb_lock); } /** @@ -1170,13 +1215,45 @@ void shrink_dcache_parent(struct dentry * parent) int found; while ((found = select_parent(parent)) != 0) - __shrink_dcache_sb(sb, found, 0); + __shrink_dcache_sb(sb, &found, 0); } EXPORT_SYMBOL(shrink_dcache_parent); +/* + * Scan `sc->nr_slab_to_reclaim' dentries and return the number which remain. + * + * We need to avoid reentering the filesystem if the caller is performing a + * GFP_NOFS allocation attempt. One example deadlock is: + * + * ext2_new_block->getblk->GFP->shrink_dcache_memory->prune_dcache-> + * prune_one_dentry->dput->dentry_iput->iput->inode->i_sb->s_op->put_inode-> + * ext2_discard_prealloc->ext2_free_blocks->lock_super->DEADLOCK. + * + * In this case we return -1 to tell the caller that we baled. + */ +static int shrink_dcache_memory(struct shrinker *shrink, + struct shrink_control *sc) +{ + int nr = sc->nr_to_scan; + gfp_t gfp_mask = sc->gfp_mask; + + if (nr) { + if (!(gfp_mask & __GFP_FS)) + return -1; + prune_dcache(nr); + } + + return (dentry_stat.nr_unused / 100) * sysctl_vfs_cache_pressure; +} + +static struct shrinker dcache_shrinker = { + .shrink = shrink_dcache_memory, + .seeks = DEFAULT_SEEKS, +}; + /** - * __d_alloc - allocate a dcache entry - * @sb: filesystem it will belong to + * d_alloc - allocate a dcache entry + * @parent: parent of entry to allocate * @name: qstr of the name * * Allocates a dentry. It returns %NULL if there is insufficient memory @@ -1184,7 +1261,7 @@ EXPORT_SYMBOL(shrink_dcache_parent); * copied and the copy passed in may be reused after this call. */ -struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name) +struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) { struct dentry *dentry; char *dname; @@ -1214,8 +1291,8 @@ struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name) spin_lock_init(&dentry->d_lock); seqcount_init(&dentry->d_seq); dentry->d_inode = NULL; - dentry->d_parent = dentry; - dentry->d_sb = sb; + dentry->d_parent = NULL; + dentry->d_sb = NULL; dentry->d_op = NULL; dentry->d_fsdata = NULL; INIT_HLIST_BL_NODE(&dentry->d_hash); @@ -1223,37 +1300,22 @@ struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name) INIT_LIST_HEAD(&dentry->d_subdirs); INIT_LIST_HEAD(&dentry->d_alias); INIT_LIST_HEAD(&dentry->d_u.d_child); - d_set_d_op(dentry, dentry->d_sb->s_d_op); - this_cpu_inc(nr_dentry); - - return dentry; -} - -/** - * d_alloc - allocate a dcache entry - * @parent: parent of entry to allocate - * @name: qstr of the name - * - * Allocates a dentry. It returns %NULL if there is insufficient memory - * available. On a success the dentry is returned. The name passed in is - * copied and the copy passed in may be reused after this call. - */ -struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) -{ - struct dentry *dentry = __d_alloc(parent->d_sb, name); - if (!dentry) - return NULL; + if (parent) { + spin_lock(&parent->d_lock); + /* + * don't need child lock because it is not subject + * to concurrency here + */ + __dget_dlock(parent); + dentry->d_parent = parent; + dentry->d_sb = parent->d_sb; + d_set_d_op(dentry, dentry->d_sb->s_d_op); + list_add(&dentry->d_u.d_child, &parent->d_subdirs); + spin_unlock(&parent->d_lock); + } - spin_lock(&parent->d_lock); - /* - * don't need child lock because it is not subject - * to concurrency here - */ - __dget_dlock(parent); - dentry->d_parent = parent; - list_add(&dentry->d_u.d_child, &parent->d_subdirs); - spin_unlock(&parent->d_lock); + this_cpu_inc(nr_dentry); return dentry; } @@ -1261,9 +1323,13 @@ EXPORT_SYMBOL(d_alloc); struct dentry *d_alloc_pseudo(struct super_block *sb, const struct qstr *name) { - struct dentry *dentry = __d_alloc(sb, name); - if (dentry) + struct dentry *dentry = d_alloc(NULL, name); + if (dentry) { + dentry->d_sb = sb; + d_set_d_op(dentry, dentry->d_sb->s_d_op); + dentry->d_parent = dentry; dentry->d_flags |= DCACHE_DISCONNECTED; + } return dentry; } EXPORT_SYMBOL(d_alloc_pseudo); @@ -1433,9 +1499,13 @@ struct dentry * d_alloc_root(struct inode * root_inode) if (root_inode) { static const struct qstr name = { .name = "/", .len = 1 }; - res = __d_alloc(root_inode->i_sb, &name); - if (res) + res = d_alloc(NULL, &name); + if (res) { + res->d_sb = root_inode->i_sb; + d_set_d_op(res, res->d_sb->s_d_op); + res->d_parent = res; d_instantiate(res, root_inode); + } } return res; } @@ -1496,11 +1566,13 @@ struct dentry *d_obtain_alias(struct inode *inode) if (res) goto out_iput; - tmp = __d_alloc(inode->i_sb, &anonstring); + tmp = d_alloc(NULL, &anonstring); if (!tmp) { res = ERR_PTR(-ENOMEM); goto out_iput; } + tmp->d_parent = tmp; /* make sure dput doesn't croak */ + spin_lock(&inode->i_lock); res = __d_find_any_alias(inode); @@ -1512,6 +1584,8 @@ struct dentry *d_obtain_alias(struct inode *inode) /* attach a disconnected dentry */ spin_lock(&tmp->d_lock); + tmp->d_sb = inode->i_sb; + d_set_d_op(tmp, tmp->d_sb->s_d_op); tmp->d_inode = inode; tmp->d_flags |= DCACHE_DISCONNECTED; list_add(&tmp->d_alias, &inode->i_dentry); @@ -1552,9 +1626,6 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry) { struct dentry *new = NULL; - if (IS_ERR(inode)) - return ERR_CAST(inode); - if (inode && S_ISDIR(inode->i_mode)) { spin_lock(&inode->i_lock); new = __d_find_alias(inode, 1); @@ -1636,23 +1707,30 @@ struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode, return found; } - /* - * We are going to instantiate this dentry, unhash it and clear the - * lookup flag so we can do that. - */ - if (unlikely(d_need_lookup(found))) - d_clear_need_lookup(found); - /* * Negative dentry: instantiate it unless the inode is a directory and * already has a dentry. */ - new = d_splice_alias(inode, found); - if (new) { - dput(found); - found = new; + spin_lock(&inode->i_lock); + if (!S_ISDIR(inode->i_mode) || list_empty(&inode->i_dentry)) { + __d_instantiate(found, inode); + spin_unlock(&inode->i_lock); + security_d_instantiate(found, inode); + return found; } - return found; + + /* + * In case a directory already has a (disconnected) entry grab a + * reference to it, move it in place and use it. + */ + new = list_entry(inode->i_dentry.next, struct dentry, d_alias); + __dget(new); + spin_unlock(&inode->i_lock); + security_d_instantiate(found, inode); + d_move(new, found); + iput(inode); + dput(found); + return new; err_out: iput(inode); @@ -2967,6 +3045,8 @@ static void __init dcache_init(void) */ dentry_cache = KMEM_CACHE(dentry, SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|SLAB_MEM_SPREAD); + + register_shrinker(&dcache_shrinker); /* Hash may have been set up in dcache_init_early */ if (!hashdist) diff --git a/trunk/fs/direct-io.c b/trunk/fs/direct-io.c index 01d2d9ef609c..ac5f164170e3 100644 --- a/trunk/fs/direct-io.c +++ b/trunk/fs/direct-io.c @@ -135,50 +135,6 @@ struct dio { struct page *pages[DIO_PAGES]; /* page buffer */ }; -static void __inode_dio_wait(struct inode *inode) -{ - wait_queue_head_t *wq = bit_waitqueue(&inode->i_state, __I_DIO_WAKEUP); - DEFINE_WAIT_BIT(q, &inode->i_state, __I_DIO_WAKEUP); - - do { - prepare_to_wait(wq, &q.wait, TASK_UNINTERRUPTIBLE); - if (atomic_read(&inode->i_dio_count)) - schedule(); - } while (atomic_read(&inode->i_dio_count)); - finish_wait(wq, &q.wait); -} - -/** - * inode_dio_wait - wait for outstanding DIO requests to finish - * @inode: inode to wait for - * - * Waits for all pending direct I/O requests to finish so that we can - * proceed with a truncate or equivalent operation. - * - * Must be called under a lock that serializes taking new references - * to i_dio_count, usually by inode->i_mutex. - */ -void inode_dio_wait(struct inode *inode) -{ - if (atomic_read(&inode->i_dio_count)) - __inode_dio_wait(inode); -} -EXPORT_SYMBOL_GPL(inode_dio_wait); - -/* - * inode_dio_done - signal finish of a direct I/O requests - * @inode: inode the direct I/O happens on - * - * This is called once we've finished processing a direct I/O request, - * and is used to wake up callers waiting for direct I/O to be quiesced. - */ -void inode_dio_done(struct inode *inode) -{ - if (atomic_dec_and_test(&inode->i_dio_count)) - wake_up_bit(&inode->i_state, __I_DIO_WAKEUP); -} -EXPORT_SYMBOL_GPL(inode_dio_done); - /* * How many pages are in the queue? */ @@ -293,12 +249,14 @@ static ssize_t dio_complete(struct dio *dio, loff_t offset, ssize_t ret, bool is if (dio->end_io && dio->result) { dio->end_io(dio->iocb, offset, transferred, dio->map_bh.b_private, ret, is_async); - } else { - if (is_async) - aio_complete(dio->iocb, ret, 0); - inode_dio_done(dio->inode); + } else if (is_async) { + aio_complete(dio->iocb, ret, 0); } + if (dio->flags & DIO_LOCKING) + /* lockdep: non-owner release */ + up_read_non_owner(&dio->inode->i_alloc_sem); + return ret; } @@ -1022,6 +980,9 @@ static int do_direct_IO(struct dio *dio) return ret; } +/* + * Releases both i_mutex and i_alloc_sem + */ static ssize_t direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, const struct iovec *iov, loff_t offset, unsigned long nr_segs, @@ -1185,16 +1146,15 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, * For writes this function is called under i_mutex and returns with * i_mutex held, for reads, i_mutex is not held on entry, but it is * taken and dropped again before returning. + * For reads and writes i_alloc_sem is taken in shared mode and released + * on I/O completion (which may happen asynchronously after returning to + * the caller). + * * - if the flags value does NOT contain DIO_LOCKING we don't use any * internal locking but rather rely on the filesystem to synchronize * direct I/O reads/writes versus each other and truncate. - * - * To help with locking against truncate we incremented the i_dio_count - * counter before starting direct I/O, and decrement it once we are done. - * Truncate can wait for it to reach zero to provide exclusion. It is - * expected that filesystem provide exclusion between new direct I/O - * and truncates. For DIO_LOCKING filesystems this is done by i_mutex, - * but other filesystems need to take care of this on their own. + * For reads and writes both i_mutex and i_alloc_sem are not held on + * entry and are never taken. */ ssize_t __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, @@ -1240,10 +1200,6 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, } } - /* watch out for a 0 len io from a tricksy fs */ - if (rw == READ && end == offset) - return 0; - dio = kmalloc(sizeof(*dio), GFP_KERNEL); retval = -ENOMEM; if (!dio) @@ -1257,7 +1213,8 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, dio->flags = flags; if (dio->flags & DIO_LOCKING) { - if (rw == READ) { + /* watch out for a 0 len io from a tricksy fs */ + if (rw == READ && end > offset) { struct address_space *mapping = iocb->ki_filp->f_mapping; @@ -1272,12 +1229,13 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, goto out; } } - } - /* - * Will be decremented at I/O completion time. - */ - atomic_inc(&inode->i_dio_count); + /* + * Will be released at I/O completion, possibly in a + * different thread. + */ + down_read_non_owner(&inode->i_alloc_sem); + } /* * For file extending writes updating i_size before data diff --git a/trunk/fs/ecryptfs/file.c b/trunk/fs/ecryptfs/file.c index c6ac98cf9baa..4ec9eb00a241 100644 --- a/trunk/fs/ecryptfs/file.c +++ b/trunk/fs/ecryptfs/file.c @@ -270,15 +270,14 @@ static int ecryptfs_release(struct inode *inode, struct file *file) } static int -ecryptfs_fsync(struct file *file, loff_t start, loff_t end, int datasync) +ecryptfs_fsync(struct file *file, int datasync) { int rc = 0; - rc = generic_file_fsync(file, start, end, datasync); + rc = generic_file_fsync(file, datasync); if (rc) goto out; - rc = vfs_fsync_range(ecryptfs_file_to_lower(file), start, end, - datasync); + rc = vfs_fsync(ecryptfs_file_to_lower(file), datasync); out: return rc; } diff --git a/trunk/fs/ecryptfs/inode.c b/trunk/fs/ecryptfs/inode.c index 340c657a108c..7349ade17de6 100644 --- a/trunk/fs/ecryptfs/inode.c +++ b/trunk/fs/ecryptfs/inode.c @@ -147,6 +147,7 @@ static int ecryptfs_interpose(struct dentry *lower_dentry, * @lower_dir_inode: inode of the parent in the lower fs of the new file * @dentry: New file's dentry * @mode: The mode of the new file + * @nd: nameidata of ecryptfs' parent's dentry & vfsmount * * Creates the file in the lower file system. * @@ -154,10 +155,31 @@ static int ecryptfs_interpose(struct dentry *lower_dentry, */ static int ecryptfs_create_underlying_file(struct inode *lower_dir_inode, - struct dentry *dentry, int mode) + struct dentry *dentry, int mode, + struct nameidata *nd) { struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); - return vfs_create(lower_dir_inode, lower_dentry, mode, NULL); + struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry); + struct dentry *dentry_save; + struct vfsmount *vfsmount_save; + unsigned int flags_save; + int rc; + + if (nd) { + dentry_save = nd->path.dentry; + vfsmount_save = nd->path.mnt; + flags_save = nd->flags; + nd->path.dentry = lower_dentry; + nd->path.mnt = lower_mnt; + nd->flags &= ~LOOKUP_OPEN; + } + rc = vfs_create(lower_dir_inode, lower_dentry, mode, nd); + if (nd) { + nd->path.dentry = dentry_save; + nd->path.mnt = vfsmount_save; + nd->flags = flags_save; + } + return rc; } /** @@ -175,7 +197,8 @@ ecryptfs_create_underlying_file(struct inode *lower_dir_inode, */ static int ecryptfs_do_create(struct inode *directory_inode, - struct dentry *ecryptfs_dentry, int mode) + struct dentry *ecryptfs_dentry, int mode, + struct nameidata *nd) { int rc; struct dentry *lower_dentry; @@ -190,7 +213,7 @@ ecryptfs_do_create(struct inode *directory_inode, goto out; } rc = ecryptfs_create_underlying_file(lower_dir_dentry->d_inode, - ecryptfs_dentry, mode); + ecryptfs_dentry, mode, nd); if (rc) { printk(KERN_ERR "%s: Failure to create dentry in lower fs; " "rc = [%d]\n", __func__, rc); @@ -271,7 +294,7 @@ ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry, int rc; /* ecryptfs_do_create() calls ecryptfs_interpose() */ - rc = ecryptfs_do_create(directory_inode, ecryptfs_dentry, mode); + rc = ecryptfs_do_create(directory_inode, ecryptfs_dentry, mode, nd); if (unlikely(rc)) { ecryptfs_printk(KERN_WARNING, "Failed to create file in" "lower filesystem\n"); @@ -919,8 +942,10 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length) } static int -ecryptfs_permission(struct inode *inode, int mask) +ecryptfs_permission(struct inode *inode, int mask, unsigned int flags) { + if (flags & IPERM_FLAG_RCU) + return -ECHILD; return inode_permission(ecryptfs_inode_to_lower(inode), mask); } diff --git a/trunk/fs/efs/namei.c b/trunk/fs/efs/namei.c index 832b10ded82f..1511bf9e5f80 100644 --- a/trunk/fs/efs/namei.c +++ b/trunk/fs/efs/namei.c @@ -60,11 +60,14 @@ static efs_ino_t efs_find_entry(struct inode *inode, const char *name, int len) struct dentry *efs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { efs_ino_t inodenum; - struct inode *inode = NULL; + struct inode * inode = NULL; inodenum = efs_find_entry(dir, dentry->d_name.name, dentry->d_name.len); - if (inodenum) + if (inodenum) { inode = efs_iget(dir->i_sb, inodenum); + if (IS_ERR(inode)) + return ERR_CAST(inode); + } return d_splice_alias(inode, dentry); } diff --git a/trunk/fs/exec.c b/trunk/fs/exec.c index 842d5700c155..d9576f261815 100644 --- a/trunk/fs/exec.c +++ b/trunk/fs/exec.c @@ -1114,13 +1114,6 @@ int flush_old_exec(struct linux_binprm * bprm) } EXPORT_SYMBOL(flush_old_exec); -void would_dump(struct linux_binprm *bprm, struct file *file) -{ - if (inode_permission(file->f_path.dentry->d_inode, MAY_READ) < 0) - bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP; -} -EXPORT_SYMBOL(would_dump); - void setup_new_exec(struct linux_binprm * bprm) { int i, ch; @@ -1160,10 +1153,9 @@ void setup_new_exec(struct linux_binprm * bprm) if (bprm->cred->uid != current_euid() || bprm->cred->gid != current_egid()) { current->pdeath_signal = 0; - } else { - would_dump(bprm, bprm->file); - if (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP) - set_dumpable(current->mm, suid_dumpable); + } else if (file_permission(bprm->file, MAY_READ) || + bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP) { + set_dumpable(current->mm, suid_dumpable); } /* diff --git a/trunk/fs/exofs/file.c b/trunk/fs/exofs/file.c index 491c6c078e7f..45ca323d8363 100644 --- a/trunk/fs/exofs/file.c +++ b/trunk/fs/exofs/file.c @@ -42,19 +42,11 @@ static int exofs_release_file(struct inode *inode, struct file *filp) * Note, in exofs all metadata is written as part of inode, regardless. * The writeout is synchronous */ -static int exofs_file_fsync(struct file *filp, loff_t start, loff_t end, - int datasync) +static int exofs_file_fsync(struct file *filp, int datasync) { - struct inode *inode = filp->f_mapping->host; int ret; - ret = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (ret) - return ret; - - mutex_lock(&inode->i_mutex); ret = sync_inode_metadata(filp->f_mapping->host, 1); - mutex_unlock(&inode->i_mutex); return ret; } diff --git a/trunk/fs/exofs/namei.c b/trunk/fs/exofs/namei.c index b54c43775f17..4d70db110cfc 100644 --- a/trunk/fs/exofs/namei.c +++ b/trunk/fs/exofs/namei.c @@ -55,7 +55,12 @@ static struct dentry *exofs_lookup(struct inode *dir, struct dentry *dentry, return ERR_PTR(-ENAMETOOLONG); ino = exofs_inode_by_name(dir, dentry); - inode = ino ? exofs_iget(dir->i_sb, ino) : NULL; + inode = NULL; + if (ino) { + inode = exofs_iget(dir->i_sb, ino); + if (IS_ERR(inode)) + return ERR_CAST(inode); + } return d_splice_alias(inode, dentry); } diff --git a/trunk/fs/ext2/acl.c b/trunk/fs/ext2/acl.c index bfe651f9ae16..abea5a17c764 100644 --- a/trunk/fs/ext2/acl.c +++ b/trunk/fs/ext2/acl.c @@ -232,11 +232,11 @@ ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl) } int -ext2_check_acl(struct inode *inode, int mask) +ext2_check_acl(struct inode *inode, int mask, unsigned int flags) { struct posix_acl *acl; - if (mask & MAY_NOT_BLOCK) { + if (flags & IPERM_FLAG_RCU) { if (!negative_cached_acl(inode, ACL_TYPE_ACCESS)) return -ECHILD; return -EAGAIN; diff --git a/trunk/fs/ext2/acl.h b/trunk/fs/ext2/acl.h index 3ff6cbb9ac44..c939b7b12099 100644 --- a/trunk/fs/ext2/acl.h +++ b/trunk/fs/ext2/acl.h @@ -54,7 +54,7 @@ static inline int ext2_acl_count(size_t size) #ifdef CONFIG_EXT2_FS_POSIX_ACL /* acl.c */ -extern int ext2_check_acl (struct inode *, int); +extern int ext2_check_acl (struct inode *, int, unsigned int); extern int ext2_acl_chmod (struct inode *); extern int ext2_init_acl (struct inode *, struct inode *); diff --git a/trunk/fs/ext2/ext2.h b/trunk/fs/ext2/ext2.h index af9fc89b1b2d..645be9e7ee47 100644 --- a/trunk/fs/ext2/ext2.h +++ b/trunk/fs/ext2/ext2.h @@ -150,8 +150,7 @@ extern void ext2_write_super (struct super_block *); extern const struct file_operations ext2_dir_operations; /* file.c */ -extern int ext2_fsync(struct file *file, loff_t start, loff_t end, - int datasync); +extern int ext2_fsync(struct file *file, int datasync); extern const struct inode_operations ext2_file_inode_operations; extern const struct file_operations ext2_file_operations; extern const struct file_operations ext2_xip_file_operations; diff --git a/trunk/fs/ext2/file.c b/trunk/fs/ext2/file.c index 82e06321de35..49eec9456c5b 100644 --- a/trunk/fs/ext2/file.c +++ b/trunk/fs/ext2/file.c @@ -40,13 +40,13 @@ static int ext2_release_file (struct inode * inode, struct file * filp) return 0; } -int ext2_fsync(struct file *file, loff_t start, loff_t end, int datasync) +int ext2_fsync(struct file *file, int datasync) { int ret; struct super_block *sb = file->f_mapping->host->i_sb; struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping; - ret = generic_file_fsync(file, start, end, datasync); + ret = generic_file_fsync(file, datasync); if (ret == -EIO || test_and_clear_bit(AS_EIO, &mapping->flags)) { /* We don't really know where the IO error happened... */ ext2_error(sb, __func__, diff --git a/trunk/fs/ext2/inode.c b/trunk/fs/ext2/inode.c index a8a58f63f07c..788e09a07f7e 100644 --- a/trunk/fs/ext2/inode.c +++ b/trunk/fs/ext2/inode.c @@ -843,8 +843,8 @@ ext2_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, struct inode *inode = mapping->host; ssize_t ret; - ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, - ext2_get_block); + ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, + iov, offset, nr_segs, ext2_get_block, NULL); if (ret < 0 && (rw & WRITE)) ext2_write_failed(mapping, offset + iov_length(iov, nr_segs)); return ret; @@ -1184,8 +1184,6 @@ static int ext2_setsize(struct inode *inode, loff_t newsize) if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) return -EPERM; - inode_dio_wait(inode); - if (mapping_is_xip(inode->i_mapping)) error = xip_truncate_page(inode->i_mapping, newsize); else if (test_opt(inode->i_sb, NOBH)) diff --git a/trunk/fs/ext2/namei.c b/trunk/fs/ext2/namei.c index d60b7099e2db..ed5c5d496ee9 100644 --- a/trunk/fs/ext2/namei.c +++ b/trunk/fs/ext2/namei.c @@ -67,11 +67,15 @@ static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, str inode = NULL; if (ino) { inode = ext2_iget(dir->i_sb, ino); - if (inode == ERR_PTR(-ESTALE)) { - ext2_error(dir->i_sb, __func__, - "deleted inode referenced: %lu", - (unsigned long) ino); - return ERR_PTR(-EIO); + if (IS_ERR(inode)) { + if (PTR_ERR(inode) == -ESTALE) { + ext2_error(dir->i_sb, __func__, + "deleted inode referenced: %lu", + (unsigned long) ino); + return ERR_PTR(-EIO); + } else { + return ERR_CAST(inode); + } } } return d_splice_alias(inode, dentry); diff --git a/trunk/fs/ext3/acl.c b/trunk/fs/ext3/acl.c index edfeb293d4cb..9d021c0d472a 100644 --- a/trunk/fs/ext3/acl.c +++ b/trunk/fs/ext3/acl.c @@ -240,11 +240,11 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type, } int -ext3_check_acl(struct inode *inode, int mask) +ext3_check_acl(struct inode *inode, int mask, unsigned int flags) { struct posix_acl *acl; - if (mask & MAY_NOT_BLOCK) { + if (flags & IPERM_FLAG_RCU) { if (!negative_cached_acl(inode, ACL_TYPE_ACCESS)) return -ECHILD; return -EAGAIN; diff --git a/trunk/fs/ext3/acl.h b/trunk/fs/ext3/acl.h index 597334626de9..5faf8048e906 100644 --- a/trunk/fs/ext3/acl.h +++ b/trunk/fs/ext3/acl.h @@ -54,7 +54,7 @@ static inline int ext3_acl_count(size_t size) #ifdef CONFIG_EXT3_FS_POSIX_ACL /* acl.c */ -extern int ext3_check_acl (struct inode *, int); +extern int ext3_check_acl (struct inode *, int, unsigned int); extern int ext3_acl_chmod (struct inode *); extern int ext3_init_acl (handle_t *, struct inode *, struct inode *); diff --git a/trunk/fs/ext3/fsync.c b/trunk/fs/ext3/fsync.c index 0bcf63adb80a..09b13bb34c94 100644 --- a/trunk/fs/ext3/fsync.c +++ b/trunk/fs/ext3/fsync.c @@ -43,7 +43,7 @@ * inode to disk. */ -int ext3_sync_file(struct file *file, loff_t start, loff_t end, int datasync) +int ext3_sync_file(struct file *file, int datasync) { struct inode *inode = file->f_mapping->host; struct ext3_inode_info *ei = EXT3_I(inode); @@ -54,17 +54,6 @@ int ext3_sync_file(struct file *file, loff_t start, loff_t end, int datasync) if (inode->i_sb->s_flags & MS_RDONLY) return 0; - ret = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (ret) - return ret; - - /* - * Taking the mutex here just to keep consistent with how fsync was - * called previously, however it looks like we don't need to take - * i_mutex at all. - */ - mutex_lock(&inode->i_mutex); - J_ASSERT(ext3_journal_current_handle() == NULL); /* @@ -81,10 +70,8 @@ int ext3_sync_file(struct file *file, loff_t start, loff_t end, int datasync) * (they were dirtied by commit). But that's OK - the blocks are * safe in-journal, which is all fsync() needs to ensure. */ - if (ext3_should_journal_data(inode)) { - mutex_unlock(&inode->i_mutex); + if (ext3_should_journal_data(inode)) return ext3_force_commit(inode->i_sb); - } if (datasync) commit_tid = atomic_read(&ei->i_datasync_tid); @@ -104,6 +91,5 @@ int ext3_sync_file(struct file *file, loff_t start, loff_t end, int datasync) */ if (needs_barrier) blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); - mutex_unlock(&inode->i_mutex); return ret; } diff --git a/trunk/fs/ext3/inode.c b/trunk/fs/ext3/inode.c index 2978a2a17a59..3451d23c3bae 100644 --- a/trunk/fs/ext3/inode.c +++ b/trunk/fs/ext3/inode.c @@ -1816,8 +1816,9 @@ static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb, } retry: - ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, - ext3_get_block); + ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, + offset, nr_segs, + ext3_get_block, NULL); /* * In case of error extending write may have instantiated a few * blocks outside i_size. Trim these off again. @@ -3215,9 +3216,6 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr) ext3_journal_stop(handle); } - if (attr->ia_valid & ATTR_SIZE) - inode_dio_wait(inode); - if (S_ISREG(inode->i_mode) && attr->ia_valid & ATTR_SIZE && attr->ia_size < inode->i_size) { handle_t *handle; diff --git a/trunk/fs/ext3/namei.c b/trunk/fs/ext3/namei.c index c095cf5640c7..34b6d9bfc48a 100644 --- a/trunk/fs/ext3/namei.c +++ b/trunk/fs/ext3/namei.c @@ -1038,11 +1038,15 @@ static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, str return ERR_PTR(-EIO); } inode = ext3_iget(dir->i_sb, ino); - if (inode == ERR_PTR(-ESTALE)) { - ext3_error(dir->i_sb, __func__, - "deleted inode referenced: %lu", - ino); - return ERR_PTR(-EIO); + if (IS_ERR(inode)) { + if (PTR_ERR(inode) == -ESTALE) { + ext3_error(dir->i_sb, __func__, + "deleted inode referenced: %lu", + ino); + return ERR_PTR(-EIO); + } else { + return ERR_CAST(inode); + } } } return d_splice_alias(inode, dentry); diff --git a/trunk/fs/ext3/super.c b/trunk/fs/ext3/super.c index b57ea2f91269..aad153ef6b78 100644 --- a/trunk/fs/ext3/super.c +++ b/trunk/fs/ext3/super.c @@ -1718,8 +1718,6 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) sbi->s_resuid = le16_to_cpu(es->s_def_resuid); sbi->s_resgid = le16_to_cpu(es->s_def_resgid); - /* enable barriers by default */ - set_opt(sbi->s_mount_opt, BARRIER); set_opt(sbi->s_mount_opt, RESERVATION); if (!parse_options ((char *) data, sb, &journal_inum, &journal_devnum, diff --git a/trunk/fs/ext4/acl.c b/trunk/fs/ext4/acl.c index 60d900fcc3db..21eacd7b7d79 100644 --- a/trunk/fs/ext4/acl.c +++ b/trunk/fs/ext4/acl.c @@ -238,11 +238,11 @@ ext4_set_acl(handle_t *handle, struct inode *inode, int type, } int -ext4_check_acl(struct inode *inode, int mask) +ext4_check_acl(struct inode *inode, int mask, unsigned int flags) { struct posix_acl *acl; - if (mask & MAY_NOT_BLOCK) { + if (flags & IPERM_FLAG_RCU) { if (!negative_cached_acl(inode, ACL_TYPE_ACCESS)) return -ECHILD; return -EAGAIN; diff --git a/trunk/fs/ext4/acl.h b/trunk/fs/ext4/acl.h index 9d843d5deac4..dec821168fd4 100644 --- a/trunk/fs/ext4/acl.h +++ b/trunk/fs/ext4/acl.h @@ -54,7 +54,7 @@ static inline int ext4_acl_count(size_t size) #ifdef CONFIG_EXT4_FS_POSIX_ACL /* acl.c */ -extern int ext4_check_acl(struct inode *, int); +extern int ext4_check_acl(struct inode *, int, unsigned int); extern int ext4_acl_chmod(struct inode *); extern int ext4_init_acl(handle_t *, struct inode *, struct inode *); diff --git a/trunk/fs/ext4/ext4.h b/trunk/fs/ext4/ext4.h index fa44df879711..1921392cd708 100644 --- a/trunk/fs/ext4/ext4.h +++ b/trunk/fs/ext4/ext4.h @@ -1758,7 +1758,7 @@ extern int ext4_htree_store_dirent(struct file *dir_file, __u32 hash, extern void ext4_htree_free_dir_info(struct dir_private_info *p); /* fsync.c */ -extern int ext4_sync_file(struct file *, loff_t, loff_t, int); +extern int ext4_sync_file(struct file *, int); extern int ext4_flush_completed_IO(struct inode *); /* hash.c */ diff --git a/trunk/fs/ext4/file.c b/trunk/fs/ext4/file.c index ce766f974b1d..2c0972322009 100644 --- a/trunk/fs/ext4/file.c +++ b/trunk/fs/ext4/file.c @@ -236,27 +236,6 @@ loff_t ext4_llseek(struct file *file, loff_t offset, int origin) } offset += file->f_pos; break; - case SEEK_DATA: - /* - * In the generic case the entire file is data, so as long as - * offset isn't at the end of the file then the offset is data. - */ - if (offset >= inode->i_size) { - mutex_unlock(&inode->i_mutex); - return -ENXIO; - } - break; - case SEEK_HOLE: - /* - * There is a virtual hole at the end of the file, so as long as - * offset isn't i_size or larger, return i_size. - */ - if (offset >= inode->i_size) { - mutex_unlock(&inode->i_mutex); - return -ENXIO; - } - offset = inode->i_size; - break; } if (offset < 0 || offset > maxbytes) { diff --git a/trunk/fs/ext4/fsync.c b/trunk/fs/ext4/fsync.c index da3bed3e0c29..ce66d2fe826c 100644 --- a/trunk/fs/ext4/fsync.c +++ b/trunk/fs/ext4/fsync.c @@ -151,32 +151,6 @@ static int ext4_sync_parent(struct inode *inode) return ret; } -/** - * __sync_file - generic_file_fsync without the locking and filemap_write - * @inode: inode to sync - * @datasync: only sync essential metadata if true - * - * This is just generic_file_fsync without the locking. This is needed for - * nojournal mode to make sure this inodes data/metadata makes it to disk - * properly. The i_mutex should be held already. - */ -static int __sync_inode(struct inode *inode, int datasync) -{ - int err; - int ret; - - ret = sync_mapping_buffers(inode->i_mapping); - if (!(inode->i_state & I_DIRTY)) - return ret; - if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) - return ret; - - err = sync_inode_metadata(inode, 1); - if (ret == 0) - ret = err; - return ret; -} - /* * akpm: A new design for ext4_sync_file(). * @@ -191,7 +165,7 @@ static int __sync_inode(struct inode *inode, int datasync) * i_mutex lock is held when entering and exiting this function */ -int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync) +int ext4_sync_file(struct file *file, int datasync) { struct inode *inode = file->f_mapping->host; struct ext4_inode_info *ei = EXT4_I(inode); @@ -204,20 +178,15 @@ int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync) trace_ext4_sync_file_enter(file, datasync); - ret = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (ret) - return ret; - mutex_lock(&inode->i_mutex); - if (inode->i_sb->s_flags & MS_RDONLY) - goto out; + return 0; ret = ext4_flush_completed_IO(inode); if (ret < 0) goto out; if (!journal) { - ret = __sync_inode(inode, datasync); + ret = generic_file_fsync(file, datasync); if (!ret && !list_empty(&inode->i_dentry)) ret = ext4_sync_parent(inode); goto out; @@ -251,7 +220,6 @@ int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync) if (needs_barrier) blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); out: - mutex_unlock(&inode->i_mutex); trace_ext4_sync_file_exit(inode, ret); return ret; } diff --git a/trunk/fs/ext4/inode.c b/trunk/fs/ext4/inode.c index 678cde834f19..e3126c051006 100644 --- a/trunk/fs/ext4/inode.c +++ b/trunk/fs/ext4/inode.c @@ -3501,8 +3501,10 @@ static ssize_t ext4_ind_direct_IO(int rw, struct kiocb *iocb, offset, nr_segs, ext4_get_block, NULL, NULL, 0); else { - ret = blockdev_direct_IO(rw, iocb, inode, iov, - offset, nr_segs, ext4_get_block); + ret = blockdev_direct_IO(rw, iocb, inode, + inode->i_sb->s_bdev, iov, + offset, nr_segs, + ext4_get_block, NULL); if (unlikely((rw & WRITE) && ret < 0)) { loff_t isize = i_size_read(inode); @@ -3573,7 +3575,6 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, ssize_t size, void *private, int ret, bool is_async) { - struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode; ext4_io_end_t *io_end = iocb->private; struct workqueue_struct *wq; unsigned long flags; @@ -3595,7 +3596,6 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, out: if (is_async) aio_complete(iocb, ret, 0); - inode_dio_done(inode); return; } @@ -3616,9 +3616,6 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, /* queue the work to convert unwritten extents to written */ queue_work(wq, &io_end->work); iocb->private = NULL; - - /* XXX: probably should move into the real I/O completion handler */ - inode_dio_done(inode); } static void ext4_end_io_buffer_write(struct buffer_head *bh, int uptodate) @@ -3751,13 +3748,11 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb, EXT4_I(inode)->cur_aio_dio = iocb->private; } - ret = __blockdev_direct_IO(rw, iocb, inode, + ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, offset, nr_segs, ext4_get_block_write, - ext4_end_io_dio, - NULL, - DIO_LOCKING | DIO_SKIP_HOLES); + ext4_end_io_dio); if (iocb->private) EXT4_I(inode)->cur_aio_dio = NULL; /* @@ -5356,8 +5351,6 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr) } if (attr->ia_valid & ATTR_SIZE) { - inode_dio_wait(inode); - if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) { struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); @@ -5850,84 +5843,80 @@ int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) struct page *page = vmf->page; loff_t size; unsigned long len; - int ret; + int ret = -EINVAL; + void *fsdata; struct file *file = vma->vm_file; struct inode *inode = file->f_path.dentry->d_inode; struct address_space *mapping = inode->i_mapping; - handle_t *handle; - get_block_t *get_block; - int retries = 0; /* - * This check is racy but catches the common case. We rely on - * __block_page_mkwrite() to do a reliable check. + * Get i_alloc_sem to stop truncates messing with the inode. We cannot + * get i_mutex because we are already holding mmap_sem. */ - vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE); - /* Delalloc case is easy... */ - if (test_opt(inode->i_sb, DELALLOC) && - !ext4_should_journal_data(inode) && - !ext4_nonda_switch(inode->i_sb)) { - do { - ret = __block_page_mkwrite(vma, vmf, - ext4_da_get_block_prep); - } while (ret == -ENOSPC && - ext4_should_retry_alloc(inode->i_sb, &retries)); - goto out_ret; + down_read(&inode->i_alloc_sem); + size = i_size_read(inode); + if (page->mapping != mapping || size <= page_offset(page) + || !PageUptodate(page)) { + /* page got truncated from under us? */ + goto out_unlock; } + ret = 0; lock_page(page); - size = i_size_read(inode); - /* Page got truncated from under us? */ - if (page->mapping != mapping || page_offset(page) > size) { - unlock_page(page); - ret = VM_FAULT_NOPAGE; - goto out; + wait_on_page_writeback(page); + if (PageMappedToDisk(page)) { + up_read(&inode->i_alloc_sem); + return VM_FAULT_LOCKED; } if (page->index == size >> PAGE_CACHE_SHIFT) len = size & ~PAGE_CACHE_MASK; else len = PAGE_CACHE_SIZE; + /* - * Return if we have all the buffers mapped. This avoids the need to do - * journal_start/journal_stop which can block and take a long time + * return if we have all the buffers mapped. This avoid + * the need to call write_begin/write_end which does a + * journal_start/journal_stop which can block and take + * long time */ if (page_has_buffers(page)) { if (!walk_page_buffers(NULL, page_buffers(page), 0, len, NULL, ext4_bh_unmapped)) { - /* Wait so that we don't change page under IO */ - wait_on_page_writeback(page); - ret = VM_FAULT_LOCKED; - goto out; + up_read(&inode->i_alloc_sem); + return VM_FAULT_LOCKED; } } unlock_page(page); - /* OK, we need to fill the hole... */ - if (ext4_should_dioread_nolock(inode)) - get_block = ext4_get_block_write; - else - get_block = ext4_get_block; -retry_alloc: - handle = ext4_journal_start(inode, ext4_writepage_trans_blocks(inode)); - if (IS_ERR(handle)) { + /* + * OK, we need to fill the hole... Do write_begin write_end + * to do block allocation/reservation.We are not holding + * inode.i__mutex here. That allow * parallel write_begin, + * write_end call. lock_page prevent this from happening + * on the same page though + */ + ret = mapping->a_ops->write_begin(file, mapping, page_offset(page), + len, AOP_FLAG_UNINTERRUPTIBLE, &page, &fsdata); + if (ret < 0) + goto out_unlock; + ret = mapping->a_ops->write_end(file, mapping, page_offset(page), + len, len, page, fsdata); + if (ret < 0) + goto out_unlock; + ret = 0; + + /* + * write_begin/end might have created a dirty page and someone + * could wander in and start the IO. Make sure that hasn't + * happened. + */ + lock_page(page); + wait_on_page_writeback(page); + up_read(&inode->i_alloc_sem); + return VM_FAULT_LOCKED; +out_unlock: + if (ret) ret = VM_FAULT_SIGBUS; - goto out; - } - ret = __block_page_mkwrite(vma, vmf, get_block); - if (!ret && ext4_should_journal_data(inode)) { - if (walk_page_buffers(handle, page_buffers(page), 0, - PAGE_CACHE_SIZE, NULL, do_journal_get_write_access)) { - unlock_page(page); - ret = VM_FAULT_SIGBUS; - goto out; - } - ext4_set_inode_state(inode, EXT4_STATE_JDATA); - } - ext4_journal_stop(handle); - if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) - goto retry_alloc; -out_ret: - ret = block_page_mkwrite_return(ret); -out: + up_read(&inode->i_alloc_sem); return ret; } diff --git a/trunk/fs/ext4/namei.c b/trunk/fs/ext4/namei.c index 707d605bf769..b754b7721f51 100644 --- a/trunk/fs/ext4/namei.c +++ b/trunk/fs/ext4/namei.c @@ -1037,11 +1037,15 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, stru return ERR_PTR(-EIO); } inode = ext4_iget(dir->i_sb, ino); - if (inode == ERR_PTR(-ESTALE)) { - EXT4_ERROR_INODE(dir, - "deleted inode referenced: %u", - ino); - return ERR_PTR(-EIO); + if (IS_ERR(inode)) { + if (PTR_ERR(inode) == -ESTALE) { + EXT4_ERROR_INODE(dir, + "deleted inode referenced: %u", + ino); + return ERR_PTR(-EIO); + } else { + return ERR_CAST(inode); + } } } return d_splice_alias(inode, dentry); diff --git a/trunk/fs/fat/fat.h b/trunk/fs/fat/fat.h index a5d3853822e0..8276cc282dec 100644 --- a/trunk/fs/fat/fat.h +++ b/trunk/fs/fat/fat.h @@ -109,7 +109,6 @@ struct msdos_inode_info { int i_attrs; /* unused attribute bits */ loff_t i_pos; /* on-disk position of directory entry or 0 */ struct hlist_node i_fat_hash; /* hash by i_location */ - struct rw_semaphore truncate_lock; /* protect bmap against truncate */ struct inode vfs_inode; }; @@ -310,8 +309,7 @@ extern int fat_setattr(struct dentry * dentry, struct iattr * attr); extern void fat_truncate_blocks(struct inode *inode, loff_t offset); extern int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); -extern int fat_file_fsync(struct file *file, loff_t start, loff_t end, - int datasync); +extern int fat_file_fsync(struct file *file, int datasync); /* fat/inode.c */ extern void fat_attach(struct inode *inode, loff_t i_pos); diff --git a/trunk/fs/fat/file.c b/trunk/fs/fat/file.c index c118acf16e43..7018e1d8902d 100644 --- a/trunk/fs/fat/file.c +++ b/trunk/fs/fat/file.c @@ -149,12 +149,12 @@ static int fat_file_release(struct inode *inode, struct file *filp) return 0; } -int fat_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync) +int fat_file_fsync(struct file *filp, int datasync) { struct inode *inode = filp->f_mapping->host; int res, err; - res = generic_file_fsync(filp, start, end, datasync); + res = generic_file_fsync(filp, datasync); err = sync_mapping_buffers(MSDOS_SB(inode->i_sb)->fat_inode->i_mapping); return res ? res : err; @@ -397,8 +397,6 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr) * sequence. */ if (attr->ia_valid & ATTR_SIZE) { - inode_dio_wait(inode); - if (attr->ia_size > inode->i_size) { error = fat_cont_expand(inode, attr->ia_size); if (error || attr->ia_valid == ATTR_SIZE) @@ -431,10 +429,8 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr) } if (attr->ia_valid & ATTR_SIZE) { - down_write(&MSDOS_I(inode)->truncate_lock); truncate_setsize(inode, attr->ia_size); fat_truncate_blocks(inode, attr->ia_size); - up_write(&MSDOS_I(inode)->truncate_lock); } setattr_copy(inode, attr); diff --git a/trunk/fs/fat/inode.c b/trunk/fs/fat/inode.c index 5942fec22c65..cb8d8391ac0b 100644 --- a/trunk/fs/fat/inode.c +++ b/trunk/fs/fat/inode.c @@ -211,8 +211,8 @@ static ssize_t fat_direct_IO(int rw, struct kiocb *iocb, * FAT need to use the DIO_LOCKING for avoiding the race * condition of fat_get_block() and ->truncate(). */ - ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, - fat_get_block); + ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, + iov, offset, nr_segs, fat_get_block, NULL); if (ret < 0 && (rw & WRITE)) fat_write_failed(mapping, offset + iov_length(iov, nr_segs)); @@ -224,9 +224,9 @@ static sector_t _fat_bmap(struct address_space *mapping, sector_t block) sector_t blocknr; /* fat_get_cluster() assumes the requested blocknr isn't truncated. */ - down_read(&MSDOS_I(mapping->host)->truncate_lock); + down_read(&mapping->host->i_alloc_sem); blocknr = generic_block_bmap(mapping, block, fat_get_block); - up_read(&MSDOS_I(mapping->host)->truncate_lock); + up_read(&mapping->host->i_alloc_sem); return blocknr; } @@ -510,8 +510,6 @@ static struct inode *fat_alloc_inode(struct super_block *sb) ei = kmem_cache_alloc(fat_inode_cachep, GFP_NOFS); if (!ei) return NULL; - - init_rwsem(&ei->truncate_lock); return &ei->vfs_inode; } diff --git a/trunk/fs/fat/namei_msdos.c b/trunk/fs/fat/namei_msdos.c index 66e83b845455..3b222dafd15b 100644 --- a/trunk/fs/fat/namei_msdos.c +++ b/trunk/fs/fat/namei_msdos.c @@ -209,20 +209,29 @@ static struct dentry *msdos_lookup(struct inode *dir, struct dentry *dentry, int err; lock_super(sb); + err = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo); - switch (err) { - case -ENOENT: - inode = NULL; - break; - case 0: - inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos); - brelse(sinfo.bh); - break; - default: - inode = ERR_PTR(err); + if (err) { + if (err == -ENOENT) { + inode = NULL; + goto out; + } + goto error; + } + + inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos); + brelse(sinfo.bh); + if (IS_ERR(inode)) { + err = PTR_ERR(inode); + goto error; } +out: unlock_super(sb); return d_splice_alias(inode, dentry); + +error: + unlock_super(sb); + return ERR_PTR(err); } /***** Creates a directory entry (name is already formatted). */ diff --git a/trunk/fs/fat/namei_vfat.c b/trunk/fs/fat/namei_vfat.c index bb3f29c3557b..20b4ea53fdc4 100644 --- a/trunk/fs/fat/namei_vfat.c +++ b/trunk/fs/fat/namei_vfat.c @@ -82,8 +82,10 @@ static int vfat_revalidate_ci(struct dentry *dentry, struct nameidata *nd) * case sensitive name which is specified by user if this is * for creation. */ - if (nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) - return 0; + if (!(nd->flags & (LOOKUP_CONTINUE | LOOKUP_PARENT))) { + if (nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) + return 0; + } return vfat_revalidate_shortname(dentry); } diff --git a/trunk/fs/fs-writeback.c b/trunk/fs/fs-writeback.c index b8c507ca42f7..0f015a0468de 100644 --- a/trunk/fs/fs-writeback.c +++ b/trunk/fs/fs-writeback.c @@ -460,6 +460,32 @@ writeback_single_inode(struct inode *inode, struct writeback_control *wbc) return ret; } +/* + * For background writeback the caller does not have the sb pinned + * before calling writeback. So make sure that we do pin it, so it doesn't + * go away while we are writing inodes from it. + */ +static bool pin_sb_for_writeback(struct super_block *sb) +{ + spin_lock(&sb_lock); + if (list_empty(&sb->s_instances)) { + spin_unlock(&sb_lock); + return false; + } + + sb->s_count++; + spin_unlock(&sb_lock); + + if (down_read_trylock(&sb->s_umount)) { + if (sb->s_root) + return true; + up_read(&sb->s_umount); + } + + put_super(sb); + return false; +} + /* * Write a portion of b_io inodes which belong to @sb. * @@ -559,7 +585,7 @@ void writeback_inodes_wb(struct bdi_writeback *wb, struct inode *inode = wb_inode(wb->b_io.prev); struct super_block *sb = inode->i_sb; - if (!grab_super_passive(sb)) { + if (!pin_sb_for_writeback(sb)) { requeue_io(inode); continue; } diff --git a/trunk/fs/fuse/dir.c b/trunk/fs/fuse/dir.c index 9f63e493a9b6..d50160714595 100644 --- a/trunk/fs/fuse/dir.c +++ b/trunk/fs/fuse/dir.c @@ -382,7 +382,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, struct fuse_entry_out outentry; struct fuse_file *ff; struct file *file; - int flags = nd->intent.open.flags; + int flags = nd->intent.open.flags - 1; if (fc->no_create) return -ENOSYS; @@ -576,7 +576,7 @@ static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode, static int fuse_create(struct inode *dir, struct dentry *entry, int mode, struct nameidata *nd) { - if (nd) { + if (nd && (nd->flags & LOOKUP_OPEN)) { int err = fuse_create_open(dir, entry, mode, nd); if (err != -ENOSYS) return err; @@ -971,9 +971,9 @@ static int fuse_access(struct inode *inode, int mask) return err; } -static int fuse_perm_getattr(struct inode *inode, int mask) +static int fuse_perm_getattr(struct inode *inode, int flags) { - if (mask & MAY_NOT_BLOCK) + if (flags & IPERM_FLAG_RCU) return -ECHILD; return fuse_do_getattr(inode, NULL, NULL); @@ -992,7 +992,7 @@ static int fuse_perm_getattr(struct inode *inode, int mask) * access request is sent. Execute permission is still checked * locally based on file mode. */ -static int fuse_permission(struct inode *inode, int mask) +static int fuse_permission(struct inode *inode, int mask, unsigned int flags) { struct fuse_conn *fc = get_fuse_conn(inode); bool refreshed = false; @@ -1011,22 +1011,23 @@ static int fuse_permission(struct inode *inode, int mask) if (fi->i_time < get_jiffies_64()) { refreshed = true; - err = fuse_perm_getattr(inode, mask); + err = fuse_perm_getattr(inode, flags); if (err) return err; } } if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { - err = generic_permission(inode, mask); + err = generic_permission(inode, mask, flags, NULL); /* If permission is denied, try to refresh file attributes. This is also needed, because the root node will at first have no permissions */ if (err == -EACCES && !refreshed) { - err = fuse_perm_getattr(inode, mask); + err = fuse_perm_getattr(inode, flags); if (!err) - err = generic_permission(inode, mask); + err = generic_permission(inode, mask, + flags, NULL); } /* Note: the opposite of the above test does not @@ -1034,7 +1035,7 @@ static int fuse_permission(struct inode *inode, int mask) noticed immediately, only after the attribute timeout has expired */ } else if (mask & (MAY_ACCESS | MAY_CHDIR)) { - if (mask & MAY_NOT_BLOCK) + if (flags & IPERM_FLAG_RCU) return -ECHILD; err = fuse_access(inode, mask); @@ -1043,7 +1044,7 @@ static int fuse_permission(struct inode *inode, int mask) if (refreshed) return -EACCES; - err = fuse_perm_getattr(inode, mask); + err = fuse_perm_getattr(inode, flags); if (!err && !(inode->i_mode & S_IXUGO)) return -EACCES; } @@ -1176,10 +1177,9 @@ static int fuse_dir_release(struct inode *inode, struct file *file) return 0; } -static int fuse_dir_fsync(struct file *file, loff_t start, loff_t end, - int datasync) +static int fuse_dir_fsync(struct file *file, int datasync) { - return fuse_fsync_common(file, start, end, datasync, 1); + return fuse_fsync_common(file, datasync, 1); } static bool update_mtime(unsigned ivalid) diff --git a/trunk/fs/fuse/file.c b/trunk/fs/fuse/file.c index 7bb685cdd00c..82a66466a24c 100644 --- a/trunk/fs/fuse/file.c +++ b/trunk/fs/fuse/file.c @@ -400,8 +400,7 @@ static void fuse_sync_writes(struct inode *inode) fuse_release_nowrite(inode); } -int fuse_fsync_common(struct file *file, loff_t start, loff_t end, - int datasync, int isdir) +int fuse_fsync_common(struct file *file, int datasync, int isdir) { struct inode *inode = file->f_mapping->host; struct fuse_conn *fc = get_fuse_conn(inode); @@ -413,15 +412,9 @@ int fuse_fsync_common(struct file *file, loff_t start, loff_t end, if (is_bad_inode(inode)) return -EIO; - err = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (err) - return err; - if ((!isdir && fc->no_fsync) || (isdir && fc->no_fsyncdir)) return 0; - mutex_lock(&inode->i_mutex); - /* * Start writeback against all dirty pages of the inode, then * wait for all outstanding writes, before sending the FSYNC @@ -429,15 +422,13 @@ int fuse_fsync_common(struct file *file, loff_t start, loff_t end, */ err = write_inode_now(inode, 0); if (err) - goto out; + return err; fuse_sync_writes(inode); req = fuse_get_req(fc); - if (IS_ERR(req)) { - err = PTR_ERR(req); - goto out; - } + if (IS_ERR(req)) + return PTR_ERR(req); memset(&inarg, 0, sizeof(inarg)); inarg.fh = ff->fh; @@ -457,15 +448,12 @@ int fuse_fsync_common(struct file *file, loff_t start, loff_t end, fc->no_fsync = 1; err = 0; } -out: - mutex_unlock(&inode->i_mutex); return err; } -static int fuse_fsync(struct file *file, loff_t start, loff_t end, - int datasync) +static int fuse_fsync(struct file *file, int datasync) { - return fuse_fsync_common(file, start, end, datasync, 0); + return fuse_fsync_common(file, datasync, 0); } void fuse_read_fill(struct fuse_req *req, struct file *file, loff_t pos, @@ -1612,32 +1600,15 @@ static loff_t fuse_file_llseek(struct file *file, loff_t offset, int origin) struct inode *inode = file->f_path.dentry->d_inode; mutex_lock(&inode->i_mutex); - if (origin != SEEK_CUR || origin != SEEK_SET) { + switch (origin) { + case SEEK_END: retval = fuse_update_attributes(inode, NULL, file, NULL); if (retval) goto exit; - } - - switch (origin) { - case SEEK_END: offset += i_size_read(inode); break; case SEEK_CUR: offset += file->f_pos; - break; - case SEEK_DATA: - if (offset >= i_size_read(inode)) { - retval = -ENXIO; - goto exit; - } - break; - case SEEK_HOLE: - if (offset >= i_size_read(inode)) { - retval = -ENXIO; - goto exit; - } - offset = i_size_read(inode); - break; } retval = -EINVAL; if (offset >= 0 && offset <= inode->i_sb->s_maxbytes) { diff --git a/trunk/fs/fuse/fuse_i.h b/trunk/fs/fuse/fuse_i.h index c6aa2d4b8517..b788becada76 100644 --- a/trunk/fs/fuse/fuse_i.h +++ b/trunk/fs/fuse/fuse_i.h @@ -589,8 +589,7 @@ void fuse_release_common(struct file *file, int opcode); /** * Send FSYNC or FSYNCDIR request */ -int fuse_fsync_common(struct file *file, loff_t start, loff_t end, - int datasync, int isdir); +int fuse_fsync_common(struct file *file, int datasync, int isdir); /** * Notify poll wakeup diff --git a/trunk/fs/generic_acl.c b/trunk/fs/generic_acl.c index 70e90b4974ce..8f26d1a58912 100644 --- a/trunk/fs/generic_acl.c +++ b/trunk/fs/generic_acl.c @@ -190,9 +190,9 @@ generic_acl_chmod(struct inode *inode) } int -generic_check_acl(struct inode *inode, int mask) +generic_check_acl(struct inode *inode, int mask, unsigned int flags) { - if (mask & MAY_NOT_BLOCK) { + if (flags & IPERM_FLAG_RCU) { if (!negative_cached_acl(inode, ACL_TYPE_ACCESS)) return -ECHILD; } else { diff --git a/trunk/fs/gfs2/acl.c b/trunk/fs/gfs2/acl.c index 8ef1079f1665..cbc07155b1a0 100644 --- a/trunk/fs/gfs2/acl.c +++ b/trunk/fs/gfs2/acl.c @@ -75,12 +75,12 @@ static struct posix_acl *gfs2_acl_get(struct gfs2_inode *ip, int type) * Returns: errno */ -int gfs2_check_acl(struct inode *inode, int mask) +int gfs2_check_acl(struct inode *inode, int mask, unsigned int flags) { struct posix_acl *acl; int error; - if (mask & MAY_NOT_BLOCK) { + if (flags & IPERM_FLAG_RCU) { if (!negative_cached_acl(inode, ACL_TYPE_ACCESS)) return -ECHILD; return -EAGAIN; diff --git a/trunk/fs/gfs2/acl.h b/trunk/fs/gfs2/acl.h index b522b0cb39ea..a93907c8159b 100644 --- a/trunk/fs/gfs2/acl.h +++ b/trunk/fs/gfs2/acl.h @@ -16,7 +16,7 @@ #define GFS2_POSIX_ACL_DEFAULT "posix_acl_default" #define GFS2_ACL_MAX_ENTRIES 25 -extern int gfs2_check_acl(struct inode *inode, int mask); +extern int gfs2_check_acl(struct inode *inode, int mask, unsigned int); extern int gfs2_acl_create(struct gfs2_inode *dip, struct inode *inode); extern int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr); extern const struct xattr_handler gfs2_xattr_system_handler; diff --git a/trunk/fs/gfs2/bmap.c b/trunk/fs/gfs2/bmap.c index 7878c473ae62..42e477f31223 100644 --- a/trunk/fs/gfs2/bmap.c +++ b/trunk/fs/gfs2/bmap.c @@ -1216,8 +1216,6 @@ int gfs2_setattr_size(struct inode *inode, u64 newsize) if (ret) return ret; - inode_dio_wait(inode); - oldsize = inode->i_size; if (newsize >= oldsize) return do_grow(inode, newsize); diff --git a/trunk/fs/gfs2/file.c b/trunk/fs/gfs2/file.c index edeb9e802903..bc2590ef5fc1 100644 --- a/trunk/fs/gfs2/file.c +++ b/trunk/fs/gfs2/file.c @@ -245,7 +245,7 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask) !capable(CAP_LINUX_IMMUTABLE)) goto out; if (!IS_IMMUTABLE(inode)) { - error = gfs2_permission(inode, MAY_WRITE); + error = gfs2_permission(inode, MAY_WRITE, 0); if (error) goto out; } @@ -546,9 +546,7 @@ static int gfs2_close(struct inode *inode, struct file *file) /** * gfs2_fsync - sync the dirty data for a file (across the cluster) - * @file: the file that points to the dentry - * @start: the start position in the file to sync - * @end: the end position in the file to sync + * @file: the file that points to the dentry (we ignore this) * @datasync: set if we can ignore timestamp changes * * The VFS will flush data for us. We only need to worry @@ -557,32 +555,23 @@ static int gfs2_close(struct inode *inode, struct file *file) * Returns: errno */ -static int gfs2_fsync(struct file *file, loff_t start, loff_t end, - int datasync) +static int gfs2_fsync(struct file *file, int datasync) { struct inode *inode = file->f_mapping->host; int sync_state = inode->i_state & (I_DIRTY_SYNC|I_DIRTY_DATASYNC); struct gfs2_inode *ip = GFS2_I(inode); int ret; - ret = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (ret) - return ret; - mutex_lock(&inode->i_mutex); - if (datasync) sync_state &= ~I_DIRTY_SYNC; if (sync_state) { ret = sync_inode_metadata(inode, 1); - if (ret) { - mutex_unlock(&inode->i_mutex); + if (ret) return ret; - } gfs2_ail_flush(ip->i_gl); } - mutex_unlock(&inode->i_mutex); return 0; } diff --git a/trunk/fs/gfs2/inode.c b/trunk/fs/gfs2/inode.c index 0fb51a96eff0..03e0c529063e 100644 --- a/trunk/fs/gfs2/inode.c +++ b/trunk/fs/gfs2/inode.c @@ -307,7 +307,7 @@ struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, } if (!is_root) { - error = gfs2_permission(dir, MAY_EXEC); + error = gfs2_permission(dir, MAY_EXEC, 0); if (error) goto out; } @@ -337,7 +337,7 @@ static int create_ok(struct gfs2_inode *dip, const struct qstr *name, { int error; - error = gfs2_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC); + error = gfs2_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC, 0); if (error) return error; @@ -792,8 +792,13 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry, static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { - struct inode *inode = gfs2_lookupi(dir, &dentry->d_name, 0); - if (inode && !IS_ERR(inode)) { + struct inode *inode = NULL; + + inode = gfs2_lookupi(dir, &dentry->d_name, 0); + if (inode && IS_ERR(inode)) + return ERR_CAST(inode); + + if (inode) { struct gfs2_glock *gl = GFS2_I(inode)->i_gl; struct gfs2_holder gh; int error; @@ -803,8 +808,11 @@ static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry, return ERR_PTR(error); } gfs2_glock_dq_uninit(&gh); + return d_splice_alias(inode, dentry); } - return d_splice_alias(inode, dentry); + d_add(dentry, inode); + + return NULL; } /** @@ -849,7 +857,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, if (inode->i_nlink == 0) goto out_gunlock; - error = gfs2_permission(dir, MAY_WRITE | MAY_EXEC); + error = gfs2_permission(dir, MAY_WRITE | MAY_EXEC, 0); if (error) goto out_gunlock; @@ -982,7 +990,7 @@ static int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name, if (IS_APPEND(&dip->i_inode)) return -EPERM; - error = gfs2_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC); + error = gfs2_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC, 0); if (error) return error; @@ -1328,7 +1336,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, } } } else { - error = gfs2_permission(ndir, MAY_WRITE | MAY_EXEC); + error = gfs2_permission(ndir, MAY_WRITE | MAY_EXEC, 0); if (error) goto out_gunlock; @@ -1363,7 +1371,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, /* Check out the dir to be renamed */ if (dir_rename) { - error = gfs2_permission(odentry->d_inode, MAY_WRITE); + error = gfs2_permission(odentry->d_inode, MAY_WRITE, 0); if (error) goto out_gunlock; } @@ -1535,7 +1543,7 @@ static void gfs2_put_link(struct dentry *dentry, struct nameidata *nd, void *p) * Returns: errno */ -int gfs2_permission(struct inode *inode, int mask) +int gfs2_permission(struct inode *inode, int mask, unsigned int flags) { struct gfs2_inode *ip; struct gfs2_holder i_gh; @@ -1545,7 +1553,7 @@ int gfs2_permission(struct inode *inode, int mask) ip = GFS2_I(inode); if (gfs2_glock_is_locked_by_me(ip->i_gl) == NULL) { - if (mask & MAY_NOT_BLOCK) + if (flags & IPERM_FLAG_RCU) return -ECHILD; error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); if (error) @@ -1556,7 +1564,7 @@ int gfs2_permission(struct inode *inode, int mask) if ((mask & MAY_WRITE) && IS_IMMUTABLE(inode)) error = -EACCES; else - error = generic_permission(inode, mask); + error = generic_permission(inode, mask, flags, gfs2_check_acl); if (unlock) gfs2_glock_dq_uninit(&i_gh); @@ -1846,7 +1854,6 @@ const struct inode_operations gfs2_file_iops = { .listxattr = gfs2_listxattr, .removexattr = gfs2_removexattr, .fiemap = gfs2_fiemap, - .check_acl = gfs2_check_acl, }; const struct inode_operations gfs2_dir_iops = { @@ -1867,7 +1874,6 @@ const struct inode_operations gfs2_dir_iops = { .listxattr = gfs2_listxattr, .removexattr = gfs2_removexattr, .fiemap = gfs2_fiemap, - .check_acl = gfs2_check_acl, }; const struct inode_operations gfs2_symlink_iops = { @@ -1882,6 +1888,5 @@ const struct inode_operations gfs2_symlink_iops = { .listxattr = gfs2_listxattr, .removexattr = gfs2_removexattr, .fiemap = gfs2_fiemap, - .check_acl = gfs2_check_acl, }; diff --git a/trunk/fs/gfs2/inode.h b/trunk/fs/gfs2/inode.h index 8d90e0c07672..31606076f701 100644 --- a/trunk/fs/gfs2/inode.h +++ b/trunk/fs/gfs2/inode.h @@ -108,7 +108,7 @@ extern int gfs2_inode_refresh(struct gfs2_inode *ip); extern struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, int is_root); -extern int gfs2_permission(struct inode *inode, int mask); +extern int gfs2_permission(struct inode *inode, int mask, unsigned int flags); extern int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr); extern struct inode *gfs2_lookup_simple(struct inode *dip, const char *name); extern void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf); diff --git a/trunk/fs/hfs/inode.c b/trunk/fs/hfs/inode.c index 96a1b625fc74..fff16c968e67 100644 --- a/trunk/fs/hfs/inode.c +++ b/trunk/fs/hfs/inode.c @@ -123,8 +123,8 @@ static ssize_t hfs_direct_IO(int rw, struct kiocb *iocb, struct inode *inode = file->f_path.dentry->d_inode->i_mapping->host; ssize_t ret; - ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, - hfs_get_block); + ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, + offset, nr_segs, hfs_get_block, NULL); /* * In case of error extending write may have instantiated a few @@ -615,8 +615,6 @@ int hfs_inode_setattr(struct dentry *dentry, struct iattr * attr) if ((attr->ia_valid & ATTR_SIZE) && attr->ia_size != i_size_read(inode)) { - inode_dio_wait(inode); - error = vmtruncate(inode, attr->ia_size); if (error) return error; @@ -627,18 +625,12 @@ int hfs_inode_setattr(struct dentry *dentry, struct iattr * attr) return 0; } -static int hfs_file_fsync(struct file *filp, loff_t start, loff_t end, - int datasync) +static int hfs_file_fsync(struct file *filp, int datasync) { struct inode *inode = filp->f_mapping->host; struct super_block * sb; int ret, err; - ret = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (ret) - return ret; - mutex_lock(&inode->i_mutex); - /* sync the inode to buffers */ ret = write_inode_now(inode, 0); @@ -655,7 +647,6 @@ static int hfs_file_fsync(struct file *filp, loff_t start, loff_t end, err = sync_blockdev(sb->s_bdev); if (!ret) ret = err; - mutex_unlock(&inode->i_mutex); return ret; } diff --git a/trunk/fs/hfsplus/hfsplus_fs.h b/trunk/fs/hfsplus/hfsplus_fs.h index d7674d051f52..81dfd1e495e3 100644 --- a/trunk/fs/hfsplus/hfsplus_fs.h +++ b/trunk/fs/hfsplus/hfsplus_fs.h @@ -404,8 +404,7 @@ int hfsplus_cat_read_inode(struct inode *, struct hfs_find_data *); int hfsplus_cat_write_inode(struct inode *); struct inode *hfsplus_new_inode(struct super_block *, int); void hfsplus_delete_inode(struct inode *); -int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end, - int datasync); +int hfsplus_file_fsync(struct file *file, int datasync); /* ioctl.c */ long hfsplus_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); diff --git a/trunk/fs/hfsplus/inode.c b/trunk/fs/hfsplus/inode.c index 4cc1e3a36ec7..010cd363d085 100644 --- a/trunk/fs/hfsplus/inode.c +++ b/trunk/fs/hfsplus/inode.c @@ -119,8 +119,8 @@ static ssize_t hfsplus_direct_IO(int rw, struct kiocb *iocb, struct inode *inode = file->f_path.dentry->d_inode->i_mapping->host; ssize_t ret; - ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, - hfsplus_get_block); + ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, + offset, nr_segs, hfsplus_get_block, NULL); /* * In case of error extending write may have instantiated a few @@ -298,8 +298,6 @@ static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr) if ((attr->ia_valid & ATTR_SIZE) && attr->ia_size != i_size_read(inode)) { - inode_dio_wait(inode); - error = vmtruncate(inode, attr->ia_size); if (error) return error; @@ -310,19 +308,13 @@ static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr) return 0; } -int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end, - int datasync) +int hfsplus_file_fsync(struct file *file, int datasync) { struct inode *inode = file->f_mapping->host; struct hfsplus_inode_info *hip = HFSPLUS_I(inode); struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb); int error = 0, error2; - error = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (error) - return error; - mutex_lock(&inode->i_mutex); - /* * Sync inode metadata into the catalog and extent trees. */ @@ -350,8 +342,6 @@ int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end, if (!test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags)) blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); - mutex_unlock(&inode->i_mutex); - return error; } diff --git a/trunk/fs/hostfs/hostfs_kern.c b/trunk/fs/hostfs/hostfs_kern.c index 0d22afdd4611..2638c834ed28 100644 --- a/trunk/fs/hostfs/hostfs_kern.c +++ b/trunk/fs/hostfs/hostfs_kern.c @@ -362,20 +362,9 @@ int hostfs_file_open(struct inode *ino, struct file *file) return 0; } -int hostfs_fsync(struct file *file, loff_t start, loff_t end, int datasync) +int hostfs_fsync(struct file *file, int datasync) { - struct inode *inode = file->f_mapping->host; - int ret; - - ret = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (ret) - return ret; - - mutex_lock(&inode->i_mutex); - ret = fsync_file(HOSTFS_I(inode)->fd, datasync); - mutex_unlock(&inode->i_mutex); - - return ret; + return fsync_file(HOSTFS_I(file->f_mapping->host)->fd, datasync); } static const struct file_operations hostfs_file_fops = { @@ -759,12 +748,12 @@ int hostfs_rename(struct inode *from_ino, struct dentry *from, return err; } -int hostfs_permission(struct inode *ino, int desired) +int hostfs_permission(struct inode *ino, int desired, unsigned int flags) { char *name; int r = 0, w = 0, x = 0, err; - if (desired & MAY_NOT_BLOCK) + if (flags & IPERM_FLAG_RCU) return -ECHILD; if (desired & MAY_READ) r = 1; @@ -781,7 +770,7 @@ int hostfs_permission(struct inode *ino, int desired) err = access_file(name, r, w, x); __putname(name); if (!err) - err = generic_permission(ino, desired); + err = generic_permission(ino, desired, flags, NULL); return err; } diff --git a/trunk/fs/hpfs/dir.c b/trunk/fs/hpfs/dir.c index 96a8ed91cedd..f46ae025bfb5 100644 --- a/trunk/fs/hpfs/dir.c +++ b/trunk/fs/hpfs/dir.c @@ -29,10 +29,6 @@ static loff_t hpfs_dir_lseek(struct file *filp, loff_t off, int whence) struct hpfs_inode_info *hpfs_inode = hpfs_i(i); struct super_block *s = i->i_sb; - /* Somebody else will have to figure out what to do here */ - if (whence == SEEK_DATA || whence == SEEK_HOLE) - return -EINVAL; - hpfs_lock(s); /*printk("dir lseek\n");*/ diff --git a/trunk/fs/hpfs/file.c b/trunk/fs/hpfs/file.c index 89d2a5803ae3..89c500ee5213 100644 --- a/trunk/fs/hpfs/file.c +++ b/trunk/fs/hpfs/file.c @@ -18,14 +18,9 @@ static int hpfs_file_release(struct inode *inode, struct file *file) return 0; } -int hpfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync) +int hpfs_file_fsync(struct file *file, int datasync) { struct inode *inode = file->f_mapping->host; - int ret; - - ret = filemap_write_and_wait_range(file->f_mapping, start, end); - if (ret) - return ret; return sync_blockdev(inode->i_sb->s_bdev); } diff --git a/trunk/fs/hpfs/hpfs_fn.h b/trunk/fs/hpfs/hpfs_fn.h index 331b5e234ef3..dd552f862c8f 100644 --- a/trunk/fs/hpfs/hpfs_fn.h +++ b/trunk/fs/hpfs/hpfs_fn.h @@ -258,7 +258,7 @@ void hpfs_set_ea(struct inode *, struct fnode *, const char *, /* file.c */ -int hpfs_file_fsync(struct file *, loff_t, loff_t, int); +int hpfs_file_fsync(struct file *, int); extern const struct file_operations hpfs_file_ops; extern const struct inode_operations hpfs_file_iops; extern const struct address_space_operations hpfs_aops; diff --git a/trunk/fs/hpfs/namei.c b/trunk/fs/hpfs/namei.c index 2df69e2f07cf..acf95dab2aac 100644 --- a/trunk/fs/hpfs/namei.c +++ b/trunk/fs/hpfs/namei.c @@ -398,7 +398,7 @@ static int hpfs_unlink(struct inode *dir, struct dentry *dentry) hpfs_unlock(dir->i_sb); return -ENOSPC; } - if (generic_permission(inode, MAY_WRITE) || + if (generic_permission(inode, MAY_WRITE, 0, NULL) || !S_ISREG(inode->i_mode) || get_write_access(inode)) { d_rehash(dentry); diff --git a/trunk/fs/hppfs/hppfs.c b/trunk/fs/hppfs/hppfs.c index 8635be5ffd97..85c098a499f3 100644 --- a/trunk/fs/hppfs/hppfs.c +++ b/trunk/fs/hppfs/hppfs.c @@ -573,10 +573,9 @@ static int hppfs_readdir(struct file *file, void *ent, filldir_t filldir) return err; } -static int hppfs_fsync(struct file *file, loff_t start, loff_t end, - int datasync) +static int hppfs_fsync(struct file *file, int datasync) { - return filemap_write_and_wait_range(file->f_mapping, start, end); + return 0; } static const struct file_operations hppfs_dir_fops = { diff --git a/trunk/fs/inode.c b/trunk/fs/inode.c index 96c77b81167c..43566d17d1b8 100644 --- a/trunk/fs/inode.c +++ b/trunk/fs/inode.c @@ -33,8 +33,8 @@ * * inode->i_lock protects: * inode->i_state, inode->i_hash, __iget() - * inode->i_sb->s_inode_lru_lock protects: - * inode->i_sb->s_inode_lru, inode->i_lru + * inode_lru_lock protects: + * inode_lru, inode->i_lru * inode_sb_list_lock protects: * sb->s_inodes, inode->i_sb_list * inode_wb_list_lock protects: @@ -46,7 +46,7 @@ * * inode_sb_list_lock * inode->i_lock - * inode->i_sb->s_inode_lru_lock + * inode_lru_lock * * inode_wb_list_lock * inode->i_lock @@ -64,9 +64,23 @@ static unsigned int i_hash_shift __read_mostly; static struct hlist_head *inode_hashtable __read_mostly; static __cacheline_aligned_in_smp DEFINE_SPINLOCK(inode_hash_lock); +static LIST_HEAD(inode_lru); +static DEFINE_SPINLOCK(inode_lru_lock); + __cacheline_aligned_in_smp DEFINE_SPINLOCK(inode_sb_list_lock); __cacheline_aligned_in_smp DEFINE_SPINLOCK(inode_wb_list_lock); +/* + * iprune_sem provides exclusion between the icache shrinking and the + * umount path. + * + * We don't actually need it to protect anything in the umount path, + * but only need to cycle through it to make sure any inode that + * prune_icache took off the LRU list has been fully torn down by the + * time we are past evict_inodes. + */ +static DECLARE_RWSEM(iprune_sem); + /* * Empty aops. Can be used for the cases where the user does not * define any of the address_space operations. @@ -81,7 +95,6 @@ EXPORT_SYMBOL(empty_aops); struct inodes_stat_t inodes_stat; static DEFINE_PER_CPU(unsigned int, nr_inodes); -static DEFINE_PER_CPU(unsigned int, nr_unused); static struct kmem_cache *inode_cachep __read_mostly; @@ -96,11 +109,7 @@ static int get_nr_inodes(void) static inline int get_nr_inodes_unused(void) { - int i; - int sum = 0; - for_each_possible_cpu(i) - sum += per_cpu(nr_unused, i); - return sum < 0 ? 0 : sum; + return inodes_stat.nr_unused; } int get_nr_dirty_inodes(void) @@ -118,7 +127,6 @@ int proc_nr_inodes(ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { inodes_stat.nr_inodes = get_nr_inodes(); - inodes_stat.nr_unused = get_nr_inodes_unused(); return proc_dointvec(table, write, buffer, lenp, ppos); } #endif @@ -168,7 +176,8 @@ int inode_init_always(struct super_block *sb, struct inode *inode) mutex_init(&inode->i_mutex); lockdep_set_class(&inode->i_mutex, &sb->s_type->i_mutex_key); - atomic_set(&inode->i_dio_count, 0); + init_rwsem(&inode->i_alloc_sem); + lockdep_set_class(&inode->i_alloc_sem, &sb->s_type->i_alloc_sem_key); mapping->a_ops = &empty_aops; mapping->host = inode; @@ -328,24 +337,22 @@ EXPORT_SYMBOL(ihold); static void inode_lru_list_add(struct inode *inode) { - spin_lock(&inode->i_sb->s_inode_lru_lock); + spin_lock(&inode_lru_lock); if (list_empty(&inode->i_lru)) { - list_add(&inode->i_lru, &inode->i_sb->s_inode_lru); - inode->i_sb->s_nr_inodes_unused++; - this_cpu_inc(nr_unused); + list_add(&inode->i_lru, &inode_lru); + inodes_stat.nr_unused++; } - spin_unlock(&inode->i_sb->s_inode_lru_lock); + spin_unlock(&inode_lru_lock); } static void inode_lru_list_del(struct inode *inode) { - spin_lock(&inode->i_sb->s_inode_lru_lock); + spin_lock(&inode_lru_lock); if (!list_empty(&inode->i_lru)) { list_del_init(&inode->i_lru); - inode->i_sb->s_nr_inodes_unused--; - this_cpu_dec(nr_unused); + inodes_stat.nr_unused--; } - spin_unlock(&inode->i_sb->s_inode_lru_lock); + spin_unlock(&inode_lru_lock); } /** @@ -530,6 +537,14 @@ void evict_inodes(struct super_block *sb) spin_unlock(&inode_sb_list_lock); dispose_list(&dispose); + + /* + * Cycle through iprune_sem to make sure any inode that prune_icache + * moved off the list before we took the lock has been fully torn + * down. + */ + down_write(&iprune_sem); + up_write(&iprune_sem); } /** @@ -592,10 +607,8 @@ static int can_unuse(struct inode *inode) } /* - * Walk the superblock inode LRU for freeable inodes and attempt to free them. - * This is called from the superblock shrinker function with a number of inodes - * to trim from the LRU. Inodes to be freed are moved to a temporary list and - * then are freed outside inode_lock by dispose_list(). + * Scan `goal' inodes on the unused list for freeable ones. They are moved to a + * temporary list and then are freed outside inode_lru_lock by dispose_list(). * * Any inodes which are pinned purely because of attached pagecache have their * pagecache removed. If the inode has metadata buffers attached to @@ -609,28 +622,29 @@ static int can_unuse(struct inode *inode) * LRU does not have strict ordering. Hence we don't want to reclaim inodes * with this flag set because they are the inodes that are out of order. */ -void prune_icache_sb(struct super_block *sb, int nr_to_scan) +static void prune_icache(int nr_to_scan) { LIST_HEAD(freeable); int nr_scanned; unsigned long reap = 0; - spin_lock(&sb->s_inode_lru_lock); - for (nr_scanned = nr_to_scan; nr_scanned >= 0; nr_scanned--) { + down_read(&iprune_sem); + spin_lock(&inode_lru_lock); + for (nr_scanned = 0; nr_scanned < nr_to_scan; nr_scanned++) { struct inode *inode; - if (list_empty(&sb->s_inode_lru)) + if (list_empty(&inode_lru)) break; - inode = list_entry(sb->s_inode_lru.prev, struct inode, i_lru); + inode = list_entry(inode_lru.prev, struct inode, i_lru); /* - * we are inverting the sb->s_inode_lru_lock/inode->i_lock here, + * we are inverting the inode_lru_lock/inode->i_lock here, * so use a trylock. If we fail to get the lock, just move the * inode to the back of the list so we don't spin on it. */ if (!spin_trylock(&inode->i_lock)) { - list_move(&inode->i_lru, &sb->s_inode_lru); + list_move(&inode->i_lru, &inode_lru); continue; } @@ -642,29 +656,28 @@ void prune_icache_sb(struct super_block *sb, int nr_to_scan) (inode->i_state & ~I_REFERENCED)) { list_del_init(&inode->i_lru); spin_unlock(&inode->i_lock); - sb->s_nr_inodes_unused--; - this_cpu_dec(nr_unused); + inodes_stat.nr_unused--; continue; } /* recently referenced inodes get one more pass */ if (inode->i_state & I_REFERENCED) { inode->i_state &= ~I_REFERENCED; - list_move(&inode->i_lru, &sb->s_inode_lru); + list_move(&inode->i_lru, &inode_lru); spin_unlock(&inode->i_lock); continue; } if (inode_has_buffers(inode) || inode->i_data.nrpages) { __iget(inode); spin_unlock(&inode->i_lock); - spin_unlock(&sb->s_inode_lru_lock); + spin_unlock(&inode_lru_lock); if (remove_inode_buffers(inode)) reap += invalidate_mapping_pages(&inode->i_data, 0, -1); iput(inode); - spin_lock(&sb->s_inode_lru_lock); + spin_lock(&inode_lru_lock); - if (inode != list_entry(sb->s_inode_lru.next, + if (inode != list_entry(inode_lru.next, struct inode, i_lru)) continue; /* wrong inode or list_empty */ /* avoid lock inversions with trylock */ @@ -680,18 +693,51 @@ void prune_icache_sb(struct super_block *sb, int nr_to_scan) spin_unlock(&inode->i_lock); list_move(&inode->i_lru, &freeable); - sb->s_nr_inodes_unused--; - this_cpu_dec(nr_unused); + inodes_stat.nr_unused--; } if (current_is_kswapd()) __count_vm_events(KSWAPD_INODESTEAL, reap); else __count_vm_events(PGINODESTEAL, reap); - spin_unlock(&sb->s_inode_lru_lock); + spin_unlock(&inode_lru_lock); dispose_list(&freeable); + up_read(&iprune_sem); } +/* + * shrink_icache_memory() will attempt to reclaim some unused inodes. Here, + * "unused" means that no dentries are referring to the inodes: the files are + * not open and the dcache references to those inodes have already been + * reclaimed. + * + * This function is passed the number of inodes to scan, and it returns the + * total number of remaining possibly-reclaimable inodes. + */ +static int shrink_icache_memory(struct shrinker *shrink, + struct shrink_control *sc) +{ + int nr = sc->nr_to_scan; + gfp_t gfp_mask = sc->gfp_mask; + + if (nr) { + /* + * Nasty deadlock avoidance. We may hold various FS locks, + * and we don't want to recurse into the FS that called us + * in clear_inode() and friends.. + */ + if (!(gfp_mask & __GFP_FS)) + return -1; + prune_icache(nr); + } + return (get_nr_inodes_unused() / 100) * sysctl_vfs_cache_pressure; +} + +static struct shrinker icache_shrinker = { + .shrink = shrink_icache_memory, + .seeks = DEFAULT_SEEKS, +}; + static void __wait_on_freeing_inode(struct inode *inode); /* * Called with the inode lock held. @@ -1285,7 +1331,7 @@ static void iput_final(struct inode *inode) WARN_ON(inode->i_state & I_NEW); - if (op->drop_inode) + if (op && op->drop_inode) drop = op->drop_inode(inode); else drop = generic_drop_inode(inode); @@ -1571,6 +1617,7 @@ void __init inode_init(void) (SLAB_RECLAIM_ACCOUNT|SLAB_PANIC| SLAB_MEM_SPREAD), init_once); + register_shrinker(&icache_shrinker); /* Hash may have been set up in inode_init_early */ if (!hashdist) diff --git a/trunk/fs/internal.h b/trunk/fs/internal.h index fe327c20af83..b29c46e4e32f 100644 --- a/trunk/fs/internal.h +++ b/trunk/fs/internal.h @@ -97,7 +97,6 @@ extern struct file *get_empty_filp(void); * super.c */ extern int do_remount_sb(struct super_block *, int, void *, int); -extern bool grab_super_passive(struct super_block *sb); extern void __put_super(struct super_block *sb); extern void put_super(struct super_block *sb); extern struct dentry *mount_fs(struct file_system_type *, @@ -136,8 +135,3 @@ extern void inode_wb_list_del(struct inode *inode); extern int get_nr_dirty_inodes(void); extern void evict_inodes(struct super_block *); extern int invalidate_inodes(struct super_block *, bool); - -/* - * dcache.c - */ -extern struct dentry *__d_alloc(struct super_block *, const struct qstr *); diff --git a/trunk/fs/isofs/dir.c b/trunk/fs/isofs/dir.c index f20437c068a0..0542b6eedf80 100644 --- a/trunk/fs/isofs/dir.c +++ b/trunk/fs/isofs/dir.c @@ -254,16 +254,19 @@ static int isofs_readdir(struct file *filp, char *tmpname; struct iso_directory_record *tmpde; struct inode *inode = filp->f_path.dentry->d_inode; + struct isofs_sb_info *sbi = ISOFS_SB(inode->i_sb); tmpname = (char *)__get_free_page(GFP_KERNEL); if (tmpname == NULL) return -ENOMEM; + mutex_lock(&sbi->s_mutex); tmpde = (struct iso_directory_record *) (tmpname+1024); result = do_isofs_readdir(inode, filp, dirent, filldir, tmpname, tmpde); free_page((unsigned long) tmpname); + mutex_unlock(&sbi->s_mutex); return result; } diff --git a/trunk/fs/isofs/inode.c b/trunk/fs/isofs/inode.c index a5d03672d04e..b3cc8586984e 100644 --- a/trunk/fs/isofs/inode.c +++ b/trunk/fs/isofs/inode.c @@ -863,6 +863,7 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) sbi->s_utf8 = opt.utf8; sbi->s_nocompress = opt.nocompress; sbi->s_overriderockperm = opt.overriderockperm; + mutex_init(&sbi->s_mutex); /* * It would be incredibly stupid to allow people to mark every file * on the disk as suid, so we merely allow them to set the default diff --git a/trunk/fs/isofs/isofs.h b/trunk/fs/isofs/isofs.h index 7d33de84f52a..2882dc089f87 100644 --- a/trunk/fs/isofs/isofs.h +++ b/trunk/fs/isofs/isofs.h @@ -55,6 +55,7 @@ struct isofs_sb_info { gid_t s_gid; uid_t s_uid; struct nls_table *s_nls_iocharset; /* Native language support table */ + struct mutex s_mutex; /* replaces BKL, please remove if possible */ }; #define ISOFS_INVALID_MODE ((mode_t) -1) diff --git a/trunk/fs/isofs/namei.c b/trunk/fs/isofs/namei.c index 1e2946f2a69e..4fb3e8074fd4 100644 --- a/trunk/fs/isofs/namei.c +++ b/trunk/fs/isofs/namei.c @@ -168,6 +168,7 @@ struct dentry *isofs_lookup(struct inode *dir, struct dentry *dentry, struct nam int found; unsigned long uninitialized_var(block); unsigned long uninitialized_var(offset); + struct isofs_sb_info *sbi = ISOFS_SB(dir->i_sb); struct inode *inode; struct page *page; @@ -175,13 +176,21 @@ struct dentry *isofs_lookup(struct inode *dir, struct dentry *dentry, struct nam if (!page) return ERR_PTR(-ENOMEM); + mutex_lock(&sbi->s_mutex); found = isofs_find_entry(dir, dentry, &block, &offset, page_address(page), 1024 + page_address(page)); __free_page(page); - inode = found ? isofs_iget(dir->i_sb, block, offset) : NULL; - + inode = NULL; + if (found) { + inode = isofs_iget(dir->i_sb, block, offset); + if (IS_ERR(inode)) { + mutex_unlock(&sbi->s_mutex); + return ERR_CAST(inode); + } + } + mutex_unlock(&sbi->s_mutex); return d_splice_alias(inode, dentry); } diff --git a/trunk/fs/isofs/rock.c b/trunk/fs/isofs/rock.c index 1fbc7de88f50..f9cd04db6eab 100644 --- a/trunk/fs/isofs/rock.c +++ b/trunk/fs/isofs/rock.c @@ -678,6 +678,7 @@ static int rock_ridge_symlink_readpage(struct file *file, struct page *page) init_rock_state(&rs, inode); block = ei->i_iget5_block; + mutex_lock(&sbi->s_mutex); bh = sb_bread(inode->i_sb, block); if (!bh) goto out_noread; @@ -747,6 +748,7 @@ static int rock_ridge_symlink_readpage(struct file *file, struct page *page) goto fail; brelse(bh); *rpnt = '\0'; + mutex_unlock(&sbi->s_mutex); SetPageUptodate(page); kunmap(page); unlock_page(page); @@ -763,6 +765,7 @@ static int rock_ridge_symlink_readpage(struct file *file, struct page *page) printk("symlink spans iso9660 blocks\n"); fail: brelse(bh); + mutex_unlock(&sbi->s_mutex); error: SetPageError(page); kunmap(page); diff --git a/trunk/fs/jffs2/acl.c b/trunk/fs/jffs2/acl.c index 3675b3cdee89..828a0e1ea438 100644 --- a/trunk/fs/jffs2/acl.c +++ b/trunk/fs/jffs2/acl.c @@ -259,12 +259,12 @@ static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl) return rc; } -int jffs2_check_acl(struct inode *inode, int mask) +int jffs2_check_acl(struct inode *inode, int mask, unsigned int flags) { struct posix_acl *acl; int rc; - if (mask & MAY_NOT_BLOCK) + if (flags & IPERM_FLAG_RCU) return -ECHILD; acl = jffs2_get_acl(inode, ACL_TYPE_ACCESS); diff --git a/trunk/fs/jffs2/acl.h b/trunk/fs/jffs2/acl.h index 5e42de8d9541..3119f59253d3 100644 --- a/trunk/fs/jffs2/acl.h +++ b/trunk/fs/jffs2/acl.h @@ -26,7 +26,7 @@ struct jffs2_acl_header { #ifdef CONFIG_JFFS2_FS_POSIX_ACL -extern int jffs2_check_acl(struct inode *, int); +extern int jffs2_check_acl(struct inode *, int, unsigned int); extern int jffs2_acl_chmod(struct inode *); extern int jffs2_init_acl_pre(struct inode *, struct inode *, int *); extern int jffs2_init_acl_post(struct inode *); diff --git a/trunk/fs/jffs2/dir.c b/trunk/fs/jffs2/dir.c index 5f243cd63afc..4bca6a2e5c07 100644 --- a/trunk/fs/jffs2/dir.c +++ b/trunk/fs/jffs2/dir.c @@ -102,8 +102,10 @@ static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target, mutex_unlock(&dir_f->sem); if (ino) { inode = jffs2_iget(dir_i->i_sb, ino); - if (IS_ERR(inode)) + if (IS_ERR(inode)) { printk(KERN_WARNING "iget() failed for ino #%u\n", ino); + return ERR_CAST(inode); + } } return d_splice_alias(inode, target); @@ -820,10 +822,7 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, if (victim_f) { /* There was a victim. Kill it off nicely */ - if (S_ISDIR(new_dentry->d_inode->i_mode)) - clear_nlink(new_dentry->d_inode); - else - drop_nlink(new_dentry->d_inode); + drop_nlink(new_dentry->d_inode); /* Don't oops if the victim was a dirent pointing to an inode which didn't exist. */ if (victim_f->inocache) { diff --git a/trunk/fs/jffs2/file.c b/trunk/fs/jffs2/file.c index 3989f7e09f7f..1c0a08d711aa 100644 --- a/trunk/fs/jffs2/file.c +++ b/trunk/fs/jffs2/file.c @@ -27,20 +27,13 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, struct page **pagep, void **fsdata); static int jffs2_readpage (struct file *filp, struct page *pg); -int jffs2_fsync(struct file *filp, loff_t start, loff_t end, int datasync) +int jffs2_fsync(struct file *filp, int datasync) { struct inode *inode = filp->f_mapping->host; struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); - int ret; - - ret = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (ret) - return ret; - mutex_lock(&inode->i_mutex); /* Trigger GC to flush any pending writes for this inode */ jffs2_flush_wbuf_gc(c, inode->i_ino); - mutex_unlock(&inode->i_mutex); return 0; } diff --git a/trunk/fs/jffs2/os-linux.h b/trunk/fs/jffs2/os-linux.h index 9c252835e8e5..65c6c43ca482 100644 --- a/trunk/fs/jffs2/os-linux.h +++ b/trunk/fs/jffs2/os-linux.h @@ -158,7 +158,7 @@ extern const struct inode_operations jffs2_dir_inode_operations; extern const struct file_operations jffs2_file_operations; extern const struct inode_operations jffs2_file_inode_operations; extern const struct address_space_operations jffs2_file_address_operations; -int jffs2_fsync(struct file *, loff_t, loff_t, int); +int jffs2_fsync(struct file *, int); int jffs2_do_readpage_unlock (struct inode *inode, struct page *pg); /* ioctl.c */ diff --git a/trunk/fs/jfs/acl.c b/trunk/fs/jfs/acl.c index 8a0a0666d5a6..e5de9422fa32 100644 --- a/trunk/fs/jfs/acl.c +++ b/trunk/fs/jfs/acl.c @@ -114,11 +114,11 @@ static int jfs_set_acl(tid_t tid, struct inode *inode, int type, return rc; } -int jfs_check_acl(struct inode *inode, int mask) +int jfs_check_acl(struct inode *inode, int mask, unsigned int flags) { struct posix_acl *acl; - if (mask & MAY_NOT_BLOCK) + if (flags & IPERM_FLAG_RCU) return -ECHILD; acl = jfs_get_acl(inode, ACL_TYPE_ACCESS); diff --git a/trunk/fs/jfs/file.c b/trunk/fs/jfs/file.c index 7527855b5cc6..2f3f531f3606 100644 --- a/trunk/fs/jfs/file.c +++ b/trunk/fs/jfs/file.c @@ -28,26 +28,19 @@ #include "jfs_acl.h" #include "jfs_debug.h" -int jfs_fsync(struct file *file, loff_t start, loff_t end, int datasync) +int jfs_fsync(struct file *file, int datasync) { struct inode *inode = file->f_mapping->host; int rc = 0; - rc = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (rc) - return rc; - - mutex_lock(&inode->i_mutex); if (!(inode->i_state & I_DIRTY) || (datasync && !(inode->i_state & I_DIRTY_DATASYNC))) { /* Make sure committed changes hit the disk */ jfs_flush_journal(JFS_SBI(inode->i_sb)->log, 1); - mutex_unlock(&inode->i_mutex); return rc; } rc |= jfs_commit_inode(inode, 1); - mutex_unlock(&inode->i_mutex); return rc ? -EIO : 0; } @@ -117,8 +110,6 @@ int jfs_setattr(struct dentry *dentry, struct iattr *iattr) if ((iattr->ia_valid & ATTR_SIZE) && iattr->ia_size != i_size_read(inode)) { - inode_dio_wait(inode); - rc = vmtruncate(inode, iattr->ia_size); if (rc) return rc; diff --git a/trunk/fs/jfs/inode.c b/trunk/fs/jfs/inode.c index 77b69b27f825..109655904bbc 100644 --- a/trunk/fs/jfs/inode.c +++ b/trunk/fs/jfs/inode.c @@ -329,8 +329,8 @@ static ssize_t jfs_direct_IO(int rw, struct kiocb *iocb, struct inode *inode = file->f_mapping->host; ssize_t ret; - ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, - jfs_get_block); + ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, + offset, nr_segs, jfs_get_block, NULL); /* * In case of error extending write may have instantiated a few diff --git a/trunk/fs/jfs/jfs_acl.h b/trunk/fs/jfs/jfs_acl.h index 54e07559878d..f9285c4900fa 100644 --- a/trunk/fs/jfs/jfs_acl.h +++ b/trunk/fs/jfs/jfs_acl.h @@ -20,7 +20,7 @@ #ifdef CONFIG_JFS_POSIX_ACL -int jfs_check_acl(struct inode *, int); +int jfs_check_acl(struct inode *, int, unsigned int flags); int jfs_init_acl(tid_t, struct inode *, struct inode *); int jfs_acl_chmod(struct inode *inode); diff --git a/trunk/fs/jfs/jfs_inode.h b/trunk/fs/jfs/jfs_inode.h index 9271cfe4a149..ec2fb8b945fc 100644 --- a/trunk/fs/jfs/jfs_inode.h +++ b/trunk/fs/jfs/jfs_inode.h @@ -21,7 +21,7 @@ struct fid; extern struct inode *ialloc(struct inode *, umode_t); -extern int jfs_fsync(struct file *, loff_t, loff_t, int); +extern int jfs_fsync(struct file *, int); extern long jfs_ioctl(struct file *, unsigned int, unsigned long); extern long jfs_compat_ioctl(struct file *, unsigned int, unsigned long); extern struct inode *jfs_iget(struct super_block *, unsigned long); diff --git a/trunk/fs/jfs/namei.c b/trunk/fs/jfs/namei.c index 03787ef6a118..eaaf2b511e89 100644 --- a/trunk/fs/jfs/namei.c +++ b/trunk/fs/jfs/namei.c @@ -1456,23 +1456,34 @@ static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry, struc ino_t inum; struct inode *ip; struct component_name key; + const char *name = dentry->d_name.name; + int len = dentry->d_name.len; int rc; - jfs_info("jfs_lookup: name = %s", dentry->d_name.name); - - if ((rc = get_UCSname(&key, dentry))) - return ERR_PTR(rc); - rc = dtSearch(dip, &key, &inum, &btstack, JFS_LOOKUP); - free_UCSname(&key); - if (rc == -ENOENT) { - ip = NULL; - } else if (rc) { - jfs_err("jfs_lookup: dtSearch returned %d", rc); - ip = ERR_PTR(rc); - } else { - ip = jfs_iget(dip->i_sb, inum); - if (IS_ERR(ip)) - jfs_err("jfs_lookup: iget failed on inum %d", (uint)inum); + jfs_info("jfs_lookup: name = %s", name); + + if ((name[0] == '.') && (len == 1)) + inum = dip->i_ino; + else if (strcmp(name, "..") == 0) + inum = PARENT(dip); + else { + if ((rc = get_UCSname(&key, dentry))) + return ERR_PTR(rc); + rc = dtSearch(dip, &key, &inum, &btstack, JFS_LOOKUP); + free_UCSname(&key); + if (rc == -ENOENT) { + d_add(dentry, NULL); + return NULL; + } else if (rc) { + jfs_err("jfs_lookup: dtSearch returned %d", rc); + return ERR_PTR(rc); + } + } + + ip = jfs_iget(dip->i_sb, inum); + if (IS_ERR(ip)) { + jfs_err("jfs_lookup: iget failed on inum %d", (uint) inum); + return ERR_CAST(ip); } return d_splice_alias(ip, dentry); @@ -1586,6 +1597,8 @@ static int jfs_ci_compare(const struct dentry *parent, static int jfs_ci_revalidate(struct dentry *dentry, struct nameidata *nd) { + if (nd && nd->flags & LOOKUP_RCU) + return -ECHILD; /* * This is not negative dentry. Always valid. * @@ -1611,8 +1624,10 @@ static int jfs_ci_revalidate(struct dentry *dentry, struct nameidata *nd) * case sensitive name which is specified by user if this is * for creation. */ - if (nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) - return 0; + if (!(nd->flags & (LOOKUP_CONTINUE | LOOKUP_PARENT))) { + if (nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) + return 0; + } return 1; } diff --git a/trunk/fs/libfs.c b/trunk/fs/libfs.c index c18e9a1235b6..275ca4749a2e 100644 --- a/trunk/fs/libfs.c +++ b/trunk/fs/libfs.c @@ -16,8 +16,6 @@ #include -#include "internal.h" - static inline int simple_positive(struct dentry *dentry) { return dentry->d_inode && !d_unhashed(dentry); @@ -248,11 +246,13 @@ struct dentry *mount_pseudo(struct file_system_type *fs_type, char *name, root->i_ino = 1; root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR; root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME; - dentry = __d_alloc(s, &d_name); + dentry = d_alloc(NULL, &d_name); if (!dentry) { iput(root); goto Enomem; } + dentry->d_sb = s; + dentry->d_parent = dentry; d_instantiate(dentry, root); s->s_root = dentry; s->s_d_op = dops; @@ -328,10 +328,8 @@ int simple_rename(struct inode *old_dir, struct dentry *old_dentry, if (new_dentry->d_inode) { simple_unlink(new_dir, new_dentry); - if (they_are_dirs) { - drop_nlink(new_dentry->d_inode); + if (they_are_dirs) drop_nlink(old_dir); - } } else if (they_are_dirs) { drop_nlink(old_dir); inc_nlink(new_dir); @@ -907,29 +905,21 @@ EXPORT_SYMBOL_GPL(generic_fh_to_parent); * filesystems which track all non-inode metadata in the buffers list * hanging off the address_space structure. */ -int generic_file_fsync(struct file *file, loff_t start, loff_t end, - int datasync) +int generic_file_fsync(struct file *file, int datasync) { struct inode *inode = file->f_mapping->host; int err; int ret; - err = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (err) - return err; - - mutex_lock(&inode->i_mutex); ret = sync_mapping_buffers(inode->i_mapping); if (!(inode->i_state & I_DIRTY)) - goto out; + return ret; if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) - goto out; + return ret; err = sync_inode_metadata(inode, 1); if (ret == 0) ret = err; -out: - mutex_unlock(&inode->i_mutex); return ret; } EXPORT_SYMBOL(generic_file_fsync); @@ -966,7 +956,7 @@ EXPORT_SYMBOL(generic_check_addressable); /* * No-op implementation of ->fsync for in-memory filesystems. */ -int noop_fsync(struct file *file, loff_t start, loff_t end, int datasync) +int noop_fsync(struct file *file, int datasync) { return 0; } diff --git a/trunk/fs/logfs/dir.c b/trunk/fs/logfs/dir.c index b3ff3d894165..1afae26cf236 100644 --- a/trunk/fs/logfs/dir.c +++ b/trunk/fs/logfs/dir.c @@ -371,9 +371,11 @@ static struct dentry *logfs_lookup(struct inode *dir, struct dentry *dentry, page_cache_release(page); inode = logfs_iget(dir->i_sb, ino); - if (IS_ERR(inode)) + if (IS_ERR(inode)) { printk(KERN_ERR"LogFS: Cannot read inode #%llx for dentry (%lx, %lx)n", ino, dir->i_ino, index); + return ERR_CAST(inode); + } return d_splice_alias(inode, dentry); } diff --git a/trunk/fs/logfs/file.c b/trunk/fs/logfs/file.c index b548c87a86f1..c2ad7028def4 100644 --- a/trunk/fs/logfs/file.c +++ b/trunk/fs/logfs/file.c @@ -219,20 +219,11 @@ long logfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } } -int logfs_fsync(struct file *file, loff_t start, loff_t end, int datasync) +int logfs_fsync(struct file *file, int datasync) { struct super_block *sb = file->f_mapping->host->i_sb; - struct inode *inode = file->f_mapping->host; - int ret; - - ret = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (ret) - return ret; - mutex_lock(&inode->i_mutex); logfs_write_anchor(sb); - mutex_unlock(&inode->i_mutex); - return 0; } diff --git a/trunk/fs/logfs/logfs.h b/trunk/fs/logfs/logfs.h index f22d108bfa5d..57afd4a6fabb 100644 --- a/trunk/fs/logfs/logfs.h +++ b/trunk/fs/logfs/logfs.h @@ -506,7 +506,7 @@ extern const struct file_operations logfs_reg_fops; extern const struct address_space_operations logfs_reg_aops; int logfs_readpage(struct file *file, struct page *page); long logfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg); -int logfs_fsync(struct file *file, loff_t start, loff_t end, int datasync); +int logfs_fsync(struct file *file, int datasync); /* gc.c */ u32 get_best_cand(struct super_block *sb, struct candidate_list *list, u32 *ec); diff --git a/trunk/fs/minix/inode.c b/trunk/fs/minix/inode.c index e7d23e25bf1d..adcdc0a4e182 100644 --- a/trunk/fs/minix/inode.c +++ b/trunk/fs/minix/inode.c @@ -596,7 +596,8 @@ static int minix_write_inode(struct inode *inode, struct writeback_control *wbc) int minix_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { - struct super_block *sb = dentry->d_sb; + struct inode *dir = dentry->d_parent->d_inode; + struct super_block *sb = dir->i_sb; generic_fillattr(dentry->d_inode, stat); if (INODE_VERSION(dentry->d_inode) == MINIX_V1) stat->blocks = (BLOCK_SIZE / 512) * V1_minix_blocks(stat->size, sb); diff --git a/trunk/fs/namei.c b/trunk/fs/namei.c index b7fad009bbf6..14ab8d3f2f0c 100644 --- a/trunk/fs/namei.c +++ b/trunk/fs/namei.c @@ -176,12 +176,12 @@ EXPORT_SYMBOL(putname); /* * This does basic POSIX ACL permission checking */ -static int acl_permission_check(struct inode *inode, int mask) +static int acl_permission_check(struct inode *inode, int mask, unsigned int flags, + int (*check_acl)(struct inode *inode, int mask, unsigned int flags)) { - int (*check_acl)(struct inode *inode, int mask); unsigned int mode = inode->i_mode; - mask &= MAY_READ | MAY_WRITE | MAY_EXEC | MAY_NOT_BLOCK; + mask &= MAY_READ | MAY_WRITE | MAY_EXEC; if (current_user_ns() != inode_userns(inode)) goto other_perms; @@ -189,9 +189,8 @@ static int acl_permission_check(struct inode *inode, int mask) if (current_fsuid() == inode->i_uid) mode >>= 6; else { - check_acl = inode->i_op->check_acl; if (IS_POSIXACL(inode) && (mode & S_IRWXG) && check_acl) { - int error = check_acl(inode, mask); + int error = check_acl(inode, mask, flags); if (error != -EAGAIN) return error; } @@ -204,7 +203,7 @@ static int acl_permission_check(struct inode *inode, int mask) /* * If the DACs are ok we don't need any capability check. */ - if ((mask & ~mode & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0) + if ((mask & ~mode) == 0) return 0; return -EACCES; } @@ -213,6 +212,8 @@ static int acl_permission_check(struct inode *inode, int mask) * generic_permission - check for access rights on a Posix-like filesystem * @inode: inode to check access rights for * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC) + * @check_acl: optional callback to check for Posix ACLs + * @flags: IPERM_FLAG_ flags. * * Used to check for read/write/execute permissions on a file. * We use "fsuid" for this, letting us set arbitrary permissions @@ -223,32 +224,24 @@ static int acl_permission_check(struct inode *inode, int mask) * request cannot be satisfied (eg. requires blocking or too much complexity). * It would then be called again in ref-walk mode. */ -int generic_permission(struct inode *inode, int mask) +int generic_permission(struct inode *inode, int mask, unsigned int flags, + int (*check_acl)(struct inode *inode, int mask, unsigned int flags)) { int ret; /* * Do the basic POSIX ACL permission checks. */ - ret = acl_permission_check(inode, mask); + ret = acl_permission_check(inode, mask, flags, check_acl); if (ret != -EACCES) return ret; - if (S_ISDIR(inode->i_mode)) { - /* DACs are overridable for directories */ - if (ns_capable(inode_userns(inode), CAP_DAC_OVERRIDE)) - return 0; - if (!(mask & MAY_WRITE)) - if (ns_capable(inode_userns(inode), CAP_DAC_READ_SEARCH)) - return 0; - return -EACCES; - } /* * Read/write DACs are always overridable. - * Executable DACs are overridable when there is - * at least one exec bit set. + * Executable DACs are overridable for all directories and + * for non-directories that have least one exec bit set. */ - if (!(mask & MAY_EXEC) || (inode->i_mode & S_IXUGO)) + if (!(mask & MAY_EXEC) || execute_ok(inode)) if (ns_capable(inode_userns(inode), CAP_DAC_OVERRIDE)) return 0; @@ -256,7 +249,7 @@ int generic_permission(struct inode *inode, int mask) * Searching includes executable on directories, else just read. */ mask &= MAY_READ | MAY_WRITE | MAY_EXEC; - if (mask == MAY_READ) + if (mask == MAY_READ || (S_ISDIR(inode->i_mode) && !(mask & MAY_WRITE))) if (ns_capable(inode_userns(inode), CAP_DAC_READ_SEARCH)) return 0; @@ -295,9 +288,10 @@ int inode_permission(struct inode *inode, int mask) } if (inode->i_op->permission) - retval = inode->i_op->permission(inode, mask); + retval = inode->i_op->permission(inode, mask, 0); else - retval = generic_permission(inode, mask); + retval = generic_permission(inode, mask, 0, + inode->i_op->check_acl); if (retval) return retval; @@ -309,6 +303,69 @@ int inode_permission(struct inode *inode, int mask) return security_inode_permission(inode, mask); } +/** + * file_permission - check for additional access rights to a given file + * @file: file to check access rights for + * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC) + * + * Used to check for read/write/execute permissions on an already opened + * file. + * + * Note: + * Do not use this function in new code. All access checks should + * be done using inode_permission(). + */ +int file_permission(struct file *file, int mask) +{ + return inode_permission(file->f_path.dentry->d_inode, mask); +} + +/* + * get_write_access() gets write permission for a file. + * put_write_access() releases this write permission. + * This is used for regular files. + * We cannot support write (and maybe mmap read-write shared) accesses and + * MAP_DENYWRITE mmappings simultaneously. The i_writecount field of an inode + * can have the following values: + * 0: no writers, no VM_DENYWRITE mappings + * < 0: (-i_writecount) vm_area_structs with VM_DENYWRITE set exist + * > 0: (i_writecount) users are writing to the file. + * + * Normally we operate on that counter with atomic_{inc,dec} and it's safe + * except for the cases where we don't hold i_writecount yet. Then we need to + * use {get,deny}_write_access() - these functions check the sign and refuse + * to do the change if sign is wrong. Exclusion between them is provided by + * the inode->i_lock spinlock. + */ + +int get_write_access(struct inode * inode) +{ + spin_lock(&inode->i_lock); + if (atomic_read(&inode->i_writecount) < 0) { + spin_unlock(&inode->i_lock); + return -ETXTBSY; + } + atomic_inc(&inode->i_writecount); + spin_unlock(&inode->i_lock); + + return 0; +} + +int deny_write_access(struct file * file) +{ + struct inode *inode = file->f_path.dentry->d_inode; + + spin_lock(&inode->i_lock); + if (atomic_read(&inode->i_writecount) > 0) { + spin_unlock(&inode->i_lock); + return -ETXTBSY; + } + atomic_dec(&inode->i_writecount); + spin_unlock(&inode->i_lock); + + return 0; +} + /** * path_get - get a reference to a path * @path: path to get the reference to @@ -435,6 +492,28 @@ static inline int d_revalidate(struct dentry *dentry, struct nameidata *nd) return dentry->d_op->d_revalidate(dentry, nd); } +static struct dentry * +do_revalidate(struct dentry *dentry, struct nameidata *nd) +{ + int status = d_revalidate(dentry, nd); + if (unlikely(status <= 0)) { + /* + * The dentry failed validation. + * If d_revalidate returned 0 attempt to invalidate + * the dentry otherwise d_revalidate is asking us + * to return a fail status. + */ + if (status < 0) { + dput(dentry); + dentry = ERR_PTR(status); + } else if (!d_invalidate(dentry)) { + dput(dentry); + dentry = NULL; + } + } + return dentry; +} + /** * complete_walk - successful completion of path walk * @nd: pointer nameidata @@ -489,6 +568,40 @@ static int complete_walk(struct nameidata *nd) return status; } +/* + * Short-cut version of permission(), for calling on directories + * during pathname resolution. Combines parts of permission() + * and generic_permission(), and tests ONLY for MAY_EXEC permission. + * + * If appropriate, check DAC only. If not appropriate, or + * short-cut DAC fails, then call ->permission() to do more + * complete permission check. + */ +static inline int exec_permission(struct inode *inode, unsigned int flags) +{ + int ret; + struct user_namespace *ns = inode_userns(inode); + + if (inode->i_op->permission) { + ret = inode->i_op->permission(inode, MAY_EXEC, flags); + } else { + ret = acl_permission_check(inode, MAY_EXEC, flags, + inode->i_op->check_acl); + } + if (likely(!ret)) + goto ok; + if (ret == -ECHILD) + return ret; + + if (ns_capable(ns, CAP_DAC_OVERRIDE) || + ns_capable(ns, CAP_DAC_READ_SEARCH)) + goto ok; + + return ret; +ok: + return security_inode_exec_permission(inode, flags); +} + static __always_inline void set_root(struct nameidata *nd) { if (!nd->root.mnt) @@ -663,7 +776,7 @@ static int follow_automount(struct path *path, unsigned flags, /* We don't want to mount if someone supplied AT_NO_AUTOMOUNT * and this is the terminal part of the path. */ - if ((flags & LOOKUP_NO_AUTOMOUNT) && !(flags & LOOKUP_PARENT)) + if ((flags & LOOKUP_NO_AUTOMOUNT) && !(flags & LOOKUP_CONTINUE)) return -EISDIR; /* we actually want to stop here */ /* We want to mount if someone is trying to open/create a file of any @@ -675,7 +788,7 @@ static int follow_automount(struct path *path, unsigned flags, * appended a '/' to the name. */ if (!(flags & LOOKUP_FOLLOW) && - !(flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY | + !(flags & (LOOKUP_CONTINUE | LOOKUP_DIRECTORY | LOOKUP_OPEN | LOOKUP_CREATE))) return -EISDIR; @@ -694,7 +807,7 @@ static int follow_automount(struct path *path, unsigned flags, * the path being looked up; if it wasn't then the remainder of * the path is inaccessible and we should say so. */ - if (PTR_ERR(mnt) == -EISDIR && (flags & LOOKUP_PARENT)) + if (PTR_ERR(mnt) == -EISDIR && (flags & LOOKUP_CONTINUE)) return -EREMOTE; return PTR_ERR(mnt); } @@ -1020,30 +1133,6 @@ static struct dentry *d_alloc_and_lookup(struct dentry *parent, return dentry; } -/* - * We already have a dentry, but require a lookup to be performed on the parent - * directory to fill in d_inode. Returns the new dentry, or ERR_PTR on error. - * parent->d_inode->i_mutex must be held. d_lookup must have verified that no - * child exists while under i_mutex. - */ -static struct dentry *d_inode_lookup(struct dentry *parent, struct dentry *dentry, - struct nameidata *nd) -{ - struct inode *inode = parent->d_inode; - struct dentry *old; - - /* Don't create child dentry for a dead directory. */ - if (unlikely(IS_DEADDIR(inode))) - return ERR_PTR(-ENOENT); - - old = inode->i_op->lookup(inode, dentry, nd); - if (unlikely(old)) { - dput(dentry); - dentry = old; - } - return dentry; -} - /* * It's more convoluted than I'd like it to be, but... it's still fairly * small and for now I'd prefer to have fast path as straight as possible. @@ -1083,8 +1172,6 @@ static int do_lookup(struct nameidata *nd, struct qstr *name, goto unlazy; } } - if (unlikely(d_need_lookup(dentry))) - goto unlazy; path->mnt = mnt; path->dentry = dentry; if (unlikely(!__follow_mount_rcu(nd, path, inode))) @@ -1099,10 +1186,6 @@ static int do_lookup(struct nameidata *nd, struct qstr *name, dentry = __d_lookup(parent, name); } - if (dentry && unlikely(d_need_lookup(dentry))) { - dput(dentry); - dentry = NULL; - } retry: if (unlikely(!dentry)) { struct inode *dir = parent->d_inode; @@ -1119,15 +1202,6 @@ static int do_lookup(struct nameidata *nd, struct qstr *name, /* known good */ need_reval = 0; status = 1; - } else if (unlikely(d_need_lookup(dentry))) { - dentry = d_inode_lookup(parent, dentry, nd); - if (IS_ERR(dentry)) { - mutex_unlock(&dir->i_mutex); - return PTR_ERR(dentry); - } - /* known good */ - need_reval = 0; - status = 1; } mutex_unlock(&dir->i_mutex); } @@ -1160,13 +1234,13 @@ static int do_lookup(struct nameidata *nd, struct qstr *name, static inline int may_lookup(struct nameidata *nd) { if (nd->flags & LOOKUP_RCU) { - int err = inode_permission(nd->inode, MAY_EXEC|MAY_NOT_BLOCK); + int err = exec_permission(nd->inode, IPERM_FLAG_RCU); if (err != -ECHILD) return err; if (unlazy_walk(nd, NULL)) return -ECHILD; } - return inode_permission(nd->inode, MAY_EXEC); + return exec_permission(nd->inode, 0); } static inline int handle_dots(struct nameidata *nd, int type) @@ -1280,6 +1354,7 @@ static int link_path_walk(const char *name, struct nameidata *nd) { struct path next; int err; + unsigned int lookup_flags = nd->flags; while (*name=='/') name++; @@ -1293,6 +1368,8 @@ static int link_path_walk(const char *name, struct nameidata *nd) unsigned int c; int type; + nd->flags |= LOOKUP_CONTINUE; + err = may_lookup(nd); if (err) break; @@ -1354,6 +1431,8 @@ static int link_path_walk(const char *name, struct nameidata *nd) /* here ends the main loop */ last_component: + /* Clear LOOKUP_CONTINUE iff it was previously unset */ + nd->flags &= lookup_flags | ~LOOKUP_CONTINUE; nd->last = this; nd->last_type = type; return 0; @@ -1436,7 +1515,7 @@ static int path_init(int dfd, const char *name, unsigned int flags, if (!S_ISDIR(dentry->d_inode->i_mode)) goto fput_fail; - retval = inode_permission(dentry->d_inode, MAY_EXEC); + retval = file_permission(file, MAY_EXEC); if (retval) goto fput_fail; } @@ -1574,22 +1653,16 @@ int kern_path(const char *name, unsigned int flags, struct path *path) * @mnt: pointer to vfs mount of the base directory * @name: pointer to file name * @flags: lookup flags - * @path: pointer to struct path to fill + * @nd: pointer to nameidata */ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt, const char *name, unsigned int flags, - struct path *path) + struct nameidata *nd) { - struct nameidata nd; - int err; - nd.root.dentry = dentry; - nd.root.mnt = mnt; - BUG_ON(flags & LOOKUP_PARENT); + nd->root.dentry = dentry; + nd->root.mnt = mnt; /* the first argument of do_path_lookup() is ignored with LOOKUP_ROOT */ - err = do_path_lookup(AT_FDCWD, name, flags | LOOKUP_ROOT, &nd); - if (!err) - *path = nd.path; - return err; + return do_path_lookup(AT_FDCWD, name, flags | LOOKUP_ROOT, nd); } static struct dentry *__lookup_hash(struct qstr *name, @@ -1599,7 +1672,7 @@ static struct dentry *__lookup_hash(struct qstr *name, struct dentry *dentry; int err; - err = inode_permission(inode, MAY_EXEC); + err = exec_permission(inode, 0); if (err) return ERR_PTR(err); @@ -1610,34 +1683,8 @@ static struct dentry *__lookup_hash(struct qstr *name, */ dentry = d_lookup(base, name); - if (dentry && d_need_lookup(dentry)) { - /* - * __lookup_hash is called with the parent dir's i_mutex already - * held, so we are good to go here. - */ - dentry = d_inode_lookup(base, dentry, nd); - if (IS_ERR(dentry)) - return dentry; - } - - if (dentry && (dentry->d_flags & DCACHE_OP_REVALIDATE)) { - int status = d_revalidate(dentry, nd); - if (unlikely(status <= 0)) { - /* - * The dentry failed validation. - * If d_revalidate returned 0 attempt to invalidate - * the dentry otherwise d_revalidate is asking us - * to return a fail status. - */ - if (status < 0) { - dput(dentry); - return ERR_PTR(status); - } else if (!d_invalidate(dentry)) { - dput(dentry); - dentry = NULL; - } - } - } + if (dentry && (dentry->d_flags & DCACHE_OP_REVALIDATE)) + dentry = do_revalidate(dentry, nd); if (!dentry) dentry = d_alloc_and_lookup(base, name, nd); @@ -1965,10 +2012,27 @@ static int handle_truncate(struct file *filp) return error; } +/* + * Note that while the flag value (low two bits) for sys_open means: + * 00 - read-only + * 01 - write-only + * 10 - read-write + * 11 - special + * it is changed into + * 00 - no permissions needed + * 01 - read-permission + * 10 - write-permission + * 11 - read-write + * for the internal routines (ie open_namei()/follow_link() etc) + * This is more logical, and also allows the 00 "no perm needed" + * to be used for symlinks (where the permissions are checked + * later). + * +*/ static inline int open_to_namei_flags(int flag) { - if ((flag & O_ACCMODE) == 3) - flag--; + if ((flag+1) & O_ACCMODE) + flag++; return flag; } @@ -2263,29 +2327,35 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt, return file; } -struct dentry *kern_path_create(int dfd, const char *pathname, struct path *path, int is_dir) +/** + * lookup_create - lookup a dentry, creating it if it doesn't exist + * @nd: nameidata info + * @is_dir: directory flag + * + * Simple function to lookup and return a dentry and create it + * if it doesn't exist. Is SMP-safe. + * + * Returns with nd->path.dentry->d_inode->i_mutex locked. + */ +struct dentry *lookup_create(struct nameidata *nd, int is_dir) { struct dentry *dentry = ERR_PTR(-EEXIST); - struct nameidata nd; - int error = do_path_lookup(dfd, pathname, LOOKUP_PARENT, &nd); - if (error) - return ERR_PTR(error); + mutex_lock_nested(&nd->path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); /* * Yucky last component or no last component at all? * (foo/., foo/.., /////) */ - if (nd.last_type != LAST_NORM) - goto out; - nd.flags &= ~LOOKUP_PARENT; - nd.flags |= LOOKUP_CREATE | LOOKUP_EXCL; - nd.intent.open.flags = O_EXCL; + if (nd->last_type != LAST_NORM) + goto fail; + nd->flags &= ~LOOKUP_PARENT; + nd->flags |= LOOKUP_CREATE | LOOKUP_EXCL; + nd->intent.open.flags = O_EXCL; /* * Do the final lookup. */ - mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); - dentry = lookup_hash(&nd); + dentry = lookup_hash(nd); if (IS_ERR(dentry)) goto fail; @@ -2297,35 +2367,18 @@ struct dentry *kern_path_create(int dfd, const char *pathname, struct path *path * all is fine. Let's be bastards - you had / on the end, you've * been asking for (non-existent) directory. -ENOENT for you. */ - if (unlikely(!is_dir && nd.last.name[nd.last.len])) { + if (unlikely(!is_dir && nd->last.name[nd->last.len])) { dput(dentry); dentry = ERR_PTR(-ENOENT); - goto fail; } - *path = nd.path; return dentry; eexist: dput(dentry); dentry = ERR_PTR(-EEXIST); fail: - mutex_unlock(&nd.path.dentry->d_inode->i_mutex); -out: - path_put(&nd.path); return dentry; } -EXPORT_SYMBOL(kern_path_create); - -struct dentry *user_path_create(int dfd, const char __user *pathname, struct path *path, int is_dir) -{ - char *tmp = getname(pathname); - struct dentry *res; - if (IS_ERR(tmp)) - return ERR_CAST(tmp); - res = kern_path_create(dfd, tmp, path, is_dir); - putname(tmp); - return res; -} -EXPORT_SYMBOL(user_path_create); +EXPORT_SYMBOL_GPL(lookup_create); int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) { @@ -2375,46 +2428,54 @@ static int may_mknod(mode_t mode) SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, int, mode, unsigned, dev) { - struct dentry *dentry; - struct path path; int error; + char *tmp; + struct dentry *dentry; + struct nameidata nd; if (S_ISDIR(mode)) return -EPERM; - dentry = user_path_create(dfd, filename, &path, 0); - if (IS_ERR(dentry)) - return PTR_ERR(dentry); + error = user_path_parent(dfd, filename, &nd, &tmp); + if (error) + return error; - if (!IS_POSIXACL(path.dentry->d_inode)) + dentry = lookup_create(&nd, 0); + if (IS_ERR(dentry)) { + error = PTR_ERR(dentry); + goto out_unlock; + } + if (!IS_POSIXACL(nd.path.dentry->d_inode)) mode &= ~current_umask(); error = may_mknod(mode); if (error) goto out_dput; - error = mnt_want_write(path.mnt); + error = mnt_want_write(nd.path.mnt); if (error) goto out_dput; - error = security_path_mknod(&path, dentry, mode, dev); + error = security_path_mknod(&nd.path, dentry, mode, dev); if (error) goto out_drop_write; switch (mode & S_IFMT) { case 0: case S_IFREG: - error = vfs_create(path.dentry->d_inode,dentry,mode,NULL); + error = vfs_create(nd.path.dentry->d_inode,dentry,mode,&nd); break; case S_IFCHR: case S_IFBLK: - error = vfs_mknod(path.dentry->d_inode,dentry,mode, + error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode, new_decode_dev(dev)); break; case S_IFIFO: case S_IFSOCK: - error = vfs_mknod(path.dentry->d_inode,dentry,mode,0); + error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode,0); break; } out_drop_write: - mnt_drop_write(path.mnt); + mnt_drop_write(nd.path.mnt); out_dput: dput(dentry); - mutex_unlock(&path.dentry->d_inode->i_mutex); - path_put(&path); +out_unlock: + mutex_unlock(&nd.path.dentry->d_inode->i_mutex); + path_put(&nd.path); + putname(tmp); return error; } @@ -2447,29 +2508,38 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, int, mode) { + int error = 0; + char * tmp; struct dentry *dentry; - struct path path; - int error; + struct nameidata nd; + + error = user_path_parent(dfd, pathname, &nd, &tmp); + if (error) + goto out_err; - dentry = user_path_create(dfd, pathname, &path, 1); + dentry = lookup_create(&nd, 1); + error = PTR_ERR(dentry); if (IS_ERR(dentry)) - return PTR_ERR(dentry); + goto out_unlock; - if (!IS_POSIXACL(path.dentry->d_inode)) + if (!IS_POSIXACL(nd.path.dentry->d_inode)) mode &= ~current_umask(); - error = mnt_want_write(path.mnt); + error = mnt_want_write(nd.path.mnt); if (error) goto out_dput; - error = security_path_mkdir(&path, dentry, mode); + error = security_path_mkdir(&nd.path, dentry, mode); if (error) goto out_drop_write; - error = vfs_mkdir(path.dentry->d_inode, dentry, mode); + error = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode); out_drop_write: - mnt_drop_write(path.mnt); + mnt_drop_write(nd.path.mnt); out_dput: dput(dentry); - mutex_unlock(&path.dentry->d_inode->i_mutex); - path_put(&path); +out_unlock: + mutex_unlock(&nd.path.dentry->d_inode->i_mutex); + path_put(&nd.path); + putname(tmp); +out_err: return error; } @@ -2729,31 +2799,38 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname, { int error; char *from; + char *to; struct dentry *dentry; - struct path path; + struct nameidata nd; from = getname(oldname); if (IS_ERR(from)) return PTR_ERR(from); - dentry = user_path_create(newdfd, newname, &path, 0); + error = user_path_parent(newdfd, newname, &nd, &to); + if (error) + goto out_putname; + + dentry = lookup_create(&nd, 0); error = PTR_ERR(dentry); if (IS_ERR(dentry)) - goto out_putname; + goto out_unlock; - error = mnt_want_write(path.mnt); + error = mnt_want_write(nd.path.mnt); if (error) goto out_dput; - error = security_path_symlink(&path, dentry, from); + error = security_path_symlink(&nd.path, dentry, from); if (error) goto out_drop_write; - error = vfs_symlink(path.dentry->d_inode, dentry, from); + error = vfs_symlink(nd.path.dentry->d_inode, dentry, from); out_drop_write: - mnt_drop_write(path.mnt); + mnt_drop_write(nd.path.mnt); out_dput: dput(dentry); - mutex_unlock(&path.dentry->d_inode->i_mutex); - path_put(&path); +out_unlock: + mutex_unlock(&nd.path.dentry->d_inode->i_mutex); + path_put(&nd.path); + putname(to); out_putname: putname(from); return error; @@ -2818,9 +2895,11 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname, int, newdfd, const char __user *, newname, int, flags) { struct dentry *new_dentry; - struct path old_path, new_path; + struct nameidata nd; + struct path old_path; int how = 0; int error; + char *to; if ((flags & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0) return -EINVAL; @@ -2842,27 +2921,32 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname, if (error) return error; - new_dentry = user_path_create(newdfd, newname, &new_path, 0); - error = PTR_ERR(new_dentry); - if (IS_ERR(new_dentry)) + error = user_path_parent(newdfd, newname, &nd, &to); + if (error) goto out; - error = -EXDEV; - if (old_path.mnt != new_path.mnt) - goto out_dput; - error = mnt_want_write(new_path.mnt); + if (old_path.mnt != nd.path.mnt) + goto out_release; + new_dentry = lookup_create(&nd, 0); + error = PTR_ERR(new_dentry); + if (IS_ERR(new_dentry)) + goto out_unlock; + error = mnt_want_write(nd.path.mnt); if (error) goto out_dput; - error = security_path_link(old_path.dentry, &new_path, new_dentry); + error = security_path_link(old_path.dentry, &nd.path, new_dentry); if (error) goto out_drop_write; - error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry); + error = vfs_link(old_path.dentry, nd.path.dentry->d_inode, new_dentry); out_drop_write: - mnt_drop_write(new_path.mnt); + mnt_drop_write(nd.path.mnt); out_dput: dput(new_dentry); - mutex_unlock(&new_path.dentry->d_inode->i_mutex); - path_put(&new_path); +out_unlock: + mutex_unlock(&nd.path.dentry->d_inode->i_mutex); +out_release: + path_put(&nd.path); + putname(to); out: path_put(&old_path); @@ -3268,9 +3352,11 @@ EXPORT_SYMBOL(page_readlink); EXPORT_SYMBOL(__page_symlink); EXPORT_SYMBOL(page_symlink); EXPORT_SYMBOL(page_symlink_inode_operations); +EXPORT_SYMBOL(kern_path_parent); EXPORT_SYMBOL(kern_path); EXPORT_SYMBOL(vfs_path_lookup); EXPORT_SYMBOL(inode_permission); +EXPORT_SYMBOL(file_permission); EXPORT_SYMBOL(unlock_rename); EXPORT_SYMBOL(vfs_create); EXPORT_SYMBOL(vfs_follow_link); diff --git a/trunk/fs/namespace.c b/trunk/fs/namespace.c index cda50fe9250a..fe59bd145d21 100644 --- a/trunk/fs/namespace.c +++ b/trunk/fs/namespace.c @@ -934,8 +934,8 @@ int mnt_had_events(struct proc_mounts *p) int res = 0; br_read_lock(vfsmount_lock); - if (p->m.poll_event != ns->event) { - p->m.poll_event = ns->event; + if (p->event != ns->event) { + p->event = ns->event; res = 1; } br_read_unlock(vfsmount_lock); diff --git a/trunk/fs/ncpfs/file.c b/trunk/fs/ncpfs/file.c index 64a326418aa2..0ed65e0c3dfe 100644 --- a/trunk/fs/ncpfs/file.c +++ b/trunk/fs/ncpfs/file.c @@ -20,9 +20,9 @@ #include "ncp_fs.h" -static int ncp_fsync(struct file *file, loff_t start, loff_t end, int datasync) +static int ncp_fsync(struct file *file, int datasync) { - return filemap_write_and_wait_range(file->f_mapping, start, end); + return 0; } /* diff --git a/trunk/fs/nfs/cache_lib.c b/trunk/fs/nfs/cache_lib.c index c98b439332fc..84690319e625 100644 --- a/trunk/fs/nfs/cache_lib.c +++ b/trunk/fs/nfs/cache_lib.c @@ -113,18 +113,19 @@ int nfs_cache_wait_for_upcall(struct nfs_cache_defer_req *dreq) int nfs_cache_register(struct cache_detail *cd) { + struct nameidata nd; struct vfsmount *mnt; - struct path path; int ret; mnt = rpc_get_mount(); if (IS_ERR(mnt)) return PTR_ERR(mnt); - ret = vfs_path_lookup(mnt->mnt_root, mnt, "/cache", 0, &path); + ret = vfs_path_lookup(mnt->mnt_root, mnt, "/cache", 0, &nd); if (ret) goto err; - ret = sunrpc_cache_register_pipefs(path.dentry, cd->name, 0600, cd); - path_put(&path); + ret = sunrpc_cache_register_pipefs(nd.path.dentry, + cd->name, 0600, cd); + path_put(&nd.path); if (!ret) return ret; err: diff --git a/trunk/fs/nfs/dir.c b/trunk/fs/nfs/dir.c index 57f578e2560a..ededdbd0db38 100644 --- a/trunk/fs/nfs/dir.c +++ b/trunk/fs/nfs/dir.c @@ -56,7 +56,7 @@ static int nfs_link(struct dentry *, struct inode *, struct dentry *); static int nfs_mknod(struct inode *, struct dentry *, int, dev_t); static int nfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *); -static int nfs_fsync_dir(struct file *, loff_t, loff_t, int); +static int nfs_fsync_dir(struct file *, int); static loff_t nfs_llseek_dir(struct file *, loff_t, int); static void nfs_readdir_clear_array(struct page*); @@ -945,19 +945,15 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin) * All directory operations under NFS are synchronous, so fsync() * is a dummy operation. */ -static int nfs_fsync_dir(struct file *filp, loff_t start, loff_t end, - int datasync) +static int nfs_fsync_dir(struct file *filp, int datasync) { struct dentry *dentry = filp->f_path.dentry; - struct inode *inode = dentry->d_inode; dfprintk(FILE, "NFS: fsync dir(%s/%s) datasync %d\n", dentry->d_parent->d_name.name, dentry->d_name.name, datasync); - mutex_lock(&inode->i_mutex); nfs_inc_stats(dentry->d_inode, NFSIOS_VFSFSYNC); - mutex_unlock(&inode->i_mutex); return 0; } @@ -1001,12 +997,14 @@ static int nfs_check_verifier(struct inode *dir, struct dentry *dentry) * Return the intent data that applies to this particular path component * * Note that the current set of intents only apply to the very last - * component of the path and none of them is set before that last - * component. + * component of the path. + * We check for this using LOOKUP_CONTINUE and LOOKUP_PARENT. */ static inline unsigned int nfs_lookup_check_intent(struct nameidata *nd, unsigned int mask) { + if (nd->flags & (LOOKUP_CONTINUE|LOOKUP_PARENT)) + return 0; return nd->flags & mask; } @@ -1340,31 +1338,25 @@ static int is_atomic_open(struct nameidata *nd) return 0; /* Are we trying to write to a read only partition? */ if (__mnt_is_readonly(nd->path.mnt) && - (nd->intent.open.flags & (O_CREAT|O_TRUNC|O_ACCMODE))) + (nd->intent.open.flags & (O_CREAT|O_TRUNC|FMODE_WRITE))) return 0; return 1; } -static fmode_t flags_to_mode(int flags) -{ - fmode_t res = (__force fmode_t)flags & FMODE_EXEC; - if ((flags & O_ACCMODE) != O_WRONLY) - res |= FMODE_READ; - if ((flags & O_ACCMODE) != O_RDONLY) - res |= FMODE_WRITE; - return res; -} - -static struct nfs_open_context *create_nfs_open_context(struct dentry *dentry, int open_flags) +static struct nfs_open_context *nameidata_to_nfs_open_context(struct dentry *dentry, struct nameidata *nd) { + struct path path = { + .mnt = nd->path.mnt, + .dentry = dentry, + }; struct nfs_open_context *ctx; struct rpc_cred *cred; - fmode_t fmode = flags_to_mode(open_flags); + fmode_t fmode = nd->intent.open.flags & (FMODE_READ | FMODE_WRITE | FMODE_EXEC); cred = rpc_lookup_cred(); if (IS_ERR(cred)) return ERR_CAST(cred); - ctx = alloc_nfs_open_context(dentry, cred, fmode); + ctx = alloc_nfs_open_context(&path, cred, fmode); put_rpccred(cred); if (ctx == NULL) return ERR_PTR(-ENOMEM); @@ -1384,13 +1376,13 @@ static int nfs_intent_set_file(struct nameidata *nd, struct nfs_open_context *ct /* If the open_intent is for execute, we have an extra check to make */ if (ctx->mode & FMODE_EXEC) { - ret = nfs_may_open(ctx->dentry->d_inode, + ret = nfs_may_open(ctx->path.dentry->d_inode, ctx->cred, nd->intent.open.flags); if (ret < 0) goto out; } - filp = lookup_instantiate_filp(nd, ctx->dentry, do_open); + filp = lookup_instantiate_filp(nd, ctx->path.dentry, do_open); if (IS_ERR(filp)) ret = PTR_ERR(filp); else @@ -1428,13 +1420,12 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry goto out; } - open_flags = nd->intent.open.flags; - - ctx = create_nfs_open_context(dentry, open_flags); + ctx = nameidata_to_nfs_open_context(dentry, nd); res = ERR_CAST(ctx); if (IS_ERR(ctx)) goto out; + open_flags = nd->intent.open.flags; if (nd->flags & LOOKUP_CREATE) { attr.ia_mode = nd->intent.open.create_mode; attr.ia_valid = ATTR_MODE; @@ -1472,8 +1463,8 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry res = d_add_unique(dentry, inode); nfs_unblock_sillyrename(dentry->d_parent); if (res != NULL) { - dput(ctx->dentry); - ctx->dentry = dget(res); + dput(ctx->path.dentry); + ctx->path.dentry = dget(res); dentry = res; } err = nfs_intent_set_file(nd, ctx); @@ -1526,7 +1517,7 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) /* We can't create new files, or truncate existing ones here */ openflags &= ~(O_CREAT|O_EXCL|O_TRUNC); - ctx = create_nfs_open_context(dentry, openflags); + ctx = nameidata_to_nfs_open_context(dentry, nd); ret = PTR_ERR(ctx); if (IS_ERR(ctx)) goto out; @@ -1579,7 +1570,7 @@ static int nfs_open_create(struct inode *dir, struct dentry *dentry, int mode, struct nfs_open_context *ctx = NULL; struct iattr attr; int error; - int open_flags = O_CREAT|O_EXCL; + int open_flags = 0; dfprintk(VFS, "NFS: create(%s/%ld), %s\n", dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); @@ -1587,27 +1578,27 @@ static int nfs_open_create(struct inode *dir, struct dentry *dentry, int mode, attr.ia_mode = mode; attr.ia_valid = ATTR_MODE; - if (nd) + if ((nd->flags & LOOKUP_CREATE) != 0) { open_flags = nd->intent.open.flags; - ctx = create_nfs_open_context(dentry, open_flags); - error = PTR_ERR(ctx); - if (IS_ERR(ctx)) - goto out_err_drop; + ctx = nameidata_to_nfs_open_context(dentry, nd); + error = PTR_ERR(ctx); + if (IS_ERR(ctx)) + goto out_err_drop; + } error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, ctx); if (error != 0) goto out_put_ctx; - if (nd) { + if (ctx != NULL) { error = nfs_intent_set_file(nd, ctx); if (error < 0) goto out_err; - } else { - put_nfs_open_context(ctx); } return 0; out_put_ctx: - put_nfs_open_context(ctx); + if (ctx != NULL) + put_nfs_open_context(ctx); out_err_drop: d_drop(dentry); out_err: @@ -1669,7 +1660,7 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode, { struct iattr attr; int error; - int open_flags = O_CREAT|O_EXCL; + int open_flags = 0; dfprintk(VFS, "NFS: create(%s/%ld), %s\n", dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); @@ -1677,7 +1668,7 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode, attr.ia_mode = mode; attr.ia_valid = ATTR_MODE; - if (nd) + if ((nd->flags & LOOKUP_CREATE) != 0) open_flags = nd->intent.open.flags; error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, NULL); @@ -2268,11 +2259,11 @@ static int nfs_open_permission_mask(int openflags) { int mask = 0; - if ((openflags & O_ACCMODE) != O_WRONLY) + if (openflags & FMODE_READ) mask |= MAY_READ; - if ((openflags & O_ACCMODE) != O_RDONLY) + if (openflags & FMODE_WRITE) mask |= MAY_WRITE; - if (openflags & __FMODE_EXEC) + if (openflags & FMODE_EXEC) mask |= MAY_EXEC; return mask; } @@ -2282,12 +2273,12 @@ int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags) return nfs_do_access(inode, cred, nfs_open_permission_mask(openflags)); } -int nfs_permission(struct inode *inode, int mask) +int nfs_permission(struct inode *inode, int mask, unsigned int flags) { struct rpc_cred *cred; int res = 0; - if (mask & MAY_NOT_BLOCK) + if (flags & IPERM_FLAG_RCU) return -ECHILD; nfs_inc_stats(inode, NFSIOS_VFSACCESS); @@ -2337,7 +2328,7 @@ int nfs_permission(struct inode *inode, int mask) out_notsup: res = nfs_revalidate_inode(NFS_SERVER(inode), inode); if (res == 0) - res = generic_permission(inode, mask); + res = generic_permission(inode, mask, flags, NULL); goto out; } diff --git a/trunk/fs/nfs/direct.c b/trunk/fs/nfs/direct.c index b35d25b98da6..8eea25366717 100644 --- a/trunk/fs/nfs/direct.c +++ b/trunk/fs/nfs/direct.c @@ -284,7 +284,7 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq, loff_t pos) { struct nfs_open_context *ctx = dreq->ctx; - struct inode *inode = ctx->dentry->d_inode; + struct inode *inode = ctx->path.dentry->d_inode; unsigned long user_addr = (unsigned long)iov->iov_base; size_t count = iov->iov_len; size_t rsize = NFS_SERVER(inode)->rsize; @@ -715,7 +715,7 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq, loff_t pos, int sync) { struct nfs_open_context *ctx = dreq->ctx; - struct inode *inode = ctx->dentry->d_inode; + struct inode *inode = ctx->path.dentry->d_inode; unsigned long user_addr = (unsigned long)iov->iov_base; size_t count = iov->iov_len; struct rpc_task *task; diff --git a/trunk/fs/nfs/file.c b/trunk/fs/nfs/file.c index 28b8c3f3cda3..2f093ed16980 100644 --- a/trunk/fs/nfs/file.c +++ b/trunk/fs/nfs/file.c @@ -55,7 +55,7 @@ static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe, static ssize_t nfs_file_write(struct kiocb *, const struct iovec *iov, unsigned long nr_segs, loff_t pos); static int nfs_file_flush(struct file *, fl_owner_t id); -static int nfs_file_fsync(struct file *, loff_t, loff_t, int datasync); +static int nfs_file_fsync(struct file *, int datasync); static int nfs_check_flags(int flags); static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl); static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl); @@ -187,11 +187,8 @@ static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin) filp->f_path.dentry->d_name.name, offset, origin); - /* - * origin == SEEK_END || SEEK_DATA || SEEK_HOLE => we must revalidate - * the cached file length - */ - if (origin != SEEK_SET || origin != SEEK_CUR) { + /* origin == SEEK_END => we must revalidate the cached file length */ + if (origin == SEEK_END) { struct inode *inode = filp->f_mapping->host; int retval = nfs_revalidate_file_size(inode, filp); @@ -308,7 +305,7 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma) * fall back to doing a synchronous write. */ static int -nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync) +nfs_file_fsync(struct file *file, int datasync) { struct dentry *dentry = file->f_path.dentry; struct nfs_open_context *ctx = nfs_file_open_context(file); @@ -316,15 +313,11 @@ nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync) int have_error, status; int ret = 0; + dprintk("NFS: fsync file(%s/%s) datasync %d\n", dentry->d_parent->d_name.name, dentry->d_name.name, datasync); - ret = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (ret) - return ret; - mutex_lock(&inode->i_mutex); - nfs_inc_stats(inode, NFSIOS_VFSFSYNC); have_error = test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); status = nfs_commit_inode(inode, FLUSH_SYNC); @@ -336,7 +329,6 @@ nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync) if (!ret && !datasync) /* application has asked for meta-data sync */ ret = pnfs_layoutcommit_inode(inode, true); - mutex_unlock(&inode->i_mutex); return ret; } diff --git a/trunk/fs/nfs/inode.c b/trunk/fs/nfs/inode.c index fe1203797b2b..6f4850deb272 100644 --- a/trunk/fs/nfs/inode.c +++ b/trunk/fs/nfs/inode.c @@ -567,7 +567,7 @@ static struct nfs_lock_context *__nfs_find_lock_context(struct nfs_open_context struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx) { struct nfs_lock_context *res, *new = NULL; - struct inode *inode = ctx->dentry->d_inode; + struct inode *inode = ctx->path.dentry->d_inode; spin_lock(&inode->i_lock); res = __nfs_find_lock_context(ctx); @@ -594,7 +594,7 @@ struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx) void nfs_put_lock_context(struct nfs_lock_context *l_ctx) { struct nfs_open_context *ctx = l_ctx->open_context; - struct inode *inode = ctx->dentry->d_inode; + struct inode *inode = ctx->path.dentry->d_inode; if (!atomic_dec_and_lock(&l_ctx->count, &inode->i_lock)) return; @@ -620,7 +620,7 @@ void nfs_close_context(struct nfs_open_context *ctx, int is_sync) return; if (!is_sync) return; - inode = ctx->dentry->d_inode; + inode = ctx->path.dentry->d_inode; if (!list_empty(&NFS_I(inode)->open_files)) return; server = NFS_SERVER(inode); @@ -629,14 +629,14 @@ void nfs_close_context(struct nfs_open_context *ctx, int is_sync) nfs_revalidate_inode(server, inode); } -struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, struct rpc_cred *cred, fmode_t f_mode) +struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct rpc_cred *cred, fmode_t f_mode) { struct nfs_open_context *ctx; ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); if (ctx != NULL) { - nfs_sb_active(dentry->d_sb); - ctx->dentry = dget(dentry); + ctx->path = *path; + path_get(&ctx->path); ctx->cred = get_rpccred(cred); ctx->state = NULL; ctx->mode = f_mode; @@ -658,8 +658,7 @@ struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx) static void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync) { - struct inode *inode = ctx->dentry->d_inode; - struct super_block *sb = ctx->dentry->d_sb; + struct inode *inode = ctx->path.dentry->d_inode; if (!list_empty(&ctx->list)) { if (!atomic_dec_and_lock(&ctx->lock_context.count, &inode->i_lock)) @@ -672,8 +671,7 @@ static void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync) NFS_PROTO(inode)->close_context(ctx, is_sync); if (ctx->cred != NULL) put_rpccred(ctx->cred); - dput(ctx->dentry); - nfs_sb_deactive(sb); + path_put(&ctx->path); kfree(ctx); } @@ -743,7 +741,7 @@ int nfs_open(struct inode *inode, struct file *filp) cred = rpc_lookup_cred(); if (IS_ERR(cred)) return PTR_ERR(cred); - ctx = alloc_nfs_open_context(filp->f_path.dentry, cred, filp->f_mode); + ctx = alloc_nfs_open_context(&filp->f_path, cred, filp->f_mode); put_rpccred(cred); if (ctx == NULL) return -ENOMEM; diff --git a/trunk/fs/nfs/nfs4_fs.h b/trunk/fs/nfs/nfs4_fs.h index b788f2eb1ba0..c4a69833dd0d 100644 --- a/trunk/fs/nfs/nfs4_fs.h +++ b/trunk/fs/nfs/nfs4_fs.h @@ -238,7 +238,7 @@ extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *); extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *); extern int nfs4_init_clientid(struct nfs_client *, struct rpc_cred *); extern int nfs41_init_clientid(struct nfs_client *, struct rpc_cred *); -extern int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc); +extern int nfs4_do_close(struct path *path, struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc); extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, struct nfs4_fs_locations *fs_locations, struct page *page); @@ -341,8 +341,8 @@ extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struc extern void nfs4_put_state_owner(struct nfs4_state_owner *); extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *); extern void nfs4_put_open_state(struct nfs4_state *); -extern void nfs4_close_state(struct nfs4_state *, fmode_t); -extern void nfs4_close_sync(struct nfs4_state *, fmode_t); +extern void nfs4_close_state(struct path *, struct nfs4_state *, fmode_t); +extern void nfs4_close_sync(struct path *, struct nfs4_state *, fmode_t); extern void nfs4_state_set_mode_locked(struct nfs4_state *, fmode_t); extern void nfs4_schedule_lease_recovery(struct nfs_client *); extern void nfs4_schedule_state_manager(struct nfs_client *); @@ -373,8 +373,8 @@ extern struct svc_version nfs4_callback_version4; #else -#define nfs4_close_state(a, b) do { } while (0) -#define nfs4_close_sync(a, b) do { } while (0) +#define nfs4_close_state(a, b, c) do { } while (0) +#define nfs4_close_sync(a, b, c) do { } while (0) #endif /* CONFIG_NFS_V4 */ #endif /* __LINUX_FS_NFS_NFS4_FS.H */ diff --git a/trunk/fs/nfs/nfs4proc.c b/trunk/fs/nfs/nfs4proc.c index 26bece8f3083..5879b23e0c99 100644 --- a/trunk/fs/nfs/nfs4proc.c +++ b/trunk/fs/nfs/nfs4proc.c @@ -763,8 +763,8 @@ struct nfs4_opendata { struct nfs_open_confirmres c_res; struct nfs_fattr f_attr; struct nfs_fattr dir_attr; + struct path path; struct dentry *dir; - struct dentry *dentry; struct nfs4_state_owner *owner; struct nfs4_state *state; struct iattr attrs; @@ -786,12 +786,12 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p) nfs_fattr_init(&p->dir_attr); } -static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, +static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, struct nfs4_state_owner *sp, fmode_t fmode, int flags, const struct iattr *attrs, gfp_t gfp_mask) { - struct dentry *parent = dget_parent(dentry); + struct dentry *parent = dget_parent(path->dentry); struct inode *dir = parent->d_inode; struct nfs_server *server = NFS_SERVER(dir); struct nfs4_opendata *p; @@ -802,8 +802,8 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid, gfp_mask); if (p->o_arg.seqid == NULL) goto err_free; - nfs_sb_active(dentry->d_sb); - p->dentry = dget(dentry); + path_get(path); + p->path = *path; p->dir = parent; p->owner = sp; atomic_inc(&sp->so_count); @@ -812,7 +812,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, p->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE); p->o_arg.clientid = server->nfs_client->cl_clientid; p->o_arg.id = sp->so_owner_id.id; - p->o_arg.name = &dentry->d_name; + p->o_arg.name = &p->path.dentry->d_name; p->o_arg.server = server; p->o_arg.bitmask = server->attr_bitmask; p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; @@ -842,15 +842,13 @@ static void nfs4_opendata_free(struct kref *kref) { struct nfs4_opendata *p = container_of(kref, struct nfs4_opendata, kref); - struct super_block *sb = p->dentry->d_sb; nfs_free_seqid(p->o_arg.seqid); if (p->state != NULL) nfs4_put_open_state(p->state); nfs4_put_state_owner(p->owner); dput(p->dir); - dput(p->dentry); - nfs_sb_deactive(sb); + path_put(&p->path); kfree(p); } @@ -1132,7 +1130,7 @@ static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context { struct nfs4_opendata *opendata; - opendata = nfs4_opendata_alloc(ctx->dentry, state->owner, 0, 0, NULL, GFP_NOFS); + opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, 0, NULL, GFP_NOFS); if (opendata == NULL) return ERR_PTR(-ENOMEM); opendata->state = state; @@ -1156,7 +1154,7 @@ static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, fmode_t fmod newstate = nfs4_opendata_to_nfs4_state(opendata); if (IS_ERR(newstate)) return PTR_ERR(newstate); - nfs4_close_state(newstate, fmode); + nfs4_close_state(&opendata->path, newstate, fmode); *res = newstate; return 0; } @@ -1354,7 +1352,7 @@ static void nfs4_open_confirm_release(void *calldata) goto out_free; state = nfs4_opendata_to_nfs4_state(data); if (!IS_ERR(state)) - nfs4_close_state(state, data->o_arg.fmode); + nfs4_close_state(&data->path, state, data->o_arg.fmode); out_free: nfs4_opendata_put(data); } @@ -1499,7 +1497,7 @@ static void nfs4_open_release(void *calldata) goto out_free; state = nfs4_opendata_to_nfs4_state(data); if (!IS_ERR(state)) - nfs4_close_state(state, data->o_arg.fmode); + nfs4_close_state(&data->path, state, data->o_arg.fmode); out_free: nfs4_opendata_put(data); } @@ -1650,7 +1648,7 @@ static int _nfs4_open_expired(struct nfs_open_context *ctx, struct nfs4_state *s return PTR_ERR(opendata); ret = nfs4_open_recover(opendata, state); if (ret == -ESTALE) - d_drop(ctx->dentry); + d_drop(ctx->path.dentry); nfs4_opendata_put(opendata); return ret; } @@ -1708,7 +1706,7 @@ static inline void nfs4_exclusive_attrset(struct nfs4_opendata *opendata, struct /* * Returns a referenced nfs4_state */ -static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, fmode_t fmode, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res) +static int _nfs4_do_open(struct inode *dir, struct path *path, fmode_t fmode, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res) { struct nfs4_state_owner *sp; struct nfs4_state *state = NULL; @@ -1725,15 +1723,15 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, fmode_t fmode status = nfs4_recover_expired_lease(server); if (status != 0) goto err_put_state_owner; - if (dentry->d_inode != NULL) - nfs4_return_incompatible_delegation(dentry->d_inode, fmode); + if (path->dentry->d_inode != NULL) + nfs4_return_incompatible_delegation(path->dentry->d_inode, fmode); status = -ENOMEM; - opendata = nfs4_opendata_alloc(dentry, sp, fmode, flags, sattr, GFP_KERNEL); + opendata = nfs4_opendata_alloc(path, sp, fmode, flags, sattr, GFP_KERNEL); if (opendata == NULL) goto err_put_state_owner; - if (dentry->d_inode != NULL) - opendata->state = nfs4_get_open_state(dentry->d_inode, sp); + if (path->dentry->d_inode != NULL) + opendata->state = nfs4_get_open_state(path->dentry->d_inode, sp); status = _nfs4_proc_open(opendata); if (status != 0) @@ -1771,14 +1769,14 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, fmode_t fmode } -static struct nfs4_state *nfs4_do_open(struct inode *dir, struct dentry *dentry, fmode_t fmode, int flags, struct iattr *sattr, struct rpc_cred *cred) +static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, fmode_t fmode, int flags, struct iattr *sattr, struct rpc_cred *cred) { struct nfs4_exception exception = { }; struct nfs4_state *res; int status; do { - status = _nfs4_do_open(dir, dentry, fmode, flags, sattr, cred, &res); + status = _nfs4_do_open(dir, path, fmode, flags, sattr, cred, &res); if (status == 0) break; /* NOTE: BAD_SEQID means the server and client disagree about the @@ -1875,6 +1873,7 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, } struct nfs4_closedata { + struct path path; struct inode *inode; struct nfs4_state *state; struct nfs_closeargs arg; @@ -1889,14 +1888,13 @@ static void nfs4_free_closedata(void *data) { struct nfs4_closedata *calldata = data; struct nfs4_state_owner *sp = calldata->state->owner; - struct super_block *sb = calldata->state->inode->i_sb; if (calldata->roc) pnfs_roc_release(calldata->state->inode); nfs4_put_open_state(calldata->state); nfs_free_seqid(calldata->arg.seqid); nfs4_put_state_owner(sp); - nfs_sb_deactive(sb); + path_put(&calldata->path); kfree(calldata); } @@ -2016,7 +2014,7 @@ static const struct rpc_call_ops nfs4_close_ops = { * * NOTE: Caller must be holding the sp->so_owner semaphore! */ -int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc) +int nfs4_do_close(struct path *path, struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc) { struct nfs_server *server = NFS_SERVER(state->inode); struct nfs4_closedata *calldata; @@ -2052,7 +2050,8 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc) calldata->res.seqid = calldata->arg.seqid; calldata->res.server = server; calldata->roc = roc; - nfs_sb_active(calldata->inode->i_sb); + path_get(path); + calldata->path = *path; msg.rpc_argp = &calldata->arg; msg.rpc_resp = &calldata->res; @@ -2081,7 +2080,7 @@ nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx, int open_flags struct nfs4_state *state; /* Protect against concurrent sillydeletes */ - state = nfs4_do_open(dir, ctx->dentry, ctx->mode, open_flags, attr, ctx->cred); + state = nfs4_do_open(dir, &ctx->path, ctx->mode, open_flags, attr, ctx->cred); if (IS_ERR(state)) return ERR_CAST(state); ctx->state = state; @@ -2093,9 +2092,9 @@ static void nfs4_close_context(struct nfs_open_context *ctx, int is_sync) if (ctx->state == NULL) return; if (is_sync) - nfs4_close_sync(ctx->state, ctx->mode); + nfs4_close_sync(&ctx->path, ctx->state, ctx->mode); else - nfs4_close_state(ctx->state, ctx->mode); + nfs4_close_state(&ctx->path, ctx->state, ctx->mode); } static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle) @@ -2617,7 +2616,10 @@ static int nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, int flags, struct nfs_open_context *ctx) { - struct dentry *de = dentry; + struct path my_path = { + .dentry = dentry, + }; + struct path *path = &my_path; struct nfs4_state *state; struct rpc_cred *cred = NULL; fmode_t fmode = 0; @@ -2625,11 +2627,11 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, if (ctx != NULL) { cred = ctx->cred; - de = ctx->dentry; + path = &ctx->path; fmode = ctx->mode; } sattr->ia_mode &= ~current_umask(); - state = nfs4_do_open(dir, de, fmode, flags, sattr, cred); + state = nfs4_do_open(dir, path, fmode, flags, sattr, cred); d_drop(dentry); if (IS_ERR(state)) { status = PTR_ERR(state); @@ -2640,7 +2642,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, if (ctx != NULL) ctx->state = state; else - nfs4_close_sync(state, fmode); + nfs4_close_sync(path, state, fmode); out: return status; } @@ -4292,7 +4294,7 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata) memcpy(data->lsp->ls_stateid.data, data->res.stateid.data, sizeof(data->lsp->ls_stateid.data)); data->lsp->ls_flags |= NFS_LOCK_INITIALIZED; - renew_lease(NFS_SERVER(data->ctx->dentry->d_inode), data->timestamp); + renew_lease(NFS_SERVER(data->ctx->path.dentry->d_inode), data->timestamp); } out: dprintk("%s: done, ret = %d!\n", __func__, data->rpc_status); diff --git a/trunk/fs/nfs/nfs4state.c b/trunk/fs/nfs/nfs4state.c index 7acfe8843626..e97dd219f84f 100644 --- a/trunk/fs/nfs/nfs4state.c +++ b/trunk/fs/nfs/nfs4state.c @@ -641,7 +641,7 @@ void nfs4_put_open_state(struct nfs4_state *state) /* * Close the current file. */ -static void __nfs4_close(struct nfs4_state *state, +static void __nfs4_close(struct path *path, struct nfs4_state *state, fmode_t fmode, gfp_t gfp_mask, int wait) { struct nfs4_state_owner *owner = state->owner; @@ -685,18 +685,18 @@ static void __nfs4_close(struct nfs4_state *state, } else { bool roc = pnfs_roc(state->inode); - nfs4_do_close(state, gfp_mask, wait, roc); + nfs4_do_close(path, state, gfp_mask, wait, roc); } } -void nfs4_close_state(struct nfs4_state *state, fmode_t fmode) +void nfs4_close_state(struct path *path, struct nfs4_state *state, fmode_t fmode) { - __nfs4_close(state, fmode, GFP_NOFS, 0); + __nfs4_close(path, state, fmode, GFP_NOFS, 0); } -void nfs4_close_sync(struct nfs4_state *state, fmode_t fmode) +void nfs4_close_sync(struct path *path, struct nfs4_state *state, fmode_t fmode) { - __nfs4_close(state, fmode, GFP_KERNEL, 1); + __nfs4_close(path, state, fmode, GFP_KERNEL, 1); } /* diff --git a/trunk/fs/nfs/pagelist.c b/trunk/fs/nfs/pagelist.c index 18449f43c568..009855716286 100644 --- a/trunk/fs/nfs/pagelist.c +++ b/trunk/fs/nfs/pagelist.c @@ -114,7 +114,7 @@ int nfs_set_page_tag_locked(struct nfs_page *req) if (!nfs_lock_request_dontget(req)) return 0; if (test_bit(PG_MAPPED, &req->wb_flags)) - radix_tree_tag_set(&NFS_I(req->wb_context->dentry->d_inode)->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); + radix_tree_tag_set(&NFS_I(req->wb_context->path.dentry->d_inode)->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); return 1; } @@ -124,7 +124,7 @@ int nfs_set_page_tag_locked(struct nfs_page *req) void nfs_clear_page_tag_locked(struct nfs_page *req) { if (test_bit(PG_MAPPED, &req->wb_flags)) { - struct inode *inode = req->wb_context->dentry->d_inode; + struct inode *inode = req->wb_context->path.dentry->d_inode; struct nfs_inode *nfsi = NFS_I(inode); spin_lock(&inode->i_lock); diff --git a/trunk/fs/nfs/read.c b/trunk/fs/nfs/read.c index a68679f538fc..20a7f952e244 100644 --- a/trunk/fs/nfs/read.c +++ b/trunk/fs/nfs/read.c @@ -144,7 +144,7 @@ int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, static void nfs_readpage_release(struct nfs_page *req) { - struct inode *d_inode = req->wb_context->dentry->d_inode; + struct inode *d_inode = req->wb_context->path.dentry->d_inode; if (PageUptodate(req->wb_page)) nfs_readpage_to_fscache(d_inode, req->wb_page, 0); @@ -152,8 +152,8 @@ static void nfs_readpage_release(struct nfs_page *req) unlock_page(req->wb_page); dprintk("NFS: read done (%s/%Ld %d@%Ld)\n", - req->wb_context->dentry->d_inode->i_sb->s_id, - (long long)NFS_FILEID(req->wb_context->dentry->d_inode), + req->wb_context->path.dentry->d_inode->i_sb->s_id, + (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode), req->wb_bytes, (long long)req_offset(req)); nfs_release_request(req); @@ -207,7 +207,7 @@ static int nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, unsigned int count, unsigned int offset, struct pnfs_layout_segment *lseg) { - struct inode *inode = req->wb_context->dentry->d_inode; + struct inode *inode = req->wb_context->path.dentry->d_inode; data->req = req; data->inode = inode; diff --git a/trunk/fs/nfs/super.c b/trunk/fs/nfs/super.c index b961ceac66b4..ce40e5c568ba 100644 --- a/trunk/fs/nfs/super.c +++ b/trunk/fs/nfs/super.c @@ -2773,12 +2773,16 @@ static void nfs_referral_loop_unprotect(void) static struct dentry *nfs_follow_remote_path(struct vfsmount *root_mnt, const char *export_path) { + struct nameidata *nd = NULL; struct mnt_namespace *ns_private; struct super_block *s; struct dentry *dentry; - struct path path; int ret; + nd = kmalloc(sizeof(*nd), GFP_KERNEL); + if (nd == NULL) + return ERR_PTR(-ENOMEM); + ns_private = create_mnt_ns(root_mnt); ret = PTR_ERR(ns_private); if (IS_ERR(ns_private)) @@ -2789,7 +2793,7 @@ static struct dentry *nfs_follow_remote_path(struct vfsmount *root_mnt, goto out_put_mnt_ns; ret = vfs_path_lookup(root_mnt->mnt_root, root_mnt, - export_path, LOOKUP_FOLLOW, &path); + export_path, LOOKUP_FOLLOW, nd); nfs_referral_loop_unprotect(); put_mnt_ns(ns_private); @@ -2797,11 +2801,12 @@ static struct dentry *nfs_follow_remote_path(struct vfsmount *root_mnt, if (ret != 0) goto out_err; - s = path.mnt->mnt_sb; + s = nd->path.mnt->mnt_sb; atomic_inc(&s->s_active); - dentry = dget(path.dentry); + dentry = dget(nd->path.dentry); - path_put(&path); + path_put(&nd->path); + kfree(nd); down_write(&s->s_umount); return dentry; out_put_mnt_ns: @@ -2809,6 +2814,7 @@ static struct dentry *nfs_follow_remote_path(struct vfsmount *root_mnt, out_mntput: mntput(root_mnt); out_err: + kfree(nd); return ERR_PTR(ret); } diff --git a/trunk/fs/nfs/write.c b/trunk/fs/nfs/write.c index 08579312c57b..727168059684 100644 --- a/trunk/fs/nfs/write.c +++ b/trunk/fs/nfs/write.c @@ -409,7 +409,7 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req) */ static void nfs_inode_remove_request(struct nfs_page *req) { - struct inode *inode = req->wb_context->dentry->d_inode; + struct inode *inode = req->wb_context->path.dentry->d_inode; struct nfs_inode *nfsi = NFS_I(inode); BUG_ON (!NFS_WBACK_BUSY(req)); @@ -438,7 +438,7 @@ nfs_mark_request_dirty(struct nfs_page *req) static void nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg) { - struct inode *inode = req->wb_context->dentry->d_inode; + struct inode *inode = req->wb_context->path.dentry->d_inode; struct nfs_inode *nfsi = NFS_I(inode); spin_lock(&inode->i_lock); @@ -852,13 +852,13 @@ static int nfs_write_rpcsetup(struct nfs_page *req, struct pnfs_layout_segment *lseg, int how) { - struct inode *inode = req->wb_context->dentry->d_inode; + struct inode *inode = req->wb_context->path.dentry->d_inode; /* Set up the RPC argument and reply structs * NB: take care not to mess about with data->commit et al. */ data->req = req; - data->inode = inode = req->wb_context->dentry->d_inode; + data->inode = inode = req->wb_context->path.dentry->d_inode; data->cred = req->wb_context->cred; data->lseg = get_lseg(lseg); @@ -1053,9 +1053,9 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata) dprintk("NFS: %5u write(%s/%lld %d@%lld)", task->tk_pid, - data->req->wb_context->dentry->d_inode->i_sb->s_id, + data->req->wb_context->path.dentry->d_inode->i_sb->s_id, (long long) - NFS_FILEID(data->req->wb_context->dentry->d_inode), + NFS_FILEID(data->req->wb_context->path.dentry->d_inode), data->req->wb_bytes, (long long)req_offset(data->req)); nfs_writeback_done(task, data); @@ -1148,8 +1148,8 @@ static void nfs_writeback_release_full(void *calldata) dprintk("NFS: %5u write (%s/%lld %d@%lld)", data->task.tk_pid, - req->wb_context->dentry->d_inode->i_sb->s_id, - (long long)NFS_FILEID(req->wb_context->dentry->d_inode), + req->wb_context->path.dentry->d_inode->i_sb->s_id, + (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode), req->wb_bytes, (long long)req_offset(req)); @@ -1347,7 +1347,7 @@ void nfs_init_commit(struct nfs_write_data *data, struct pnfs_layout_segment *lseg) { struct nfs_page *first = nfs_list_entry(head->next); - struct inode *inode = first->wb_context->dentry->d_inode; + struct inode *inode = first->wb_context->path.dentry->d_inode; /* Set up the RPC argument and reply structs * NB: take care not to mess about with data->commit et al. */ @@ -1435,8 +1435,8 @@ void nfs_commit_release_pages(struct nfs_write_data *data) nfs_clear_request_commit(req); dprintk("NFS: commit (%s/%lld %d@%lld)", - req->wb_context->dentry->d_sb->s_id, - (long long)NFS_FILEID(req->wb_context->dentry->d_inode), + req->wb_context->path.dentry->d_inode->i_sb->s_id, + (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode), req->wb_bytes, (long long)req_offset(req)); if (status < 0) { diff --git a/trunk/fs/nfsd/nfs4recover.c b/trunk/fs/nfsd/nfs4recover.c index 29d77f60585b..ffb59ef6f82f 100644 --- a/trunk/fs/nfsd/nfs4recover.c +++ b/trunk/fs/nfsd/nfs4recover.c @@ -191,42 +191,52 @@ nfsd4_build_namelist(void *arg, const char *name, int namlen, } static int -nfsd4_list_rec_dir(recdir_func *f) +nfsd4_list_rec_dir(struct dentry *dir, recdir_func *f) { const struct cred *original_cred; - struct dentry *dir = rec_file->f_path.dentry; + struct file *filp; LIST_HEAD(names); + struct name_list *entry; + struct dentry *dentry; int status; + if (!rec_file) + return 0; + status = nfs4_save_creds(&original_cred); if (status < 0) return status; - status = vfs_llseek(rec_file, 0, SEEK_SET); - if (status < 0) { - nfs4_reset_creds(original_cred); - return status; - } - - status = vfs_readdir(rec_file, nfsd4_build_namelist, &names); + filp = dentry_open(dget(dir), mntget(rec_file->f_path.mnt), O_RDONLY, + current_cred()); + status = PTR_ERR(filp); + if (IS_ERR(filp)) + goto out; + status = vfs_readdir(filp, nfsd4_build_namelist, &names); + fput(filp); mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); while (!list_empty(&names)) { - struct name_list *entry; entry = list_entry(names.next, struct name_list, list); - if (!status) { - struct dentry *dentry; - dentry = lookup_one_len(entry->name, dir, HEXDIR_LEN-1); - if (IS_ERR(dentry)) { - status = PTR_ERR(dentry); - break; - } - status = f(dir, dentry); - dput(dentry); + + dentry = lookup_one_len(entry->name, dir, HEXDIR_LEN-1); + if (IS_ERR(dentry)) { + status = PTR_ERR(dentry); + break; } + status = f(dir, dentry); + dput(dentry); + if (status) + break; list_del(&entry->list); kfree(entry); } mutex_unlock(&dir->d_inode->i_mutex); +out: + while (!list_empty(&names)) { + entry = list_entry(names.next, struct name_list, list); + list_del(&entry->list); + kfree(entry); + } nfs4_reset_creds(original_cred); return status; } @@ -312,7 +322,7 @@ nfsd4_recdir_purge_old(void) { status = mnt_want_write(rec_file->f_path.mnt); if (status) goto out; - status = nfsd4_list_rec_dir(purge_old); + status = nfsd4_list_rec_dir(rec_file->f_path.dentry, purge_old); if (status == 0) vfs_fsync(rec_file, 0); mnt_drop_write(rec_file->f_path.mnt); @@ -342,7 +352,7 @@ nfsd4_recdir_load(void) { if (!rec_file) return 0; - status = nfsd4_list_rec_dir(load_recdir); + status = nfsd4_list_rec_dir(rec_file->f_path.dentry, load_recdir); if (status) printk("nfsd4: failed loading clients from recovery" " directory %s\n", rec_file->f_path.dentry->d_name.name); diff --git a/trunk/fs/nilfs2/file.c b/trunk/fs/nilfs2/file.c index 26601529dc17..d7eeca62febd 100644 --- a/trunk/fs/nilfs2/file.c +++ b/trunk/fs/nilfs2/file.c @@ -27,7 +27,7 @@ #include "nilfs.h" #include "segment.h" -int nilfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) +int nilfs_sync_file(struct file *file, int datasync) { /* * Called from fsync() system call @@ -40,15 +40,8 @@ int nilfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) struct inode *inode = file->f_mapping->host; int err; - err = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (err) - return err; - mutex_lock(&inode->i_mutex); - - if (!nilfs_inode_dirty(inode)) { - mutex_unlock(&inode->i_mutex); + if (!nilfs_inode_dirty(inode)) return 0; - } if (datasync) err = nilfs_construct_dsync_segment(inode->i_sb, inode, 0, @@ -56,7 +49,6 @@ int nilfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) else err = nilfs_construct_segment(inode->i_sb); - mutex_unlock(&inode->i_mutex); return err; } diff --git a/trunk/fs/nilfs2/inode.c b/trunk/fs/nilfs2/inode.c index 666628b395f1..b9b45fc2903e 100644 --- a/trunk/fs/nilfs2/inode.c +++ b/trunk/fs/nilfs2/inode.c @@ -259,8 +259,8 @@ nilfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, return 0; /* Needs synchronization with the cleaner */ - size = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, - nilfs_get_block); + size = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, + offset, nr_segs, nilfs_get_block, NULL); /* * In case of error extending write may have instantiated a few @@ -778,8 +778,6 @@ int nilfs_setattr(struct dentry *dentry, struct iattr *iattr) if ((iattr->ia_valid & ATTR_SIZE) && iattr->ia_size != i_size_read(inode)) { - inode_dio_wait(inode); - err = vmtruncate(inode, iattr->ia_size); if (unlikely(err)) goto out_err; @@ -801,14 +799,14 @@ int nilfs_setattr(struct dentry *dentry, struct iattr *iattr) return err; } -int nilfs_permission(struct inode *inode, int mask) +int nilfs_permission(struct inode *inode, int mask, unsigned int flags) { struct nilfs_root *root = NILFS_I(inode)->i_root; if ((mask & MAY_WRITE) && root && root->cno != NILFS_CPTREE_CURRENT_CNO) return -EROFS; /* snapshot is not writable */ - return generic_permission(inode, mask); + return generic_permission(inode, mask, flags, NULL); } int nilfs_load_inode_block(struct inode *inode, struct buffer_head **pbh) diff --git a/trunk/fs/nilfs2/namei.c b/trunk/fs/nilfs2/namei.c index a3141990061e..546849b3e88f 100644 --- a/trunk/fs/nilfs2/namei.c +++ b/trunk/fs/nilfs2/namei.c @@ -72,7 +72,12 @@ nilfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) return ERR_PTR(-ENAMETOOLONG); ino = nilfs_inode_by_name(dir, &dentry->d_name); - inode = ino ? nilfs_iget(dir->i_sb, NILFS_I(dir)->i_root, ino) : NULL; + inode = NULL; + if (ino) { + inode = nilfs_iget(dir->i_sb, NILFS_I(dir)->i_root, ino); + if (IS_ERR(inode)) + return ERR_CAST(inode); + } return d_splice_alias(inode, dentry); } diff --git a/trunk/fs/nilfs2/nilfs.h b/trunk/fs/nilfs2/nilfs.h index 255d5e1c03b7..f02b9ad43a21 100644 --- a/trunk/fs/nilfs2/nilfs.h +++ b/trunk/fs/nilfs2/nilfs.h @@ -235,7 +235,7 @@ extern void nilfs_set_link(struct inode *, struct nilfs_dir_entry *, struct page *, struct inode *); /* file.c */ -extern int nilfs_sync_file(struct file *, loff_t, loff_t, int); +extern int nilfs_sync_file(struct file *, int); /* ioctl.c */ long nilfs_ioctl(struct file *, unsigned int, unsigned long); @@ -264,7 +264,7 @@ extern void nilfs_update_inode(struct inode *, struct buffer_head *); extern void nilfs_truncate(struct inode *); extern void nilfs_evict_inode(struct inode *); extern int nilfs_setattr(struct dentry *, struct iattr *); -int nilfs_permission(struct inode *inode, int mask); +int nilfs_permission(struct inode *inode, int mask, unsigned int flags); int nilfs_load_inode_block(struct inode *inode, struct buffer_head **pbh); extern int nilfs_inode_dirty(struct inode *); int nilfs_set_file_dirty(struct inode *inode, unsigned nr_dirty); diff --git a/trunk/fs/ntfs/dir.c b/trunk/fs/ntfs/dir.c index 99e36107ff60..0f48e7c5d9e1 100644 --- a/trunk/fs/ntfs/dir.c +++ b/trunk/fs/ntfs/dir.c @@ -1527,20 +1527,13 @@ static int ntfs_dir_open(struct inode *vi, struct file *filp) * this problem for now. We do write the $BITMAP attribute if it is present * which is the important one for a directory so things are not too bad. */ -static int ntfs_dir_fsync(struct file *filp, loff_t start, loff_t end, - int datasync) +static int ntfs_dir_fsync(struct file *filp, int datasync) { struct inode *bmp_vi, *vi = filp->f_mapping->host; int err, ret; ntfs_attr na; ntfs_debug("Entering for inode 0x%lx.", vi->i_ino); - - err = filemap_write_and_wait_range(vi->i_mapping, start, end); - if (err) - return err; - mutex_lock(&vi->i_mutex); - BUG_ON(!S_ISDIR(vi->i_mode)); /* If the bitmap attribute inode is in memory sync it, too. */ na.mft_no = vi->i_ino; @@ -1562,7 +1555,6 @@ static int ntfs_dir_fsync(struct file *filp, loff_t start, loff_t end, else ntfs_warning(vi->i_sb, "Failed to f%ssync inode 0x%lx. Error " "%u.", datasync ? "data" : "", vi->i_ino, -ret); - mutex_unlock(&vi->i_mutex); return ret; } diff --git a/trunk/fs/ntfs/file.c b/trunk/fs/ntfs/file.c index c587e2d27183..f4b1057abdd2 100644 --- a/trunk/fs/ntfs/file.c +++ b/trunk/fs/ntfs/file.c @@ -1832,8 +1832,9 @@ static ssize_t ntfs_file_buffered_write(struct kiocb *iocb, * fails again. */ if (unlikely(NInoTruncateFailed(ni))) { - inode_dio_wait(vi); + down_write(&vi->i_alloc_sem); err = ntfs_truncate(vi); + up_write(&vi->i_alloc_sem); if (err || NInoTruncateFailed(ni)) { if (!err) err = -EIO; @@ -2152,19 +2153,12 @@ static ssize_t ntfs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, * with this inode but since we have no simple way of getting to them we ignore * this problem for now. */ -static int ntfs_file_fsync(struct file *filp, loff_t start, loff_t end, - int datasync) +static int ntfs_file_fsync(struct file *filp, int datasync) { struct inode *vi = filp->f_mapping->host; int err, ret = 0; ntfs_debug("Entering for inode 0x%lx.", vi->i_ino); - - err = filemap_write_and_wait_range(vi->i_mapping, start, end); - if (err) - return err; - mutex_lock(&vi->i_mutex); - BUG_ON(S_ISDIR(vi->i_mode)); if (!datasync || !NInoNonResident(NTFS_I(vi))) ret = __ntfs_write_inode(vi, 1); @@ -2182,7 +2176,6 @@ static int ntfs_file_fsync(struct file *filp, loff_t start, loff_t end, else ntfs_warning(vi->i_sb, "Failed to f%ssync inode 0x%lx. Error " "%u.", datasync ? "data" : "", vi->i_ino, -ret); - mutex_unlock(&vi->i_mutex); return ret; } diff --git a/trunk/fs/ntfs/inode.c b/trunk/fs/ntfs/inode.c index 1371487da955..c05d6dcf77a4 100644 --- a/trunk/fs/ntfs/inode.c +++ b/trunk/fs/ntfs/inode.c @@ -2357,7 +2357,12 @@ static const char *es = " Leaving inconsistent metadata. Unmount and run " * * Returns 0 on success or -errno on error. * - * Called with ->i_mutex held. + * Called with ->i_mutex held. In all but one case ->i_alloc_sem is held for + * writing. The only case in the kernel where ->i_alloc_sem is not held is + * mm/filemap.c::generic_file_buffered_write() where vmtruncate() is called + * with the current i_size as the offset. The analogous place in NTFS is in + * fs/ntfs/file.c::ntfs_file_buffered_write() where we call vmtruncate() again + * without holding ->i_alloc_sem. */ int ntfs_truncate(struct inode *vi) { @@ -2882,7 +2887,8 @@ void ntfs_truncate_vfs(struct inode *vi) { * We also abort all changes of user, group, and mode as we do not implement * the NTFS ACLs yet. * - * Called with ->i_mutex held. + * Called with ->i_mutex held. For the ATTR_SIZE (i.e. ->truncate) case, also + * called with ->i_alloc_sem held for writing. */ int ntfs_setattr(struct dentry *dentry, struct iattr *attr) { diff --git a/trunk/fs/ocfs2/acl.c b/trunk/fs/ocfs2/acl.c index 1cee970eb55a..e913ad130fdd 100644 --- a/trunk/fs/ocfs2/acl.c +++ b/trunk/fs/ocfs2/acl.c @@ -290,14 +290,14 @@ static int ocfs2_set_acl(handle_t *handle, return ret; } -int ocfs2_check_acl(struct inode *inode, int mask) +int ocfs2_check_acl(struct inode *inode, int mask, unsigned int flags) { struct ocfs2_super *osb; struct buffer_head *di_bh = NULL; struct posix_acl *acl; int ret = -EAGAIN; - if (mask & MAY_NOT_BLOCK) + if (flags & IPERM_FLAG_RCU) return -ECHILD; osb = OCFS2_SB(inode->i_sb); diff --git a/trunk/fs/ocfs2/acl.h b/trunk/fs/ocfs2/acl.h index 5c5d31f05853..4fe7c9cf4bfb 100644 --- a/trunk/fs/ocfs2/acl.h +++ b/trunk/fs/ocfs2/acl.h @@ -26,7 +26,7 @@ struct ocfs2_acl_entry { __le32 e_id; }; -extern int ocfs2_check_acl(struct inode *, int); +extern int ocfs2_check_acl(struct inode *, int, unsigned int); extern int ocfs2_acl_chmod(struct inode *); extern int ocfs2_init_acl(handle_t *, struct inode *, struct inode *, struct buffer_head *, struct buffer_head *, diff --git a/trunk/fs/ocfs2/aops.c b/trunk/fs/ocfs2/aops.c index c1efe939c774..ac97bca282d2 100644 --- a/trunk/fs/ocfs2/aops.c +++ b/trunk/fs/ocfs2/aops.c @@ -551,8 +551,9 @@ static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock, /* * ocfs2_dio_end_io is called by the dio core when a dio is finished. We're - * particularly interested in the aio/dio case. We use the rw_lock DLM lock - * to protect io on one node from truncation on another. + * particularly interested in the aio/dio case. Like the core uses + * i_alloc_sem, we use the rw_lock DLM lock to protect io on one node from + * truncation on another. */ static void ocfs2_dio_end_io(struct kiocb *iocb, loff_t offset, @@ -567,8 +568,10 @@ static void ocfs2_dio_end_io(struct kiocb *iocb, /* this io's submitter should not have unlocked this before we could */ BUG_ON(!ocfs2_iocb_is_rw_locked(iocb)); - if (ocfs2_iocb_is_sem_locked(iocb)) + if (ocfs2_iocb_is_sem_locked(iocb)) { + up_read(&inode->i_alloc_sem); ocfs2_iocb_clear_sem_locked(iocb); + } ocfs2_iocb_clear_rw_locked(iocb); @@ -577,7 +580,6 @@ static void ocfs2_dio_end_io(struct kiocb *iocb, if (is_async) aio_complete(iocb, ret, 0); - inode_dio_done(inode); } /* diff --git a/trunk/fs/ocfs2/file.c b/trunk/fs/ocfs2/file.c index 0fc2bd34039d..b1e35a392ca5 100644 --- a/trunk/fs/ocfs2/file.c +++ b/trunk/fs/ocfs2/file.c @@ -171,8 +171,7 @@ static int ocfs2_dir_release(struct inode *inode, struct file *file) return 0; } -static int ocfs2_sync_file(struct file *file, loff_t start, loff_t end, - int datasync) +static int ocfs2_sync_file(struct file *file, int datasync) { int err = 0; journal_t *journal; @@ -185,16 +184,6 @@ static int ocfs2_sync_file(struct file *file, loff_t start, loff_t end, file->f_path.dentry->d_name.name, (unsigned long long)datasync); - err = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (err) - return err; - - /* - * Probably don't need the i_mutex at all in here, just putting it here - * to be consistent with how fsync used to be called, someone more - * familiar with the fs could possibly remove it. - */ - mutex_lock(&inode->i_mutex); if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) { /* * We still have to flush drive's caches to get data to the @@ -211,7 +200,6 @@ static int ocfs2_sync_file(struct file *file, loff_t start, loff_t end, bail: if (err) mlog_errno(err); - mutex_unlock(&inode->i_mutex); return (err < 0) ? -EIO : 0; } @@ -1154,8 +1142,6 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) if (status) goto bail_unlock; - inode_dio_wait(inode); - if (i_size_read(inode) > attr->ia_size) { if (ocfs2_should_order_data(inode)) { status = ocfs2_begin_ordered_truncate(inode, @@ -1293,11 +1279,11 @@ int ocfs2_getattr(struct vfsmount *mnt, return err; } -int ocfs2_permission(struct inode *inode, int mask) +int ocfs2_permission(struct inode *inode, int mask, unsigned int flags) { int ret; - if (mask & MAY_NOT_BLOCK) + if (flags & IPERM_FLAG_RCU) return -ECHILD; ret = ocfs2_inode_lock(inode, NULL, 0); @@ -1307,7 +1293,7 @@ int ocfs2_permission(struct inode *inode, int mask) goto out; } - ret = generic_permission(inode, mask); + ret = generic_permission(inode, mask, flags, ocfs2_check_acl); ocfs2_inode_unlock(inode, 0); out: @@ -2250,8 +2236,9 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb, ocfs2_iocb_clear_sem_locked(iocb); relock: - /* to match setattr's i_mutex -> rw_lock ordering */ + /* to match setattr's i_mutex -> i_alloc_sem -> rw_lock ordering */ if (direct_io) { + down_read(&inode->i_alloc_sem); have_alloc_sem = 1; /* communicate with ocfs2_dio_end_io */ ocfs2_iocb_set_sem_locked(iocb); @@ -2303,6 +2290,7 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb, */ if (direct_io && !can_do_direct) { ocfs2_rw_unlock(inode, rw_level); + up_read(&inode->i_alloc_sem); have_alloc_sem = 0; rw_level = -1; @@ -2373,7 +2361,8 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb, /* * deep in g_f_a_w_n()->ocfs2_direct_IO we pass in a ocfs2_dio_end_io * function pointer which is called when o_direct io completes so that - * it can unlock our rw lock. + * it can unlock our rw lock. (it's the clustered equivalent of + * i_alloc_sem; protects truncate from racing with pending ios). * Unfortunately there are error cases which call end_io and others * that don't. so we don't have to unlock the rw_lock if either an * async dio is going to do it in the future or an end_io after an @@ -2389,8 +2378,10 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb, ocfs2_rw_unlock(inode, rw_level); out_sems: - if (have_alloc_sem) + if (have_alloc_sem) { + up_read(&inode->i_alloc_sem); ocfs2_iocb_clear_sem_locked(iocb); + } mutex_unlock(&inode->i_mutex); @@ -2540,6 +2531,7 @@ static ssize_t ocfs2_file_aio_read(struct kiocb *iocb, * need locks to protect pending reads from racing with truncate. */ if (filp->f_flags & O_DIRECT) { + down_read(&inode->i_alloc_sem); have_alloc_sem = 1; ocfs2_iocb_set_sem_locked(iocb); @@ -2582,9 +2574,10 @@ static ssize_t ocfs2_file_aio_read(struct kiocb *iocb, } bail: - if (have_alloc_sem) + if (have_alloc_sem) { + up_read(&inode->i_alloc_sem); ocfs2_iocb_clear_sem_locked(iocb); - + } if (rw_level != -1) ocfs2_rw_unlock(inode, rw_level); @@ -2600,14 +2593,12 @@ const struct inode_operations ocfs2_file_iops = { .listxattr = ocfs2_listxattr, .removexattr = generic_removexattr, .fiemap = ocfs2_fiemap, - .check_acl = ocfs2_check_acl, }; const struct inode_operations ocfs2_special_file_iops = { .setattr = ocfs2_setattr, .getattr = ocfs2_getattr, .permission = ocfs2_permission, - .check_acl = ocfs2_check_acl, }; /* diff --git a/trunk/fs/ocfs2/file.h b/trunk/fs/ocfs2/file.h index 97bf761c9e7c..f5afbbef6703 100644 --- a/trunk/fs/ocfs2/file.h +++ b/trunk/fs/ocfs2/file.h @@ -61,7 +61,7 @@ int ocfs2_zero_extend(struct inode *inode, struct buffer_head *di_bh, int ocfs2_setattr(struct dentry *dentry, struct iattr *attr); int ocfs2_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); -int ocfs2_permission(struct inode *inode, int mask); +int ocfs2_permission(struct inode *inode, int mask, unsigned int flags); int ocfs2_should_update_atime(struct inode *inode, struct vfsmount *vfsmnt); diff --git a/trunk/fs/ocfs2/namei.c b/trunk/fs/ocfs2/namei.c index 33889dc52dd7..e5d738cd9cc0 100644 --- a/trunk/fs/ocfs2/namei.c +++ b/trunk/fs/ocfs2/namei.c @@ -2498,5 +2498,4 @@ const struct inode_operations ocfs2_dir_iops = { .listxattr = ocfs2_listxattr, .removexattr = generic_removexattr, .fiemap = ocfs2_fiemap, - .check_acl = ocfs2_check_acl, }; diff --git a/trunk/fs/ocfs2/refcounttree.c b/trunk/fs/ocfs2/refcounttree.c index cf7823382664..ebfd3825f12a 100644 --- a/trunk/fs/ocfs2/refcounttree.c +++ b/trunk/fs/ocfs2/refcounttree.c @@ -4368,6 +4368,25 @@ static inline int ocfs2_may_create(struct inode *dir, struct dentry *child) return inode_permission(dir, MAY_WRITE | MAY_EXEC); } +/* copied from user_path_parent. */ +static int ocfs2_user_path_parent(const char __user *path, + struct nameidata *nd, char **name) +{ + char *s = getname(path); + int error; + + if (IS_ERR(s)) + return PTR_ERR(s); + + error = kern_path_parent(s, nd); + if (error) + putname(s); + else + *name = s; + + return error; +} + /** * ocfs2_vfs_reflink - Create a reference-counted link * @@ -4441,8 +4460,10 @@ int ocfs2_reflink_ioctl(struct inode *inode, bool preserve) { struct dentry *new_dentry; - struct path old_path, new_path; + struct nameidata nd; + struct path old_path; int error; + char *to = NULL; if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb))) return -EOPNOTSUPP; @@ -4453,33 +4474,39 @@ int ocfs2_reflink_ioctl(struct inode *inode, return error; } - new_dentry = user_path_create(AT_FDCWD, newname, &new_path, 0); - error = PTR_ERR(new_dentry); - if (IS_ERR(new_dentry)) { + error = ocfs2_user_path_parent(newname, &nd, &to); + if (error) { mlog_errno(error); goto out; } error = -EXDEV; - if (old_path.mnt != new_path.mnt) { + if (old_path.mnt != nd.path.mnt) + goto out_release; + new_dentry = lookup_create(&nd, 0); + error = PTR_ERR(new_dentry); + if (IS_ERR(new_dentry)) { mlog_errno(error); - goto out_dput; + goto out_unlock; } - error = mnt_want_write(new_path.mnt); + error = mnt_want_write(nd.path.mnt); if (error) { mlog_errno(error); goto out_dput; } error = ocfs2_vfs_reflink(old_path.dentry, - new_path.dentry->d_inode, + nd.path.dentry->d_inode, new_dentry, preserve); - mnt_drop_write(new_path.mnt); + mnt_drop_write(nd.path.mnt); out_dput: dput(new_dentry); - mutex_unlock(&new_path.dentry->d_inode->i_mutex); - path_put(&new_path); +out_unlock: + mutex_unlock(&nd.path.dentry->d_inode->i_mutex); +out_release: + path_put(&nd.path); + putname(to); out: path_put(&old_path); diff --git a/trunk/fs/open.c b/trunk/fs/open.c index 739b751aa73e..b52cf013ffa1 100644 --- a/trunk/fs/open.c +++ b/trunk/fs/open.c @@ -793,7 +793,7 @@ struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry return nd->intent.open.file; out_err: release_open_intent(nd); - nd->intent.open.file = ERR_CAST(dentry); + nd->intent.open.file = (struct file *)dentry; goto out; } EXPORT_SYMBOL_GPL(lookup_instantiate_filp); diff --git a/trunk/fs/proc/base.c b/trunk/fs/proc/base.c index 91fb655a5cbf..c47719aaadef 100644 --- a/trunk/fs/proc/base.c +++ b/trunk/fs/proc/base.c @@ -673,7 +673,7 @@ static int mounts_open_common(struct inode *inode, struct file *file, p->m.private = p; p->ns = ns; p->root = root; - p->m.poll_event = ns->event; + p->event = ns->event; return 0; @@ -2167,9 +2167,9 @@ static const struct file_operations proc_fd_operations = { * /proc/pid/fd needs a special permission handler so that a process can still * access /proc/self/fd after it has executed a setuid(). */ -static int proc_fd_permission(struct inode *inode, int mask) +static int proc_fd_permission(struct inode *inode, int mask, unsigned int flags) { - int rv = generic_permission(inode, mask); + int rv = generic_permission(inode, mask, flags, NULL); if (rv == 0) return 0; if (task_pid(current) == proc_pid(inode)) diff --git a/trunk/fs/proc/proc_sysctl.c b/trunk/fs/proc/proc_sysctl.c index 1a77dbef226f..d167de365a8d 100644 --- a/trunk/fs/proc/proc_sysctl.c +++ b/trunk/fs/proc/proc_sysctl.c @@ -294,7 +294,7 @@ static int proc_sys_readdir(struct file *filp, void *dirent, filldir_t filldir) return ret; } -static int proc_sys_permission(struct inode *inode, int mask) +static int proc_sys_permission(struct inode *inode, int mask,unsigned int flags) { /* * sysctl entries that are not writeable, @@ -316,7 +316,7 @@ static int proc_sys_permission(struct inode *inode, int mask) if (!table) /* global root - r-xr-xr-x */ error = mask & MAY_WRITE ? -EACCES : 0; else /* Use the permissions on the sysctl table entry */ - error = sysctl_perm(head->root, table, mask & ~MAY_NOT_BLOCK); + error = sysctl_perm(head->root, table, mask); sysctl_head_finish(head); return error; diff --git a/trunk/fs/read_write.c b/trunk/fs/read_write.c index 5907b49e4d7e..5520f8ad5504 100644 --- a/trunk/fs/read_write.c +++ b/trunk/fs/read_write.c @@ -64,23 +64,6 @@ generic_file_llseek_unlocked(struct file *file, loff_t offset, int origin) return file->f_pos; offset += file->f_pos; break; - case SEEK_DATA: - /* - * In the generic case the entire file is data, so as long as - * offset isn't at the end of the file then the offset is data. - */ - if (offset >= inode->i_size) - return -ENXIO; - break; - case SEEK_HOLE: - /* - * There is a virtual hole at the end of the file, so as long as - * offset isn't i_size or larger, return i_size. - */ - if (offset >= inode->i_size) - return -ENXIO; - offset = inode->i_size; - break; } if (offset < 0 && !unsigned_offsets(file)) @@ -145,13 +128,12 @@ EXPORT_SYMBOL(no_llseek); loff_t default_llseek(struct file *file, loff_t offset, int origin) { - struct inode *inode = file->f_path.dentry->d_inode; loff_t retval; - mutex_lock(&inode->i_mutex); + mutex_lock(&file->f_dentry->d_inode->i_mutex); switch (origin) { case SEEK_END: - offset += i_size_read(inode); + offset += i_size_read(file->f_path.dentry->d_inode); break; case SEEK_CUR: if (offset == 0) { @@ -159,26 +141,6 @@ loff_t default_llseek(struct file *file, loff_t offset, int origin) goto out; } offset += file->f_pos; - break; - case SEEK_DATA: - /* - * In the generic case the entire file is data, so as - * long as offset isn't at the end of the file then the - * offset is data. - */ - if (offset >= inode->i_size) - return -ENXIO; - break; - case SEEK_HOLE: - /* - * There is a virtual hole at the end of the file, so - * as long as offset isn't i_size or larger, return - * i_size. - */ - if (offset >= inode->i_size) - return -ENXIO; - offset = inode->i_size; - break; } retval = -EINVAL; if (offset >= 0 || unsigned_offsets(file)) { @@ -189,7 +151,7 @@ loff_t default_llseek(struct file *file, loff_t offset, int origin) retval = offset; } out: - mutex_unlock(&inode->i_mutex); + mutex_unlock(&file->f_dentry->d_inode->i_mutex); return retval; } EXPORT_SYMBOL(default_llseek); diff --git a/trunk/fs/reiserfs/dir.c b/trunk/fs/reiserfs/dir.c index 133e9355dc6f..198dabf1b2bb 100644 --- a/trunk/fs/reiserfs/dir.c +++ b/trunk/fs/reiserfs/dir.c @@ -14,8 +14,7 @@ extern const struct reiserfs_key MIN_KEY; static int reiserfs_readdir(struct file *, void *, filldir_t); -static int reiserfs_dir_fsync(struct file *filp, loff_t start, loff_t end, - int datasync); +static int reiserfs_dir_fsync(struct file *filp, int datasync); const struct file_operations reiserfs_dir_operations = { .llseek = generic_file_llseek, @@ -28,21 +27,13 @@ const struct file_operations reiserfs_dir_operations = { #endif }; -static int reiserfs_dir_fsync(struct file *filp, loff_t start, loff_t end, - int datasync) +static int reiserfs_dir_fsync(struct file *filp, int datasync) { struct inode *inode = filp->f_mapping->host; int err; - - err = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (err) - return err; - - mutex_lock(&inode->i_mutex); reiserfs_write_lock(inode->i_sb); err = reiserfs_commit_for_inode(inode); reiserfs_write_unlock(inode->i_sb); - mutex_unlock(&inode->i_mutex); if (err < 0) return err; return 0; diff --git a/trunk/fs/reiserfs/file.c b/trunk/fs/reiserfs/file.c index c7156dc39ce7..91f080cc76c8 100644 --- a/trunk/fs/reiserfs/file.c +++ b/trunk/fs/reiserfs/file.c @@ -140,18 +140,12 @@ static void reiserfs_vfs_truncate_file(struct inode *inode) * be removed... */ -static int reiserfs_sync_file(struct file *filp, loff_t start, loff_t end, - int datasync) +static int reiserfs_sync_file(struct file *filp, int datasync) { struct inode *inode = filp->f_mapping->host; int err; int barrier_done; - err = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (err) - return err; - - mutex_lock(&inode->i_mutex); BUG_ON(!S_ISREG(inode->i_mode)); err = sync_mapping_buffers(inode->i_mapping); reiserfs_write_lock(inode->i_sb); @@ -159,7 +153,6 @@ static int reiserfs_sync_file(struct file *filp, loff_t start, loff_t end, reiserfs_write_unlock(inode->i_sb); if (barrier_done != 1 && reiserfs_barrier_flush(inode->i_sb)) blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); - mutex_unlock(&inode->i_mutex); if (barrier_done < 0) return barrier_done; return (err < 0) ? -EIO : 0; @@ -319,5 +312,4 @@ const struct inode_operations reiserfs_file_inode_operations = { .listxattr = reiserfs_listxattr, .removexattr = reiserfs_removexattr, .permission = reiserfs_permission, - .check_acl = reiserfs_check_acl, }; diff --git a/trunk/fs/reiserfs/inode.c b/trunk/fs/reiserfs/inode.c index 2922b90ceac1..4fd5bb33dbb5 100644 --- a/trunk/fs/reiserfs/inode.c +++ b/trunk/fs/reiserfs/inode.c @@ -3068,8 +3068,9 @@ static ssize_t reiserfs_direct_IO(int rw, struct kiocb *iocb, struct inode *inode = file->f_mapping->host; ssize_t ret; - ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, - reiserfs_get_blocks_direct_io); + ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, + offset, nr_segs, + reiserfs_get_blocks_direct_io, NULL); /* * In case of error extending write may have instantiated a few @@ -3113,9 +3114,6 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) error = -EFBIG; goto out; } - - inode_dio_wait(inode); - /* fill in hole pointers in the expanding truncate case. */ if (attr->ia_size > inode->i_size) { error = generic_cont_expand_simple(inode, attr->ia_size); diff --git a/trunk/fs/reiserfs/namei.c b/trunk/fs/reiserfs/namei.c index 551f1b79dbc4..118662690cdf 100644 --- a/trunk/fs/reiserfs/namei.c +++ b/trunk/fs/reiserfs/namei.c @@ -1529,7 +1529,6 @@ const struct inode_operations reiserfs_dir_inode_operations = { .listxattr = reiserfs_listxattr, .removexattr = reiserfs_removexattr, .permission = reiserfs_permission, - .check_acl = reiserfs_check_acl, }; /* @@ -1546,7 +1545,6 @@ const struct inode_operations reiserfs_symlink_inode_operations = { .listxattr = reiserfs_listxattr, .removexattr = reiserfs_removexattr, .permission = reiserfs_permission, - .check_acl = reiserfs_check_acl, }; @@ -1560,5 +1558,5 @@ const struct inode_operations reiserfs_special_inode_operations = { .listxattr = reiserfs_listxattr, .removexattr = reiserfs_removexattr, .permission = reiserfs_permission, - .check_acl = reiserfs_check_acl, + }; diff --git a/trunk/fs/reiserfs/super.c b/trunk/fs/reiserfs/super.c index 14363b96b6af..aa91089162cb 100644 --- a/trunk/fs/reiserfs/super.c +++ b/trunk/fs/reiserfs/super.c @@ -1643,7 +1643,6 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) /* Set default values for options: non-aggressive tails, RO on errors */ REISERFS_SB(s)->s_mount_opt |= (1 << REISERFS_SMALLTAIL); REISERFS_SB(s)->s_mount_opt |= (1 << REISERFS_ERROR_RO); - REISERFS_SB(s)->s_mount_opt |= (1 << REISERFS_BARRIER_FLUSH); /* no preallocation minimum, be smart in reiserfs_file_write instead */ REISERFS_SB(s)->s_alloc_options.preallocmin = 0; diff --git a/trunk/fs/reiserfs/xattr.c b/trunk/fs/reiserfs/xattr.c index 6938d8c68d6e..d78089690965 100644 --- a/trunk/fs/reiserfs/xattr.c +++ b/trunk/fs/reiserfs/xattr.c @@ -555,10 +555,11 @@ reiserfs_xattr_set_handle(struct reiserfs_transaction_handle *th, reiserfs_write_unlock(inode->i_sb); mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_XATTR); - inode_dio_wait(dentry->d_inode); + down_write(&dentry->d_inode->i_alloc_sem); reiserfs_write_lock(inode->i_sb); err = reiserfs_setattr(dentry, &newattrs); + up_write(&dentry->d_inode->i_alloc_sem); mutex_unlock(&dentry->d_inode->i_mutex); } else update_ctime(inode); @@ -867,18 +868,12 @@ ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size) return err; } -int reiserfs_check_acl(struct inode *inode, int mask) +static int reiserfs_check_acl(struct inode *inode, int mask, unsigned int flags) { struct posix_acl *acl; int error = -EAGAIN; /* do regular unix permission checks by default */ - /* - * Stat data v1 doesn't support ACLs. - */ - if (get_inode_sd_version(inode) == STAT_DATA_V1) - return -EAGAIN; - - if (mask & MAY_NOT_BLOCK) + if (flags & IPERM_FLAG_RCU) return -ECHILD; acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS); @@ -957,7 +952,7 @@ static int xattr_mount_check(struct super_block *s) return 0; } -int reiserfs_permission(struct inode *inode, int mask) +int reiserfs_permission(struct inode *inode, int mask, unsigned int flags) { /* * We don't do permission checks on the internal objects. @@ -966,7 +961,15 @@ int reiserfs_permission(struct inode *inode, int mask) if (IS_PRIVATE(inode)) return 0; - return generic_permission(inode, mask); +#ifdef CONFIG_REISERFS_FS_XATTR + /* + * Stat data v1 doesn't support ACLs. + */ + if (get_inode_sd_version(inode) != STAT_DATA_V1) + return generic_permission(inode, mask, flags, + reiserfs_check_acl); +#endif + return generic_permission(inode, mask, flags, NULL); } static int xattr_hide_revalidate(struct dentry *dentry, struct nameidata *nd) diff --git a/trunk/fs/squashfs/namei.c b/trunk/fs/squashfs/namei.c index 0682b38d7e31..4bc63ac64bc0 100644 --- a/trunk/fs/squashfs/namei.c +++ b/trunk/fs/squashfs/namei.c @@ -220,6 +220,11 @@ static struct dentry *squashfs_lookup(struct inode *dir, struct dentry *dentry, blk, off, ino_num); inode = squashfs_iget(dir->i_sb, ino, ino_num); + if (IS_ERR(inode)) { + err = PTR_ERR(inode); + goto failed; + } + goto exit_lookup; } } @@ -227,7 +232,10 @@ static struct dentry *squashfs_lookup(struct inode *dir, struct dentry *dentry, exit_lookup: kfree(dire); - return d_splice_alias(inode, dentry); + if (inode) + return d_splice_alias(inode, dentry); + d_add(dentry, inode); + return ERR_PTR(0); data_error: err = -EIO; diff --git a/trunk/fs/super.c b/trunk/fs/super.c index 7943f04cb3a9..ab3d672db0de 100644 --- a/trunk/fs/super.c +++ b/trunk/fs/super.c @@ -38,69 +38,6 @@ LIST_HEAD(super_blocks); DEFINE_SPINLOCK(sb_lock); -/* - * One thing we have to be careful of with a per-sb shrinker is that we don't - * drop the last active reference to the superblock from within the shrinker. - * If that happens we could trigger unregistering the shrinker from within the - * shrinker path and that leads to deadlock on the shrinker_rwsem. Hence we - * take a passive reference to the superblock to avoid this from occurring. - */ -static int prune_super(struct shrinker *shrink, struct shrink_control *sc) -{ - struct super_block *sb; - int fs_objects = 0; - int total_objects; - - sb = container_of(shrink, struct super_block, s_shrink); - - /* - * Deadlock avoidance. We may hold various FS locks, and we don't want - * to recurse into the FS that called us in clear_inode() and friends.. - */ - if (sc->nr_to_scan && !(sc->gfp_mask & __GFP_FS)) - return -1; - - if (!grab_super_passive(sb)) - return -1; - - if (sb->s_op && sb->s_op->nr_cached_objects) - fs_objects = sb->s_op->nr_cached_objects(sb); - - total_objects = sb->s_nr_dentry_unused + - sb->s_nr_inodes_unused + fs_objects + 1; - - if (sc->nr_to_scan) { - int dentries; - int inodes; - - /* proportion the scan between the caches */ - dentries = (sc->nr_to_scan * sb->s_nr_dentry_unused) / - total_objects; - inodes = (sc->nr_to_scan * sb->s_nr_inodes_unused) / - total_objects; - if (fs_objects) - fs_objects = (sc->nr_to_scan * fs_objects) / - total_objects; - /* - * prune the dcache first as the icache is pinned by it, then - * prune the icache, followed by the filesystem specific caches - */ - prune_dcache_sb(sb, dentries); - prune_icache_sb(sb, inodes); - - if (fs_objects && sb->s_op->free_cached_objects) { - sb->s_op->free_cached_objects(sb, fs_objects); - fs_objects = sb->s_op->nr_cached_objects(sb); - } - total_objects = sb->s_nr_dentry_unused + - sb->s_nr_inodes_unused + fs_objects; - } - - total_objects = (total_objects / 100) * sysctl_vfs_cache_pressure; - drop_super(sb); - return total_objects; -} - /** * alloc_super - create new superblock * @type: filesystem type superblock should belong to @@ -140,8 +77,6 @@ static struct super_block *alloc_super(struct file_system_type *type) INIT_HLIST_BL_HEAD(&s->s_anon); INIT_LIST_HEAD(&s->s_inodes); INIT_LIST_HEAD(&s->s_dentry_lru); - INIT_LIST_HEAD(&s->s_inode_lru); - spin_lock_init(&s->s_inode_lru_lock); init_rwsem(&s->s_umount); mutex_init(&s->s_lock); lockdep_set_class(&s->s_umount, &type->s_umount_key); @@ -179,10 +114,6 @@ static struct super_block *alloc_super(struct file_system_type *type) s->s_op = &default_op; s->s_time_gran = 1000000000; s->cleancache_poolid = -1; - - s->s_shrink.seeks = DEFAULT_SEEKS; - s->s_shrink.shrink = prune_super; - s->s_shrink.batch = 1024; } out: return s; @@ -250,10 +181,6 @@ void deactivate_locked_super(struct super_block *s) if (atomic_dec_and_test(&s->s_active)) { cleancache_flush_fs(s); fs->kill_sb(s); - - /* caches are now gone, we can safely kill the shrinker now */ - unregister_shrinker(&s->s_shrink); - /* * We need to call rcu_barrier so all the delayed rcu free * inodes are flushed before we release the fs module. @@ -313,39 +240,6 @@ static int grab_super(struct super_block *s) __releases(sb_lock) return 0; } -/* - * grab_super_passive - acquire a passive reference - * @s: reference we are trying to grab - * - * Tries to acquire a passive reference. This is used in places where we - * cannot take an active reference but we need to ensure that the - * superblock does not go away while we are working on it. It returns - * false if a reference was not gained, and returns true with the s_umount - * lock held in read mode if a reference is gained. On successful return, - * the caller must drop the s_umount lock and the passive reference when - * done. - */ -bool grab_super_passive(struct super_block *sb) -{ - spin_lock(&sb_lock); - if (list_empty(&sb->s_instances)) { - spin_unlock(&sb_lock); - return false; - } - - sb->s_count++; - spin_unlock(&sb_lock); - - if (down_read_trylock(&sb->s_umount)) { - if (sb->s_root) - return true; - up_read(&sb->s_umount); - } - - put_super(sb); - return false; -} - /* * Superblock locking. We really ought to get rid of these two. */ @@ -382,6 +276,7 @@ void generic_shutdown_super(struct super_block *sb) { const struct super_operations *sop = sb->s_op; + if (sb->s_root) { shrink_dcache_for_umount(sb); sync_filesystem(sb); @@ -469,7 +364,6 @@ struct super_block *sget(struct file_system_type *type, list_add(&s->s_instances, &type->fs_supers); spin_unlock(&sb_lock); get_filesystem(type); - register_shrinker(&s->s_shrink); return s; } @@ -557,42 +451,6 @@ void iterate_supers(void (*f)(struct super_block *, void *), void *arg) spin_unlock(&sb_lock); } -/** - * iterate_supers_type - call function for superblocks of given type - * @type: fs type - * @f: function to call - * @arg: argument to pass to it - * - * Scans the superblock list and calls given function, passing it - * locked superblock and given argument. - */ -void iterate_supers_type(struct file_system_type *type, - void (*f)(struct super_block *, void *), void *arg) -{ - struct super_block *sb, *p = NULL; - - spin_lock(&sb_lock); - list_for_each_entry(sb, &type->fs_supers, s_instances) { - sb->s_count++; - spin_unlock(&sb_lock); - - down_read(&sb->s_umount); - if (sb->s_root) - f(sb, arg); - up_read(&sb->s_umount); - - spin_lock(&sb_lock); - if (p) - __put_super(p); - p = sb; - } - if (p) - __put_super(p); - spin_unlock(&sb_lock); -} - -EXPORT_SYMBOL(iterate_supers_type); - /** * get_super - get the superblock of a device * @bdev: device to get the superblock for @@ -799,7 +657,7 @@ static DEFINE_IDA(unnamed_dev_ida); static DEFINE_SPINLOCK(unnamed_dev_lock);/* protects the above */ static int unnamed_dev_start = 0; /* don't bother trying below it */ -int get_anon_bdev(dev_t *p) +int set_anon_super(struct super_block *s, void *data) { int dev; int error; @@ -826,38 +684,24 @@ int get_anon_bdev(dev_t *p) spin_unlock(&unnamed_dev_lock); return -EMFILE; } - *p = MKDEV(0, dev & MINORMASK); + s->s_dev = MKDEV(0, dev & MINORMASK); + s->s_bdi = &noop_backing_dev_info; return 0; } -EXPORT_SYMBOL(get_anon_bdev); -void free_anon_bdev(dev_t dev) +EXPORT_SYMBOL(set_anon_super); + +void kill_anon_super(struct super_block *sb) { - int slot = MINOR(dev); + int slot = MINOR(sb->s_dev); + + generic_shutdown_super(sb); spin_lock(&unnamed_dev_lock); ida_remove(&unnamed_dev_ida, slot); if (slot < unnamed_dev_start) unnamed_dev_start = slot; spin_unlock(&unnamed_dev_lock); } -EXPORT_SYMBOL(free_anon_bdev); - -int set_anon_super(struct super_block *s, void *data) -{ - int error = get_anon_bdev(&s->s_dev); - if (!error) - s->s_bdi = &noop_backing_dev_info; - return error; -} - -EXPORT_SYMBOL(set_anon_super); - -void kill_anon_super(struct super_block *sb) -{ - dev_t dev = sb->s_dev; - generic_shutdown_super(sb); - free_anon_bdev(dev); -} EXPORT_SYMBOL(kill_anon_super); diff --git a/trunk/fs/sync.c b/trunk/fs/sync.c index c98a7477edfd..c38ec163da6c 100644 --- a/trunk/fs/sync.c +++ b/trunk/fs/sync.c @@ -165,9 +165,28 @@ SYSCALL_DEFINE1(syncfs, int, fd) */ int vfs_fsync_range(struct file *file, loff_t start, loff_t end, int datasync) { - if (!file->f_op || !file->f_op->fsync) - return -EINVAL; - return file->f_op->fsync(file, start, end, datasync); + struct address_space *mapping = file->f_mapping; + int err, ret; + + if (!file->f_op || !file->f_op->fsync) { + ret = -EINVAL; + goto out; + } + + ret = filemap_write_and_wait_range(mapping, start, end); + + /* + * We need to protect against concurrent writers, which could cause + * livelocks in fsync_buffers_list(). + */ + mutex_lock(&mapping->host->i_mutex); + err = file->f_op->fsync(file, datasync); + if (!ret) + ret = err; + mutex_unlock(&mapping->host->i_mutex); + +out: + return ret; } EXPORT_SYMBOL(vfs_fsync_range); diff --git a/trunk/fs/sysfs/inode.c b/trunk/fs/sysfs/inode.c index e3f091a81c72..0a12eb89cd32 100644 --- a/trunk/fs/sysfs/inode.c +++ b/trunk/fs/sysfs/inode.c @@ -349,11 +349,11 @@ int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const void *ns, const cha return -ENOENT; } -int sysfs_permission(struct inode *inode, int mask) +int sysfs_permission(struct inode *inode, int mask, unsigned int flags) { struct sysfs_dirent *sd; - if (mask & MAY_NOT_BLOCK) + if (flags & IPERM_FLAG_RCU) return -ECHILD; sd = inode->i_private; @@ -362,5 +362,5 @@ int sysfs_permission(struct inode *inode, int mask) sysfs_refresh_inode(sd, inode); mutex_unlock(&sysfs_mutex); - return generic_permission(inode, mask); + return generic_permission(inode, mask, flags, NULL); } diff --git a/trunk/fs/sysfs/sysfs.h b/trunk/fs/sysfs/sysfs.h index 845ab3ad229d..2ed2404f3113 100644 --- a/trunk/fs/sysfs/sysfs.h +++ b/trunk/fs/sysfs/sysfs.h @@ -201,7 +201,7 @@ static inline void __sysfs_put(struct sysfs_dirent *sd) struct inode *sysfs_get_inode(struct super_block *sb, struct sysfs_dirent *sd); void sysfs_evict_inode(struct inode *inode); int sysfs_sd_setattr(struct sysfs_dirent *sd, struct iattr *iattr); -int sysfs_permission(struct inode *inode, int mask); +int sysfs_permission(struct inode *inode, int mask, unsigned int flags); int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, diff --git a/trunk/fs/ubifs/file.c b/trunk/fs/ubifs/file.c index f9c234bf33d3..7cf738a4544d 100644 --- a/trunk/fs/ubifs/file.c +++ b/trunk/fs/ubifs/file.c @@ -1304,7 +1304,7 @@ static void *ubifs_follow_link(struct dentry *dentry, struct nameidata *nd) return NULL; } -int ubifs_fsync(struct file *file, loff_t start, loff_t end, int datasync) +int ubifs_fsync(struct file *file, int datasync) { struct inode *inode = file->f_mapping->host; struct ubifs_info *c = inode->i_sb->s_fs_info; @@ -1319,16 +1319,14 @@ int ubifs_fsync(struct file *file, loff_t start, loff_t end, int datasync) */ return 0; - err = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (err) - return err; - mutex_lock(&inode->i_mutex); - - /* Synchronize the inode unless this is a 'datasync()' call. */ + /* + * VFS has already synchronized dirty pages for this inode. Synchronize + * the inode unless this is a 'datasync()' call. + */ if (!datasync || (inode->i_state & I_DIRTY_DATASYNC)) { err = inode->i_sb->s_op->write_inode(inode, NULL); if (err) - goto out; + return err; } /* @@ -1336,9 +1334,10 @@ int ubifs_fsync(struct file *file, loff_t start, loff_t end, int datasync) * them. */ err = ubifs_sync_wbufs_by_inode(c, inode); -out: - mutex_unlock(&inode->i_mutex); - return err; + if (err) + return err; + + return 0; } /** diff --git a/trunk/fs/ubifs/ubifs.h b/trunk/fs/ubifs/ubifs.h index 27f22551f805..702b79258e30 100644 --- a/trunk/fs/ubifs/ubifs.h +++ b/trunk/fs/ubifs/ubifs.h @@ -1729,7 +1729,7 @@ const struct ubifs_lprops *ubifs_fast_find_frdi_idx(struct ubifs_info *c); int ubifs_calc_dark(const struct ubifs_info *c, int spc); /* file.c */ -int ubifs_fsync(struct file *file, loff_t start, loff_t end, int datasync); +int ubifs_fsync(struct file *file, int datasync); int ubifs_setattr(struct dentry *dentry, struct iattr *attr); /* dir.c */ diff --git a/trunk/fs/udf/file.c b/trunk/fs/udf/file.c index d8ffa7cc661d..2a346bb1d9f5 100644 --- a/trunk/fs/udf/file.c +++ b/trunk/fs/udf/file.c @@ -150,7 +150,7 @@ long udf_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) long old_block, new_block; int result = -EINVAL; - if (inode_permission(inode, MAY_READ) != 0) { + if (file_permission(filp, MAY_READ) != 0) { udf_debug("no permission to access inode %lu\n", inode->i_ino); result = -EPERM; goto out; diff --git a/trunk/fs/ufs/namei.c b/trunk/fs/ufs/namei.c index 639d49162241..b57aab9a1184 100644 --- a/trunk/fs/ufs/namei.c +++ b/trunk/fs/ufs/namei.c @@ -59,6 +59,8 @@ static struct dentry *ufs_lookup(struct inode * dir, struct dentry *dentry, stru if (ino) inode = ufs_iget(dir->i_sb, ino); unlock_ufs(dir->i_sb); + if (IS_ERR(inode)) + return ERR_CAST(inode); return d_splice_alias(inode, dentry); } diff --git a/trunk/fs/xfs/linux-2.6/xfs_acl.c b/trunk/fs/xfs/linux-2.6/xfs_acl.c index cac48fe22ad5..115ac6919533 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_acl.c +++ b/trunk/fs/xfs/linux-2.6/xfs_acl.c @@ -219,7 +219,7 @@ xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) } int -xfs_check_acl(struct inode *inode, int mask) +xfs_check_acl(struct inode *inode, int mask, unsigned int flags) { struct xfs_inode *ip; struct posix_acl *acl; @@ -235,7 +235,7 @@ xfs_check_acl(struct inode *inode, int mask) if (!XFS_IFORK_Q(ip)) return -EAGAIN; - if (mask & MAY_NOT_BLOCK) { + if (flags & IPERM_FLAG_RCU) { if (!negative_cached_acl(inode, ACL_TYPE_ACCESS)) return -ECHILD; return -EAGAIN; diff --git a/trunk/fs/xfs/linux-2.6/xfs_aops.c b/trunk/fs/xfs/linux-2.6/xfs_aops.c index 63e971e2b837..26384fe3f26d 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_aops.c +++ b/trunk/fs/xfs/linux-2.6/xfs_aops.c @@ -1329,9 +1329,6 @@ xfs_end_io_direct_write( } else { xfs_finish_ioend_sync(ioend); } - - /* XXX: probably should move into the real I/O completion handler */ - inode_dio_done(ioend->io_inode); } STATIC ssize_t diff --git a/trunk/fs/xfs/linux-2.6/xfs_file.c b/trunk/fs/xfs/linux-2.6/xfs_file.c index cca00f49e092..8073f61efb8e 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_file.c +++ b/trunk/fs/xfs/linux-2.6/xfs_file.c @@ -127,8 +127,6 @@ xfs_iozero( STATIC int xfs_file_fsync( struct file *file, - loff_t start, - loff_t end, int datasync) { struct inode *inode = file->f_mapping->host; @@ -140,10 +138,6 @@ xfs_file_fsync( trace_xfs_file_fsync(ip); - error = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (error) - return error; - if (XFS_FORCED_SHUTDOWN(mp)) return -XFS_ERROR(EIO); @@ -881,11 +875,18 @@ xfs_file_aio_write( /* Handle various SYNC-type writes */ if ((file->f_flags & O_DSYNC) || IS_SYNC(inode)) { loff_t end = pos + ret - 1; + int error, error2; xfs_rw_iunlock(ip, iolock); - ret = -xfs_file_fsync(file, pos, end, - (file->f_flags & __O_SYNC) ? 0 : 1); + error = filemap_write_and_wait_range(mapping, pos, end); xfs_rw_ilock(ip, iolock); + + error2 = -xfs_file_fsync(file, + (file->f_flags & __O_SYNC) ? 0 : 1); + if (error) + ret = error; + else if (error2) + ret = error2; } out_unlock: diff --git a/trunk/fs/xfs/linux-2.6/xfs_super.c b/trunk/fs/xfs/linux-2.6/xfs_super.c index 9a72dda58bd0..25fd2cd6c8b0 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_super.c +++ b/trunk/fs/xfs/linux-2.6/xfs_super.c @@ -1024,6 +1024,11 @@ xfs_fs_put_super( { struct xfs_mount *mp = XFS_M(sb); + /* + * Unregister the memory shrinker before we tear down the mount + * structure so we don't have memory reclaim racing with us here. + */ + xfs_inode_shrinker_unregister(mp); xfs_syncd_stop(mp); /* @@ -1406,6 +1411,8 @@ xfs_fs_fill_super( sb->s_time_gran = 1; set_posix_acl_flag(sb); + xfs_inode_shrinker_register(mp); + error = xfs_mountfs(mp); if (error) goto out_filestream_unmount; @@ -1432,6 +1439,7 @@ xfs_fs_fill_super( return 0; out_filestream_unmount: + xfs_inode_shrinker_unregister(mp); xfs_filestream_unmount(mp); out_free_sb: xfs_freesb(mp); @@ -1450,6 +1458,8 @@ xfs_fs_fill_super( out_syncd_stop: xfs_syncd_stop(mp); out_unmount: + xfs_inode_shrinker_unregister(mp); + /* * Blow away any referenced inode in the filestreams cache. * This can and will cause log traffic as inodes go inactive @@ -1473,21 +1483,6 @@ xfs_fs_mount( return mount_bdev(fs_type, flags, dev_name, data, xfs_fs_fill_super); } -static int -xfs_fs_nr_cached_objects( - struct super_block *sb) -{ - return xfs_reclaim_inodes_count(XFS_M(sb)); -} - -static void -xfs_fs_free_cached_objects( - struct super_block *sb, - int nr_to_scan) -{ - xfs_reclaim_inodes_nr(XFS_M(sb), nr_to_scan); -} - static const struct super_operations xfs_super_operations = { .alloc_inode = xfs_fs_alloc_inode, .destroy_inode = xfs_fs_destroy_inode, @@ -1501,8 +1496,6 @@ static const struct super_operations xfs_super_operations = { .statfs = xfs_fs_statfs, .remount_fs = xfs_fs_remount, .show_options = xfs_fs_show_options, - .nr_cached_objects = xfs_fs_nr_cached_objects, - .free_cached_objects = xfs_fs_free_cached_objects, }; static struct file_system_type xfs_fs_type = { diff --git a/trunk/fs/xfs/linux-2.6/xfs_sync.c b/trunk/fs/xfs/linux-2.6/xfs_sync.c index e4c938afb910..5cc158e52d4c 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_sync.c +++ b/trunk/fs/xfs/linux-2.6/xfs_sync.c @@ -179,8 +179,6 @@ xfs_inode_ag_walk( if (error == EFSCORRUPTED) break; - cond_resched(); - } while (nr_found && !done); if (skipped) { @@ -986,8 +984,6 @@ xfs_reclaim_inodes_ag( *nr_to_scan -= XFS_LOOKUP_BATCH; - cond_resched(); - } while (nr_found && !done && *nr_to_scan > 0); if (trylock && !done) @@ -1005,7 +1001,7 @@ xfs_reclaim_inodes_ag( * ensure that when we get more reclaimers than AGs we block rather * than spin trying to execute reclaim. */ - if (skipped && (flags & SYNC_WAIT) && *nr_to_scan > 0) { + if (trylock && skipped && *nr_to_scan > 0) { trylock = 0; goto restart; } @@ -1023,38 +1019,44 @@ xfs_reclaim_inodes( } /* - * Scan a certain number of inodes for reclaim. + * Inode cache shrinker. * * When called we make sure that there is a background (fast) inode reclaim in - * progress, while we will throttle the speed of reclaim via doing synchronous + * progress, while we will throttle the speed of reclaim via doiing synchronous * reclaim of inodes. That means if we come across dirty inodes, we wait for * them to be cleaned, which we hope will not be very long due to the * background walker having already kicked the IO off on those dirty inodes. */ -void -xfs_reclaim_inodes_nr( - struct xfs_mount *mp, - int nr_to_scan) +static int +xfs_reclaim_inode_shrink( + struct shrinker *shrink, + struct shrink_control *sc) { - /* kick background reclaimer and push the AIL */ - xfs_syncd_queue_reclaim(mp); - xfs_ail_push_all(mp->m_ail); + struct xfs_mount *mp; + struct xfs_perag *pag; + xfs_agnumber_t ag; + int reclaimable; + int nr_to_scan = sc->nr_to_scan; + gfp_t gfp_mask = sc->gfp_mask; + + mp = container_of(shrink, struct xfs_mount, m_inode_shrink); + if (nr_to_scan) { + /* kick background reclaimer and push the AIL */ + xfs_syncd_queue_reclaim(mp); + xfs_ail_push_all(mp->m_ail); - xfs_reclaim_inodes_ag(mp, SYNC_TRYLOCK | SYNC_WAIT, &nr_to_scan); -} + if (!(gfp_mask & __GFP_FS)) + return -1; -/* - * Return the number of reclaimable inodes in the filesystem for - * the shrinker to determine how much to reclaim. - */ -int -xfs_reclaim_inodes_count( - struct xfs_mount *mp) -{ - struct xfs_perag *pag; - xfs_agnumber_t ag = 0; - int reclaimable = 0; + xfs_reclaim_inodes_ag(mp, SYNC_TRYLOCK | SYNC_WAIT, + &nr_to_scan); + /* terminate if we don't exhaust the scan */ + if (nr_to_scan > 0) + return -1; + } + reclaimable = 0; + ag = 0; while ((pag = xfs_perag_get_tag(mp, ag, XFS_ICI_RECLAIM_TAG))) { ag = pag->pag_agno + 1; reclaimable += pag->pag_ici_reclaimable; @@ -1063,3 +1065,18 @@ xfs_reclaim_inodes_count( return reclaimable; } +void +xfs_inode_shrinker_register( + struct xfs_mount *mp) +{ + mp->m_inode_shrink.shrink = xfs_reclaim_inode_shrink; + mp->m_inode_shrink.seeks = DEFAULT_SEEKS; + register_shrinker(&mp->m_inode_shrink); +} + +void +xfs_inode_shrinker_unregister( + struct xfs_mount *mp) +{ + unregister_shrinker(&mp->m_inode_shrink); +} diff --git a/trunk/fs/xfs/linux-2.6/xfs_sync.h b/trunk/fs/xfs/linux-2.6/xfs_sync.h index 941202e7ac6e..e914fd621746 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_sync.h +++ b/trunk/fs/xfs/linux-2.6/xfs_sync.h @@ -35,8 +35,6 @@ void xfs_quiesce_attr(struct xfs_mount *mp); void xfs_flush_inodes(struct xfs_inode *ip); int xfs_reclaim_inodes(struct xfs_mount *mp, int mode); -int xfs_reclaim_inodes_count(struct xfs_mount *mp); -void xfs_reclaim_inodes_nr(struct xfs_mount *mp, int nr_to_scan); void xfs_inode_set_reclaim_tag(struct xfs_inode *ip); void __xfs_inode_set_reclaim_tag(struct xfs_perag *pag, struct xfs_inode *ip); @@ -48,4 +46,7 @@ int xfs_inode_ag_iterator(struct xfs_mount *mp, int (*execute)(struct xfs_inode *ip, struct xfs_perag *pag, int flags), int flags); +void xfs_inode_shrinker_register(struct xfs_mount *mp); +void xfs_inode_shrinker_unregister(struct xfs_mount *mp); + #endif diff --git a/trunk/fs/xfs/xfs_acl.h b/trunk/fs/xfs/xfs_acl.h index 0135e2a669d7..11dd72070cbb 100644 --- a/trunk/fs/xfs/xfs_acl.h +++ b/trunk/fs/xfs/xfs_acl.h @@ -42,7 +42,7 @@ struct xfs_acl { #define SGI_ACL_DEFAULT_SIZE (sizeof(SGI_ACL_DEFAULT)-1) #ifdef CONFIG_XFS_POSIX_ACL -extern int xfs_check_acl(struct inode *inode, int mask); +extern int xfs_check_acl(struct inode *inode, int mask, unsigned int flags); extern struct posix_acl *xfs_get_acl(struct inode *inode, int type); extern int xfs_inherit_acl(struct inode *inode, struct posix_acl *default_acl); extern int xfs_acl_chmod(struct inode *inode); diff --git a/trunk/include/asm-generic/delay.h b/trunk/include/asm-generic/delay.h index 0f79054ce7cd..4586fec75ddb 100644 --- a/trunk/include/asm-generic/delay.h +++ b/trunk/include/asm-generic/delay.h @@ -1,44 +1,9 @@ #ifndef __ASM_GENERIC_DELAY_H #define __ASM_GENERIC_DELAY_H -/* Undefined functions to get compile-time errors */ -extern void __bad_udelay(void); -extern void __bad_ndelay(void); - extern void __udelay(unsigned long usecs); -extern void __ndelay(unsigned long nsecs); -extern void __const_udelay(unsigned long xloops); extern void __delay(unsigned long loops); -/* - * The weird n/20000 thing suppresses a "comparison is always false due to - * limited range of data type" warning with non-const 8-bit arguments. - */ - -/* 0x10c7 is 2**32 / 1000000 (rounded up) */ -#define udelay(n) \ - ({ \ - if (__builtin_constant_p(n)) { \ - if ((n) / 20000 >= 1) \ - __bad_udelay(); \ - else \ - __const_udelay((n) * 0x10c7ul); \ - } else { \ - __udelay(n); \ - } \ - }) - -/* 0x5 is 2**32 / 1000000000 (rounded up) */ -#define ndelay(n) \ - ({ \ - if (__builtin_constant_p(n)) { \ - if ((n) / 20000 >= 1) \ - __bad_ndelay(); \ - else \ - __const_udelay((n) * 5ul); \ - } else { \ - __ndelay(n); \ - } \ - }) +#define udelay(n) __udelay(n) #endif /* __ASM_GENERIC_DELAY_H */ diff --git a/trunk/include/asm-generic/io.h b/trunk/include/asm-generic/io.h index 912088773a69..e0ffa3ddb02a 100644 --- a/trunk/include/asm-generic/io.h +++ b/trunk/include/asm-generic/io.h @@ -307,11 +307,7 @@ static inline void *phys_to_virt(unsigned long address) /* * Change "struct page" to physical address. - * - * This implementation is for the no-MMU case only... if you have an MMU - * you'll need to provide your own definitions. */ -#ifndef CONFIG_MMU static inline void __iomem *ioremap(phys_addr_t offset, unsigned long size) { return (void __iomem*) (unsigned long)offset; @@ -330,9 +326,7 @@ static inline void __iomem *ioremap(phys_addr_t offset, unsigned long size) static inline void iounmap(void *addr) { } -#endif /* CONFIG_MMU */ -#ifdef CONFIG_HAS_IOPORT #ifndef CONFIG_GENERIC_IOMAP static inline void __iomem *ioport_map(unsigned long port, unsigned int nr) { @@ -346,10 +340,9 @@ static inline void ioport_unmap(void __iomem *p) extern void __iomem *ioport_map(unsigned long port, unsigned int nr); extern void ioport_unmap(void __iomem *p); #endif /* CONFIG_GENERIC_IOMAP */ -#endif /* CONFIG_HAS_IOPORT */ #define xlate_dev_kmem_ptr(p) p -#define xlate_dev_mem_ptr(p) __va(p) +#define xlate_dev_mem_ptr(p) ((void *) (p)) #ifndef virt_to_bus static inline unsigned long virt_to_bus(volatile void *address) diff --git a/trunk/include/asm-generic/iomap.h b/trunk/include/asm-generic/iomap.h index c74ef2c6e633..76b0cc5637f8 100644 --- a/trunk/include/asm-generic/iomap.h +++ b/trunk/include/asm-generic/iomap.h @@ -56,21 +56,17 @@ extern void iowrite8_rep(void __iomem *port, const void *buf, unsigned long coun extern void iowrite16_rep(void __iomem *port, const void *buf, unsigned long count); extern void iowrite32_rep(void __iomem *port, const void *buf, unsigned long count); -#ifdef CONFIG_HAS_IOPORT /* Create a virtual mapping cookie for an IO port range */ extern void __iomem *ioport_map(unsigned long port, unsigned int nr); extern void ioport_unmap(void __iomem *); -#endif #ifndef ARCH_HAS_IOREMAP_WC #define ioremap_wc ioremap_nocache #endif -#ifdef CONFIG_PCI /* Create a virtual mapping cookie for a PCI BAR (memory or IO) */ struct pci_dev; extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max); extern void pci_iounmap(struct pci_dev *dev, void __iomem *); -#endif #endif diff --git a/trunk/include/linux/anon_inodes.h b/trunk/include/linux/anon_inodes.h index 8013a45242fe..69a21e0ebd33 100644 --- a/trunk/include/linux/anon_inodes.h +++ b/trunk/include/linux/anon_inodes.h @@ -8,8 +8,6 @@ #ifndef _LINUX_ANON_INODES_H #define _LINUX_ANON_INODES_H -struct file_operations; - struct file *anon_inode_getfile(const char *name, const struct file_operations *fops, void *priv, int flags); diff --git a/trunk/include/linux/atomic.h b/trunk/include/linux/atomic.h index bc6615d4132b..ee456c79b0e6 100644 --- a/trunk/include/linux/atomic.h +++ b/trunk/include/linux/atomic.h @@ -34,32 +34,6 @@ static inline int atomic_inc_not_zero_hint(atomic_t *v, int hint) } #endif -#ifndef atomic_inc_unless_negative -static inline int atomic_inc_unless_negative(atomic_t *p) -{ - int v, v1; - for (v = 0; v >= 0; v = v1) { - v1 = atomic_cmpxchg(p, v, v + 1); - if (likely(v1 == v)) - return 1; - } - return 0; -} -#endif - -#ifndef atomic_dec_unless_positive -static inline int atomic_dec_unless_positive(atomic_t *p) -{ - int v, v1; - for (v = 0; v <= 0; v = v1) { - v1 = atomic_cmpxchg(p, v, v - 1); - if (likely(v1 == v)) - return 1; - } - return 0; -} -#endif - #ifndef CONFIG_ARCH_HAS_ATOMIC_OR static inline void atomic_or(int i, atomic_t *v) { diff --git a/trunk/include/linux/binfmts.h b/trunk/include/linux/binfmts.h index fd88a3945aa1..8845613fd7e3 100644 --- a/trunk/include/linux/binfmts.h +++ b/trunk/include/linux/binfmts.h @@ -111,7 +111,6 @@ extern int __must_check remove_arg_zero(struct linux_binprm *); extern int search_binary_handler(struct linux_binprm *, struct pt_regs *); extern int flush_old_exec(struct linux_binprm * bprm); extern void setup_new_exec(struct linux_binprm * bprm); -extern void would_dump(struct linux_binprm *, struct file *); extern int suid_dumpable; #define SUID_DUMP_DISABLE 0 /* No setuid dumping */ diff --git a/trunk/include/linux/bit_spinlock.h b/trunk/include/linux/bit_spinlock.h index 564d997e2168..b4326bfa684f 100644 --- a/trunk/include/linux/bit_spinlock.h +++ b/trunk/include/linux/bit_spinlock.h @@ -88,7 +88,7 @@ static inline int bit_spin_is_locked(int bitnum, unsigned long *addr) { #if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) return test_bit(bitnum, addr); -#elif defined CONFIG_PREEMPT_COUNT +#elif defined CONFIG_PREEMPT return preempt_count(); #else return 1; diff --git a/trunk/include/linux/clocksource.h b/trunk/include/linux/clocksource.h index 139c4db55f17..18a1baf31f2d 100644 --- a/trunk/include/linux/clocksource.h +++ b/trunk/include/linux/clocksource.h @@ -22,10 +22,6 @@ typedef u64 cycle_t; struct clocksource; -#ifdef CONFIG_ARCH_CLOCKSOURCE_DATA -#include -#endif - /** * struct cyclecounter - hardware abstraction for a free running counter * Provides completely state-free accessors to the underlying hardware. @@ -157,7 +153,7 @@ extern u64 timecounter_cyc2time(struct timecounter *tc, * @shift: cycle to nanosecond divisor (power of two) * @max_idle_ns: max idle time permitted by the clocksource (nsecs) * @flags: flags describing special properties - * @archdata: arch-specific data + * @vread: vsyscall based read * @suspend: suspend function for the clocksource, if necessary * @resume: resume function for the clocksource, if necessary */ @@ -173,13 +169,16 @@ struct clocksource { u32 shift; u64 max_idle_ns; -#ifdef CONFIG_ARCH_CLOCKSOURCE_DATA - struct arch_clocksource_data archdata; +#ifdef CONFIG_IA64 + void *fsys_mmio; /* used by fsyscall asm code */ +#define CLKSRC_FSYS_MMIO_SET(mmio, addr) ((mmio) = (addr)) +#else +#define CLKSRC_FSYS_MMIO_SET(mmio, addr) do { } while (0) #endif - const char *name; struct list_head list; int rating; + cycle_t (*vread)(void); int (*enable)(struct clocksource *cs); void (*disable)(struct clocksource *cs); unsigned long flags; diff --git a/trunk/include/linux/dcache.h b/trunk/include/linux/dcache.h index 3f22d8d6d8a3..19d90a55541d 100644 --- a/trunk/include/linux/dcache.h +++ b/trunk/include/linux/dcache.h @@ -216,7 +216,6 @@ struct dentry_operations { #define DCACHE_MOUNTED 0x10000 /* is a mountpoint */ #define DCACHE_NEED_AUTOMOUNT 0x20000 /* handle automount on this dir */ #define DCACHE_MANAGE_TRANSIT 0x40000 /* manage transit from this dirent */ -#define DCACHE_NEED_LOOKUP 0x80000 /* dentry requires i_op->lookup */ #define DCACHE_MANAGED_DENTRY \ (DCACHE_MOUNTED|DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT) @@ -417,12 +416,7 @@ static inline bool d_mountpoint(struct dentry *dentry) return dentry->d_flags & DCACHE_MOUNTED; } -static inline bool d_need_lookup(struct dentry *dentry) -{ - return dentry->d_flags & DCACHE_NEED_LOOKUP; -} - -extern void d_clear_need_lookup(struct dentry *dentry); +extern struct dentry *lookup_create(struct nameidata *nd, int is_dir); extern int sysctl_vfs_cache_pressure; diff --git a/trunk/include/linux/dw_apb_timer.h b/trunk/include/linux/dw_apb_timer.h deleted file mode 100644 index 49638ea3b776..000000000000 --- a/trunk/include/linux/dw_apb_timer.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * (C) Copyright 2009 Intel Corporation - * Author: Jacob Pan (jacob.jun.pan@intel.com) - * - * Shared with ARM platforms, Jamie Iles, Picochip 2011 - * - * 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. - * - * Support for the Synopsys DesignWare APB Timers. - */ -#ifndef __DW_APB_TIMER_H__ -#define __DW_APB_TIMER_H__ - -#include -#include -#include - -#define APBTMRS_REG_SIZE 0x14 - -struct dw_apb_timer { - void __iomem *base; - unsigned long freq; - int irq; -}; - -struct dw_apb_clock_event_device { - struct clock_event_device ced; - struct dw_apb_timer timer; - struct irqaction irqaction; - void (*eoi)(struct dw_apb_timer *); -}; - -struct dw_apb_clocksource { - struct dw_apb_timer timer; - struct clocksource cs; -}; - -void dw_apb_clockevent_register(struct dw_apb_clock_event_device *dw_ced); -void dw_apb_clockevent_pause(struct dw_apb_clock_event_device *dw_ced); -void dw_apb_clockevent_resume(struct dw_apb_clock_event_device *dw_ced); -void dw_apb_clockevent_stop(struct dw_apb_clock_event_device *dw_ced); - -struct dw_apb_clock_event_device * -dw_apb_clockevent_init(int cpu, const char *name, unsigned rating, - void __iomem *base, int irq, unsigned long freq); -struct dw_apb_clocksource * -dw_apb_clocksource_init(unsigned rating, char *name, void __iomem *base, - unsigned long freq); -void dw_apb_clocksource_register(struct dw_apb_clocksource *dw_cs); -void dw_apb_clocksource_start(struct dw_apb_clocksource *dw_cs); -cycle_t dw_apb_clocksource_read(struct dw_apb_clocksource *dw_cs); -void dw_apb_clocksource_unregister(struct dw_apb_clocksource *dw_cs); - -#endif /* __DW_APB_TIMER_H__ */ diff --git a/trunk/include/linux/efi.h b/trunk/include/linux/efi.h index ec2572693925..e376270cd26e 100644 --- a/trunk/include/linux/efi.h +++ b/trunk/include/linux/efi.h @@ -101,13 +101,6 @@ typedef struct { u64 attribute; } efi_memory_desc_t; -typedef struct { - efi_guid_t guid; - u32 headersize; - u32 flags; - u32 imagesize; -} efi_capsule_header_t; - typedef int (*efi_freemem_callback_t) (u64 start, u64 end, void *arg); /* @@ -163,9 +156,6 @@ typedef struct { unsigned long set_variable; unsigned long get_next_high_mono_count; unsigned long reset_system; - unsigned long update_capsule; - unsigned long query_capsule_caps; - unsigned long query_variable_info; } efi_runtime_services_t; typedef efi_status_t efi_get_time_t (efi_time_t *tm, efi_time_cap_t *tc); @@ -178,7 +168,7 @@ typedef efi_status_t efi_get_variable_t (efi_char16_t *name, efi_guid_t *vendor, typedef efi_status_t efi_get_next_variable_t (unsigned long *name_size, efi_char16_t *name, efi_guid_t *vendor); typedef efi_status_t efi_set_variable_t (efi_char16_t *name, efi_guid_t *vendor, - u32 attr, unsigned long data_size, + unsigned long attr, unsigned long data_size, void *data); typedef efi_status_t efi_get_next_high_mono_count_t (u32 *count); typedef void efi_reset_system_t (int reset_type, efi_status_t status, @@ -187,17 +177,6 @@ typedef efi_status_t efi_set_virtual_address_map_t (unsigned long memory_map_siz unsigned long descriptor_size, u32 descriptor_version, efi_memory_desc_t *virtual_map); -typedef efi_status_t efi_query_variable_info_t(u32 attr, - u64 *storage_space, - u64 *remaining_space, - u64 *max_variable_size); -typedef efi_status_t efi_update_capsule_t(efi_capsule_header_t **capsules, - unsigned long count, - unsigned long sg_list); -typedef efi_status_t efi_query_capsule_caps_t(efi_capsule_header_t **capsules, - unsigned long count, - u64 *max_size, - int *reset_type); /* * EFI Configuration Table and GUID definitions @@ -239,13 +218,6 @@ typedef struct { #define EFI_SYSTEM_TABLE_SIGNATURE ((u64)0x5453595320494249ULL) -#define EFI_2_30_SYSTEM_TABLE_REVISION ((2 << 16) | (30)) -#define EFI_2_20_SYSTEM_TABLE_REVISION ((2 << 16) | (20)) -#define EFI_2_10_SYSTEM_TABLE_REVISION ((2 << 16) | (10)) -#define EFI_2_00_SYSTEM_TABLE_REVISION ((2 << 16) | (00)) -#define EFI_1_10_SYSTEM_TABLE_REVISION ((1 << 16) | (10)) -#define EFI_1_02_SYSTEM_TABLE_REVISION ((1 << 16) | (02)) - typedef struct { efi_table_hdr_t hdr; unsigned long fw_vendor; /* physical addr of CHAR16 vendor string */ @@ -278,7 +250,6 @@ struct efi_memory_map { */ extern struct efi { efi_system_table_t *systab; /* EFI system table */ - unsigned int runtime_version; /* Runtime services version */ unsigned long mps; /* MPS table */ unsigned long acpi; /* ACPI table (IA64 ext 0.71) */ unsigned long acpi20; /* ACPI table (ACPI 2.0) */ @@ -295,9 +266,6 @@ extern struct efi { efi_get_variable_t *get_variable; efi_get_next_variable_t *get_next_variable; efi_set_variable_t *set_variable; - efi_query_variable_info_t *query_variable_info; - efi_update_capsule_t *update_capsule; - efi_query_capsule_caps_t *query_capsule_caps; efi_get_next_high_mono_count_t *get_next_high_mono_count; efi_reset_system_t *reset_system; efi_set_virtual_address_map_t *set_virtual_address_map; diff --git a/trunk/include/linux/ext3_fs.h b/trunk/include/linux/ext3_fs.h index 0c473fd79acb..5e06acf95d0f 100644 --- a/trunk/include/linux/ext3_fs.h +++ b/trunk/include/linux/ext3_fs.h @@ -877,7 +877,7 @@ extern int ext3_htree_store_dirent(struct file *dir_file, __u32 hash, extern void ext3_htree_free_dir_info(struct dir_private_info *p); /* fsync.c */ -extern int ext3_sync_file(struct file *, loff_t, loff_t, int); +extern int ext3_sync_file(struct file *, int); /* hash.c */ extern int ext3fs_dirhash(const char *name, int len, struct diff --git a/trunk/include/linux/fb.h b/trunk/include/linux/fb.h index 1d6836c498dd..6a8274877171 100644 --- a/trunk/include/linux/fb.h +++ b/trunk/include/linux/fb.h @@ -1043,8 +1043,7 @@ extern void fb_deferred_io_open(struct fb_info *info, struct inode *inode, struct file *file); extern void fb_deferred_io_cleanup(struct fb_info *info); -extern int fb_deferred_io_fsync(struct file *file, loff_t start, - loff_t end, int datasync); +extern int fb_deferred_io_fsync(struct file *file, int datasync); static inline bool fb_be_math(struct fb_info *info) { diff --git a/trunk/include/linux/fs.h b/trunk/include/linux/fs.h index b224dc468a23..b5b979247863 100644 --- a/trunk/include/linux/fs.h +++ b/trunk/include/linux/fs.h @@ -32,9 +32,7 @@ #define SEEK_SET 0 /* seek relative to beginning of file */ #define SEEK_CUR 1 /* seek relative to current file position */ #define SEEK_END 2 /* seek relative to end of file */ -#define SEEK_DATA 3 /* seek to the next data */ -#define SEEK_HOLE 4 /* seek to the next hole */ -#define SEEK_MAX SEEK_HOLE +#define SEEK_MAX SEEK_END struct fstrim_range { __u64 start; @@ -65,7 +63,6 @@ struct inodes_stat_t { #define MAY_ACCESS 16 #define MAY_OPEN 32 #define MAY_CHDIR 64 -#define MAY_NOT_BLOCK 128 /* called from RCU mode, don't block */ /* * flags in file.f_mode. Note that FMODE_READ and FMODE_WRITE must correspond @@ -395,9 +392,8 @@ struct inodes_stat_t { #include #include #include -#include -#include +#include #include struct export_operations; @@ -781,7 +777,7 @@ struct inode { struct timespec i_ctime; blkcnt_t i_blocks; unsigned short i_bytes; - atomic_t i_dio_count; + struct rw_semaphore i_alloc_sem; const struct file_operations *i_fop; /* former ->i_op->default_file_ops */ struct file_lock *i_flock; struct address_space *i_mapping; @@ -1400,11 +1396,6 @@ struct super_block { struct list_head s_dentry_lru; /* unused dentry lru */ int s_nr_dentry_unused; /* # of dentry on lru */ - /* s_inode_lru_lock protects s_inode_lru and s_nr_inodes_unused */ - spinlock_t s_inode_lru_lock ____cacheline_aligned_in_smp; - struct list_head s_inode_lru; /* unused inode lru */ - int s_nr_inodes_unused; /* # of inodes on lru */ - struct block_device *s_bdev; struct backing_dev_info *s_bdi; struct mtd_info *s_mtd; @@ -1447,14 +1438,8 @@ struct super_block { * Saved pool identifier for cleancache (-1 means none) */ int cleancache_poolid; - - struct shrinker s_shrink; /* per-sb shrinker handle */ }; -/* superblock cache pruning functions */ -extern void prune_icache_sb(struct super_block *sb, int nr_to_scan); -extern void prune_dcache_sb(struct super_block *sb, int nr_to_scan); - extern struct timespec current_fs_time(struct super_block *sb); /* @@ -1505,6 +1490,7 @@ extern void dentry_unhash(struct dentry *dentry); /* * VFS file helper functions. */ +extern int file_permission(struct file *, int); extern void inode_init_owner(struct inode *inode, const struct inode *dir, mode_t mode); /* @@ -1552,6 +1538,11 @@ struct block_device_operations; #define HAVE_COMPAT_IOCTL 1 #define HAVE_UNLOCKED_IOCTL 1 +/* + * NOTE: + * all file operations except setlease can be called without + * the big kernel lock held in all filesystems. + */ struct file_operations { struct module *owner; loff_t (*llseek) (struct file *, loff_t, int); @@ -1567,7 +1558,7 @@ struct file_operations { int (*open) (struct inode *, struct file *); int (*flush) (struct file *, fl_owner_t id); int (*release) (struct inode *, struct file *); - int (*fsync) (struct file *, loff_t, loff_t, int datasync); + int (*fsync) (struct file *, int datasync); int (*aio_fsync) (struct kiocb *, int datasync); int (*fasync) (int, struct file *, int); int (*lock) (struct file *, int, struct file_lock *); @@ -1582,11 +1573,13 @@ struct file_operations { loff_t len); }; +#define IPERM_FLAG_RCU 0x0001 + struct inode_operations { struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *); void * (*follow_link) (struct dentry *, struct nameidata *); - int (*permission) (struct inode *, int); - int (*check_acl)(struct inode *, int); + int (*permission) (struct inode *, int, unsigned int); + int (*check_acl)(struct inode *, int, unsigned int); int (*readlink) (struct dentry *, char __user *,int); void (*put_link) (struct dentry *, struct nameidata *, void *); @@ -1652,8 +1645,6 @@ struct super_operations { ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t); #endif int (*bdev_try_to_free_page)(struct super_block*, struct page*, gfp_t); - int (*nr_cached_objects)(struct super_block *); - void (*free_cached_objects)(struct super_block *, int); }; /* @@ -1702,10 +1693,6 @@ struct super_operations { * set during data writeback, and cleared with a wakeup * on the bit address once it is done. * - * I_REFERENCED Marks the inode as recently references on the LRU list. - * - * I_DIO_WAKEUP Never set. Only used as a key for wait_on_bit(). - * * Q: What is the difference between I_WILL_FREE and I_FREEING? */ #define I_DIRTY_SYNC (1 << 0) @@ -1719,8 +1706,6 @@ struct super_operations { #define __I_SYNC 7 #define I_SYNC (1 << __I_SYNC) #define I_REFERENCED (1 << 8) -#define __I_DIO_WAKEUP 9 -#define I_DIO_WAKEUP (1 << I_DIO_WAKEUP) #define I_DIRTY (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES) @@ -1831,6 +1816,7 @@ struct file_system_type { struct lock_class_key i_lock_key; struct lock_class_key i_mutex_key; struct lock_class_key i_mutex_dir_key; + struct lock_class_key i_alloc_sem_key; }; extern struct dentry *mount_ns(struct file_system_type *fs_type, int flags, @@ -1851,8 +1837,6 @@ void kill_litter_super(struct super_block *sb); void deactivate_super(struct super_block *sb); void deactivate_locked_super(struct super_block *sb); int set_anon_super(struct super_block *s, void *data); -int get_anon_bdev(dev_t *); -void free_anon_bdev(dev_t); struct super_block *sget(struct file_system_type *type, int (*test)(struct super_block *,void *), int (*set)(struct super_block *,void *), @@ -2204,38 +2188,16 @@ extern sector_t bmap(struct inode *, sector_t); #endif extern int notify_change(struct dentry *, struct iattr *); extern int inode_permission(struct inode *, int); -extern int generic_permission(struct inode *, int); +extern int generic_permission(struct inode *, int, unsigned int, + int (*check_acl)(struct inode *, int, unsigned int)); static inline bool execute_ok(struct inode *inode) { return (inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode); } -/* - * get_write_access() gets write permission for a file. - * put_write_access() releases this write permission. - * This is used for regular files. - * We cannot support write (and maybe mmap read-write shared) accesses and - * MAP_DENYWRITE mmappings simultaneously. The i_writecount field of an inode - * can have the following values: - * 0: no writers, no VM_DENYWRITE mappings - * < 0: (-i_writecount) vm_area_structs with VM_DENYWRITE set exist - * > 0: (i_writecount) users are writing to the file. - * - * Normally we operate on that counter with atomic_{inc,dec} and it's safe - * except for the cases where we don't hold i_writecount yet. Then we need to - * use {get,deny}_write_access() - these functions check the sign and refuse - * to do the change if sign is wrong. - */ -static inline int get_write_access(struct inode *inode) -{ - return atomic_inc_unless_negative(&inode->i_writecount) ? 0 : -ETXTBSY; -} -static inline int deny_write_access(struct file *file) -{ - struct inode *inode = file->f_path.dentry->d_inode; - return atomic_dec_unless_positive(&inode->i_writecount) ? 0 : -ETXTBSY; -} +extern int get_write_access(struct inode *); +extern int deny_write_access(struct file *); static inline void put_write_access(struct inode * inode) { atomic_dec(&inode->i_writecount); @@ -2355,8 +2317,7 @@ extern int generic_segment_checks(const struct iovec *iov, /* fs/block_dev.c */ extern ssize_t blkdev_aio_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos); -extern int blkdev_fsync(struct file *filp, loff_t start, loff_t end, - int datasync); +extern int blkdev_fsync(struct file *filp, int datasync); /* fs/splice.c */ extern ssize_t generic_file_splice_read(struct file *, loff_t *, @@ -2407,8 +2368,6 @@ enum { }; void dio_end_io(struct bio *bio, int error); -void inode_dio_wait(struct inode *inode); -void inode_dio_done(struct inode *inode); ssize_t __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, struct block_device *bdev, const struct iovec *iov, loff_t offset, @@ -2416,17 +2375,14 @@ ssize_t __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, dio_submit_t submit_io, int flags); static inline ssize_t blockdev_direct_IO(int rw, struct kiocb *iocb, - struct inode *inode, const struct iovec *iov, loff_t offset, - unsigned long nr_segs, get_block_t get_block) + struct inode *inode, struct block_device *bdev, const struct iovec *iov, + loff_t offset, unsigned long nr_segs, get_block_t get_block, + dio_iodone_t end_io) { - return __blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, - offset, nr_segs, get_block, NULL, NULL, + return __blockdev_direct_IO(rw, iocb, inode, bdev, iov, offset, + nr_segs, get_block, end_io, NULL, DIO_LOCKING | DIO_SKIP_HOLES); } -#else -static inline void inode_dio_wait(struct inode *inode) -{ -} #endif extern const struct file_operations generic_ro_fops; @@ -2476,8 +2432,6 @@ extern struct super_block *get_active_super(struct block_device *bdev); extern struct super_block *user_get_super(dev_t); extern void drop_super(struct super_block *sb); extern void iterate_supers(void (*)(struct super_block *, void *), void *); -extern void iterate_supers_type(struct file_system_type *, - void (*)(struct super_block *, void *), void *); extern int dcache_dir_open(struct inode *, struct file *); extern int dcache_dir_close(struct inode *, struct file *); @@ -2490,7 +2444,7 @@ extern int simple_link(struct dentry *, struct inode *, struct dentry *); extern int simple_unlink(struct inode *, struct dentry *); extern int simple_rmdir(struct inode *, struct dentry *); extern int simple_rename(struct inode *, struct dentry *, struct inode *, struct dentry *); -extern int noop_fsync(struct file *, loff_t, loff_t, int); +extern int noop_fsync(struct file *, int); extern int simple_empty(struct dentry *); extern int simple_readpage(struct file *file, struct page *page); extern int simple_write_begin(struct file *file, struct address_space *mapping, @@ -2515,7 +2469,7 @@ extern ssize_t simple_read_from_buffer(void __user *to, size_t count, extern ssize_t simple_write_to_buffer(void *to, size_t available, loff_t *ppos, const void __user *from, size_t count); -extern int generic_file_fsync(struct file *, loff_t, loff_t, int); +extern int generic_file_fsync(struct file *, int); extern int generic_check_addressable(unsigned, u64); diff --git a/trunk/include/linux/ftrace.h b/trunk/include/linux/ftrace.h index f0c0e8a47ae6..9d88e1cb5dbb 100644 --- a/trunk/include/linux/ftrace.h +++ b/trunk/include/linux/ftrace.h @@ -19,8 +19,6 @@ #include -struct ftrace_hash; - #ifdef CONFIG_FUNCTION_TRACER extern int ftrace_enabled; @@ -31,6 +29,8 @@ ftrace_enable_sysctl(struct ctl_table *table, int write, typedef void (*ftrace_func_t)(unsigned long ip, unsigned long parent_ip); +struct ftrace_hash; + enum { FTRACE_OPS_FL_ENABLED = 1 << 0, FTRACE_OPS_FL_GLOBAL = 1 << 1, @@ -123,8 +123,7 @@ stack_trace_sysctl(struct ctl_table *table, int write, struct ftrace_func_command { struct list_head list; char *name; - int (*func)(struct ftrace_hash *hash, - char *func, char *cmd, + int (*func)(char *func, char *cmd, char *params, int enable); }; diff --git a/trunk/include/linux/ftrace_event.h b/trunk/include/linux/ftrace_event.h index 96efa6794ea5..59d3ef100eb9 100644 --- a/trunk/include/linux/ftrace_event.h +++ b/trunk/include/linux/ftrace_event.h @@ -76,7 +76,6 @@ struct trace_iterator { struct trace_entry *ent; unsigned long lost_events; int leftover; - int ent_size; int cpu; u64 ts; @@ -130,10 +129,6 @@ void trace_current_buffer_unlock_commit(struct ring_buffer *buffer, void trace_nowake_buffer_unlock_commit(struct ring_buffer *buffer, struct ring_buffer_event *event, unsigned long flags, int pc); -void trace_nowake_buffer_unlock_commit_regs(struct ring_buffer *buffer, - struct ring_buffer_event *event, - unsigned long flags, int pc, - struct pt_regs *regs); void trace_current_buffer_discard_commit(struct ring_buffer *buffer, struct ring_buffer_event *event); diff --git a/trunk/include/linux/generic_acl.h b/trunk/include/linux/generic_acl.h index 574bea4013b6..0437e377b555 100644 --- a/trunk/include/linux/generic_acl.h +++ b/trunk/include/linux/generic_acl.h @@ -10,6 +10,6 @@ extern const struct xattr_handler generic_acl_default_handler; int generic_acl_init(struct inode *, struct inode *); int generic_acl_chmod(struct inode *); -int generic_check_acl(struct inode *inode, int mask); +int generic_check_acl(struct inode *inode, int mask, unsigned int flags); #endif /* LINUX_GENERIC_ACL_H */ diff --git a/trunk/include/linux/hardirq.h b/trunk/include/linux/hardirq.h index f743883f769e..ba362171e8ae 100644 --- a/trunk/include/linux/hardirq.h +++ b/trunk/include/linux/hardirq.h @@ -93,7 +93,7 @@ */ #define in_nmi() (preempt_count() & NMI_MASK) -#if defined(CONFIG_PREEMPT_COUNT) +#if defined(CONFIG_PREEMPT) # define PREEMPT_CHECK_OFFSET 1 #else # define PREEMPT_CHECK_OFFSET 0 @@ -115,7 +115,7 @@ #define in_atomic_preempt_off() \ ((preempt_count() & ~PREEMPT_ACTIVE) != PREEMPT_CHECK_OFFSET) -#ifdef CONFIG_PREEMPT_COUNT +#ifdef CONFIG_PREEMPT # define preemptible() (preempt_count() == 0 && !irqs_disabled()) # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1) #else diff --git a/trunk/include/linux/hw_breakpoint.h b/trunk/include/linux/hw_breakpoint.h index 6ae9c631a1be..d1e55fed2c7d 100644 --- a/trunk/include/linux/hw_breakpoint.h +++ b/trunk/include/linux/hw_breakpoint.h @@ -73,7 +73,6 @@ static inline unsigned long hw_breakpoint_len(struct perf_event *bp) extern struct perf_event * register_user_hw_breakpoint(struct perf_event_attr *attr, perf_overflow_handler_t triggered, - void *context, struct task_struct *tsk); /* FIXME: only change from the attr, and don't unregister */ @@ -86,13 +85,11 @@ modify_user_hw_breakpoint(struct perf_event *bp, struct perf_event_attr *attr); extern struct perf_event * register_wide_hw_breakpoint_cpu(struct perf_event_attr *attr, perf_overflow_handler_t triggered, - void *context, int cpu); extern struct perf_event * __percpu * register_wide_hw_breakpoint(struct perf_event_attr *attr, - perf_overflow_handler_t triggered, - void *context); + perf_overflow_handler_t triggered); extern int register_perf_hw_breakpoint(struct perf_event *bp); extern int __register_perf_hw_breakpoint(struct perf_event *bp); @@ -118,7 +115,6 @@ static inline int __init init_hw_breakpoint(void) { return 0; } static inline struct perf_event * register_user_hw_breakpoint(struct perf_event_attr *attr, perf_overflow_handler_t triggered, - void *context, struct task_struct *tsk) { return NULL; } static inline int modify_user_hw_breakpoint(struct perf_event *bp, @@ -126,12 +122,10 @@ modify_user_hw_breakpoint(struct perf_event *bp, static inline struct perf_event * register_wide_hw_breakpoint_cpu(struct perf_event_attr *attr, perf_overflow_handler_t triggered, - void *context, int cpu) { return NULL; } static inline struct perf_event * __percpu * register_wide_hw_breakpoint(struct perf_event_attr *attr, - perf_overflow_handler_t triggered, - void *context) { return NULL; } + perf_overflow_handler_t triggered) { return NULL; } static inline int register_perf_hw_breakpoint(struct perf_event *bp) { return -ENOSYS; } static inline int diff --git a/trunk/include/linux/i8253.h b/trunk/include/linux/i8253.h deleted file mode 100644 index e6bb36a97519..000000000000 --- a/trunk/include/linux/i8253.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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. - * - * Machine specific IO port address definition for generic. - * Written by Osamu Tomita - */ -#ifndef __LINUX_I8253_H -#define __LINUX_I8253_H - -#include -#include -#include - -/* i8253A PIT registers */ -#define PIT_MODE 0x43 -#define PIT_CH0 0x40 -#define PIT_CH2 0x42 - -#define PIT_LATCH ((PIT_TICK_RATE + HZ/2) / HZ) - -extern raw_spinlock_t i8253_lock; -extern struct clock_event_device i8253_clockevent; -extern void clockevent_i8253_init(bool oneshot); - -extern void setup_pit_timer(void); - -#endif /* __LINUX_I8253_H */ diff --git a/trunk/include/linux/iommu.h b/trunk/include/linux/iommu.h index 9940319d6f9d..0a2ba4098996 100644 --- a/trunk/include/linux/iommu.h +++ b/trunk/include/linux/iommu.h @@ -19,8 +19,6 @@ #ifndef __LINUX_IOMMU_H #define __LINUX_IOMMU_H -#include - #define IOMMU_READ (1) #define IOMMU_WRITE (2) #define IOMMU_CACHE (4) /* DMA cache coherency */ diff --git a/trunk/include/linux/irq.h b/trunk/include/linux/irq.h index 5f695041090c..baa397eb9c33 100644 --- a/trunk/include/linux/irq.h +++ b/trunk/include/linux/irq.h @@ -96,6 +96,11 @@ enum { #define IRQ_NO_BALANCING_MASK (IRQ_PER_CPU | IRQ_NO_BALANCING) +static inline __deprecated bool CHECK_IRQ_PER_CPU(unsigned int status) +{ + return status & IRQ_PER_CPU; +} + /* * Return value for chip->irq_set_affinity() * diff --git a/trunk/include/linux/iscsi_boot_sysfs.h b/trunk/include/linux/iscsi_boot_sysfs.h index f0a2f8b0aa13..f1e6c184f14f 100644 --- a/trunk/include/linux/iscsi_boot_sysfs.h +++ b/trunk/include/linux/iscsi_boot_sysfs.h @@ -92,13 +92,6 @@ struct iscsi_boot_kobj { * properties. */ mode_t (*is_visible) (void *data, int type); - - /* - * Driver specific release function. - * - * The function should free the data passed in. - */ - void (*release) (void *data); }; struct iscsi_boot_kset { @@ -110,21 +103,18 @@ struct iscsi_boot_kobj * iscsi_boot_create_initiator(struct iscsi_boot_kset *boot_kset, int index, void *data, ssize_t (*show) (void *data, int type, char *buf), - mode_t (*is_visible) (void *data, int type), - void (*release) (void *data)); + mode_t (*is_visible) (void *data, int type)); struct iscsi_boot_kobj * iscsi_boot_create_ethernet(struct iscsi_boot_kset *boot_kset, int index, void *data, ssize_t (*show) (void *data, int type, char *buf), - mode_t (*is_visible) (void *data, int type), - void (*release) (void *data)); + mode_t (*is_visible) (void *data, int type)); struct iscsi_boot_kobj * iscsi_boot_create_target(struct iscsi_boot_kset *boot_kset, int index, void *data, ssize_t (*show) (void *data, int type, char *buf), - mode_t (*is_visible) (void *data, int type), - void (*release) (void *data)); + mode_t (*is_visible) (void *data, int type)); struct iscsi_boot_kset *iscsi_boot_create_kset(const char *set_name); struct iscsi_boot_kset *iscsi_boot_create_host_kset(unsigned int hostno); diff --git a/trunk/include/linux/kernel.h b/trunk/include/linux/kernel.h index 567a6f7bbeed..953352a88336 100644 --- a/trunk/include/linux/kernel.h +++ b/trunk/include/linux/kernel.h @@ -121,7 +121,7 @@ extern int _cond_resched(void); # define might_resched() do { } while (0) #endif -#ifdef CONFIG_DEBUG_ATOMIC_SLEEP +#ifdef CONFIG_DEBUG_SPINLOCK_SLEEP void __might_sleep(const char *file, int line, int preempt_offset); /** * might_sleep - annotation for functions that can sleep diff --git a/trunk/include/linux/kvm.h b/trunk/include/linux/kvm.h index 2c366b52f505..55ef181521ff 100644 --- a/trunk/include/linux/kvm.h +++ b/trunk/include/linux/kvm.h @@ -161,7 +161,6 @@ struct kvm_pit_config { #define KVM_EXIT_NMI 16 #define KVM_EXIT_INTERNAL_ERROR 17 #define KVM_EXIT_OSI 18 -#define KVM_EXIT_PAPR_HCALL 19 /* For KVM_EXIT_INTERNAL_ERROR */ #define KVM_INTERNAL_ERROR_EMULATION 1 @@ -265,11 +264,6 @@ struct kvm_run { struct { __u64 gprs[32]; } osi; - struct { - __u64 nr; - __u64 ret; - __u64 args[9]; - } papr_hcall; /* Fix the size of the union. */ char padding[256]; }; @@ -550,9 +544,6 @@ struct kvm_ppc_pvinfo { #define KVM_CAP_TSC_CONTROL 60 #define KVM_CAP_GET_TSC_KHZ 61 #define KVM_CAP_PPC_BOOKE_SREGS 62 -#define KVM_CAP_SPAPR_TCE 63 -#define KVM_CAP_PPC_SMT 64 -#define KVM_CAP_PPC_RMA 65 #ifdef KVM_CAP_IRQ_ROUTING @@ -755,9 +746,6 @@ struct kvm_clock_data { /* Available with KVM_CAP_XCRS */ #define KVM_GET_XCRS _IOR(KVMIO, 0xa6, struct kvm_xcrs) #define KVM_SET_XCRS _IOW(KVMIO, 0xa7, struct kvm_xcrs) -#define KVM_CREATE_SPAPR_TCE _IOW(KVMIO, 0xa8, struct kvm_create_spapr_tce) -/* Available with KVM_CAP_RMA */ -#define KVM_ALLOCATE_RMA _IOR(KVMIO, 0xa9, struct kvm_allocate_rma) #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0) @@ -785,14 +773,20 @@ struct kvm_assigned_pci_dev { struct kvm_assigned_irq { __u32 assigned_dev_id; - __u32 host_irq; /* ignored (legacy field) */ + __u32 host_irq; __u32 guest_irq; __u32 flags; union { + struct { + __u32 addr_lo; + __u32 addr_hi; + __u32 data; + } guest_msi; __u32 reserved[12]; }; }; + struct kvm_assigned_msix_nr { __u32 assigned_dev_id; __u16 entry_nr; diff --git a/trunk/include/linux/kvm_host.h b/trunk/include/linux/kvm_host.h index eabb21a30c34..31ebb59cbd2f 100644 --- a/trunk/include/linux/kvm_host.h +++ b/trunk/include/linux/kvm_host.h @@ -47,7 +47,6 @@ #define KVM_REQ_DEACTIVATE_FPU 10 #define KVM_REQ_EVENT 11 #define KVM_REQ_APF_HALT 12 -#define KVM_REQ_STEAL_UPDATE 13 #define KVM_USERSPACE_IRQ_SOURCE_ID 0 @@ -327,17 +326,12 @@ static inline struct kvm_memslots *kvm_memslots(struct kvm *kvm) static inline int is_error_hpa(hpa_t hpa) { return hpa >> HPA_MSB; } extern struct page *bad_page; -extern struct page *fault_page; - extern pfn_t bad_pfn; -extern pfn_t fault_pfn; int is_error_page(struct page *page); int is_error_pfn(pfn_t pfn); int is_hwpoison_pfn(pfn_t pfn); int is_fault_pfn(pfn_t pfn); -int is_noslot_pfn(pfn_t pfn); -int is_invalid_pfn(pfn_t pfn); int kvm_is_error_hva(unsigned long addr); int kvm_set_memory_region(struct kvm *kvm, struct kvm_userspace_memory_region *mem, @@ -387,8 +381,6 @@ int kvm_read_guest_page(struct kvm *kvm, gfn_t gfn, void *data, int offset, int kvm_read_guest_atomic(struct kvm *kvm, gpa_t gpa, void *data, unsigned long len); int kvm_read_guest(struct kvm *kvm, gpa_t gpa, void *data, unsigned long len); -int kvm_read_guest_cached(struct kvm *kvm, struct gfn_to_hva_cache *ghc, - void *data, unsigned long len); int kvm_write_guest_page(struct kvm *kvm, gfn_t gfn, const void *data, int offset, int len); int kvm_write_guest(struct kvm *kvm, gpa_t gpa, const void *data, diff --git a/trunk/include/linux/libata.h b/trunk/include/linux/libata.h index efd6f9800762..5a9926b34072 100644 --- a/trunk/include/linux/libata.h +++ b/trunk/include/linux/libata.h @@ -74,16 +74,6 @@ #define BPRINTK(fmt, args...) if (ap->flags & ATA_FLAG_DEBUGMSG) printk(KERN_ERR "%s: " fmt, __func__, ## args) -#define ata_print_version_once(dev, version) \ -({ \ - static bool __print_once; \ - \ - if (!__print_once) { \ - __print_once = true; \ - ata_print_version(dev, version); \ - } \ -}) - /* NEW: debug levels */ #define HAVE_LIBATA_MSG 1 @@ -1254,50 +1244,20 @@ static inline int sata_srst_pmp(struct ata_link *link) /* * printk helpers */ -__attribute__((format (printf, 3, 4))) -int ata_port_printk(const struct ata_port *ap, const char *level, - const char *fmt, ...); -__attribute__((format (printf, 3, 4))) -int ata_link_printk(const struct ata_link *link, const char *level, - const char *fmt, ...); -__attribute__((format (printf, 3, 4))) -int ata_dev_printk(const struct ata_device *dev, const char *level, - const char *fmt, ...); - -#define ata_port_err(ap, fmt, ...) \ - ata_port_printk(ap, KERN_ERR, fmt, ##__VA_ARGS__) -#define ata_port_warn(ap, fmt, ...) \ - ata_port_printk(ap, KERN_WARNING, fmt, ##__VA_ARGS__) -#define ata_port_notice(ap, fmt, ...) \ - ata_port_printk(ap, KERN_NOTICE, fmt, ##__VA_ARGS__) -#define ata_port_info(ap, fmt, ...) \ - ata_port_printk(ap, KERN_INFO, fmt, ##__VA_ARGS__) -#define ata_port_dbg(ap, fmt, ...) \ - ata_port_printk(ap, KERN_DEBUG, fmt, ##__VA_ARGS__) - -#define ata_link_err(link, fmt, ...) \ - ata_link_printk(link, KERN_ERR, fmt, ##__VA_ARGS__) -#define ata_link_warn(link, fmt, ...) \ - ata_link_printk(link, KERN_WARNING, fmt, ##__VA_ARGS__) -#define ata_link_notice(link, fmt, ...) \ - ata_link_printk(link, KERN_NOTICE, fmt, ##__VA_ARGS__) -#define ata_link_info(link, fmt, ...) \ - ata_link_printk(link, KERN_INFO, fmt, ##__VA_ARGS__) -#define ata_link_dbg(link, fmt, ...) \ - ata_link_printk(link, KERN_DEBUG, fmt, ##__VA_ARGS__) - -#define ata_dev_err(dev, fmt, ...) \ - ata_dev_printk(dev, KERN_ERR, fmt, ##__VA_ARGS__) -#define ata_dev_warn(dev, fmt, ...) \ - ata_dev_printk(dev, KERN_WARNING, fmt, ##__VA_ARGS__) -#define ata_dev_notice(dev, fmt, ...) \ - ata_dev_printk(dev, KERN_NOTICE, fmt, ##__VA_ARGS__) -#define ata_dev_info(dev, fmt, ...) \ - ata_dev_printk(dev, KERN_INFO, fmt, ##__VA_ARGS__) -#define ata_dev_dbg(dev, fmt, ...) \ - ata_dev_printk(dev, KERN_DEBUG, fmt, ##__VA_ARGS__) - -void ata_print_version(const struct device *dev, const char *version); +#define ata_port_printk(ap, lv, fmt, args...) \ + printk("%sata%u: "fmt, lv, (ap)->print_id , ##args) + +#define ata_link_printk(link, lv, fmt, args...) do { \ + if (sata_pmp_attached((link)->ap) || (link)->ap->slave_link) \ + printk("%sata%u.%02u: "fmt, lv, (link)->ap->print_id, \ + (link)->pmp , ##args); \ + else \ + printk("%sata%u: "fmt, lv, (link)->ap->print_id , ##args); \ + } while(0) + +#define ata_dev_printk(dev, lv, fmt, args...) \ + printk("%sata%u.%02u: "fmt, lv, (dev)->link->ap->print_id, \ + (dev)->link->pmp + (dev)->devno , ##args) /* * ata_eh_info helpers diff --git a/trunk/include/linux/mm.h b/trunk/include/linux/mm.h index 8a45ad22a170..9670f71d7be9 100644 --- a/trunk/include/linux/mm.h +++ b/trunk/include/linux/mm.h @@ -15,7 +15,6 @@ #include #include #include -#include struct mempolicy; struct anon_vma; @@ -1122,6 +1121,44 @@ static inline void sync_mm_rss(struct task_struct *task, struct mm_struct *mm) } #endif +/* + * This struct is used to pass information from page reclaim to the shrinkers. + * We consolidate the values for easier extention later. + */ +struct shrink_control { + gfp_t gfp_mask; + + /* How many slab objects shrinker() should scan and try to reclaim */ + unsigned long nr_to_scan; +}; + +/* + * A callback you can register to apply pressure to ageable caches. + * + * 'sc' is passed shrink_control which includes a count 'nr_to_scan' + * and a 'gfpmask'. It should look through the least-recently-used + * 'nr_to_scan' entries and attempt to free them up. It should return + * the number of objects which remain in the cache. If it returns -1, it means + * it cannot do any scanning at this time (eg. there is a risk of deadlock). + * + * The 'gfpmask' refers to the allocation we are currently trying to + * fulfil. + * + * Note that 'shrink' will be passed nr_to_scan == 0 when the VM is + * querying the cache size, so a fastpath for that case is appropriate. + */ +struct shrinker { + int (*shrink)(struct shrinker *, struct shrink_control *sc); + int seeks; /* seeks to recreate an obj */ + + /* These are for internal use */ + struct list_head list; + long nr; /* objs pending delete */ +}; +#define DEFAULT_SEEKS 2 /* A good number if you don't know better. */ +extern void register_shrinker(struct shrinker *); +extern void unregister_shrinker(struct shrinker *); + int vma_wants_writenotify(struct vm_area_struct *vma); extern pte_t *__get_locked_pte(struct mm_struct *mm, unsigned long addr, @@ -1276,7 +1313,6 @@ extern void remove_active_range(unsigned int nid, unsigned long start_pfn, unsigned long end_pfn); extern void remove_all_active_ranges(void); void sort_node_map(void); -unsigned long node_map_pfn_alignment(void); unsigned long __absent_pages_in_range(int nid, unsigned long start_pfn, unsigned long end_pfn); extern unsigned long absent_pages_in_range(unsigned long start_pfn, diff --git a/trunk/include/linux/mnt_namespace.h b/trunk/include/linux/mnt_namespace.h index 29304855652d..0b89efc6f215 100644 --- a/trunk/include/linux/mnt_namespace.h +++ b/trunk/include/linux/mnt_namespace.h @@ -18,6 +18,7 @@ struct proc_mounts { struct seq_file m; /* must be the first element */ struct mnt_namespace *ns; struct path root; + int event; }; struct fs_struct; diff --git a/trunk/include/linux/module.h b/trunk/include/linux/module.h index 1c30087a2d81..d9ca2d5dc6d0 100644 --- a/trunk/include/linux/module.h +++ b/trunk/include/linux/module.h @@ -48,18 +48,10 @@ struct modversion_info struct module; -struct module_kobject { - struct kobject kobj; - struct module *mod; - struct kobject *drivers_dir; - struct module_param_attrs *mp; -}; - struct module_attribute { - struct attribute attr; - ssize_t (*show)(struct module_attribute *, struct module_kobject *, - char *); - ssize_t (*store)(struct module_attribute *, struct module_kobject *, + struct attribute attr; + ssize_t (*show)(struct module_attribute *, struct module *, char *); + ssize_t (*store)(struct module_attribute *, struct module *, const char *, size_t count); void (*setup)(struct module *, const char *); int (*test)(struct module *); @@ -73,9 +65,15 @@ struct module_version_attribute { } __attribute__ ((__aligned__(sizeof(void *)))); extern ssize_t __modver_version_show(struct module_attribute *, - struct module_kobject *, char *); + struct module *, char *); -extern struct module_attribute module_uevent; +struct module_kobject +{ + struct kobject kobj; + struct module *mod; + struct kobject *drivers_dir; + struct module_param_attrs *mp; +}; /* These are either module local, or the kernel's dummy ones. */ extern int init_module(void); diff --git a/trunk/include/linux/moduleloader.h b/trunk/include/linux/moduleloader.h index b2be02ebf453..c1f40c2f7ffb 100644 --- a/trunk/include/linux/moduleloader.h +++ b/trunk/include/linux/moduleloader.h @@ -5,12 +5,7 @@ #include #include -/* These may be implemented by architectures that need to hook into the - * module loader code. Architectures that don't need to do anything special - * can just rely on the 'weak' default hooks defined in kernel/module.c. - * Note, however, that at least one of apply_relocate or apply_relocate_add - * must be implemented by each architecture. - */ +/* These must be implemented by the specific architecture */ /* Adjust arch-specific sections. Return 0 on success. */ int module_frob_arch_sections(Elf_Ehdr *hdr, diff --git a/trunk/include/linux/mutex.h b/trunk/include/linux/mutex.h index 7f87217e9d1f..a940fe435aca 100644 --- a/trunk/include/linux/mutex.h +++ b/trunk/include/linux/mutex.h @@ -92,7 +92,7 @@ do { \ \ __mutex_init((mutex), #mutex, &__key); \ } while (0) -static inline void mutex_destroy(struct mutex *lock) {} +# define mutex_destroy(mutex) do { } while (0) #endif #ifdef CONFIG_DEBUG_LOCK_ALLOC diff --git a/trunk/include/linux/namei.h b/trunk/include/linux/namei.h index 76fe2c62ae71..eba45ea10298 100644 --- a/trunk/include/linux/namei.h +++ b/trunk/include/linux/namei.h @@ -48,6 +48,7 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND}; */ #define LOOKUP_FOLLOW 0x0001 #define LOOKUP_DIRECTORY 0x0002 +#define LOOKUP_CONTINUE 0x0004 #define LOOKUP_PARENT 0x0010 #define LOOKUP_REVAL 0x0020 @@ -74,11 +75,9 @@ extern int user_path_at(int, const char __user *, unsigned, struct path *); extern int kern_path(const char *, unsigned, struct path *); -extern struct dentry *kern_path_create(int, const char *, struct path *, int); -extern struct dentry *user_path_create(int, const char __user *, struct path *, int); extern int kern_path_parent(const char *, struct nameidata *); extern int vfs_path_lookup(struct dentry *, struct vfsmount *, - const char *, unsigned int, struct path *); + const char *, unsigned int, struct nameidata *); extern struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry, int (*open)(struct inode *, struct file *)); diff --git a/trunk/include/linux/nfs_fs.h b/trunk/include/linux/nfs_fs.h index 8b579beb6358..1b93b9c60e55 100644 --- a/trunk/include/linux/nfs_fs.h +++ b/trunk/include/linux/nfs_fs.h @@ -85,7 +85,7 @@ struct nfs_lock_context { struct nfs4_state; struct nfs_open_context { struct nfs_lock_context lock_context; - struct dentry *dentry; + struct path path; struct rpc_cred *cred; struct nfs4_state *state; fmode_t mode; @@ -360,7 +360,7 @@ extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *); extern int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr); extern int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr); extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *); -extern int nfs_permission(struct inode *, int); +extern int nfs_permission(struct inode *, int, unsigned int); extern int nfs_open(struct inode *, struct file *); extern int nfs_release(struct inode *, struct file *); extern int nfs_attribute_timeout(struct inode *inode); @@ -372,7 +372,7 @@ extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr); extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx); extern void put_nfs_open_context(struct nfs_open_context *ctx); extern struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, fmode_t mode); -extern struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, struct rpc_cred *cred, fmode_t f_mode); +extern struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct rpc_cred *cred, fmode_t f_mode); extern void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx); extern struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx); extern void nfs_put_lock_context(struct nfs_lock_context *l_ctx); diff --git a/trunk/include/linux/nsproxy.h b/trunk/include/linux/nsproxy.h index cc37a55ad004..50d20aba57d3 100644 --- a/trunk/include/linux/nsproxy.h +++ b/trunk/include/linux/nsproxy.h @@ -68,7 +68,6 @@ void switch_task_namespaces(struct task_struct *tsk, struct nsproxy *new); void free_nsproxy(struct nsproxy *ns); int unshare_nsproxy_namespaces(unsigned long, struct nsproxy **, struct fs_struct *); -int __init nsproxy_cache_init(void); static inline void put_nsproxy(struct nsproxy *ns) { diff --git a/trunk/include/linux/pagemap.h b/trunk/include/linux/pagemap.h index 8e38d4c140ff..716875e53520 100644 --- a/trunk/include/linux/pagemap.h +++ b/trunk/include/linux/pagemap.h @@ -134,7 +134,7 @@ static inline int page_cache_get_speculative(struct page *page) VM_BUG_ON(in_interrupt()); #if !defined(CONFIG_SMP) && defined(CONFIG_TREE_RCU) -# ifdef CONFIG_PREEMPT_COUNT +# ifdef CONFIG_PREEMPT VM_BUG_ON(!in_atomic()); # endif /* @@ -172,7 +172,7 @@ static inline int page_cache_add_speculative(struct page *page, int count) VM_BUG_ON(in_interrupt()); #if !defined(CONFIG_SMP) && defined(CONFIG_TREE_RCU) -# ifdef CONFIG_PREEMPT_COUNT +# ifdef CONFIG_PREEMPT VM_BUG_ON(!in_atomic()); # endif VM_BUG_ON(page_count(page) == 0); diff --git a/trunk/include/linux/pci.h b/trunk/include/linux/pci.h index 4e4203a96312..2d292182dde5 100644 --- a/trunk/include/linux/pci.h +++ b/trunk/include/linux/pci.h @@ -1617,16 +1617,5 @@ 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 */ -/** - * pci_find_upstream_pcie_bridge - find upstream PCIe-to-PCI bridge of a device - * @pdev: the PCI device - * - * if the device is PCIE, return NULL - * if the device isn't connected to a PCIe bridge (that is its parent is a - * legacy PCI bridge and the bridge is directly connected to bus 0), return its - * parent - */ -struct pci_dev *pci_find_upstream_pcie_bridge(struct pci_dev *pdev); - #endif /* __KERNEL__ */ #endif /* LINUX_PCI_H */ diff --git a/trunk/include/linux/pci_ids.h b/trunk/include/linux/pci_ids.h index 74173c585afa..057093043067 100644 --- a/trunk/include/linux/pci_ids.h +++ b/trunk/include/linux/pci_ids.h @@ -1308,7 +1308,6 @@ #define PCI_SUBDEVICE_ID_CREATIVE_SB08801 0x0041 #define PCI_SUBDEVICE_ID_CREATIVE_SB08802 0x0042 #define PCI_SUBDEVICE_ID_CREATIVE_SB08803 0x0043 -#define PCI_SUBDEVICE_ID_CREATIVE_SB1270 0x0062 #define PCI_SUBDEVICE_ID_CREATIVE_HENDRIX 0x6000 #define PCI_VENDOR_ID_ECTIVA 0x1102 /* duplicate: CREATIVE */ diff --git a/trunk/include/linux/perf_event.h b/trunk/include/linux/perf_event.h index 3f2711ccf910..e0786e35f247 100644 --- a/trunk/include/linux/perf_event.h +++ b/trunk/include/linux/perf_event.h @@ -61,7 +61,7 @@ enum perf_hw_id { /* * Generalized hardware cache events: * - * { L1-D, L1-I, LLC, ITLB, DTLB, BPU, NODE } x + * { L1-D, L1-I, LLC, ITLB, DTLB, BPU } x * { read, write, prefetch } x * { accesses, misses } */ @@ -72,7 +72,6 @@ enum perf_hw_cache_id { PERF_COUNT_HW_CACHE_DTLB = 3, PERF_COUNT_HW_CACHE_ITLB = 4, PERF_COUNT_HW_CACHE_BPU = 5, - PERF_COUNT_HW_CACHE_NODE = 6, PERF_COUNT_HW_CACHE_MAX, /* non-ABI */ }; @@ -537,16 +536,6 @@ struct perf_branch_stack { struct task_struct; -/* - * extra PMU register associated with an event - */ -struct hw_perf_event_extra { - u64 config; /* register value */ - unsigned int reg; /* register address or index */ - int alloc; /* extra register already allocated */ - int idx; /* index in shared_regs->regs[] */ -}; - /** * struct hw_perf_event - performance event hardware details: */ @@ -560,7 +549,9 @@ struct hw_perf_event { unsigned long event_base; int idx; int last_cpu; - struct hw_perf_event_extra extra_reg; + unsigned int extra_reg; + u64 extra_config; + int extra_alloc; }; struct { /* software */ struct hrtimer hrtimer; @@ -689,9 +680,36 @@ enum perf_event_active_state { }; struct file; + +#define PERF_BUFFER_WRITABLE 0x01 + +struct perf_buffer { + atomic_t refcount; + struct rcu_head rcu_head; +#ifdef CONFIG_PERF_USE_VMALLOC + struct work_struct work; + int page_order; /* allocation order */ +#endif + int nr_pages; /* nr of data pages */ + int writable; /* are we writable */ + + atomic_t poll; /* POLL_ for wakeups */ + + local_t head; /* write position */ + local_t nest; /* nested writers */ + local_t events; /* event limit */ + local_t wakeup; /* wakeup stamp */ + local_t lost; /* nr records lost */ + + long watermark; /* wakeup watermark */ + + struct perf_event_mmap_page *user_page; + void *data_pages[0]; +}; + struct perf_sample_data; -typedef void (*perf_overflow_handler_t)(struct perf_event *, +typedef void (*perf_overflow_handler_t)(struct perf_event *, int, struct perf_sample_data *, struct pt_regs *regs); @@ -727,8 +745,6 @@ struct perf_cgroup { }; #endif -struct ring_buffer; - /** * struct perf_event - performance event kernel representation: */ @@ -818,7 +834,7 @@ struct perf_event { atomic_t mmap_count; int mmap_locked; struct user_struct *mmap_user; - struct ring_buffer *rb; + struct perf_buffer *buffer; /* poll related */ wait_queue_head_t waitq; @@ -839,7 +855,6 @@ struct perf_event { u64 id; perf_overflow_handler_t overflow_handler; - void *overflow_handler_context; #ifdef CONFIG_EVENT_TRACING struct ftrace_event_call *tp_event; @@ -904,8 +919,8 @@ struct perf_event_context { u64 parent_gen; u64 generation; int pin_count; - int nr_cgroups; /* cgroup events present */ struct rcu_head rcu_head; + int nr_cgroups; /* cgroup events present */ }; /* @@ -930,11 +945,13 @@ struct perf_cpu_context { struct perf_output_handle { struct perf_event *event; - struct ring_buffer *rb; + struct perf_buffer *buffer; unsigned long wakeup; unsigned long size; void *addr; int page; + int nmi; + int sample; }; #ifdef CONFIG_PERF_EVENTS @@ -955,15 +972,13 @@ extern void perf_pmu_disable(struct pmu *pmu); extern void perf_pmu_enable(struct pmu *pmu); extern int perf_event_task_disable(void); extern int perf_event_task_enable(void); -extern int perf_event_refresh(struct perf_event *event, int refresh); extern void perf_event_update_userpage(struct perf_event *event); extern int perf_event_release_kernel(struct perf_event *event); extern struct perf_event * perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu, struct task_struct *task, - perf_overflow_handler_t callback, - void *context); + perf_overflow_handler_t callback); extern u64 perf_event_read_value(struct perf_event *event, u64 *enabled, u64 *running); @@ -1003,7 +1018,7 @@ extern void perf_prepare_sample(struct perf_event_header *header, struct perf_event *event, struct pt_regs *regs); -extern int perf_event_overflow(struct perf_event *event, +extern int perf_event_overflow(struct perf_event *event, int nmi, struct perf_sample_data *data, struct pt_regs *regs); @@ -1022,7 +1037,7 @@ static inline int is_software_event(struct perf_event *event) extern struct jump_label_key perf_swevent_enabled[PERF_COUNT_SW_MAX]; -extern void __perf_sw_event(u32, u64, struct pt_regs *, u64); +extern void __perf_sw_event(u32, u64, int, struct pt_regs *, u64); #ifndef perf_arch_fetch_caller_regs static inline void perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip) { } @@ -1044,7 +1059,7 @@ static inline void perf_fetch_caller_regs(struct pt_regs *regs) } static __always_inline void -perf_sw_event(u32 event_id, u64 nr, struct pt_regs *regs, u64 addr) +perf_sw_event(u32 event_id, u64 nr, int nmi, struct pt_regs *regs, u64 addr) { struct pt_regs hot_regs; @@ -1053,7 +1068,7 @@ perf_sw_event(u32 event_id, u64 nr, struct pt_regs *regs, u64 addr) perf_fetch_caller_regs(&hot_regs); regs = &hot_regs; } - __perf_sw_event(event_id, nr, regs, addr); + __perf_sw_event(event_id, nr, nmi, regs, addr); } } @@ -1067,7 +1082,7 @@ static inline void perf_event_task_sched_in(struct task_struct *task) static inline void perf_event_task_sched_out(struct task_struct *task, struct task_struct *next) { - perf_sw_event(PERF_COUNT_SW_CONTEXT_SWITCHES, 1, NULL, 0); + perf_sw_event(PERF_COUNT_SW_CONTEXT_SWITCHES, 1, 1, NULL, 0); __perf_event_task_sched_out(task, next); } @@ -1128,7 +1143,8 @@ extern void perf_bp_event(struct perf_event *event, void *data); #endif extern int perf_output_begin(struct perf_output_handle *handle, - struct perf_event *event, unsigned int size); + struct perf_event *event, unsigned int size, + int nmi, int sample); extern void perf_output_end(struct perf_output_handle *handle); extern void perf_output_copy(struct perf_output_handle *handle, const void *buf, unsigned int len); @@ -1150,13 +1166,10 @@ static inline void perf_event_delayed_put(struct task_struct *task) { } static inline void perf_event_print_debug(void) { } static inline int perf_event_task_disable(void) { return -EINVAL; } static inline int perf_event_task_enable(void) { return -EINVAL; } -static inline int perf_event_refresh(struct perf_event *event, int refresh) -{ - return -EINVAL; -} static inline void -perf_sw_event(u32 event_id, u64 nr, struct pt_regs *regs, u64 addr) { } +perf_sw_event(u32 event_id, u64 nr, int nmi, + struct pt_regs *regs, u64 addr) { } static inline void perf_bp_event(struct perf_event *event, void *data) { } diff --git a/trunk/include/linux/plist.h b/trunk/include/linux/plist.h index aa0fb390bd29..c9b9f322c8d8 100644 --- a/trunk/include/linux/plist.h +++ b/trunk/include/linux/plist.h @@ -77,9 +77,14 @@ #include #include +#include struct plist_head { struct list_head node_list; +#ifdef CONFIG_DEBUG_PI_LIST + raw_spinlock_t *rawlock; + spinlock_t *spinlock; +#endif }; struct plist_node { @@ -88,13 +93,37 @@ struct plist_node { struct list_head node_list; }; +#ifdef CONFIG_DEBUG_PI_LIST +# define PLIST_HEAD_LOCK_INIT(_lock) .spinlock = _lock +# define PLIST_HEAD_LOCK_INIT_RAW(_lock) .rawlock = _lock +#else +# define PLIST_HEAD_LOCK_INIT(_lock) +# define PLIST_HEAD_LOCK_INIT_RAW(_lock) +#endif + +#define _PLIST_HEAD_INIT(head) \ + .node_list = LIST_HEAD_INIT((head).node_list) + /** * PLIST_HEAD_INIT - static struct plist_head initializer * @head: struct plist_head variable name + * @_lock: lock to initialize for this list + */ +#define PLIST_HEAD_INIT(head, _lock) \ +{ \ + _PLIST_HEAD_INIT(head), \ + PLIST_HEAD_LOCK_INIT(&(_lock)) \ +} + +/** + * PLIST_HEAD_INIT_RAW - static struct plist_head initializer + * @head: struct plist_head variable name + * @_lock: lock to initialize for this list */ -#define PLIST_HEAD_INIT(head) \ +#define PLIST_HEAD_INIT_RAW(head, _lock) \ { \ - .node_list = LIST_HEAD_INIT((head).node_list) \ + _PLIST_HEAD_INIT(head), \ + PLIST_HEAD_LOCK_INIT_RAW(&(_lock)) \ } /** @@ -112,11 +141,31 @@ struct plist_node { /** * plist_head_init - dynamic struct plist_head initializer * @head: &struct plist_head pointer + * @lock: spinlock protecting the list (debugging) */ static inline void -plist_head_init(struct plist_head *head) +plist_head_init(struct plist_head *head, spinlock_t *lock) { INIT_LIST_HEAD(&head->node_list); +#ifdef CONFIG_DEBUG_PI_LIST + head->spinlock = lock; + head->rawlock = NULL; +#endif +} + +/** + * plist_head_init_raw - dynamic struct plist_head initializer + * @head: &struct plist_head pointer + * @lock: raw_spinlock protecting the list (debugging) + */ +static inline void +plist_head_init_raw(struct plist_head *head, raw_spinlock_t *lock) +{ + INIT_LIST_HEAD(&head->node_list); +#ifdef CONFIG_DEBUG_PI_LIST + head->rawlock = lock; + head->spinlock = NULL; +#endif } /** diff --git a/trunk/include/linux/preempt.h b/trunk/include/linux/preempt.h index 58969b2a8a82..2e681d9555bd 100644 --- a/trunk/include/linux/preempt.h +++ b/trunk/include/linux/preempt.h @@ -27,21 +27,6 @@ asmlinkage void preempt_schedule(void); -#define preempt_check_resched() \ -do { \ - if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) \ - preempt_schedule(); \ -} while (0) - -#else /* !CONFIG_PREEMPT */ - -#define preempt_check_resched() do { } while (0) - -#endif /* CONFIG_PREEMPT */ - - -#ifdef CONFIG_PREEMPT_COUNT - #define preempt_disable() \ do { \ inc_preempt_count(); \ @@ -54,6 +39,12 @@ do { \ dec_preempt_count(); \ } while (0) +#define preempt_check_resched() \ +do { \ + if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) \ + preempt_schedule(); \ +} while (0) + #define preempt_enable() \ do { \ preempt_enable_no_resched(); \ @@ -89,17 +80,18 @@ do { \ preempt_check_resched(); \ } while (0) -#else /* !CONFIG_PREEMPT_COUNT */ +#else #define preempt_disable() do { } while (0) #define preempt_enable_no_resched() do { } while (0) #define preempt_enable() do { } while (0) +#define preempt_check_resched() do { } while (0) #define preempt_disable_notrace() do { } while (0) #define preempt_enable_no_resched_notrace() do { } while (0) #define preempt_enable_notrace() do { } while (0) -#endif /* CONFIG_PREEMPT_COUNT */ +#endif #ifdef CONFIG_PREEMPT_NOTIFIERS diff --git a/trunk/include/linux/rculist.h b/trunk/include/linux/rculist.h index d079290843a9..e3beb315517a 100644 --- a/trunk/include/linux/rculist.h +++ b/trunk/include/linux/rculist.h @@ -183,7 +183,7 @@ static inline void list_splice_init_rcu(struct list_head *list, struct list_head *last = list->prev; struct list_head *at = head->next; - if (list_empty(list)) + if (list_empty(head)) return; /* "first" and "last" tracking list, so initialize it. */ diff --git a/trunk/include/linux/rcupdate.h b/trunk/include/linux/rcupdate.h index 8f4f881a0ad8..99f9aa7c2804 100644 --- a/trunk/include/linux/rcupdate.h +++ b/trunk/include/linux/rcupdate.h @@ -239,7 +239,7 @@ extern int rcu_read_lock_bh_held(void); * Check debug_lockdep_rcu_enabled() to prevent false positives during boot * and while lockdep is disabled. */ -#ifdef CONFIG_PREEMPT_COUNT +#ifdef CONFIG_PREEMPT static inline int rcu_read_lock_sched_held(void) { int lockdep_opinion = 0; @@ -250,12 +250,12 @@ static inline int rcu_read_lock_sched_held(void) lockdep_opinion = lock_is_held(&rcu_sched_lock_map); return lockdep_opinion || preempt_count() != 0 || irqs_disabled(); } -#else /* #ifdef CONFIG_PREEMPT_COUNT */ +#else /* #ifdef CONFIG_PREEMPT */ static inline int rcu_read_lock_sched_held(void) { return 1; } -#endif /* #else #ifdef CONFIG_PREEMPT_COUNT */ +#endif /* #else #ifdef CONFIG_PREEMPT */ #else /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ @@ -276,17 +276,17 @@ static inline int rcu_read_lock_bh_held(void) return 1; } -#ifdef CONFIG_PREEMPT_COUNT +#ifdef CONFIG_PREEMPT static inline int rcu_read_lock_sched_held(void) { return preempt_count() != 0 || irqs_disabled(); } -#else /* #ifdef CONFIG_PREEMPT_COUNT */ +#else /* #ifdef CONFIG_PREEMPT */ static inline int rcu_read_lock_sched_held(void) { return 1; } -#endif /* #else #ifdef CONFIG_PREEMPT_COUNT */ +#endif /* #else #ifdef CONFIG_PREEMPT */ #endif /* #else #ifdef CONFIG_DEBUG_LOCK_ALLOC */ diff --git a/trunk/include/linux/regmap.h b/trunk/include/linux/regmap.h deleted file mode 100644 index 60a65cd7e1a0..000000000000 --- a/trunk/include/linux/regmap.h +++ /dev/null @@ -1,82 +0,0 @@ -#ifndef __LINUX_REGMAP_H -#define __LINUX_REGMAP_H - -/* - * Register map access API - * - * Copyright 2011 Wolfson Microelectronics plc - * - * Author: Mark Brown - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include - -struct i2c_client; -struct spi_device; - -struct regmap_config { - int reg_bits; - int val_bits; -}; - -typedef int (*regmap_hw_write)(struct device *dev, const void *data, - size_t count); -typedef int (*regmap_hw_gather_write)(struct device *dev, - const void *reg, size_t reg_len, - const void *val, size_t val_len); -typedef int (*regmap_hw_read)(struct device *dev, - const void *reg_buf, size_t reg_size, - void *val_buf, size_t val_size); - -/** - * Description of a hardware bus for the register map infrastructure. - * - * @list: Internal use. - * @type: Bus type, used to identify bus to be used for a device. - * @write: Write operation. - * @gather_write: Write operation with split register/value, return -ENOTSUPP - * if not implemented on a given device. - * @read: Read operation. Data is returned in the buffer used to transmit - * data. - * @owner: Module with the bus implementation, used to pin the implementation - * in memory. - * @read_flag_mask: Mask to be set in the top byte of the register when doing - * a read. - */ -struct regmap_bus { - struct list_head list; - struct bus_type *type; - regmap_hw_write write; - regmap_hw_gather_write gather_write; - regmap_hw_read read; - struct module *owner; - u8 read_flag_mask; -}; - -struct regmap *regmap_init(struct device *dev, - const struct regmap_bus *bus, - const struct regmap_config *config); -struct regmap *regmap_init_i2c(struct i2c_client *i2c, - const struct regmap_config *config); -struct regmap *regmap_init_spi(struct spi_device *dev, - const struct regmap_config *config); - -void regmap_exit(struct regmap *map); -int regmap_write(struct regmap *map, unsigned int reg, unsigned int val); -int regmap_raw_write(struct regmap *map, unsigned int reg, - const void *val, size_t val_len); -int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val); -int regmap_raw_read(struct regmap *map, unsigned int reg, - void *val, size_t val_len); -int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, - size_t val_count); -int regmap_update_bits(struct regmap *map, unsigned int reg, - unsigned int mask, unsigned int val); - -#endif diff --git a/trunk/include/linux/reiserfs_xattr.h b/trunk/include/linux/reiserfs_xattr.h index 57958c0e1d38..6deef5dc95fb 100644 --- a/trunk/include/linux/reiserfs_xattr.h +++ b/trunk/include/linux/reiserfs_xattr.h @@ -41,11 +41,10 @@ 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); +int reiserfs_permission(struct inode *inode, int mask, unsigned int flags); #ifdef CONFIG_REISERFS_FS_XATTR #define has_xattr_dir(inode) (REISERFS_I(inode)->i_flags & i_has_xattr_dir) -int reiserfs_check_acl(struct inode *inode, int mask); ssize_t reiserfs_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size); int reiserfs_setxattr(struct dentry *dentry, const char *name, @@ -123,7 +122,6 @@ static inline void reiserfs_init_xattr_rwsem(struct inode *inode) #define reiserfs_setxattr NULL #define reiserfs_listxattr NULL #define reiserfs_removexattr NULL -#define reiserfs_check_acl NULL static inline void reiserfs_init_xattr_rwsem(struct inode *inode) { diff --git a/trunk/include/linux/ring_buffer.h b/trunk/include/linux/ring_buffer.h index b891de96000f..ab38ac80b0f9 100644 --- a/trunk/include/linux/ring_buffer.h +++ b/trunk/include/linux/ring_buffer.h @@ -169,7 +169,7 @@ void ring_buffer_set_clock(struct ring_buffer *buffer, size_t ring_buffer_page_len(void *page); -void *ring_buffer_alloc_read_page(struct ring_buffer *buffer, int cpu); +void *ring_buffer_alloc_read_page(struct ring_buffer *buffer); void ring_buffer_free_read_page(struct ring_buffer *buffer, void *data); int ring_buffer_read_page(struct ring_buffer *buffer, void **data_page, size_t len, int cpu, int full); diff --git a/trunk/include/linux/rtmutex.h b/trunk/include/linux/rtmutex.h index de17134244f3..8d522ffeda33 100644 --- a/trunk/include/linux/rtmutex.h +++ b/trunk/include/linux/rtmutex.h @@ -66,7 +66,7 @@ struct hrtimer_sleeper; #define __RT_MUTEX_INITIALIZER(mutexname) \ { .wait_lock = __RAW_SPIN_LOCK_UNLOCKED(mutexname.wait_lock) \ - , .wait_list = PLIST_HEAD_INIT(mutexname.wait_list) \ + , .wait_list = PLIST_HEAD_INIT_RAW(mutexname.wait_list, mutexname.wait_lock) \ , .owner = NULL \ __DEBUG_RT_MUTEX_INITIALIZER(mutexname)} @@ -100,7 +100,7 @@ extern void rt_mutex_unlock(struct rt_mutex *lock); #ifdef CONFIG_RT_MUTEXES # define INIT_RT_MUTEXES(tsk) \ - .pi_waiters = PLIST_HEAD_INIT(tsk.pi_waiters), \ + .pi_waiters = PLIST_HEAD_INIT(tsk.pi_waiters, tsk.pi_lock), \ INIT_RT_MUTEX_DEBUG(tsk) #else # define INIT_RT_MUTEXES(tsk) diff --git a/trunk/include/linux/rwsem.h b/trunk/include/linux/rwsem.h index 77950dfa0a9e..a8afe9cd000c 100644 --- a/trunk/include/linux/rwsem.h +++ b/trunk/include/linux/rwsem.h @@ -124,9 +124,19 @@ extern void downgrade_write(struct rw_semaphore *sem); */ extern void down_read_nested(struct rw_semaphore *sem, int subclass); extern void down_write_nested(struct rw_semaphore *sem, int subclass); +/* + * Take/release a lock when not the owner will release it. + * + * [ This API should be avoided as much as possible - the + * proper abstraction for this case is completions. ] + */ +extern void down_read_non_owner(struct rw_semaphore *sem); +extern void up_read_non_owner(struct rw_semaphore *sem); #else # define down_read_nested(sem, subclass) down_read(sem) # define down_write_nested(sem, subclass) down_write(sem) +# define down_read_non_owner(sem) down_read(sem) +# define up_read_non_owner(sem) up_read(sem) #endif #endif /* _LINUX_RWSEM_H */ diff --git a/trunk/include/linux/sched.h b/trunk/include/linux/sched.h index ed766add9b23..f6ef727ee4fc 100644 --- a/trunk/include/linux/sched.h +++ b/trunk/include/linux/sched.h @@ -2526,7 +2526,7 @@ extern int _cond_resched(void); extern int __cond_resched_lock(spinlock_t *lock); -#ifdef CONFIG_PREEMPT_COUNT +#ifdef CONFIG_PREEMPT #define PREEMPT_LOCK_OFFSET PREEMPT_OFFSET #else #define PREEMPT_LOCK_OFFSET 0 diff --git a/trunk/include/linux/seccomp.h b/trunk/include/linux/seccomp.h index cc7a4e9cc7ad..167c33361d9c 100644 --- a/trunk/include/linux/seccomp.h +++ b/trunk/include/linux/seccomp.h @@ -19,11 +19,6 @@ static inline void secure_computing(int this_syscall) extern long prctl_get_seccomp(void); extern long prctl_set_seccomp(unsigned long); -static inline int seccomp_mode(seccomp_t *s) -{ - return s->mode; -} - #else /* CONFIG_SECCOMP */ #include @@ -42,11 +37,6 @@ static inline long prctl_set_seccomp(unsigned long arg2) return -EINVAL; } -static inline int seccomp_mode(seccomp_t *s) -{ - return 0; -} - #endif /* CONFIG_SECCOMP */ #endif /* _LINUX_SECCOMP_H */ diff --git a/trunk/include/linux/security.h b/trunk/include/linux/security.h index ebd2a53a3d07..8ce59ef3e5af 100644 --- a/trunk/include/linux/security.h +++ b/trunk/include/linux/security.h @@ -1456,7 +1456,7 @@ struct security_operations { struct inode *new_dir, struct dentry *new_dentry); int (*inode_readlink) (struct dentry *dentry); int (*inode_follow_link) (struct dentry *dentry, struct nameidata *nd); - int (*inode_permission) (struct inode *inode, int mask); + int (*inode_permission) (struct inode *inode, int mask, unsigned flags); int (*inode_setattr) (struct dentry *dentry, struct iattr *attr); int (*inode_getattr) (struct vfsmount *mnt, struct dentry *dentry); int (*inode_setxattr) (struct dentry *dentry, const char *name, @@ -1720,6 +1720,7 @@ int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry, int security_inode_readlink(struct dentry *dentry); int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd); int security_inode_permission(struct inode *inode, int mask); +int security_inode_exec_permission(struct inode *inode, unsigned int flags); int security_inode_setattr(struct dentry *dentry, struct iattr *attr); int security_inode_getattr(struct vfsmount *mnt, struct dentry *dentry); int security_inode_setxattr(struct dentry *dentry, const char *name, @@ -2112,6 +2113,12 @@ static inline int security_inode_permission(struct inode *inode, int mask) return 0; } +static inline int security_inode_exec_permission(struct inode *inode, + unsigned int flags) +{ + return 0; +} + static inline int security_inode_setattr(struct dentry *dentry, struct iattr *attr) { diff --git a/trunk/include/linux/seq_file.h b/trunk/include/linux/seq_file.h index be720cd2038d..03c0232b4169 100644 --- a/trunk/include/linux/seq_file.h +++ b/trunk/include/linux/seq_file.h @@ -23,7 +23,6 @@ struct seq_file { u64 version; struct mutex lock; const struct seq_operations *op; - int poll_event; void *private; }; diff --git a/trunk/include/linux/shrinker.h b/trunk/include/linux/shrinker.h deleted file mode 100644 index 790651b4e5ba..000000000000 --- a/trunk/include/linux/shrinker.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef _LINUX_SHRINKER_H -#define _LINUX_SHRINKER_H - -/* - * This struct is used to pass information from page reclaim to the shrinkers. - * We consolidate the values for easier extention later. - */ -struct shrink_control { - gfp_t gfp_mask; - - /* How many slab objects shrinker() should scan and try to reclaim */ - unsigned long nr_to_scan; -}; - -/* - * A callback you can register to apply pressure to ageable caches. - * - * 'sc' is passed shrink_control which includes a count 'nr_to_scan' - * and a 'gfpmask'. It should look through the least-recently-used - * 'nr_to_scan' entries and attempt to free them up. It should return - * the number of objects which remain in the cache. If it returns -1, it means - * it cannot do any scanning at this time (eg. there is a risk of deadlock). - * - * The 'gfpmask' refers to the allocation we are currently trying to - * fulfil. - * - * Note that 'shrink' will be passed nr_to_scan == 0 when the VM is - * querying the cache size, so a fastpath for that case is appropriate. - */ -struct shrinker { - int (*shrink)(struct shrinker *, struct shrink_control *sc); - int seeks; /* seeks to recreate an obj */ - long batch; /* reclaim batch size, 0 = default */ - - /* These are for internal use */ - struct list_head list; - long nr; /* objs pending delete */ -}; -#define DEFAULT_SEEKS 2 /* A good number if you don't know better. */ -extern void register_shrinker(struct shrinker *); -extern void unregister_shrinker(struct shrinker *); -#endif diff --git a/trunk/include/linux/stacktrace.h b/trunk/include/linux/stacktrace.h index 115b570e3bff..25310f1d7f37 100644 --- a/trunk/include/linux/stacktrace.h +++ b/trunk/include/linux/stacktrace.h @@ -14,8 +14,8 @@ struct stack_trace { }; extern void save_stack_trace(struct stack_trace *trace); -extern void save_stack_trace_regs(struct pt_regs *regs, - struct stack_trace *trace); +extern void save_stack_trace_regs(struct stack_trace *trace, + struct pt_regs *regs); extern void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace); diff --git a/trunk/include/linux/stop_machine.h b/trunk/include/linux/stop_machine.h index 4a9d0c7edc65..092dc9b1ce7d 100644 --- a/trunk/include/linux/stop_machine.h +++ b/trunk/include/linux/stop_machine.h @@ -124,19 +124,15 @@ int stop_machine(int (*fn)(void *), void *data, const struct cpumask *cpus); */ int __stop_machine(int (*fn)(void *), void *data, const struct cpumask *cpus); -int stop_machine_from_inactive_cpu(int (*fn)(void *), void *data, - const struct cpumask *cpus); - #else /* CONFIG_STOP_MACHINE && CONFIG_SMP */ static inline int __stop_machine(int (*fn)(void *), void *data, const struct cpumask *cpus) { - unsigned long flags; int ret; - local_irq_save(flags); + local_irq_disable(); ret = fn(data); - local_irq_restore(flags); + local_irq_enable(); return ret; } @@ -146,11 +142,5 @@ static inline int stop_machine(int (*fn)(void *), void *data, return __stop_machine(fn, data, cpus); } -static inline int stop_machine_from_inactive_cpu(int (*fn)(void *), void *data, - const struct cpumask *cpus) -{ - return __stop_machine(fn, data, cpus); -} - #endif /* CONFIG_STOP_MACHINE && CONFIG_SMP */ #endif /* _LINUX_STOP_MACHINE */ diff --git a/trunk/include/net/9p/9p.h b/trunk/include/net/9p/9p.h index 342dcf13d039..008711e8e78f 100644 --- a/trunk/include/net/9p/9p.h +++ b/trunk/include/net/9p/9p.h @@ -40,7 +40,6 @@ * @P9_DEBUG_FID: fid allocation/deallocation tracking * @P9_DEBUG_PKT: packet marshalling/unmarshalling * @P9_DEBUG_FSC: FS-cache tracing - * @P9_DEBUG_VPKT: Verbose packet debugging (full packet dump) * * These flags are passed at mount time to turn on various levels of * verbosity and tracing which will be output to the system logs. @@ -58,7 +57,6 @@ enum p9_debug_flags { P9_DEBUG_FID = (1<<9), P9_DEBUG_PKT = (1<<10), P9_DEBUG_FSC = (1<<11), - P9_DEBUG_VPKT = (1<<12), }; #ifdef CONFIG_NET_9P_DEBUG @@ -76,14 +74,10 @@ do { \ } \ } while (0) -#define P9_DUMP_PKT(way, pdu) p9pdu_dump(way, pdu) - #else #define P9_DPRINTK(level, format, arg...) do { } while (0) -#define P9_DUMP_PKT(way, pdu) do { } while (0) #endif - #define P9_EPRINTK(level, format, arg...) \ do { \ printk(level "9p: %s (%d): " \ @@ -181,10 +175,6 @@ enum p9_msg_t { P9_RLINK, P9_TMKDIR = 72, P9_RMKDIR, - P9_TRENAMEAT = 74, - P9_RRENAMEAT, - P9_TUNLINKAT = 76, - P9_RUNLINKAT, P9_TVERSION = 100, P9_RVERSION, P9_TAUTH = 102, @@ -330,6 +320,21 @@ enum p9_qid_t { /* Room for readdir header */ #define P9_READDIRHDRSZ 24 +/** + * struct p9_str - length prefixed string type + * @len: length of the string + * @str: the string + * + * The protocol uses length prefixed strings for all + * string data, so we replicate that for our internal + * string members. + */ + +struct p9_str { + u16 len; + char *str; +}; + /** * struct p9_qid - file system entity information * @type: 8-bit type &p9_qid_t @@ -366,11 +371,11 @@ struct p9_qid { * @atime: Last access/read time * @mtime: Last modify/write time * @length: file length - * @name: last element of path (aka filename) - * @uid: owner name - * @gid: group owner - * @muid: last modifier - * @extension: area used to encode extended UNIX support + * @name: last element of path (aka filename) in type &p9_str + * @uid: owner name in type &p9_str + * @gid: group owner in type &p9_str + * @muid: last modifier in type &p9_str + * @extension: area used to encode extended UNIX support in type &p9_str * @n_uid: numeric user id of owner (part of 9p2000.u extension) * @n_gid: numeric group id (part of 9p2000.u extension) * @n_muid: numeric user id of laster modifier (part of 9p2000.u extension) @@ -507,6 +512,11 @@ struct p9_getlock { char *client_id; }; +/* Structures for Protocol Operations */ +struct p9_tstatfs { + u32 fid; +}; + struct p9_rstatfs { u32 type; u32 bsize; @@ -519,6 +529,159 @@ struct p9_rstatfs { u32 namelen; }; +struct p9_trename { + u32 fid; + u32 newdirfid; + struct p9_str name; +}; + +struct p9_rrename { +}; + +struct p9_tversion { + u32 msize; + struct p9_str version; +}; + +struct p9_rversion { + u32 msize; + struct p9_str version; +}; + +struct p9_tauth { + u32 afid; + struct p9_str uname; + struct p9_str aname; + u32 n_uname; /* 9P2000.u extensions */ +}; + +struct p9_rauth { + struct p9_qid qid; +}; + +struct p9_rerror { + struct p9_str error; + u32 errno; /* 9p2000.u extension */ +}; + +struct p9_tflush { + u16 oldtag; +}; + +struct p9_rflush { +}; + +struct p9_tattach { + u32 fid; + u32 afid; + struct p9_str uname; + struct p9_str aname; + u32 n_uname; /* 9P2000.u extensions */ +}; + +struct p9_rattach { + struct p9_qid qid; +}; + +struct p9_twalk { + u32 fid; + u32 newfid; + u16 nwname; + struct p9_str wnames[16]; +}; + +struct p9_rwalk { + u16 nwqid; + struct p9_qid wqids[16]; +}; + +struct p9_topen { + u32 fid; + u8 mode; +}; + +struct p9_ropen { + struct p9_qid qid; + u32 iounit; +}; + +struct p9_tcreate { + u32 fid; + struct p9_str name; + u32 perm; + u8 mode; + struct p9_str extension; +}; + +struct p9_rcreate { + struct p9_qid qid; + u32 iounit; +}; + +struct p9_tread { + u32 fid; + u64 offset; + u32 count; +}; + +struct p9_rread { + u32 count; + u8 *data; +}; + +struct p9_twrite { + u32 fid; + u64 offset; + u32 count; + u8 *data; +}; + +struct p9_rwrite { + u32 count; +}; + +struct p9_treaddir { + u32 fid; + u64 offset; + u32 count; +}; + +struct p9_rreaddir { + u32 count; + u8 *data; +}; + + +struct p9_tclunk { + u32 fid; +}; + +struct p9_rclunk { +}; + +struct p9_tremove { + u32 fid; +}; + +struct p9_rremove { +}; + +struct p9_tstat { + u32 fid; +}; + +struct p9_rstat { + struct p9_wstat stat; +}; + +struct p9_twstat { + u32 fid; + struct p9_wstat stat; +}; + +struct p9_rwstat { +}; + /** * struct p9_fcall - primary packet structure * @size: prefixed length of the structure diff --git a/trunk/include/net/9p/client.h b/trunk/include/net/9p/client.h index 55ce72ce9861..d26d5e98a173 100644 --- a/trunk/include/net/9p/client.h +++ b/trunk/include/net/9p/client.h @@ -36,9 +36,9 @@ */ enum p9_proto_versions{ - p9_proto_legacy, - p9_proto_2000u, - p9_proto_2000L, + p9_proto_legacy = 0, + p9_proto_2000u = 1, + p9_proto_2000L = 2, }; @@ -211,10 +211,7 @@ struct p9_dirent { }; int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb); -int p9_client_rename(struct p9_fid *fid, struct p9_fid *newdirfid, - const char *name); -int p9_client_renameat(struct p9_fid *olddirfid, const char *old_name, - struct p9_fid *newdirfid, const char *new_name); +int p9_client_rename(struct p9_fid *fid, struct p9_fid *newdirfid, char *name); struct p9_client *p9_client_create(const char *dev_name, char *options); void p9_client_destroy(struct p9_client *clnt); void p9_client_disconnect(struct p9_client *clnt); @@ -234,7 +231,6 @@ int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode, int p9_client_clunk(struct p9_fid *fid); int p9_client_fsync(struct p9_fid *fid, int datasync); int p9_client_remove(struct p9_fid *fid); -int p9_client_unlinkat(struct p9_fid *dfid, const char *name, int flags); int p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, u32 count); int p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, diff --git a/trunk/include/net/9p/transport.h b/trunk/include/net/9p/transport.h index 83531ebeee99..d8549fb9c742 100644 --- a/trunk/include/net/9p/transport.h +++ b/trunk/include/net/9p/transport.h @@ -67,7 +67,7 @@ struct p9_trans_module { void v9fs_register_trans(struct p9_trans_module *m); void v9fs_unregister_trans(struct p9_trans_module *m); -struct p9_trans_module *v9fs_get_trans_by_name(char *s); +struct p9_trans_module *v9fs_get_trans_by_name(const substring_t *name); struct p9_trans_module *v9fs_get_default_trans(void); void v9fs_put_trans(struct p9_trans_module *m); #endif /* NET_9P_TRANSPORT_H */ diff --git a/trunk/include/scsi/iscsi_proto.h b/trunk/include/scsi/iscsi_proto.h index ea68b3c56dbf..dd0a52cea95a 100644 --- a/trunk/include/scsi/iscsi_proto.h +++ b/trunk/include/scsi/iscsi_proto.h @@ -60,7 +60,7 @@ struct iscsi_hdr { uint8_t rsvd2[2]; uint8_t hlength; /* AHSs total length */ uint8_t dlength[3]; /* Data length */ - struct scsi_lun lun; + uint8_t lun[8]; itt_t itt; /* Initiator Task Tag, opaque for target */ __be32 ttt; /* Target Task Tag */ __be32 statsn; @@ -122,7 +122,7 @@ struct iscsi_cmd { __be16 rsvd2; uint8_t hlength; uint8_t dlength[3]; - struct scsi_lun lun; + uint8_t lun[8]; itt_t itt; /* Initiator Task Tag */ __be32 data_length; __be32 cmdsn; @@ -198,7 +198,7 @@ struct iscsi_async { uint8_t rsvd2[2]; uint8_t rsvd3; uint8_t dlength[3]; - struct scsi_lun lun; + uint8_t lun[8]; uint8_t rsvd4[8]; __be32 statsn; __be32 exp_cmdsn; @@ -226,7 +226,7 @@ struct iscsi_nopout { __be16 rsvd2; uint8_t rsvd3; uint8_t dlength[3]; - struct scsi_lun lun; + uint8_t lun[8]; itt_t itt; /* Initiator Task Tag */ __be32 ttt; /* Target Transfer Tag */ __be32 cmdsn; @@ -241,7 +241,7 @@ struct iscsi_nopin { __be16 rsvd2; uint8_t rsvd3; uint8_t dlength[3]; - struct scsi_lun lun; + uint8_t lun[8]; itt_t itt; /* Initiator Task Tag */ __be32 ttt; /* Target Transfer Tag */ __be32 statsn; @@ -257,7 +257,7 @@ struct iscsi_tm { uint8_t rsvd1[2]; uint8_t hlength; uint8_t dlength[3]; - struct scsi_lun lun; + uint8_t lun[8]; itt_t itt; /* Initiator Task Tag */ itt_t rtt; /* Reference Task Tag */ __be32 cmdsn; @@ -315,7 +315,7 @@ struct iscsi_r2t_rsp { uint8_t rsvd2[2]; uint8_t hlength; uint8_t dlength[3]; - struct scsi_lun lun; + uint8_t lun[8]; itt_t itt; /* Initiator Task Tag */ __be32 ttt; /* Target Transfer Tag */ __be32 statsn; @@ -333,7 +333,7 @@ struct iscsi_data { uint8_t rsvd2[2]; uint8_t rsvd3; uint8_t dlength[3]; - struct scsi_lun lun; + uint8_t lun[8]; itt_t itt; __be32 ttt; __be32 rsvd4; @@ -353,7 +353,7 @@ struct iscsi_data_rsp { uint8_t cmd_status; uint8_t hlength; uint8_t dlength[3]; - struct scsi_lun lun; + uint8_t lun[8]; itt_t itt; __be32 ttt; __be32 statsn; diff --git a/trunk/include/scsi/libfc.h b/trunk/include/scsi/libfc.h index 7d96829b0c00..a3cbda4ddb5c 100644 --- a/trunk/include/scsi/libfc.h +++ b/trunk/include/scsi/libfc.h @@ -510,14 +510,6 @@ struct libfc_function_template { * STATUS: OPTIONAL */ int (*ddp_done)(struct fc_lport *, u16); - /* - * Sets up the DDP context for a given exchange id on the given - * scatterlist if LLD supports DDP for FCoE target. - * - * STATUS: OPTIONAL - */ - int (*ddp_target)(struct fc_lport *, u16, struct scatterlist *, - unsigned int); /* * Allow LLD to fill its own Link Error Status Block * diff --git a/trunk/include/scsi/libiscsi.h b/trunk/include/scsi/libiscsi.h index cedcff371c88..0f4367751b71 100644 --- a/trunk/include/scsi/libiscsi.h +++ b/trunk/include/scsi/libiscsi.h @@ -115,7 +115,7 @@ struct iscsi_task { /* copied values in case we need to send tmfs */ itt_t hdr_itt; __be32 cmdsn; - struct scsi_lun lun; + uint8_t lun[8]; int itt; /* this ITT */ diff --git a/trunk/include/sound/rawmidi.h b/trunk/include/sound/rawmidi.h index 6b14359d9fed..2480e7d10dcf 100644 --- a/trunk/include/sound/rawmidi.h +++ b/trunk/include/sound/rawmidi.h @@ -27,7 +27,6 @@ #include #include #include -#include #if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE) #include "seq_device.h" @@ -64,7 +63,6 @@ struct snd_rawmidi_global_ops { }; struct snd_rawmidi_runtime { - struct snd_rawmidi_substream *substream; unsigned int drain: 1, /* drain stage */ oss: 1; /* OSS compatible mode */ /* midi stream buffer */ @@ -81,7 +79,7 @@ struct snd_rawmidi_runtime { /* event handler (new bytes, input only) */ void (*event)(struct snd_rawmidi_substream *substream); /* defers calls to event [input] or ops->trigger [output] */ - struct work_struct event_work; + struct tasklet_struct tasklet; /* private data */ void *private_data; void (*private_free)(struct snd_rawmidi_substream *substream); diff --git a/trunk/include/sound/soc-dai.h b/trunk/include/sound/soc-dai.h index 5ad5f3a50c68..1bafe95dcf41 100644 --- a/trunk/include/sound/soc-dai.h +++ b/trunk/include/sound/soc-dai.h @@ -209,10 +209,6 @@ struct snd_soc_dai_driver { struct snd_soc_pcm_stream capture; struct snd_soc_pcm_stream playback; unsigned int symmetric_rates:1; - - /* probe ordering - for components with runtime dependencies */ - int probe_order; - int remove_order; }; /* diff --git a/trunk/include/sound/soc-dapm.h b/trunk/include/sound/soc-dapm.h index e09505c5a490..c46e7d89561d 100644 --- a/trunk/include/sound/soc-dapm.h +++ b/trunk/include/sound/soc-dapm.h @@ -348,8 +348,6 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm); void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm); int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm, const struct snd_soc_dapm_route *route, int num); -int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm, - const struct snd_soc_dapm_route *route, int num); /* dapm events */ int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, @@ -431,7 +429,6 @@ struct snd_soc_dapm_path { /* status */ u32 connect:1; /* source and sink widgets are connected */ u32 walked:1; /* path has been walked */ - u32 weak:1; /* path ignored for power management */ int (*connected)(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink); @@ -447,7 +444,6 @@ struct snd_soc_dapm_widget { char *name; /* widget name */ char *sname; /* stream name */ struct snd_soc_codec *codec; - struct snd_soc_platform *platform; struct list_head list; struct snd_soc_dapm_context *dapm; @@ -511,11 +507,10 @@ struct snd_soc_dapm_context { struct device *dev; /* from parent - for debug */ struct snd_soc_codec *codec; /* parent codec */ - struct snd_soc_platform *platform; /* parent platform */ struct snd_soc_card *card; /* parent card */ /* used during DAPM updates */ - enum snd_soc_bias_level target_bias_level; + int dev_power; struct list_head list; #ifdef CONFIG_DEBUG_FS diff --git a/trunk/include/sound/soc.h b/trunk/include/sound/soc.h index aa19f5a32ba8..3a4bd3a3c68d 100644 --- a/trunk/include/sound/soc.h +++ b/trunk/include/sound/soc.h @@ -202,16 +202,6 @@ #define SOC_VALUE_ENUM_SINGLE_DECL(name, xreg, xshift, xmask, xtexts, xvalues) \ SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xmask, xtexts, xvalues) -/* - * Component probe and remove ordering levels for components with runtime - * dependencies. - */ -#define SND_SOC_COMP_ORDER_FIRST -2 -#define SND_SOC_COMP_ORDER_EARLY -1 -#define SND_SOC_COMP_ORDER_NORMAL 0 -#define SND_SOC_COMP_ORDER_LATE 1 -#define SND_SOC_COMP_ORDER_LAST 2 - /* * Bias levels * @@ -224,10 +214,10 @@ * @OFF: Power Off. No restrictions on transition times. */ enum snd_soc_bias_level { - SND_SOC_BIAS_OFF = 0, - SND_SOC_BIAS_STANDBY = 1, - SND_SOC_BIAS_PREPARE = 2, - SND_SOC_BIAS_ON = 3, + SND_SOC_BIAS_OFF, + SND_SOC_BIAS_STANDBY, + SND_SOC_BIAS_PREPARE, + SND_SOC_BIAS_ON, }; struct snd_jack; @@ -268,11 +258,6 @@ enum snd_soc_compress_type { SND_SOC_RBTREE_COMPRESSION }; -enum snd_soc_pcm_subclass { - SND_SOC_PCM_CLASS_PCM = 0, - SND_SOC_PCM_CLASS_BE = 1, -}; - int snd_soc_codec_set_sysclk(struct snd_soc_codec *codec, int clk_id, unsigned int freq, int dir); int snd_soc_codec_set_pll(struct snd_soc_codec *codec, int pll_id, int source, @@ -312,10 +297,6 @@ int snd_soc_default_readable_register(struct snd_soc_codec *codec, unsigned int reg); int snd_soc_default_writable_register(struct snd_soc_codec *codec, unsigned int reg); -int snd_soc_platform_read(struct snd_soc_platform *platform, - unsigned int reg); -int snd_soc_platform_write(struct snd_soc_platform *platform, - unsigned int reg, unsigned int val); /* Utility functions to get clock rates from various things */ int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots); @@ -368,8 +349,6 @@ struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template, const char *prefix); int snd_soc_add_controls(struct snd_soc_codec *codec, const struct snd_kcontrol_new *controls, int num_controls); -int snd_soc_add_platform_controls(struct snd_soc_platform *platform, - const struct snd_kcontrol_new *controls, int num_controls); int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol, @@ -633,10 +612,6 @@ struct snd_soc_codec_driver { void (*seq_notifier)(struct snd_soc_dapm_context *, enum snd_soc_dapm_type, int); - - /* probe ordering - for components with runtime dependencies */ - int probe_order; - int remove_order; }; /* SoC platform interface */ @@ -648,17 +623,10 @@ struct snd_soc_platform_driver { int (*resume)(struct snd_soc_dai *dai); /* pcm creation and destruction */ - int (*pcm_new)(struct snd_soc_pcm_runtime *); + int (*pcm_new)(struct snd_card *, struct snd_soc_dai *, + struct snd_pcm *); void (*pcm_free)(struct snd_pcm *); - /* Default control and setup, added after probe() is run */ - const struct snd_kcontrol_new *controls; - int num_controls; - const struct snd_soc_dapm_widget *dapm_widgets; - int num_dapm_widgets; - const struct snd_soc_dapm_route *dapm_routes; - int num_dapm_routes; - /* * For platform caused delay reporting. * Optional. @@ -668,14 +636,6 @@ struct snd_soc_platform_driver { /* platform stream ops */ struct snd_pcm_ops *ops; - - /* probe ordering - for components with runtime dependencies */ - int probe_order; - int remove_order; - - /* platform IO - used for platform DAPM */ - unsigned int (*read)(struct snd_soc_platform *, unsigned int); - int (*write)(struct snd_soc_platform *, unsigned int, unsigned int); }; struct snd_soc_platform { @@ -690,8 +650,6 @@ struct snd_soc_platform { struct snd_soc_card *card; struct list_head list; struct list_head card_list; - - struct snd_soc_dapm_context dapm; }; struct snd_soc_dai_link { @@ -767,10 +725,8 @@ struct snd_soc_card { /* callbacks */ int (*set_bias_level)(struct snd_soc_card *, - struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level); int (*set_bias_level_post)(struct snd_soc_card *, - struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level); long pmdown_time; @@ -833,9 +789,6 @@ struct snd_soc_pcm_runtime { struct device dev; struct snd_soc_card *card; struct snd_soc_dai_link *dai_link; - struct mutex pcm_mutex; - enum snd_soc_pcm_subclass pcm_subclass; - struct snd_pcm_ops ops; unsigned int complete:1; unsigned int dev_registered:1; diff --git a/trunk/include/trace/events/asoc.h b/trunk/include/trace/events/asoc.h index 603f5a0f0365..ae973d2e27a1 100644 --- a/trunk/include/trace/events/asoc.h +++ b/trunk/include/trace/events/asoc.h @@ -9,7 +9,6 @@ struct snd_soc_jack; struct snd_soc_codec; -struct snd_soc_platform; struct snd_soc_card; struct snd_soc_dapm_widget; @@ -60,50 +59,6 @@ DEFINE_EVENT(snd_soc_reg, snd_soc_reg_read, ); -DECLARE_EVENT_CLASS(snd_soc_preg, - - TP_PROTO(struct snd_soc_platform *platform, unsigned int reg, - unsigned int val), - - TP_ARGS(platform, reg, val), - - TP_STRUCT__entry( - __string( name, platform->name ) - __field( int, id ) - __field( unsigned int, reg ) - __field( unsigned int, val ) - ), - - TP_fast_assign( - __assign_str(name, platform->name); - __entry->id = platform->id; - __entry->reg = reg; - __entry->val = val; - ), - - TP_printk("platform=%s.%d reg=%x val=%x", __get_str(name), - (int)__entry->id, (unsigned int)__entry->reg, - (unsigned int)__entry->val) -); - -DEFINE_EVENT(snd_soc_preg, snd_soc_preg_write, - - TP_PROTO(struct snd_soc_platform *platform, unsigned int reg, - unsigned int val), - - TP_ARGS(platform, reg, val) - -); - -DEFINE_EVENT(snd_soc_preg, snd_soc_preg_read, - - TP_PROTO(struct snd_soc_platform *platform, unsigned int reg, - unsigned int val), - - TP_ARGS(platform, reg, val) - -); - DECLARE_EVENT_CLASS(snd_soc_card, TP_PROTO(struct snd_soc_card *card, int val), diff --git a/trunk/include/trace/events/vmscan.h b/trunk/include/trace/events/vmscan.h index 36851f7f13da..b2c33bd955fa 100644 --- a/trunk/include/trace/events/vmscan.h +++ b/trunk/include/trace/events/vmscan.h @@ -179,83 +179,6 @@ DEFINE_EVENT(mm_vmscan_direct_reclaim_end_template, mm_vmscan_memcg_softlimit_re TP_ARGS(nr_reclaimed) ); -TRACE_EVENT(mm_shrink_slab_start, - TP_PROTO(struct shrinker *shr, struct shrink_control *sc, - long nr_objects_to_shrink, unsigned long pgs_scanned, - unsigned long lru_pgs, unsigned long cache_items, - unsigned long long delta, unsigned long total_scan), - - TP_ARGS(shr, sc, nr_objects_to_shrink, pgs_scanned, lru_pgs, - cache_items, delta, total_scan), - - TP_STRUCT__entry( - __field(struct shrinker *, shr) - __field(void *, shrink) - __field(long, nr_objects_to_shrink) - __field(gfp_t, gfp_flags) - __field(unsigned long, pgs_scanned) - __field(unsigned long, lru_pgs) - __field(unsigned long, cache_items) - __field(unsigned long long, delta) - __field(unsigned long, total_scan) - ), - - TP_fast_assign( - __entry->shr = shr; - __entry->shrink = shr->shrink; - __entry->nr_objects_to_shrink = nr_objects_to_shrink; - __entry->gfp_flags = sc->gfp_mask; - __entry->pgs_scanned = pgs_scanned; - __entry->lru_pgs = lru_pgs; - __entry->cache_items = cache_items; - __entry->delta = delta; - __entry->total_scan = total_scan; - ), - - TP_printk("%pF %p: objects to shrink %ld gfp_flags %s pgs_scanned %ld lru_pgs %ld cache items %ld delta %lld total_scan %ld", - __entry->shrink, - __entry->shr, - __entry->nr_objects_to_shrink, - show_gfp_flags(__entry->gfp_flags), - __entry->pgs_scanned, - __entry->lru_pgs, - __entry->cache_items, - __entry->delta, - __entry->total_scan) -); - -TRACE_EVENT(mm_shrink_slab_end, - TP_PROTO(struct shrinker *shr, int shrinker_retval, - long unused_scan_cnt, long new_scan_cnt), - - TP_ARGS(shr, shrinker_retval, unused_scan_cnt, new_scan_cnt), - - TP_STRUCT__entry( - __field(struct shrinker *, shr) - __field(void *, shrink) - __field(long, unused_scan) - __field(long, new_scan) - __field(int, retval) - __field(long, total_scan) - ), - - TP_fast_assign( - __entry->shr = shr; - __entry->shrink = shr->shrink; - __entry->unused_scan = unused_scan_cnt; - __entry->new_scan = new_scan_cnt; - __entry->retval = shrinker_retval; - __entry->total_scan = new_scan_cnt - unused_scan_cnt; - ), - - TP_printk("%pF %p: unused scan count %ld new scan count %ld total_scan %ld last shrinker return val %d", - __entry->shrink, - __entry->shr, - __entry->unused_scan, - __entry->new_scan, - __entry->total_scan, - __entry->retval) -); DECLARE_EVENT_CLASS(mm_vmscan_lru_isolate_template, diff --git a/trunk/include/trace/events/xen.h b/trunk/include/trace/events/xen.h deleted file mode 100644 index 44d8decee09e..000000000000 --- a/trunk/include/trace/events/xen.h +++ /dev/null @@ -1,504 +0,0 @@ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM xen - -#if !defined(_TRACE_XEN_H) || defined(TRACE_HEADER_MULTI_READ) -#define _TRACE_XEN_H - -#include -#include -#include - -/* Multicalls */ -DECLARE_EVENT_CLASS(xen_mc__batch, - TP_PROTO(enum paravirt_lazy_mode mode), - TP_ARGS(mode), - TP_STRUCT__entry( - __field(enum paravirt_lazy_mode, mode) - ), - TP_fast_assign(__entry->mode = mode), - TP_printk("start batch LAZY_%s", - (__entry->mode == PARAVIRT_LAZY_MMU) ? "MMU" : - (__entry->mode == PARAVIRT_LAZY_CPU) ? "CPU" : "NONE") - ); -#define DEFINE_XEN_MC_BATCH(name) \ - DEFINE_EVENT(xen_mc__batch, name, \ - TP_PROTO(enum paravirt_lazy_mode mode), \ - TP_ARGS(mode)) - -DEFINE_XEN_MC_BATCH(xen_mc_batch); -DEFINE_XEN_MC_BATCH(xen_mc_issue); - -TRACE_EVENT(xen_mc_entry, - TP_PROTO(struct multicall_entry *mc, unsigned nargs), - TP_ARGS(mc, nargs), - TP_STRUCT__entry( - __field(unsigned int, op) - __field(unsigned int, nargs) - __array(unsigned long, args, 6) - ), - TP_fast_assign(__entry->op = mc->op; - __entry->nargs = nargs; - memcpy(__entry->args, mc->args, sizeof(unsigned long) * nargs); - memset(__entry->args + nargs, 0, sizeof(unsigned long) * (6 - nargs)); - ), - TP_printk("op %u%s args [%lx, %lx, %lx, %lx, %lx, %lx]", - __entry->op, xen_hypercall_name(__entry->op), - __entry->args[0], __entry->args[1], __entry->args[2], - __entry->args[3], __entry->args[4], __entry->args[5]) - ); - -TRACE_EVENT(xen_mc_entry_alloc, - TP_PROTO(size_t args), - TP_ARGS(args), - TP_STRUCT__entry( - __field(size_t, args) - ), - TP_fast_assign(__entry->args = args), - TP_printk("alloc entry %zu arg bytes", __entry->args) - ); - -TRACE_EVENT(xen_mc_callback, - TP_PROTO(xen_mc_callback_fn_t fn, void *data), - TP_ARGS(fn, data), - TP_STRUCT__entry( - __field(xen_mc_callback_fn_t, fn) - __field(void *, data) - ), - TP_fast_assign( - __entry->fn = fn; - __entry->data = data; - ), - TP_printk("callback %pf, data %p", - __entry->fn, __entry->data) - ); - -TRACE_EVENT(xen_mc_flush_reason, - TP_PROTO(enum xen_mc_flush_reason reason), - TP_ARGS(reason), - TP_STRUCT__entry( - __field(enum xen_mc_flush_reason, reason) - ), - TP_fast_assign(__entry->reason = reason), - TP_printk("flush reason %s", - (__entry->reason == XEN_MC_FL_NONE) ? "NONE" : - (__entry->reason == XEN_MC_FL_BATCH) ? "BATCH" : - (__entry->reason == XEN_MC_FL_ARGS) ? "ARGS" : - (__entry->reason == XEN_MC_FL_CALLBACK) ? "CALLBACK" : "??") - ); - -TRACE_EVENT(xen_mc_flush, - TP_PROTO(unsigned mcidx, unsigned argidx, unsigned cbidx), - TP_ARGS(mcidx, argidx, cbidx), - TP_STRUCT__entry( - __field(unsigned, mcidx) - __field(unsigned, argidx) - __field(unsigned, cbidx) - ), - TP_fast_assign(__entry->mcidx = mcidx; - __entry->argidx = argidx; - __entry->cbidx = cbidx), - TP_printk("flushing %u hypercalls, %u arg bytes, %u callbacks", - __entry->mcidx, __entry->argidx, __entry->cbidx) - ); - -TRACE_EVENT(xen_mc_extend_args, - TP_PROTO(unsigned long op, size_t args, enum xen_mc_extend_args res), - TP_ARGS(op, args, res), - TP_STRUCT__entry( - __field(unsigned int, op) - __field(size_t, args) - __field(enum xen_mc_extend_args, res) - ), - TP_fast_assign(__entry->op = op; - __entry->args = args; - __entry->res = res), - TP_printk("extending op %u%s by %zu bytes res %s", - __entry->op, xen_hypercall_name(__entry->op), - __entry->args, - __entry->res == XEN_MC_XE_OK ? "OK" : - __entry->res == XEN_MC_XE_BAD_OP ? "BAD_OP" : - __entry->res == XEN_MC_XE_NO_SPACE ? "NO_SPACE" : "???") - ); - -/* mmu */ -DECLARE_EVENT_CLASS(xen_mmu__set_pte, - TP_PROTO(pte_t *ptep, pte_t pteval), - TP_ARGS(ptep, pteval), - TP_STRUCT__entry( - __field(pte_t *, ptep) - __field(pteval_t, pteval) - ), - TP_fast_assign(__entry->ptep = ptep; - __entry->pteval = pteval.pte), - TP_printk("ptep %p pteval %0*llx (raw %0*llx)", - __entry->ptep, - (int)sizeof(pteval_t) * 2, (unsigned long long)pte_val(native_make_pte(__entry->pteval)), - (int)sizeof(pteval_t) * 2, (unsigned long long)__entry->pteval) - ); - -#define DEFINE_XEN_MMU_SET_PTE(name) \ - DEFINE_EVENT(xen_mmu__set_pte, name, \ - TP_PROTO(pte_t *ptep, pte_t pteval), \ - TP_ARGS(ptep, pteval)) - -DEFINE_XEN_MMU_SET_PTE(xen_mmu_set_pte); -DEFINE_XEN_MMU_SET_PTE(xen_mmu_set_pte_atomic); - -TRACE_EVENT(xen_mmu_set_domain_pte, - TP_PROTO(pte_t *ptep, pte_t pteval, unsigned domid), - TP_ARGS(ptep, pteval, domid), - TP_STRUCT__entry( - __field(pte_t *, ptep) - __field(pteval_t, pteval) - __field(unsigned, domid) - ), - TP_fast_assign(__entry->ptep = ptep; - __entry->pteval = pteval.pte; - __entry->domid = domid), - TP_printk("ptep %p pteval %0*llx (raw %0*llx) domid %u", - __entry->ptep, - (int)sizeof(pteval_t) * 2, (unsigned long long)pte_val(native_make_pte(__entry->pteval)), - (int)sizeof(pteval_t) * 2, (unsigned long long)__entry->pteval, - __entry->domid) - ); - -TRACE_EVENT(xen_mmu_set_pte_at, - TP_PROTO(struct mm_struct *mm, unsigned long addr, - pte_t *ptep, pte_t pteval), - TP_ARGS(mm, addr, ptep, pteval), - TP_STRUCT__entry( - __field(struct mm_struct *, mm) - __field(unsigned long, addr) - __field(pte_t *, ptep) - __field(pteval_t, pteval) - ), - TP_fast_assign(__entry->mm = mm; - __entry->addr = addr; - __entry->ptep = ptep; - __entry->pteval = pteval.pte), - TP_printk("mm %p addr %lx ptep %p pteval %0*llx (raw %0*llx)", - __entry->mm, __entry->addr, __entry->ptep, - (int)sizeof(pteval_t) * 2, (unsigned long long)pte_val(native_make_pte(__entry->pteval)), - (int)sizeof(pteval_t) * 2, (unsigned long long)__entry->pteval) - ); - -TRACE_EVENT(xen_mmu_pte_clear, - TP_PROTO(struct mm_struct *mm, unsigned long addr, pte_t *ptep), - TP_ARGS(mm, addr, ptep), - TP_STRUCT__entry( - __field(struct mm_struct *, mm) - __field(unsigned long, addr) - __field(pte_t *, ptep) - ), - TP_fast_assign(__entry->mm = mm; - __entry->addr = addr; - __entry->ptep = ptep), - TP_printk("mm %p addr %lx ptep %p", - __entry->mm, __entry->addr, __entry->ptep) - ); - -TRACE_EVENT(xen_mmu_set_pmd, - TP_PROTO(pmd_t *pmdp, pmd_t pmdval), - TP_ARGS(pmdp, pmdval), - TP_STRUCT__entry( - __field(pmd_t *, pmdp) - __field(pmdval_t, pmdval) - ), - TP_fast_assign(__entry->pmdp = pmdp; - __entry->pmdval = pmdval.pmd), - TP_printk("pmdp %p pmdval %0*llx (raw %0*llx)", - __entry->pmdp, - (int)sizeof(pmdval_t) * 2, (unsigned long long)pmd_val(native_make_pmd(__entry->pmdval)), - (int)sizeof(pmdval_t) * 2, (unsigned long long)__entry->pmdval) - ); - -TRACE_EVENT(xen_mmu_pmd_clear, - TP_PROTO(pmd_t *pmdp), - TP_ARGS(pmdp), - TP_STRUCT__entry( - __field(pmd_t *, pmdp) - ), - TP_fast_assign(__entry->pmdp = pmdp), - TP_printk("pmdp %p", __entry->pmdp) - ); - -#if PAGETABLE_LEVELS >= 4 - -TRACE_EVENT(xen_mmu_set_pud, - TP_PROTO(pud_t *pudp, pud_t pudval), - TP_ARGS(pudp, pudval), - TP_STRUCT__entry( - __field(pud_t *, pudp) - __field(pudval_t, pudval) - ), - TP_fast_assign(__entry->pudp = pudp; - __entry->pudval = native_pud_val(pudval)), - TP_printk("pudp %p pudval %0*llx (raw %0*llx)", - __entry->pudp, - (int)sizeof(pudval_t) * 2, (unsigned long long)pud_val(native_make_pud(__entry->pudval)), - (int)sizeof(pudval_t) * 2, (unsigned long long)__entry->pudval) - ); - -TRACE_EVENT(xen_mmu_set_pgd, - TP_PROTO(pgd_t *pgdp, pgd_t *user_pgdp, pgd_t pgdval), - TP_ARGS(pgdp, user_pgdp, pgdval), - TP_STRUCT__entry( - __field(pgd_t *, pgdp) - __field(pgd_t *, user_pgdp) - __field(pgdval_t, pgdval) - ), - TP_fast_assign(__entry->pgdp = pgdp; - __entry->user_pgdp = user_pgdp; - __entry->pgdval = pgdval.pgd), - TP_printk("pgdp %p user_pgdp %p pgdval %0*llx (raw %0*llx)", - __entry->pgdp, __entry->user_pgdp, - (int)sizeof(pgdval_t) * 2, (unsigned long long)pgd_val(native_make_pgd(__entry->pgdval)), - (int)sizeof(pgdval_t) * 2, (unsigned long long)__entry->pgdval) - ); - -TRACE_EVENT(xen_mmu_pud_clear, - TP_PROTO(pud_t *pudp), - TP_ARGS(pudp), - TP_STRUCT__entry( - __field(pud_t *, pudp) - ), - TP_fast_assign(__entry->pudp = pudp), - TP_printk("pudp %p", __entry->pudp) - ); -#else - -TRACE_EVENT(xen_mmu_set_pud, - TP_PROTO(pud_t *pudp, pud_t pudval), - TP_ARGS(pudp, pudval), - TP_STRUCT__entry( - __field(pud_t *, pudp) - __field(pudval_t, pudval) - ), - TP_fast_assign(__entry->pudp = pudp; - __entry->pudval = native_pud_val(pudval)), - TP_printk("pudp %p pudval %0*llx (raw %0*llx)", - __entry->pudp, - (int)sizeof(pudval_t) * 2, (unsigned long long)pgd_val(native_make_pgd(__entry->pudval)), - (int)sizeof(pudval_t) * 2, (unsigned long long)__entry->pudval) - ); - -#endif - -TRACE_EVENT(xen_mmu_pgd_clear, - TP_PROTO(pgd_t *pgdp), - TP_ARGS(pgdp), - TP_STRUCT__entry( - __field(pgd_t *, pgdp) - ), - TP_fast_assign(__entry->pgdp = pgdp), - TP_printk("pgdp %p", __entry->pgdp) - ); - -DECLARE_EVENT_CLASS(xen_mmu_ptep_modify_prot, - TP_PROTO(struct mm_struct *mm, unsigned long addr, - pte_t *ptep, pte_t pteval), - TP_ARGS(mm, addr, ptep, pteval), - TP_STRUCT__entry( - __field(struct mm_struct *, mm) - __field(unsigned long, addr) - __field(pte_t *, ptep) - __field(pteval_t, pteval) - ), - TP_fast_assign(__entry->mm = mm; - __entry->addr = addr; - __entry->ptep = ptep; - __entry->pteval = pteval.pte), - TP_printk("mm %p addr %lx ptep %p pteval %0*llx (raw %0*llx)", - __entry->mm, __entry->addr, __entry->ptep, - (int)sizeof(pteval_t) * 2, (unsigned long long)pte_val(native_make_pte(__entry->pteval)), - (int)sizeof(pteval_t) * 2, (unsigned long long)__entry->pteval) - ); -#define DEFINE_XEN_MMU_PTEP_MODIFY_PROT(name) \ - DEFINE_EVENT(xen_mmu_ptep_modify_prot, name, \ - TP_PROTO(struct mm_struct *mm, unsigned long addr, \ - pte_t *ptep, pte_t pteval), \ - TP_ARGS(mm, addr, ptep, pteval)) - -DEFINE_XEN_MMU_PTEP_MODIFY_PROT(xen_mmu_ptep_modify_prot_start); -DEFINE_XEN_MMU_PTEP_MODIFY_PROT(xen_mmu_ptep_modify_prot_commit); - -TRACE_EVENT(xen_mmu_alloc_ptpage, - TP_PROTO(struct mm_struct *mm, unsigned long pfn, unsigned level, bool pinned), - TP_ARGS(mm, pfn, level, pinned), - TP_STRUCT__entry( - __field(struct mm_struct *, mm) - __field(unsigned long, pfn) - __field(unsigned, level) - __field(bool, pinned) - ), - TP_fast_assign(__entry->mm = mm; - __entry->pfn = pfn; - __entry->level = level; - __entry->pinned = pinned), - TP_printk("mm %p pfn %lx level %d %spinned", - __entry->mm, __entry->pfn, __entry->level, - __entry->pinned ? "" : "un") - ); - -TRACE_EVENT(xen_mmu_release_ptpage, - TP_PROTO(unsigned long pfn, unsigned level, bool pinned), - TP_ARGS(pfn, level, pinned), - TP_STRUCT__entry( - __field(unsigned long, pfn) - __field(unsigned, level) - __field(bool, pinned) - ), - TP_fast_assign(__entry->pfn = pfn; - __entry->level = level; - __entry->pinned = pinned), - TP_printk("pfn %lx level %d %spinned", - __entry->pfn, __entry->level, - __entry->pinned ? "" : "un") - ); - -DECLARE_EVENT_CLASS(xen_mmu_pgd, - TP_PROTO(struct mm_struct *mm, pgd_t *pgd), - TP_ARGS(mm, pgd), - TP_STRUCT__entry( - __field(struct mm_struct *, mm) - __field(pgd_t *, pgd) - ), - TP_fast_assign(__entry->mm = mm; - __entry->pgd = pgd), - TP_printk("mm %p pgd %p", __entry->mm, __entry->pgd) - ); -#define DEFINE_XEN_MMU_PGD_EVENT(name) \ - DEFINE_EVENT(xen_mmu_pgd, name, \ - TP_PROTO(struct mm_struct *mm, pgd_t *pgd), \ - TP_ARGS(mm, pgd)) - -DEFINE_XEN_MMU_PGD_EVENT(xen_mmu_pgd_pin); -DEFINE_XEN_MMU_PGD_EVENT(xen_mmu_pgd_unpin); - -TRACE_EVENT(xen_mmu_flush_tlb, - TP_PROTO(int x), - TP_ARGS(x), - TP_STRUCT__entry(__array(char, x, 0)), - TP_fast_assign((void)x), - TP_printk("%s", "") - ); - -TRACE_EVENT(xen_mmu_flush_tlb_single, - TP_PROTO(unsigned long addr), - TP_ARGS(addr), - TP_STRUCT__entry( - __field(unsigned long, addr) - ), - TP_fast_assign(__entry->addr = addr), - TP_printk("addr %lx", __entry->addr) - ); - -TRACE_EVENT(xen_mmu_flush_tlb_others, - TP_PROTO(const struct cpumask *cpus, struct mm_struct *mm, - unsigned long addr), - TP_ARGS(cpus, mm, addr), - TP_STRUCT__entry( - __field(unsigned, ncpus) - __field(struct mm_struct *, mm) - __field(unsigned long, addr) - ), - TP_fast_assign(__entry->ncpus = cpumask_weight(cpus); - __entry->mm = mm; - __entry->addr = addr), - TP_printk("ncpus %d mm %p addr %lx", - __entry->ncpus, __entry->mm, __entry->addr) - ); - -TRACE_EVENT(xen_mmu_write_cr3, - TP_PROTO(bool kernel, unsigned long cr3), - TP_ARGS(kernel, cr3), - TP_STRUCT__entry( - __field(bool, kernel) - __field(unsigned long, cr3) - ), - TP_fast_assign(__entry->kernel = kernel; - __entry->cr3 = cr3), - TP_printk("%s cr3 %lx", - __entry->kernel ? "kernel" : "user", __entry->cr3) - ); - - -/* CPU */ -TRACE_EVENT(xen_cpu_write_ldt_entry, - TP_PROTO(struct desc_struct *dt, int entrynum, u64 desc), - TP_ARGS(dt, entrynum, desc), - TP_STRUCT__entry( - __field(struct desc_struct *, dt) - __field(int, entrynum) - __field(u64, desc) - ), - TP_fast_assign(__entry->dt = dt; - __entry->entrynum = entrynum; - __entry->desc = desc; - ), - TP_printk("dt %p entrynum %d entry %016llx", - __entry->dt, __entry->entrynum, - (unsigned long long)__entry->desc) - ); - -TRACE_EVENT(xen_cpu_write_idt_entry, - TP_PROTO(gate_desc *dt, int entrynum, const gate_desc *ent), - TP_ARGS(dt, entrynum, ent), - TP_STRUCT__entry( - __field(gate_desc *, dt) - __field(int, entrynum) - ), - TP_fast_assign(__entry->dt = dt; - __entry->entrynum = entrynum; - ), - TP_printk("dt %p entrynum %d", - __entry->dt, __entry->entrynum) - ); - -TRACE_EVENT(xen_cpu_load_idt, - TP_PROTO(const struct desc_ptr *desc), - TP_ARGS(desc), - TP_STRUCT__entry( - __field(unsigned long, addr) - ), - TP_fast_assign(__entry->addr = desc->address), - TP_printk("addr %lx", __entry->addr) - ); - -TRACE_EVENT(xen_cpu_write_gdt_entry, - TP_PROTO(struct desc_struct *dt, int entrynum, const void *desc, int type), - TP_ARGS(dt, entrynum, desc, type), - TP_STRUCT__entry( - __field(u64, desc) - __field(struct desc_struct *, dt) - __field(int, entrynum) - __field(int, type) - ), - TP_fast_assign(__entry->dt = dt; - __entry->entrynum = entrynum; - __entry->desc = *(u64 *)desc; - __entry->type = type; - ), - TP_printk("dt %p entrynum %d type %d desc %016llx", - __entry->dt, __entry->entrynum, __entry->type, - (unsigned long long)__entry->desc) - ); - -TRACE_EVENT(xen_cpu_set_ldt, - TP_PROTO(const void *addr, unsigned entries), - TP_ARGS(addr, entries), - TP_STRUCT__entry( - __field(const void *, addr) - __field(unsigned, entries) - ), - TP_fast_assign(__entry->addr = addr; - __entry->entries = entries), - TP_printk("addr %p entries %u", - __entry->addr, __entry->entries) - ); - - -#endif /* _TRACE_XEN_H */ - -/* This part must be outside protection */ -#include diff --git a/trunk/init/Kconfig b/trunk/init/Kconfig index e20aa3112240..412c21b00d51 100644 --- a/trunk/init/Kconfig +++ b/trunk/init/Kconfig @@ -917,8 +917,6 @@ config ANON_INODES menuconfig EXPERT bool "Configure standard kernel features (expert users)" - # Unhide debug options, to make the on-by-default options visible - select DEBUG_KERNEL help This option allows certain base kernel options and settings to be disabled or tweaked. This is for specialized @@ -1009,19 +1007,14 @@ config ELF_CORE help Enable support for generating core dumps. Disabling saves about 4k. - config PCSPKR_PLATFORM bool "Enable PC-Speaker support" if EXPERT - depends on HAVE_PCSPKR_PLATFORM - select I8253_LOCK + depends on ALPHA || X86 || MIPS || PPC_PREP || PPC_CHRP || PPC_PSERIES default y help This option allows to disable the internal PC-Speaker support, saving some memory. -config HAVE_PCSPKR_PLATFORM - bool - config BASE_FULL default y bool "Enable full-sized data structures for core" if EXPERT diff --git a/trunk/ipc/sem.c b/trunk/ipc/sem.c index 8b929e6a6eda..34193ed69fbe 100644 --- a/trunk/ipc/sem.c +++ b/trunk/ipc/sem.c @@ -689,6 +689,12 @@ static int count_semzcnt (struct sem_array * sma, ushort semnum) return semzcnt; } +static void free_un(struct rcu_head *head) +{ + struct sem_undo *un = container_of(head, struct sem_undo, rcu); + kfree(un); +} + /* Free a semaphore set. freeary() is called with sem_ids.rw_mutex locked * as a writer and the spinlock for this semaphore set hold. sem_ids.rw_mutex * remains locked on exit. @@ -708,7 +714,7 @@ static void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp) un->semid = -1; list_del_rcu(&un->list_proc); spin_unlock(&un->ulp->lock); - kfree_rcu(un, rcu); + call_rcu(&un->rcu, free_un); } /* Wake up all pending processes and let them fail with EIDRM. */ @@ -1606,7 +1612,7 @@ void exit_sem(struct task_struct *tsk) sem_unlock(sma); wake_up_sem_queue_do(&tasks); - kfree_rcu(un, rcu); + call_rcu(&un->rcu, free_un); } kfree(ulp); } diff --git a/trunk/ipc/shm.c b/trunk/ipc/shm.c index 27884adb1a90..ab3385a21b27 100644 --- a/trunk/ipc/shm.c +++ b/trunk/ipc/shm.c @@ -277,13 +277,13 @@ static int shm_release(struct inode *ino, struct file *file) return 0; } -static int shm_fsync(struct file *file, loff_t start, loff_t end, int datasync) +static int shm_fsync(struct file *file, int datasync) { struct shm_file_data *sfd = shm_file_data(file); if (!sfd->file->f_op->fsync) return -EINVAL; - return sfd->file->f_op->fsync(sfd->file, start, end, datasync); + return sfd->file->f_op->fsync(sfd->file, datasync); } static unsigned long shm_get_unmapped_area(struct file *file, diff --git a/trunk/ipc/util.c b/trunk/ipc/util.c index 75261a31d48d..5c0d28921ba8 100644 --- a/trunk/ipc/util.c +++ b/trunk/ipc/util.c @@ -579,6 +579,19 @@ static void ipc_schedule_free(struct rcu_head *head) schedule_work(&sched->work); } +/** + * ipc_immediate_free - free ipc + rcu space + * @head: RCU callback structure that contains pointer to be freed + * + * Free from the RCU callback context. + */ +static void ipc_immediate_free(struct rcu_head *head) +{ + struct ipc_rcu_grace *free = + container_of(head, struct ipc_rcu_grace, rcu); + kfree(free); +} + void ipc_rcu_putref(void *ptr) { if (--container_of(ptr, struct ipc_rcu_hdr, data)->refcount > 0) @@ -588,7 +601,8 @@ void ipc_rcu_putref(void *ptr) call_rcu(&container_of(ptr, struct ipc_rcu_grace, data)->rcu, ipc_schedule_free); } else { - kfree_rcu(container_of(ptr, struct ipc_rcu_grace, data), rcu); + call_rcu(&container_of(ptr, struct ipc_rcu_grace, data)->rcu, + ipc_immediate_free); } } diff --git a/trunk/kernel/Kconfig.preempt b/trunk/kernel/Kconfig.preempt index 24e7cb0ba26a..bf987b95b356 100644 --- a/trunk/kernel/Kconfig.preempt +++ b/trunk/kernel/Kconfig.preempt @@ -35,7 +35,6 @@ config PREEMPT_VOLUNTARY config PREEMPT bool "Preemptible Kernel (Low-Latency Desktop)" - select PREEMPT_COUNT help This option reduces the latency of the kernel by making all kernel code (that is not executing in a critical section) @@ -53,5 +52,3 @@ config PREEMPT endchoice -config PREEMPT_COUNT - bool \ No newline at end of file diff --git a/trunk/kernel/async.c b/trunk/kernel/async.c index d5fe7af0de2e..cd9dbb913c77 100644 --- a/trunk/kernel/async.c +++ b/trunk/kernel/async.c @@ -49,13 +49,12 @@ asynchronous and synchronous parts of the kernel. */ #include -#include -#include #include #include #include #include #include +#include static async_cookie_t next_cookie = 1; @@ -129,8 +128,7 @@ static void async_run_entry_fn(struct work_struct *work) /* 2) run (and print duration) */ if (initcall_debug && system_state == SYSTEM_BOOTING) { - printk(KERN_DEBUG "calling %lli_%pF @ %i\n", - (long long)entry->cookie, + printk("calling %lli_%pF @ %i\n", (long long)entry->cookie, entry->func, task_pid_nr(current)); calltime = ktime_get(); } @@ -138,7 +136,7 @@ static void async_run_entry_fn(struct work_struct *work) if (initcall_debug && system_state == SYSTEM_BOOTING) { rettime = ktime_get(); delta = ktime_sub(rettime, calltime); - printk(KERN_DEBUG "initcall %lli_%pF returned 0 after %lld usecs\n", + printk("initcall %lli_%pF returned 0 after %lld usecs\n", (long long)entry->cookie, entry->func, (long long)ktime_to_ns(delta) >> 10); @@ -272,7 +270,7 @@ void async_synchronize_cookie_domain(async_cookie_t cookie, ktime_t starttime, delta, endtime; if (initcall_debug && system_state == SYSTEM_BOOTING) { - printk(KERN_DEBUG "async_waiting @ %i\n", task_pid_nr(current)); + printk("async_waiting @ %i\n", task_pid_nr(current)); starttime = ktime_get(); } @@ -282,7 +280,7 @@ void async_synchronize_cookie_domain(async_cookie_t cookie, endtime = ktime_get(); delta = ktime_sub(endtime, starttime); - printk(KERN_DEBUG "async_continuing @ %i after %lli usec\n", + printk("async_continuing @ %i after %lli usec\n", task_pid_nr(current), (long long)ktime_to_ns(delta) >> 10); } diff --git a/trunk/kernel/audit_tree.c b/trunk/kernel/audit_tree.c index 5bf0790497e7..e99dda04b126 100644 --- a/trunk/kernel/audit_tree.c +++ b/trunk/kernel/audit_tree.c @@ -93,10 +93,16 @@ static inline void get_tree(struct audit_tree *tree) atomic_inc(&tree->count); } +static void __put_tree(struct rcu_head *rcu) +{ + struct audit_tree *tree = container_of(rcu, struct audit_tree, head); + kfree(tree); +} + static inline void put_tree(struct audit_tree *tree) { if (atomic_dec_and_test(&tree->count)) - kfree_rcu(tree, head); + call_rcu(&tree->head, __put_tree); } /* to avoid bringing the entire thing in audit.h */ diff --git a/trunk/kernel/cgroup.c b/trunk/kernel/cgroup.c index e1c72c0f512b..2731d115d725 100644 --- a/trunk/kernel/cgroup.c +++ b/trunk/kernel/cgroup.c @@ -3542,8 +3542,7 @@ static int cgroup_write_event_control(struct cgroup *cgrp, struct cftype *cft, } /* the process need read permission on control file */ - /* AV: shouldn't we check that it's been opened for read instead? */ - ret = inode_permission(cfile->f_path.dentry->d_inode, MAY_READ); + ret = file_permission(cfile, MAY_READ); if (ret < 0) goto fail; diff --git a/trunk/kernel/compat.c b/trunk/kernel/compat.c index 18197ae2d465..fc9eb093acd5 100644 --- a/trunk/kernel/compat.c +++ b/trunk/kernel/compat.c @@ -890,7 +890,6 @@ sigset_from_compat (sigset_t *set, compat_sigset_t *compat) case 1: set->sig[0] = compat->sig[0] | (((long)compat->sig[1]) << 32 ); } } -EXPORT_SYMBOL_GPL(sigset_from_compat); asmlinkage long compat_sys_rt_sigtimedwait (compat_sigset_t __user *uthese, diff --git a/trunk/kernel/delayacct.c b/trunk/kernel/delayacct.c index 418b3f7053aa..ead9b610aa71 100644 --- a/trunk/kernel/delayacct.c +++ b/trunk/kernel/delayacct.c @@ -19,10 +19,8 @@ #include #include #include -#include int delayacct_on __read_mostly = 1; /* Delay accounting turned on/off */ -EXPORT_SYMBOL_GPL(delayacct_on); struct kmem_cache *delayacct_cache; static int __init delayacct_setup_disable(char *str) diff --git a/trunk/kernel/events/Makefile b/trunk/kernel/events/Makefile index 89e5e8aa4c36..1ce23d3d8394 100644 --- a/trunk/kernel/events/Makefile +++ b/trunk/kernel/events/Makefile @@ -2,5 +2,5 @@ ifdef CONFIG_FUNCTION_TRACER CFLAGS_REMOVE_core.o = -pg endif -obj-y := core.o ring_buffer.o +obj-y := core.o obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o diff --git a/trunk/kernel/events/core.c b/trunk/kernel/events/core.c index b8785e26ee1c..9efe7108ccaf 100644 --- a/trunk/kernel/events/core.c +++ b/trunk/kernel/events/core.c @@ -36,8 +36,6 @@ #include #include -#include "internal.h" - #include struct remote_function_call { @@ -202,22 +200,6 @@ __get_cpu_context(struct perf_event_context *ctx) return this_cpu_ptr(ctx->pmu->pmu_cpu_context); } -static void perf_ctx_lock(struct perf_cpu_context *cpuctx, - struct perf_event_context *ctx) -{ - raw_spin_lock(&cpuctx->ctx.lock); - if (ctx) - raw_spin_lock(&ctx->lock); -} - -static void perf_ctx_unlock(struct perf_cpu_context *cpuctx, - struct perf_event_context *ctx) -{ - if (ctx) - raw_spin_unlock(&ctx->lock); - raw_spin_unlock(&cpuctx->ctx.lock); -} - #ifdef CONFIG_CGROUP_PERF /* @@ -358,8 +340,11 @@ void perf_cgroup_switch(struct task_struct *task, int mode) rcu_read_lock(); list_for_each_entry_rcu(pmu, &pmus, entry) { + cpuctx = this_cpu_ptr(pmu->pmu_cpu_context); + perf_pmu_disable(cpuctx->ctx.pmu); + /* * perf_cgroup_events says at least one * context on this CPU has cgroup events. @@ -368,8 +353,6 @@ void perf_cgroup_switch(struct task_struct *task, int mode) * events for a context. */ if (cpuctx->ctx.nr_cgroups > 0) { - perf_ctx_lock(cpuctx, cpuctx->task_ctx); - perf_pmu_disable(cpuctx->ctx.pmu); if (mode & PERF_CGROUP_SWOUT) { cpu_ctx_sched_out(cpuctx, EVENT_ALL); @@ -389,9 +372,9 @@ void perf_cgroup_switch(struct task_struct *task, int mode) cpuctx->cgrp = perf_cgroup_from_task(task); cpu_ctx_sched_in(cpuctx, EVENT_ALL, task); } - perf_pmu_enable(cpuctx->ctx.pmu); - perf_ctx_unlock(cpuctx, cpuctx->task_ctx); } + + perf_pmu_enable(cpuctx->ctx.pmu); } rcu_read_unlock(); @@ -748,7 +731,6 @@ static u64 perf_event_time(struct perf_event *event) /* * Update the total_time_enabled and total_time_running fields for a event. - * The caller of this function needs to hold the ctx->lock. */ static void update_event_times(struct perf_event *event) { @@ -1123,10 +1105,6 @@ static int __perf_remove_from_context(void *info) raw_spin_lock(&ctx->lock); event_sched_out(event, cpuctx, ctx); list_del_event(event, ctx); - if (!ctx->nr_events && cpuctx->task_ctx == ctx) { - ctx->is_active = 0; - cpuctx->task_ctx = NULL; - } raw_spin_unlock(&ctx->lock); return 0; @@ -1476,24 +1454,8 @@ static void add_event_to_ctx(struct perf_event *event, event->tstamp_stopped = tstamp; } -static void task_ctx_sched_out(struct perf_event_context *ctx); -static void -ctx_sched_in(struct perf_event_context *ctx, - struct perf_cpu_context *cpuctx, - enum event_type_t event_type, - struct task_struct *task); - -static void perf_event_sched_in(struct perf_cpu_context *cpuctx, - struct perf_event_context *ctx, - struct task_struct *task) -{ - cpu_ctx_sched_in(cpuctx, EVENT_PINNED, task); - if (ctx) - ctx_sched_in(ctx, cpuctx, EVENT_PINNED, task); - cpu_ctx_sched_in(cpuctx, EVENT_FLEXIBLE, task); - if (ctx) - ctx_sched_in(ctx, cpuctx, EVENT_FLEXIBLE, task); -} +static void perf_event_context_sched_in(struct perf_event_context *ctx, + struct task_struct *tsk); /* * Cross CPU call to install and enable a performance event @@ -1504,37 +1466,20 @@ static int __perf_install_in_context(void *info) { struct perf_event *event = info; struct perf_event_context *ctx = event->ctx; + struct perf_event *leader = event->group_leader; struct perf_cpu_context *cpuctx = __get_cpu_context(ctx); - struct perf_event_context *task_ctx = cpuctx->task_ctx; - struct task_struct *task = current; - - perf_ctx_lock(cpuctx, task_ctx); - perf_pmu_disable(cpuctx->ctx.pmu); - - /* - * If there was an active task_ctx schedule it out. - */ - if (task_ctx) - task_ctx_sched_out(task_ctx); + int err; /* - * If the context we're installing events in is not the - * active task_ctx, flip them. + * In case we're installing a new context to an already running task, + * could also happen before perf_event_task_sched_in() on architectures + * which do context switches with IRQs enabled. */ - if (ctx->task && task_ctx != ctx) { - if (task_ctx) - raw_spin_unlock(&task_ctx->lock); - raw_spin_lock(&ctx->lock); - task_ctx = ctx; - } - - if (task_ctx) { - cpuctx->task_ctx = task_ctx; - task = task_ctx->task; - } - - cpu_ctx_sched_out(cpuctx, EVENT_ALL); + if (ctx->task && !cpuctx->task_ctx) + perf_event_context_sched_in(ctx, ctx->task); + raw_spin_lock(&ctx->lock); + ctx->is_active = 1; update_context_time(ctx); /* * update cgrp time only if current cgrp @@ -1545,13 +1490,43 @@ static int __perf_install_in_context(void *info) add_event_to_ctx(event, ctx); + if (!event_filter_match(event)) + goto unlock; + /* - * Schedule everything back in + * Don't put the event on if it is disabled or if + * it is in a group and the group isn't on. */ - perf_event_sched_in(cpuctx, task_ctx, task); + if (event->state != PERF_EVENT_STATE_INACTIVE || + (leader != event && leader->state != PERF_EVENT_STATE_ACTIVE)) + goto unlock; - perf_pmu_enable(cpuctx->ctx.pmu); - perf_ctx_unlock(cpuctx, task_ctx); + /* + * An exclusive event can't go on if there are already active + * hardware events, and no hardware event can go on if there + * is already an exclusive event on. + */ + if (!group_can_go_on(event, cpuctx, 1)) + err = -EEXIST; + else + err = event_sched_in(event, cpuctx, ctx); + + if (err) { + /* + * This event couldn't go on. If it is in a group + * then we have to pull the whole group off. + * If the event group is pinned then put it in error state. + */ + if (leader != event) + group_sched_out(leader, cpuctx, ctx); + if (leader->attr.pinned) { + update_group_times(leader); + leader->state = PERF_EVENT_STATE_ERROR; + } + } + +unlock: + raw_spin_unlock(&ctx->lock); return 0; } @@ -1764,7 +1739,7 @@ void perf_event_enable(struct perf_event *event) raw_spin_unlock_irq(&ctx->lock); } -int perf_event_refresh(struct perf_event *event, int refresh) +static int perf_event_refresh(struct perf_event *event, int refresh) { /* * not supported on inherited events @@ -1777,35 +1752,36 @@ int perf_event_refresh(struct perf_event *event, int refresh) return 0; } -EXPORT_SYMBOL_GPL(perf_event_refresh); static void ctx_sched_out(struct perf_event_context *ctx, struct perf_cpu_context *cpuctx, enum event_type_t event_type) { struct perf_event *event; - int is_active = ctx->is_active; - ctx->is_active &= ~event_type; + raw_spin_lock(&ctx->lock); + perf_pmu_disable(ctx->pmu); + ctx->is_active = 0; if (likely(!ctx->nr_events)) - return; - + goto out; update_context_time(ctx); update_cgrp_time_from_cpuctx(cpuctx); + if (!ctx->nr_active) - return; + goto out; - perf_pmu_disable(ctx->pmu); - if ((is_active & EVENT_PINNED) && (event_type & EVENT_PINNED)) { + if (event_type & EVENT_PINNED) { list_for_each_entry(event, &ctx->pinned_groups, group_entry) group_sched_out(event, cpuctx, ctx); } - if ((is_active & EVENT_FLEXIBLE) && (event_type & EVENT_FLEXIBLE)) { + if (event_type & EVENT_FLEXIBLE) { list_for_each_entry(event, &ctx->flexible_groups, group_entry) group_sched_out(event, cpuctx, ctx); } +out: perf_pmu_enable(ctx->pmu); + raw_spin_unlock(&ctx->lock); } /* @@ -1953,10 +1929,8 @@ static void perf_event_context_sched_out(struct task_struct *task, int ctxn, rcu_read_unlock(); if (do_switch) { - raw_spin_lock(&ctx->lock); ctx_sched_out(ctx, cpuctx, EVENT_ALL); cpuctx->task_ctx = NULL; - raw_spin_unlock(&ctx->lock); } } @@ -1991,7 +1965,8 @@ void __perf_event_task_sched_out(struct task_struct *task, perf_cgroup_sched_out(task); } -static void task_ctx_sched_out(struct perf_event_context *ctx) +static void task_ctx_sched_out(struct perf_event_context *ctx, + enum event_type_t event_type) { struct perf_cpu_context *cpuctx = __get_cpu_context(ctx); @@ -2001,7 +1976,7 @@ static void task_ctx_sched_out(struct perf_event_context *ctx) if (WARN_ON_ONCE(ctx != cpuctx->task_ctx)) return; - ctx_sched_out(ctx, cpuctx, EVENT_ALL); + ctx_sched_out(ctx, cpuctx, event_type); cpuctx->task_ctx = NULL; } @@ -2080,11 +2055,11 @@ ctx_sched_in(struct perf_event_context *ctx, struct task_struct *task) { u64 now; - int is_active = ctx->is_active; - ctx->is_active |= event_type; + raw_spin_lock(&ctx->lock); + ctx->is_active = 1; if (likely(!ctx->nr_events)) - return; + goto out; now = perf_clock(); ctx->timestamp = now; @@ -2093,12 +2068,15 @@ ctx_sched_in(struct perf_event_context *ctx, * First go through the list and put on any pinned groups * in order to give them the best chance of going on. */ - if (!(is_active & EVENT_PINNED) && (event_type & EVENT_PINNED)) + if (event_type & EVENT_PINNED) ctx_pinned_sched_in(ctx, cpuctx); /* Then walk through the lower prio flexible groups */ - if (!(is_active & EVENT_FLEXIBLE) && (event_type & EVENT_FLEXIBLE)) + if (event_type & EVENT_FLEXIBLE) ctx_flexible_sched_in(ctx, cpuctx); + +out: + raw_spin_unlock(&ctx->lock); } static void cpu_ctx_sched_in(struct perf_cpu_context *cpuctx, @@ -2110,6 +2088,19 @@ static void cpu_ctx_sched_in(struct perf_cpu_context *cpuctx, ctx_sched_in(ctx, cpuctx, event_type, task); } +static void task_ctx_sched_in(struct perf_event_context *ctx, + enum event_type_t event_type) +{ + struct perf_cpu_context *cpuctx; + + cpuctx = __get_cpu_context(ctx); + if (cpuctx->task_ctx == ctx) + return; + + ctx_sched_in(ctx, cpuctx, event_type, NULL); + cpuctx->task_ctx = ctx; +} + static void perf_event_context_sched_in(struct perf_event_context *ctx, struct task_struct *task) { @@ -2119,7 +2110,6 @@ static void perf_event_context_sched_in(struct perf_event_context *ctx, if (cpuctx->task_ctx == ctx) return; - perf_ctx_lock(cpuctx, ctx); perf_pmu_disable(ctx->pmu); /* * We want to keep the following priority order: @@ -2128,18 +2118,18 @@ static void perf_event_context_sched_in(struct perf_event_context *ctx, */ cpu_ctx_sched_out(cpuctx, EVENT_FLEXIBLE); - perf_event_sched_in(cpuctx, ctx, task); + ctx_sched_in(ctx, cpuctx, EVENT_PINNED, task); + cpu_ctx_sched_in(cpuctx, EVENT_FLEXIBLE, task); + ctx_sched_in(ctx, cpuctx, EVENT_FLEXIBLE, task); cpuctx->task_ctx = ctx; - perf_pmu_enable(ctx->pmu); - perf_ctx_unlock(cpuctx, ctx); - /* * Since these rotations are per-cpu, we need to ensure the * cpu-context we got scheduled on is actually rotating. */ perf_pmu_rotate_start(ctx->pmu); + perf_pmu_enable(ctx->pmu); } /* @@ -2279,6 +2269,7 @@ static void perf_ctx_adjust_freq(struct perf_event_context *ctx, u64 period) u64 interrupts, now; s64 delta; + raw_spin_lock(&ctx->lock); list_for_each_entry_rcu(event, &ctx->event_list, event_entry) { if (event->state != PERF_EVENT_STATE_ACTIVE) continue; @@ -2310,6 +2301,7 @@ static void perf_ctx_adjust_freq(struct perf_event_context *ctx, u64 period) if (delta > 0) perf_adjust_period(event, period, delta); } + raw_spin_unlock(&ctx->lock); } /* @@ -2317,12 +2309,16 @@ static void perf_ctx_adjust_freq(struct perf_event_context *ctx, u64 period) */ static void rotate_ctx(struct perf_event_context *ctx) { + raw_spin_lock(&ctx->lock); + /* * Rotate the first entry last of non-pinned groups. Rotation might be * disabled by the inheritance code. */ if (!ctx->rotate_disable) list_rotate_left(&ctx->flexible_groups); + + raw_spin_unlock(&ctx->lock); } /* @@ -2349,7 +2345,6 @@ static void perf_rotate_context(struct perf_cpu_context *cpuctx) rotate = 1; } - perf_ctx_lock(cpuctx, cpuctx->task_ctx); perf_pmu_disable(cpuctx->ctx.pmu); perf_ctx_adjust_freq(&cpuctx->ctx, interval); if (ctx) @@ -2360,20 +2355,21 @@ static void perf_rotate_context(struct perf_cpu_context *cpuctx) cpu_ctx_sched_out(cpuctx, EVENT_FLEXIBLE); if (ctx) - ctx_sched_out(ctx, cpuctx, EVENT_FLEXIBLE); + task_ctx_sched_out(ctx, EVENT_FLEXIBLE); rotate_ctx(&cpuctx->ctx); if (ctx) rotate_ctx(ctx); - perf_event_sched_in(cpuctx, ctx, current); + cpu_ctx_sched_in(cpuctx, EVENT_FLEXIBLE, current); + if (ctx) + task_ctx_sched_in(ctx, EVENT_FLEXIBLE); done: if (remove) list_del_init(&cpuctx->rotation_list); perf_pmu_enable(cpuctx->ctx.pmu); - perf_ctx_unlock(cpuctx, cpuctx->task_ctx); } void perf_event_task_tick(void) @@ -2428,9 +2424,9 @@ static void perf_event_enable_on_exec(struct perf_event_context *ctx) * in. */ perf_cgroup_sched_out(current); + task_ctx_sched_out(ctx, EVENT_ALL); raw_spin_lock(&ctx->lock); - task_ctx_sched_out(ctx); list_for_each_entry(event, &ctx->pinned_groups, group_entry) { ret = event_enable_on_exec(event, ctx); @@ -2839,12 +2835,16 @@ find_get_context(struct pmu *pmu, struct task_struct *task, int cpu) unclone_ctx(ctx); ++ctx->pin_count; raw_spin_unlock_irqrestore(&ctx->lock, flags); - } else { + } + + if (!ctx) { ctx = alloc_perf_context(pmu, task); err = -ENOMEM; if (!ctx) goto errout; + get_ctx(ctx); + err = 0; mutex_lock(&task->perf_event_mutex); /* @@ -2856,14 +2856,14 @@ find_get_context(struct pmu *pmu, struct task_struct *task, int cpu) else if (task->perf_event_ctxp[ctxn]) err = -EAGAIN; else { - get_ctx(ctx); ++ctx->pin_count; rcu_assign_pointer(task->perf_event_ctxp[ctxn], ctx); } mutex_unlock(&task->perf_event_mutex); if (unlikely(err)) { - put_ctx(ctx); + put_task_struct(task); + kfree(ctx); if (err == -EAGAIN) goto retry; @@ -2890,7 +2890,7 @@ static void free_event_rcu(struct rcu_head *head) kfree(event); } -static void ring_buffer_put(struct ring_buffer *rb); +static void perf_buffer_put(struct perf_buffer *buffer); static void free_event(struct perf_event *event) { @@ -2913,9 +2913,9 @@ static void free_event(struct perf_event *event) } } - if (event->rb) { - ring_buffer_put(event->rb); - event->rb = NULL; + if (event->buffer) { + perf_buffer_put(event->buffer); + event->buffer = NULL; } if (is_cgroup_event(event)) @@ -2934,6 +2934,12 @@ int perf_event_release_kernel(struct perf_event *event) { struct perf_event_context *ctx = event->ctx; + /* + * Remove from the PMU, can't get re-enabled since we got + * here because the last ref went. + */ + perf_event_disable(event); + WARN_ON_ONCE(ctx->parent_ctx); /* * There are two ways this annotation is useful: @@ -2950,8 +2956,8 @@ int perf_event_release_kernel(struct perf_event *event) mutex_lock_nested(&ctx->mutex, SINGLE_DEPTH_NESTING); raw_spin_lock_irq(&ctx->lock); perf_group_detach(event); + list_del_event(event, ctx); raw_spin_unlock_irq(&ctx->lock); - perf_remove_from_context(event); mutex_unlock(&ctx->mutex); free_event(event); @@ -3143,13 +3149,13 @@ perf_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) static unsigned int perf_poll(struct file *file, poll_table *wait) { struct perf_event *event = file->private_data; - struct ring_buffer *rb; + struct perf_buffer *buffer; unsigned int events = POLL_HUP; rcu_read_lock(); - rb = rcu_dereference(event->rb); - if (rb) - events = atomic_xchg(&rb->poll, 0); + buffer = rcu_dereference(event->buffer); + if (buffer) + events = atomic_xchg(&buffer->poll, 0); rcu_read_unlock(); poll_wait(file, &event->waitq, wait); @@ -3352,18 +3358,6 @@ static int perf_event_index(struct perf_event *event) return event->hw.idx + 1 - PERF_EVENT_INDEX_OFFSET; } -static void calc_timer_values(struct perf_event *event, - u64 *running, - u64 *enabled) -{ - u64 now, ctx_time; - - now = perf_clock(); - ctx_time = event->shadow_ctx_time + now; - *enabled = ctx_time - event->tstamp_enabled; - *running = ctx_time - event->tstamp_running; -} - /* * Callers need to ensure there can be no nesting of this function, otherwise * the seqlock logic goes bad. We can not serialize this because the arch @@ -3372,25 +3366,14 @@ static void calc_timer_values(struct perf_event *event, void perf_event_update_userpage(struct perf_event *event) { struct perf_event_mmap_page *userpg; - struct ring_buffer *rb; - u64 enabled, running; + struct perf_buffer *buffer; rcu_read_lock(); - /* - * compute total_time_enabled, total_time_running - * based on snapshot values taken when the event - * was last scheduled in. - * - * we cannot simply called update_context_time() - * because of locking issue as we can be called in - * NMI context - */ - calc_timer_values(event, &enabled, &running); - rb = rcu_dereference(event->rb); - if (!rb) + buffer = rcu_dereference(event->buffer); + if (!buffer) goto unlock; - userpg = rb->user_page; + userpg = buffer->user_page; /* * Disable preemption so as to not let the corresponding user-space @@ -3404,10 +3387,10 @@ void perf_event_update_userpage(struct perf_event *event) if (event->state == PERF_EVENT_STATE_ACTIVE) userpg->offset -= local64_read(&event->hw.prev_count); - userpg->time_enabled = enabled + + userpg->time_enabled = event->total_time_enabled + atomic64_read(&event->child_total_time_enabled); - userpg->time_running = running + + userpg->time_running = event->total_time_running + atomic64_read(&event->child_total_time_running); barrier(); @@ -3417,10 +3400,220 @@ void perf_event_update_userpage(struct perf_event *event) rcu_read_unlock(); } +static unsigned long perf_data_size(struct perf_buffer *buffer); + +static void +perf_buffer_init(struct perf_buffer *buffer, long watermark, int flags) +{ + long max_size = perf_data_size(buffer); + + if (watermark) + buffer->watermark = min(max_size, watermark); + + if (!buffer->watermark) + buffer->watermark = max_size / 2; + + if (flags & PERF_BUFFER_WRITABLE) + buffer->writable = 1; + + atomic_set(&buffer->refcount, 1); +} + +#ifndef CONFIG_PERF_USE_VMALLOC + +/* + * Back perf_mmap() with regular GFP_KERNEL-0 pages. + */ + +static struct page * +perf_mmap_to_page(struct perf_buffer *buffer, unsigned long pgoff) +{ + if (pgoff > buffer->nr_pages) + return NULL; + + if (pgoff == 0) + return virt_to_page(buffer->user_page); + + return virt_to_page(buffer->data_pages[pgoff - 1]); +} + +static void *perf_mmap_alloc_page(int cpu) +{ + struct page *page; + int node; + + node = (cpu == -1) ? cpu : cpu_to_node(cpu); + page = alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 0); + if (!page) + return NULL; + + return page_address(page); +} + +static struct perf_buffer * +perf_buffer_alloc(int nr_pages, long watermark, int cpu, int flags) +{ + struct perf_buffer *buffer; + unsigned long size; + int i; + + size = sizeof(struct perf_buffer); + size += nr_pages * sizeof(void *); + + buffer = kzalloc(size, GFP_KERNEL); + if (!buffer) + goto fail; + + buffer->user_page = perf_mmap_alloc_page(cpu); + if (!buffer->user_page) + goto fail_user_page; + + for (i = 0; i < nr_pages; i++) { + buffer->data_pages[i] = perf_mmap_alloc_page(cpu); + if (!buffer->data_pages[i]) + goto fail_data_pages; + } + + buffer->nr_pages = nr_pages; + + perf_buffer_init(buffer, watermark, flags); + + return buffer; + +fail_data_pages: + for (i--; i >= 0; i--) + free_page((unsigned long)buffer->data_pages[i]); + + free_page((unsigned long)buffer->user_page); + +fail_user_page: + kfree(buffer); + +fail: + return NULL; +} + +static void perf_mmap_free_page(unsigned long addr) +{ + struct page *page = virt_to_page((void *)addr); + + page->mapping = NULL; + __free_page(page); +} + +static void perf_buffer_free(struct perf_buffer *buffer) +{ + int i; + + perf_mmap_free_page((unsigned long)buffer->user_page); + for (i = 0; i < buffer->nr_pages; i++) + perf_mmap_free_page((unsigned long)buffer->data_pages[i]); + kfree(buffer); +} + +static inline int page_order(struct perf_buffer *buffer) +{ + return 0; +} + +#else + +/* + * Back perf_mmap() with vmalloc memory. + * + * Required for architectures that have d-cache aliasing issues. + */ + +static inline int page_order(struct perf_buffer *buffer) +{ + return buffer->page_order; +} + +static struct page * +perf_mmap_to_page(struct perf_buffer *buffer, unsigned long pgoff) +{ + if (pgoff > (1UL << page_order(buffer))) + return NULL; + + return vmalloc_to_page((void *)buffer->user_page + pgoff * PAGE_SIZE); +} + +static void perf_mmap_unmark_page(void *addr) +{ + struct page *page = vmalloc_to_page(addr); + + page->mapping = NULL; +} + +static void perf_buffer_free_work(struct work_struct *work) +{ + struct perf_buffer *buffer; + void *base; + int i, nr; + + buffer = container_of(work, struct perf_buffer, work); + nr = 1 << page_order(buffer); + + base = buffer->user_page; + for (i = 0; i < nr + 1; i++) + perf_mmap_unmark_page(base + (i * PAGE_SIZE)); + + vfree(base); + kfree(buffer); +} + +static void perf_buffer_free(struct perf_buffer *buffer) +{ + schedule_work(&buffer->work); +} + +static struct perf_buffer * +perf_buffer_alloc(int nr_pages, long watermark, int cpu, int flags) +{ + struct perf_buffer *buffer; + unsigned long size; + void *all_buf; + + size = sizeof(struct perf_buffer); + size += sizeof(void *); + + buffer = kzalloc(size, GFP_KERNEL); + if (!buffer) + goto fail; + + INIT_WORK(&buffer->work, perf_buffer_free_work); + + all_buf = vmalloc_user((nr_pages + 1) * PAGE_SIZE); + if (!all_buf) + goto fail_all_buf; + + buffer->user_page = all_buf; + buffer->data_pages[0] = all_buf + PAGE_SIZE; + buffer->page_order = ilog2(nr_pages); + buffer->nr_pages = 1; + + perf_buffer_init(buffer, watermark, flags); + + return buffer; + +fail_all_buf: + kfree(buffer); + +fail: + return NULL; +} + +#endif + +static unsigned long perf_data_size(struct perf_buffer *buffer) +{ + return buffer->nr_pages << (PAGE_SHIFT + page_order(buffer)); +} + static int perf_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct perf_event *event = vma->vm_file->private_data; - struct ring_buffer *rb; + struct perf_buffer *buffer; int ret = VM_FAULT_SIGBUS; if (vmf->flags & FAULT_FLAG_MKWRITE) { @@ -3430,14 +3623,14 @@ static int perf_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) } rcu_read_lock(); - rb = rcu_dereference(event->rb); - if (!rb) + buffer = rcu_dereference(event->buffer); + if (!buffer) goto unlock; if (vmf->pgoff && (vmf->flags & FAULT_FLAG_WRITE)) goto unlock; - vmf->page = perf_mmap_to_page(rb, vmf->pgoff); + vmf->page = perf_mmap_to_page(buffer, vmf->pgoff); if (!vmf->page) goto unlock; @@ -3452,35 +3645,35 @@ static int perf_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) return ret; } -static void rb_free_rcu(struct rcu_head *rcu_head) +static void perf_buffer_free_rcu(struct rcu_head *rcu_head) { - struct ring_buffer *rb; + struct perf_buffer *buffer; - rb = container_of(rcu_head, struct ring_buffer, rcu_head); - rb_free(rb); + buffer = container_of(rcu_head, struct perf_buffer, rcu_head); + perf_buffer_free(buffer); } -static struct ring_buffer *ring_buffer_get(struct perf_event *event) +static struct perf_buffer *perf_buffer_get(struct perf_event *event) { - struct ring_buffer *rb; + struct perf_buffer *buffer; rcu_read_lock(); - rb = rcu_dereference(event->rb); - if (rb) { - if (!atomic_inc_not_zero(&rb->refcount)) - rb = NULL; + buffer = rcu_dereference(event->buffer); + if (buffer) { + if (!atomic_inc_not_zero(&buffer->refcount)) + buffer = NULL; } rcu_read_unlock(); - return rb; + return buffer; } -static void ring_buffer_put(struct ring_buffer *rb) +static void perf_buffer_put(struct perf_buffer *buffer) { - if (!atomic_dec_and_test(&rb->refcount)) + if (!atomic_dec_and_test(&buffer->refcount)) return; - call_rcu(&rb->rcu_head, rb_free_rcu); + call_rcu(&buffer->rcu_head, perf_buffer_free_rcu); } static void perf_mmap_open(struct vm_area_struct *vma) @@ -3495,16 +3688,16 @@ static void perf_mmap_close(struct vm_area_struct *vma) struct perf_event *event = vma->vm_file->private_data; if (atomic_dec_and_mutex_lock(&event->mmap_count, &event->mmap_mutex)) { - unsigned long size = perf_data_size(event->rb); + unsigned long size = perf_data_size(event->buffer); struct user_struct *user = event->mmap_user; - struct ring_buffer *rb = event->rb; + struct perf_buffer *buffer = event->buffer; atomic_long_sub((size >> PAGE_SHIFT) + 1, &user->locked_vm); vma->vm_mm->locked_vm -= event->mmap_locked; - rcu_assign_pointer(event->rb, NULL); + rcu_assign_pointer(event->buffer, NULL); mutex_unlock(&event->mmap_mutex); - ring_buffer_put(rb); + perf_buffer_put(buffer); free_uid(user); } } @@ -3522,7 +3715,7 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) unsigned long user_locked, user_lock_limit; struct user_struct *user = current_user(); unsigned long locked, lock_limit; - struct ring_buffer *rb; + struct perf_buffer *buffer; unsigned long vma_size; unsigned long nr_pages; long user_extra, extra; @@ -3531,7 +3724,7 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) /* * Don't allow mmap() of inherited per-task counters. This would * create a performance issue due to all children writing to the - * same rb. + * same buffer. */ if (event->cpu == -1 && event->attr.inherit) return -EINVAL; @@ -3543,7 +3736,7 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) nr_pages = (vma_size / PAGE_SIZE) - 1; /* - * If we have rb pages ensure they're a power-of-two number, so we + * If we have buffer pages ensure they're a power-of-two number, so we * can do bitmasks instead of modulo. */ if (nr_pages != 0 && !is_power_of_2(nr_pages)) @@ -3557,9 +3750,9 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) WARN_ON_ONCE(event->ctx->parent_ctx); mutex_lock(&event->mmap_mutex); - if (event->rb) { - if (event->rb->nr_pages == nr_pages) - atomic_inc(&event->rb->refcount); + if (event->buffer) { + if (event->buffer->nr_pages == nr_pages) + atomic_inc(&event->buffer->refcount); else ret = -EINVAL; goto unlock; @@ -3589,20 +3782,18 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) goto unlock; } - WARN_ON(event->rb); + WARN_ON(event->buffer); if (vma->vm_flags & VM_WRITE) - flags |= RING_BUFFER_WRITABLE; + flags |= PERF_BUFFER_WRITABLE; - rb = rb_alloc(nr_pages, - event->attr.watermark ? event->attr.wakeup_watermark : 0, - event->cpu, flags); - - if (!rb) { + buffer = perf_buffer_alloc(nr_pages, event->attr.wakeup_watermark, + event->cpu, flags); + if (!buffer) { ret = -ENOMEM; goto unlock; } - rcu_assign_pointer(event->rb, rb); + rcu_assign_pointer(event->buffer, buffer); atomic_long_add(user_extra, &user->locked_vm); event->mmap_locked = extra; @@ -3701,6 +3892,117 @@ int perf_unregister_guest_info_callbacks(struct perf_guest_info_callbacks *cbs) } EXPORT_SYMBOL_GPL(perf_unregister_guest_info_callbacks); +/* + * Output + */ +static bool perf_output_space(struct perf_buffer *buffer, unsigned long tail, + unsigned long offset, unsigned long head) +{ + unsigned long mask; + + if (!buffer->writable) + return true; + + mask = perf_data_size(buffer) - 1; + + offset = (offset - tail) & mask; + head = (head - tail) & mask; + + if ((int)(head - offset) < 0) + return false; + + return true; +} + +static void perf_output_wakeup(struct perf_output_handle *handle) +{ + atomic_set(&handle->buffer->poll, POLL_IN); + + if (handle->nmi) { + handle->event->pending_wakeup = 1; + irq_work_queue(&handle->event->pending); + } else + perf_event_wakeup(handle->event); +} + +/* + * We need to ensure a later event_id doesn't publish a head when a former + * event isn't done writing. However since we need to deal with NMIs we + * cannot fully serialize things. + * + * We only publish the head (and generate a wakeup) when the outer-most + * event completes. + */ +static void perf_output_get_handle(struct perf_output_handle *handle) +{ + struct perf_buffer *buffer = handle->buffer; + + preempt_disable(); + local_inc(&buffer->nest); + handle->wakeup = local_read(&buffer->wakeup); +} + +static void perf_output_put_handle(struct perf_output_handle *handle) +{ + struct perf_buffer *buffer = handle->buffer; + unsigned long head; + +again: + head = local_read(&buffer->head); + + /* + * IRQ/NMI can happen here, which means we can miss a head update. + */ + + if (!local_dec_and_test(&buffer->nest)) + goto out; + + /* + * Publish the known good head. Rely on the full barrier implied + * by atomic_dec_and_test() order the buffer->head read and this + * write. + */ + buffer->user_page->data_head = head; + + /* + * Now check if we missed an update, rely on the (compiler) + * barrier in atomic_dec_and_test() to re-read buffer->head. + */ + if (unlikely(head != local_read(&buffer->head))) { + local_inc(&buffer->nest); + goto again; + } + + if (handle->wakeup != local_read(&buffer->wakeup)) + perf_output_wakeup(handle); + +out: + preempt_enable(); +} + +__always_inline void perf_output_copy(struct perf_output_handle *handle, + const void *buf, unsigned int len) +{ + do { + unsigned long size = min_t(unsigned long, handle->size, len); + + memcpy(handle->addr, buf, size); + + len -= size; + handle->addr += size; + buf += size; + handle->size -= size; + if (!handle->size) { + struct perf_buffer *buffer = handle->buffer; + + handle->page++; + handle->page &= buffer->nr_pages - 1; + handle->addr = buffer->data_pages[handle->page]; + handle->size = PAGE_SIZE << page_order(buffer); + } + } while (len); +} + static void __perf_event_header__init_id(struct perf_event_header *header, struct perf_sample_data *data, struct perf_event *event) @@ -3731,9 +4033,9 @@ static void __perf_event_header__init_id(struct perf_event_header *header, } } -void perf_event_header__init_id(struct perf_event_header *header, - struct perf_sample_data *data, - struct perf_event *event) +static void perf_event_header__init_id(struct perf_event_header *header, + struct perf_sample_data *data, + struct perf_event *event) { if (event->attr.sample_id_all) __perf_event_header__init_id(header, data, event); @@ -3760,14 +4062,121 @@ static void __perf_event__output_id_sample(struct perf_output_handle *handle, perf_output_put(handle, data->cpu_entry); } -void perf_event__output_id_sample(struct perf_event *event, - struct perf_output_handle *handle, - struct perf_sample_data *sample) +static void perf_event__output_id_sample(struct perf_event *event, + struct perf_output_handle *handle, + struct perf_sample_data *sample) { if (event->attr.sample_id_all) __perf_event__output_id_sample(handle, sample); } +int perf_output_begin(struct perf_output_handle *handle, + struct perf_event *event, unsigned int size, + int nmi, int sample) +{ + struct perf_buffer *buffer; + unsigned long tail, offset, head; + int have_lost; + struct perf_sample_data sample_data; + struct { + struct perf_event_header header; + u64 id; + u64 lost; + } lost_event; + + rcu_read_lock(); + /* + * For inherited events we send all the output towards the parent. + */ + if (event->parent) + event = event->parent; + + buffer = rcu_dereference(event->buffer); + if (!buffer) + goto out; + + handle->buffer = buffer; + handle->event = event; + handle->nmi = nmi; + handle->sample = sample; + + if (!buffer->nr_pages) + goto out; + + have_lost = local_read(&buffer->lost); + if (have_lost) { + lost_event.header.size = sizeof(lost_event); + perf_event_header__init_id(&lost_event.header, &sample_data, + event); + size += lost_event.header.size; + } + + perf_output_get_handle(handle); + + do { + /* + * Userspace could choose to issue a mb() before updating the + * tail pointer. So that all reads will be completed before the + * write is issued. + */ + tail = ACCESS_ONCE(buffer->user_page->data_tail); + smp_rmb(); + offset = head = local_read(&buffer->head); + head += size; + if (unlikely(!perf_output_space(buffer, tail, offset, head))) + goto fail; + } while (local_cmpxchg(&buffer->head, offset, head) != offset); + + if (head - local_read(&buffer->wakeup) > buffer->watermark) + local_add(buffer->watermark, &buffer->wakeup); + + handle->page = offset >> (PAGE_SHIFT + page_order(buffer)); + handle->page &= buffer->nr_pages - 1; + handle->size = offset & ((PAGE_SIZE << page_order(buffer)) - 1); + handle->addr = buffer->data_pages[handle->page]; + handle->addr += handle->size; + handle->size = (PAGE_SIZE << page_order(buffer)) - handle->size; + + if (have_lost) { + lost_event.header.type = PERF_RECORD_LOST; + lost_event.header.misc = 0; + lost_event.id = event->id; + lost_event.lost = local_xchg(&buffer->lost, 0); + + perf_output_put(handle, lost_event); + perf_event__output_id_sample(event, handle, &sample_data); + } + + return 0; + +fail: + local_inc(&buffer->lost); + perf_output_put_handle(handle); +out: + rcu_read_unlock(); + + return -ENOSPC; +} + +void perf_output_end(struct perf_output_handle *handle) +{ + struct perf_event *event = handle->event; + struct perf_buffer *buffer = handle->buffer; + + int wakeup_events = event->attr.wakeup_events; + + if (handle->sample && wakeup_events) { + int events = local_inc_return(&buffer->events); + if (events >= wakeup_events) { + local_sub(wakeup_events, &buffer->events); + local_inc(&buffer->wakeup); + } + } + + perf_output_put_handle(handle); + rcu_read_unlock(); +} + static void perf_output_read_one(struct perf_output_handle *handle, struct perf_event *event, u64 enabled, u64 running) @@ -3788,7 +4197,7 @@ static void perf_output_read_one(struct perf_output_handle *handle, if (read_format & PERF_FORMAT_ID) values[n++] = primary_event_id(event); - __output_copy(handle, values, n * sizeof(u64)); + perf_output_copy(handle, values, n * sizeof(u64)); } /* @@ -3818,7 +4227,7 @@ static void perf_output_read_group(struct perf_output_handle *handle, if (read_format & PERF_FORMAT_ID) values[n++] = primary_event_id(leader); - __output_copy(handle, values, n * sizeof(u64)); + perf_output_copy(handle, values, n * sizeof(u64)); list_for_each_entry(sub, &leader->sibling_list, group_entry) { n = 0; @@ -3830,7 +4239,7 @@ static void perf_output_read_group(struct perf_output_handle *handle, if (read_format & PERF_FORMAT_ID) values[n++] = primary_event_id(sub); - __output_copy(handle, values, n * sizeof(u64)); + perf_output_copy(handle, values, n * sizeof(u64)); } } @@ -3840,7 +4249,7 @@ static void perf_output_read_group(struct perf_output_handle *handle, static void perf_output_read(struct perf_output_handle *handle, struct perf_event *event) { - u64 enabled = 0, running = 0; + u64 enabled = 0, running = 0, now, ctx_time; u64 read_format = event->attr.read_format; /* @@ -3852,8 +4261,12 @@ static void perf_output_read(struct perf_output_handle *handle, * because of locking issue as we are called in * NMI context */ - if (read_format & PERF_FORMAT_TOTAL_TIMES) - calc_timer_values(event, &enabled, &running); + if (read_format & PERF_FORMAT_TOTAL_TIMES) { + now = perf_clock(); + ctx_time = event->shadow_ctx_time + now; + enabled = ctx_time - event->tstamp_enabled; + running = ctx_time - event->tstamp_running; + } if (event->attr.read_format & PERF_FORMAT_GROUP) perf_output_read_group(handle, event, enabled, running); @@ -3906,7 +4319,7 @@ void perf_output_sample(struct perf_output_handle *handle, size *= sizeof(u64); - __output_copy(handle, data->callchain, size); + perf_output_copy(handle, data->callchain, size); } else { u64 nr = 0; perf_output_put(handle, nr); @@ -3916,8 +4329,8 @@ void perf_output_sample(struct perf_output_handle *handle, if (sample_type & PERF_SAMPLE_RAW) { if (data->raw) { perf_output_put(handle, data->raw->size); - __output_copy(handle, data->raw->data, - data->raw->size); + perf_output_copy(handle, data->raw->data, + data->raw->size); } else { struct { u32 size; @@ -3929,20 +4342,6 @@ void perf_output_sample(struct perf_output_handle *handle, perf_output_put(handle, raw); } } - - if (!event->attr.watermark) { - int wakeup_events = event->attr.wakeup_events; - - if (wakeup_events) { - struct ring_buffer *rb = handle->rb; - int events = local_inc_return(&rb->events); - - if (events >= wakeup_events) { - local_sub(wakeup_events, &rb->events); - local_inc(&rb->wakeup); - } - } - } } void perf_prepare_sample(struct perf_event_header *header, @@ -3987,7 +4386,7 @@ void perf_prepare_sample(struct perf_event_header *header, } } -static void perf_event_output(struct perf_event *event, +static void perf_event_output(struct perf_event *event, int nmi, struct perf_sample_data *data, struct pt_regs *regs) { @@ -3999,7 +4398,7 @@ static void perf_event_output(struct perf_event *event, perf_prepare_sample(&header, data, event, regs); - if (perf_output_begin(&handle, event, header.size)) + if (perf_output_begin(&handle, event, header.size, nmi, 1)) goto exit; perf_output_sample(&handle, &header, data, event); @@ -4039,7 +4438,7 @@ perf_event_read_event(struct perf_event *event, int ret; perf_event_header__init_id(&read_event.header, &sample, event); - ret = perf_output_begin(&handle, event, read_event.header.size); + ret = perf_output_begin(&handle, event, read_event.header.size, 0, 0); if (ret) return; @@ -4082,7 +4481,7 @@ static void perf_event_task_output(struct perf_event *event, perf_event_header__init_id(&task_event->event_id.header, &sample, event); ret = perf_output_begin(&handle, event, - task_event->event_id.header.size); + task_event->event_id.header.size, 0, 0); if (ret) goto out; @@ -4219,7 +4618,7 @@ static void perf_event_comm_output(struct perf_event *event, perf_event_header__init_id(&comm_event->event_id.header, &sample, event); ret = perf_output_begin(&handle, event, - comm_event->event_id.header.size); + comm_event->event_id.header.size, 0, 0); if (ret) goto out; @@ -4228,7 +4627,7 @@ static void perf_event_comm_output(struct perf_event *event, comm_event->event_id.tid = perf_event_tid(event, comm_event->task); perf_output_put(&handle, comm_event->event_id); - __output_copy(&handle, comm_event->comm, + perf_output_copy(&handle, comm_event->comm, comm_event->comm_size); perf_event__output_id_sample(event, &handle, &sample); @@ -4366,7 +4765,7 @@ static void perf_event_mmap_output(struct perf_event *event, perf_event_header__init_id(&mmap_event->event_id.header, &sample, event); ret = perf_output_begin(&handle, event, - mmap_event->event_id.header.size); + mmap_event->event_id.header.size, 0, 0); if (ret) goto out; @@ -4374,7 +4773,7 @@ static void perf_event_mmap_output(struct perf_event *event, mmap_event->event_id.tid = perf_event_tid(event, current); perf_output_put(&handle, mmap_event->event_id); - __output_copy(&handle, mmap_event->file_name, + perf_output_copy(&handle, mmap_event->file_name, mmap_event->file_size); perf_event__output_id_sample(event, &handle, &sample); @@ -4430,7 +4829,7 @@ static void perf_event_mmap_event(struct perf_mmap_event *mmap_event) if (file) { /* - * d_path works from the end of the rb backwards, so we + * d_path works from the end of the buffer backwards, so we * need to add enough zero bytes after the string to handle * the 64bit alignment we do later. */ @@ -4561,7 +4960,7 @@ static void perf_log_throttle(struct perf_event *event, int enable) perf_event_header__init_id(&throttle_event.header, &sample, event); ret = perf_output_begin(&handle, event, - throttle_event.header.size); + throttle_event.header.size, 1, 0); if (ret) return; @@ -4574,7 +4973,7 @@ static void perf_log_throttle(struct perf_event *event, int enable) * Generic event overflow handling, sampling. */ -static int __perf_event_overflow(struct perf_event *event, +static int __perf_event_overflow(struct perf_event *event, int nmi, int throttle, struct perf_sample_data *data, struct pt_regs *regs) { @@ -4617,28 +5016,34 @@ static int __perf_event_overflow(struct perf_event *event, if (events && atomic_dec_and_test(&event->event_limit)) { ret = 1; event->pending_kill = POLL_HUP; - event->pending_disable = 1; - irq_work_queue(&event->pending); + if (nmi) { + event->pending_disable = 1; + irq_work_queue(&event->pending); + } else + perf_event_disable(event); } if (event->overflow_handler) - event->overflow_handler(event, data, regs); + event->overflow_handler(event, nmi, data, regs); else - perf_event_output(event, data, regs); + perf_event_output(event, nmi, data, regs); if (event->fasync && event->pending_kill) { - event->pending_wakeup = 1; - irq_work_queue(&event->pending); + if (nmi) { + event->pending_wakeup = 1; + irq_work_queue(&event->pending); + } else + perf_event_wakeup(event); } return ret; } -int perf_event_overflow(struct perf_event *event, +int perf_event_overflow(struct perf_event *event, int nmi, struct perf_sample_data *data, struct pt_regs *regs) { - return __perf_event_overflow(event, 1, data, regs); + return __perf_event_overflow(event, nmi, 1, data, regs); } /* @@ -4687,7 +5092,7 @@ static u64 perf_swevent_set_period(struct perf_event *event) } static void perf_swevent_overflow(struct perf_event *event, u64 overflow, - struct perf_sample_data *data, + int nmi, struct perf_sample_data *data, struct pt_regs *regs) { struct hw_perf_event *hwc = &event->hw; @@ -4701,7 +5106,7 @@ static void perf_swevent_overflow(struct perf_event *event, u64 overflow, return; for (; overflow; overflow--) { - if (__perf_event_overflow(event, throttle, + if (__perf_event_overflow(event, nmi, throttle, data, regs)) { /* * We inhibit the overflow from happening when @@ -4714,7 +5119,7 @@ static void perf_swevent_overflow(struct perf_event *event, u64 overflow, } static void perf_swevent_event(struct perf_event *event, u64 nr, - struct perf_sample_data *data, + int nmi, struct perf_sample_data *data, struct pt_regs *regs) { struct hw_perf_event *hwc = &event->hw; @@ -4728,12 +5133,12 @@ static void perf_swevent_event(struct perf_event *event, u64 nr, return; if (nr == 1 && hwc->sample_period == 1 && !event->attr.freq) - return perf_swevent_overflow(event, 1, data, regs); + return perf_swevent_overflow(event, 1, nmi, data, regs); if (local64_add_negative(nr, &hwc->period_left)) return; - perf_swevent_overflow(event, 0, data, regs); + perf_swevent_overflow(event, 0, nmi, data, regs); } static int perf_exclude_event(struct perf_event *event, @@ -4821,7 +5226,7 @@ find_swevent_head(struct swevent_htable *swhash, struct perf_event *event) } static void do_perf_sw_event(enum perf_type_id type, u32 event_id, - u64 nr, + u64 nr, int nmi, struct perf_sample_data *data, struct pt_regs *regs) { @@ -4837,7 +5242,7 @@ static void do_perf_sw_event(enum perf_type_id type, u32 event_id, hlist_for_each_entry_rcu(event, node, head, hlist_entry) { if (perf_swevent_match(event, type, event_id, data, regs)) - perf_swevent_event(event, nr, data, regs); + perf_swevent_event(event, nr, nmi, data, regs); } end: rcu_read_unlock(); @@ -4858,7 +5263,8 @@ inline void perf_swevent_put_recursion_context(int rctx) put_recursion_context(swhash->recursion, rctx); } -void __perf_sw_event(u32 event_id, u64 nr, struct pt_regs *regs, u64 addr) +void __perf_sw_event(u32 event_id, u64 nr, int nmi, + struct pt_regs *regs, u64 addr) { struct perf_sample_data data; int rctx; @@ -4870,7 +5276,7 @@ void __perf_sw_event(u32 event_id, u64 nr, struct pt_regs *regs, u64 addr) perf_sample_data_init(&data, addr); - do_perf_sw_event(PERF_TYPE_SOFTWARE, event_id, nr, &data, regs); + do_perf_sw_event(PERF_TYPE_SOFTWARE, event_id, nr, nmi, &data, regs); perf_swevent_put_recursion_context(rctx); preempt_enable_notrace(); @@ -5118,7 +5524,7 @@ void perf_tp_event(u64 addr, u64 count, void *record, int entry_size, hlist_for_each_entry_rcu(event, node, head, hlist_entry) { if (perf_tp_event_match(event, &data, regs)) - perf_swevent_event(event, count, &data, regs); + perf_swevent_event(event, count, 1, &data, regs); } perf_swevent_put_recursion_context(rctx); @@ -5211,7 +5617,7 @@ void perf_bp_event(struct perf_event *bp, void *data) perf_sample_data_init(&sample, bp->attr.bp_addr); if (!bp->hw.state && !perf_exclude_event(bp, regs)) - perf_swevent_event(bp, 1, &sample, regs); + perf_swevent_event(bp, 1, 1, &sample, regs); } #endif @@ -5240,7 +5646,7 @@ static enum hrtimer_restart perf_swevent_hrtimer(struct hrtimer *hrtimer) if (regs && !perf_exclude_event(event, regs)) { if (!(event->attr.exclude_idle && current->pid == 0)) - if (perf_event_overflow(event, &data, regs)) + if (perf_event_overflow(event, 0, &data, regs)) ret = HRTIMER_NORESTART; } @@ -5580,7 +5986,6 @@ static int pmu_dev_alloc(struct pmu *pmu) } static struct lock_class_key cpuctx_mutex; -static struct lock_class_key cpuctx_lock; int perf_pmu_register(struct pmu *pmu, char *name, int type) { @@ -5631,7 +6036,6 @@ int perf_pmu_register(struct pmu *pmu, char *name, int type) cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu); __perf_event_init_context(&cpuctx->ctx); lockdep_set_class(&cpuctx->ctx.mutex, &cpuctx_mutex); - lockdep_set_class(&cpuctx->ctx.lock, &cpuctx_lock); cpuctx->ctx.type = cpu_context; cpuctx->ctx.pmu = pmu; cpuctx->jiffies_interval = 1; @@ -5746,8 +6150,7 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, struct task_struct *task, struct perf_event *group_leader, struct perf_event *parent_event, - perf_overflow_handler_t overflow_handler, - void *context) + perf_overflow_handler_t overflow_handler) { struct pmu *pmu; struct perf_event *event; @@ -5805,13 +6208,10 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, #endif } - if (!overflow_handler && parent_event) { + if (!overflow_handler && parent_event) overflow_handler = parent_event->overflow_handler; - context = parent_event->overflow_handler_context; - } event->overflow_handler = overflow_handler; - event->overflow_handler_context = context; if (attr->disabled) event->state = PERF_EVENT_STATE_OFF; @@ -5926,6 +6326,13 @@ static int perf_copy_attr(struct perf_event_attr __user *uattr, if (ret) return -EFAULT; + /* + * If the type exists, the corresponding creation will verify + * the attr->config. + */ + if (attr->type >= PERF_TYPE_MAX) + return -EINVAL; + if (attr->__reserved_1) return -EINVAL; @@ -5947,7 +6354,7 @@ static int perf_copy_attr(struct perf_event_attr __user *uattr, static int perf_event_set_output(struct perf_event *event, struct perf_event *output_event) { - struct ring_buffer *rb = NULL, *old_rb = NULL; + struct perf_buffer *buffer = NULL, *old_buffer = NULL; int ret = -EINVAL; if (!output_event) @@ -5964,7 +6371,7 @@ perf_event_set_output(struct perf_event *event, struct perf_event *output_event) goto out; /* - * If its not a per-cpu rb, it must be the same task. + * If its not a per-cpu buffer, it must be the same task. */ if (output_event->cpu == -1 && output_event->ctx != event->ctx) goto out; @@ -5976,20 +6383,20 @@ perf_event_set_output(struct perf_event *event, struct perf_event *output_event) goto unlock; if (output_event) { - /* get the rb we want to redirect to */ - rb = ring_buffer_get(output_event); - if (!rb) + /* get the buffer we want to redirect to */ + buffer = perf_buffer_get(output_event); + if (!buffer) goto unlock; } - old_rb = event->rb; - rcu_assign_pointer(event->rb, rb); + old_buffer = event->buffer; + rcu_assign_pointer(event->buffer, buffer); ret = 0; unlock: mutex_unlock(&event->mmap_mutex); - if (old_rb) - ring_buffer_put(old_rb); + if (old_buffer) + perf_buffer_put(old_buffer); out: return ret; } @@ -6071,8 +6478,7 @@ SYSCALL_DEFINE5(perf_event_open, } } - event = perf_event_alloc(&attr, cpu, task, group_leader, NULL, - NULL, NULL); + event = perf_event_alloc(&attr, cpu, task, group_leader, NULL, NULL); if (IS_ERR(event)) { err = PTR_ERR(event); goto err_task; @@ -6257,8 +6663,7 @@ SYSCALL_DEFINE5(perf_event_open, struct perf_event * perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu, struct task_struct *task, - perf_overflow_handler_t overflow_handler, - void *context) + perf_overflow_handler_t overflow_handler) { struct perf_event_context *ctx; struct perf_event *event; @@ -6268,8 +6673,7 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu, * Get the target context (task or percpu): */ - event = perf_event_alloc(attr, cpu, task, NULL, NULL, - overflow_handler, context); + event = perf_event_alloc(attr, cpu, task, NULL, NULL, overflow_handler); if (IS_ERR(event)) { err = PTR_ERR(event); goto err; @@ -6376,6 +6780,7 @@ static void perf_event_exit_task_context(struct task_struct *child, int ctxn) * our context. */ child_ctx = rcu_dereference_raw(child->perf_event_ctxp[ctxn]); + task_ctx_sched_out(child_ctx, EVENT_ALL); /* * Take the context lock here so that if find_get_context is @@ -6383,7 +6788,6 @@ static void perf_event_exit_task_context(struct task_struct *child, int ctxn) * incremented the context's refcount before we do put_ctx below. */ raw_spin_lock(&child_ctx->lock); - task_ctx_sched_out(child_ctx); child->perf_event_ctxp[ctxn] = NULL; /* * If this context is a clone; unclone it so it can't get @@ -6553,7 +6957,7 @@ inherit_event(struct perf_event *parent_event, parent_event->cpu, child, group_leader, parent_event, - NULL, NULL); + NULL); if (IS_ERR(child_event)) return child_event; get_ctx(child_ctx); @@ -6580,8 +6984,6 @@ inherit_event(struct perf_event *parent_event, child_event->ctx = child_ctx; child_event->overflow_handler = parent_event->overflow_handler; - child_event->overflow_handler_context - = parent_event->overflow_handler_context; /* * Precalculate sample_data sizes diff --git a/trunk/kernel/events/hw_breakpoint.c b/trunk/kernel/events/hw_breakpoint.c index b7971d6f38bf..086adf25a55e 100644 --- a/trunk/kernel/events/hw_breakpoint.c +++ b/trunk/kernel/events/hw_breakpoint.c @@ -431,11 +431,9 @@ int register_perf_hw_breakpoint(struct perf_event *bp) struct perf_event * register_user_hw_breakpoint(struct perf_event_attr *attr, perf_overflow_handler_t triggered, - void *context, struct task_struct *tsk) { - return perf_event_create_kernel_counter(attr, -1, tsk, triggered, - context); + return perf_event_create_kernel_counter(attr, -1, tsk, triggered); } EXPORT_SYMBOL_GPL(register_user_hw_breakpoint); @@ -504,8 +502,7 @@ EXPORT_SYMBOL_GPL(unregister_hw_breakpoint); */ struct perf_event * __percpu * register_wide_hw_breakpoint(struct perf_event_attr *attr, - perf_overflow_handler_t triggered, - void *context) + perf_overflow_handler_t triggered) { struct perf_event * __percpu *cpu_events, **pevent, *bp; long err; @@ -518,8 +515,7 @@ register_wide_hw_breakpoint(struct perf_event_attr *attr, get_online_cpus(); for_each_online_cpu(cpu) { pevent = per_cpu_ptr(cpu_events, cpu); - bp = perf_event_create_kernel_counter(attr, cpu, NULL, - triggered, context); + bp = perf_event_create_kernel_counter(attr, cpu, NULL, triggered); *pevent = bp; diff --git a/trunk/kernel/events/internal.h b/trunk/kernel/events/internal.h deleted file mode 100644 index 09097dd8116c..000000000000 --- a/trunk/kernel/events/internal.h +++ /dev/null @@ -1,96 +0,0 @@ -#ifndef _KERNEL_EVENTS_INTERNAL_H -#define _KERNEL_EVENTS_INTERNAL_H - -#define RING_BUFFER_WRITABLE 0x01 - -struct ring_buffer { - atomic_t refcount; - struct rcu_head rcu_head; -#ifdef CONFIG_PERF_USE_VMALLOC - struct work_struct work; - int page_order; /* allocation order */ -#endif - int nr_pages; /* nr of data pages */ - int writable; /* are we writable */ - - atomic_t poll; /* POLL_ for wakeups */ - - local_t head; /* write position */ - local_t nest; /* nested writers */ - local_t events; /* event limit */ - local_t wakeup; /* wakeup stamp */ - local_t lost; /* nr records lost */ - - long watermark; /* wakeup watermark */ - - struct perf_event_mmap_page *user_page; - void *data_pages[0]; -}; - -extern void rb_free(struct ring_buffer *rb); -extern struct ring_buffer * -rb_alloc(int nr_pages, long watermark, int cpu, int flags); -extern void perf_event_wakeup(struct perf_event *event); - -extern void -perf_event_header__init_id(struct perf_event_header *header, - struct perf_sample_data *data, - struct perf_event *event); -extern void -perf_event__output_id_sample(struct perf_event *event, - struct perf_output_handle *handle, - struct perf_sample_data *sample); - -extern struct page * -perf_mmap_to_page(struct ring_buffer *rb, unsigned long pgoff); - -#ifdef CONFIG_PERF_USE_VMALLOC -/* - * Back perf_mmap() with vmalloc memory. - * - * Required for architectures that have d-cache aliasing issues. - */ - -static inline int page_order(struct ring_buffer *rb) -{ - return rb->page_order; -} - -#else - -static inline int page_order(struct ring_buffer *rb) -{ - return 0; -} -#endif - -static unsigned long perf_data_size(struct ring_buffer *rb) -{ - return rb->nr_pages << (PAGE_SHIFT + page_order(rb)); -} - -static inline void -__output_copy(struct perf_output_handle *handle, - const void *buf, unsigned int len) -{ - do { - unsigned long size = min_t(unsigned long, handle->size, len); - - memcpy(handle->addr, buf, size); - - len -= size; - handle->addr += size; - buf += size; - handle->size -= size; - if (!handle->size) { - struct ring_buffer *rb = handle->rb; - - handle->page++; - handle->page &= rb->nr_pages - 1; - handle->addr = rb->data_pages[handle->page]; - handle->size = PAGE_SIZE << page_order(rb); - } - } while (len); -} - -#endif /* _KERNEL_EVENTS_INTERNAL_H */ diff --git a/trunk/kernel/events/ring_buffer.c b/trunk/kernel/events/ring_buffer.c deleted file mode 100644 index a2a29205cc0f..000000000000 --- a/trunk/kernel/events/ring_buffer.c +++ /dev/null @@ -1,380 +0,0 @@ -/* - * Performance events ring-buffer code: - * - * Copyright (C) 2008 Thomas Gleixner - * Copyright (C) 2008-2011 Red Hat, Inc., Ingo Molnar - * Copyright (C) 2008-2011 Red Hat, Inc., Peter Zijlstra - * Copyright 2009 Paul Mackerras, IBM Corp. - * - * For licensing details see kernel-base/COPYING - */ - -#include -#include -#include - -#include "internal.h" - -static bool perf_output_space(struct ring_buffer *rb, unsigned long tail, - unsigned long offset, unsigned long head) -{ - unsigned long mask; - - if (!rb->writable) - return true; - - mask = perf_data_size(rb) - 1; - - offset = (offset - tail) & mask; - head = (head - tail) & mask; - - if ((int)(head - offset) < 0) - return false; - - return true; -} - -static void perf_output_wakeup(struct perf_output_handle *handle) -{ - atomic_set(&handle->rb->poll, POLL_IN); - - handle->event->pending_wakeup = 1; - irq_work_queue(&handle->event->pending); -} - -/* - * We need to ensure a later event_id doesn't publish a head when a former - * event isn't done writing. However since we need to deal with NMIs we - * cannot fully serialize things. - * - * We only publish the head (and generate a wakeup) when the outer-most - * event completes. - */ -static void perf_output_get_handle(struct perf_output_handle *handle) -{ - struct ring_buffer *rb = handle->rb; - - preempt_disable(); - local_inc(&rb->nest); - handle->wakeup = local_read(&rb->wakeup); -} - -static void perf_output_put_handle(struct perf_output_handle *handle) -{ - struct ring_buffer *rb = handle->rb; - unsigned long head; - -again: - head = local_read(&rb->head); - - /* - * IRQ/NMI can happen here, which means we can miss a head update. - */ - - if (!local_dec_and_test(&rb->nest)) - goto out; - - /* - * Publish the known good head. Rely on the full barrier implied - * by atomic_dec_and_test() order the rb->head read and this - * write. - */ - rb->user_page->data_head = head; - - /* - * Now check if we missed an update, rely on the (compiler) - * barrier in atomic_dec_and_test() to re-read rb->head. - */ - if (unlikely(head != local_read(&rb->head))) { - local_inc(&rb->nest); - goto again; - } - - if (handle->wakeup != local_read(&rb->wakeup)) - perf_output_wakeup(handle); - -out: - preempt_enable(); -} - -int perf_output_begin(struct perf_output_handle *handle, - struct perf_event *event, unsigned int size) -{ - struct ring_buffer *rb; - unsigned long tail, offset, head; - int have_lost; - struct perf_sample_data sample_data; - struct { - struct perf_event_header header; - u64 id; - u64 lost; - } lost_event; - - rcu_read_lock(); - /* - * For inherited events we send all the output towards the parent. - */ - if (event->parent) - event = event->parent; - - rb = rcu_dereference(event->rb); - if (!rb) - goto out; - - handle->rb = rb; - handle->event = event; - - if (!rb->nr_pages) - goto out; - - have_lost = local_read(&rb->lost); - if (have_lost) { - lost_event.header.size = sizeof(lost_event); - perf_event_header__init_id(&lost_event.header, &sample_data, - event); - size += lost_event.header.size; - } - - perf_output_get_handle(handle); - - do { - /* - * Userspace could choose to issue a mb() before updating the - * tail pointer. So that all reads will be completed before the - * write is issued. - */ - tail = ACCESS_ONCE(rb->user_page->data_tail); - smp_rmb(); - offset = head = local_read(&rb->head); - head += size; - if (unlikely(!perf_output_space(rb, tail, offset, head))) - goto fail; - } while (local_cmpxchg(&rb->head, offset, head) != offset); - - if (head - local_read(&rb->wakeup) > rb->watermark) - local_add(rb->watermark, &rb->wakeup); - - handle->page = offset >> (PAGE_SHIFT + page_order(rb)); - handle->page &= rb->nr_pages - 1; - handle->size = offset & ((PAGE_SIZE << page_order(rb)) - 1); - handle->addr = rb->data_pages[handle->page]; - handle->addr += handle->size; - handle->size = (PAGE_SIZE << page_order(rb)) - handle->size; - - if (have_lost) { - lost_event.header.type = PERF_RECORD_LOST; - lost_event.header.misc = 0; - lost_event.id = event->id; - lost_event.lost = local_xchg(&rb->lost, 0); - - perf_output_put(handle, lost_event); - perf_event__output_id_sample(event, handle, &sample_data); - } - - return 0; - -fail: - local_inc(&rb->lost); - perf_output_put_handle(handle); -out: - rcu_read_unlock(); - - return -ENOSPC; -} - -void perf_output_copy(struct perf_output_handle *handle, - const void *buf, unsigned int len) -{ - __output_copy(handle, buf, len); -} - -void perf_output_end(struct perf_output_handle *handle) -{ - perf_output_put_handle(handle); - rcu_read_unlock(); -} - -static void -ring_buffer_init(struct ring_buffer *rb, long watermark, int flags) -{ - long max_size = perf_data_size(rb); - - if (watermark) - rb->watermark = min(max_size, watermark); - - if (!rb->watermark) - rb->watermark = max_size / 2; - - if (flags & RING_BUFFER_WRITABLE) - rb->writable = 1; - - atomic_set(&rb->refcount, 1); -} - -#ifndef CONFIG_PERF_USE_VMALLOC - -/* - * Back perf_mmap() with regular GFP_KERNEL-0 pages. - */ - -struct page * -perf_mmap_to_page(struct ring_buffer *rb, unsigned long pgoff) -{ - if (pgoff > rb->nr_pages) - return NULL; - - if (pgoff == 0) - return virt_to_page(rb->user_page); - - return virt_to_page(rb->data_pages[pgoff - 1]); -} - -static void *perf_mmap_alloc_page(int cpu) -{ - struct page *page; - int node; - - node = (cpu == -1) ? cpu : cpu_to_node(cpu); - page = alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 0); - if (!page) - return NULL; - - return page_address(page); -} - -struct ring_buffer *rb_alloc(int nr_pages, long watermark, int cpu, int flags) -{ - struct ring_buffer *rb; - unsigned long size; - int i; - - size = sizeof(struct ring_buffer); - size += nr_pages * sizeof(void *); - - rb = kzalloc(size, GFP_KERNEL); - if (!rb) - goto fail; - - rb->user_page = perf_mmap_alloc_page(cpu); - if (!rb->user_page) - goto fail_user_page; - - for (i = 0; i < nr_pages; i++) { - rb->data_pages[i] = perf_mmap_alloc_page(cpu); - if (!rb->data_pages[i]) - goto fail_data_pages; - } - - rb->nr_pages = nr_pages; - - ring_buffer_init(rb, watermark, flags); - - return rb; - -fail_data_pages: - for (i--; i >= 0; i--) - free_page((unsigned long)rb->data_pages[i]); - - free_page((unsigned long)rb->user_page); - -fail_user_page: - kfree(rb); - -fail: - return NULL; -} - -static void perf_mmap_free_page(unsigned long addr) -{ - struct page *page = virt_to_page((void *)addr); - - page->mapping = NULL; - __free_page(page); -} - -void rb_free(struct ring_buffer *rb) -{ - int i; - - perf_mmap_free_page((unsigned long)rb->user_page); - for (i = 0; i < rb->nr_pages; i++) - perf_mmap_free_page((unsigned long)rb->data_pages[i]); - kfree(rb); -} - -#else - -struct page * -perf_mmap_to_page(struct ring_buffer *rb, unsigned long pgoff) -{ - if (pgoff > (1UL << page_order(rb))) - return NULL; - - return vmalloc_to_page((void *)rb->user_page + pgoff * PAGE_SIZE); -} - -static void perf_mmap_unmark_page(void *addr) -{ - struct page *page = vmalloc_to_page(addr); - - page->mapping = NULL; -} - -static void rb_free_work(struct work_struct *work) -{ - struct ring_buffer *rb; - void *base; - int i, nr; - - rb = container_of(work, struct ring_buffer, work); - nr = 1 << page_order(rb); - - base = rb->user_page; - for (i = 0; i < nr + 1; i++) - perf_mmap_unmark_page(base + (i * PAGE_SIZE)); - - vfree(base); - kfree(rb); -} - -void rb_free(struct ring_buffer *rb) -{ - schedule_work(&rb->work); -} - -struct ring_buffer *rb_alloc(int nr_pages, long watermark, int cpu, int flags) -{ - struct ring_buffer *rb; - unsigned long size; - void *all_buf; - - size = sizeof(struct ring_buffer); - size += sizeof(void *); - - rb = kzalloc(size, GFP_KERNEL); - if (!rb) - goto fail; - - INIT_WORK(&rb->work, rb_free_work); - - all_buf = vmalloc_user((nr_pages + 1) * PAGE_SIZE); - if (!all_buf) - goto fail_all_buf; - - rb->user_page = all_buf; - rb->data_pages[0] = all_buf + PAGE_SIZE; - rb->page_order = ilog2(nr_pages); - rb->nr_pages = 1; - - ring_buffer_init(rb, watermark, flags); - - return rb; - -fail_all_buf: - kfree(rb); - -fail: - return NULL; -} - -#endif diff --git a/trunk/kernel/fork.c b/trunk/kernel/fork.c index aeae5b11b62e..4d4117e01504 100644 --- a/trunk/kernel/fork.c +++ b/trunk/kernel/fork.c @@ -1012,7 +1012,7 @@ static void rt_mutex_init_task(struct task_struct *p) { raw_spin_lock_init(&p->pi_lock); #ifdef CONFIG_RT_MUTEXES - plist_head_init(&p->pi_waiters); + plist_head_init_raw(&p->pi_waiters, &p->pi_lock); p->pi_blocked_on = NULL; #endif } @@ -1585,7 +1585,6 @@ void __init proc_caches_init(void) SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_NOTRACK, NULL); vm_area_cachep = KMEM_CACHE(vm_area_struct, SLAB_PANIC); mmap_init(); - nsproxy_cache_init(); } /* diff --git a/trunk/kernel/futex.c b/trunk/kernel/futex.c index 3fbc76cbb9aa..fe28dc282eae 100644 --- a/trunk/kernel/futex.c +++ b/trunk/kernel/futex.c @@ -2697,7 +2697,7 @@ static int __init futex_init(void) futex_cmpxchg_enabled = 1; for (i = 0; i < ARRAY_SIZE(futex_queues); i++) { - plist_head_init(&futex_queues[i].chain); + plist_head_init(&futex_queues[i].chain, &futex_queues[i].lock); spin_lock_init(&futex_queues[i].lock); } diff --git a/trunk/kernel/kprobes.c b/trunk/kernel/kprobes.c index b30fd54eb985..77981813a1e7 100644 --- a/trunk/kernel/kprobes.c +++ b/trunk/kernel/kprobes.c @@ -1255,29 +1255,19 @@ static int __kprobes in_kprobes_functions(unsigned long addr) /* * If we have a symbol_name argument, look it up and add the offset field * to it. This way, we can specify a relative address to a symbol. - * This returns encoded errors if it fails to look up symbol or invalid - * combination of parameters. */ static kprobe_opcode_t __kprobes *kprobe_addr(struct kprobe *p) { kprobe_opcode_t *addr = p->addr; - - if ((p->symbol_name && p->addr) || - (!p->symbol_name && !p->addr)) - goto invalid; - if (p->symbol_name) { + if (addr) + return NULL; kprobe_lookup_name(p->symbol_name, addr); - if (!addr) - return ERR_PTR(-ENOENT); } - addr = (kprobe_opcode_t *)(((char *)addr) + p->offset); - if (addr) - return addr; - -invalid: - return ERR_PTR(-EINVAL); + if (!addr) + return NULL; + return (kprobe_opcode_t *)(((char *)addr) + p->offset); } /* Check passed kprobe is valid and return kprobe in kprobe_table. */ @@ -1321,8 +1311,8 @@ int __kprobes register_kprobe(struct kprobe *p) kprobe_opcode_t *addr; addr = kprobe_addr(p); - if (IS_ERR(addr)) - return PTR_ERR(addr); + if (!addr) + return -EINVAL; p->addr = addr; ret = check_kprobe_rereg(p); @@ -1345,8 +1335,6 @@ int __kprobes register_kprobe(struct kprobe *p) */ probed_mod = __module_text_address((unsigned long) p->addr); if (probed_mod) { - /* Return -ENOENT if fail. */ - ret = -ENOENT; /* * We must hold a refcount of the probed module while updating * its code to prohibit unexpected unloading. @@ -1363,7 +1351,6 @@ int __kprobes register_kprobe(struct kprobe *p) module_put(probed_mod); goto fail_with_jump_label; } - /* ret will be updated by following code */ } preempt_enable(); jump_label_unlock(); @@ -1412,7 +1399,7 @@ int __kprobes register_kprobe(struct kprobe *p) fail_with_jump_label: preempt_enable(); jump_label_unlock(); - return ret; + return -EINVAL; } EXPORT_SYMBOL_GPL(register_kprobe); @@ -1699,8 +1686,8 @@ int __kprobes register_kretprobe(struct kretprobe *rp) if (kretprobe_blacklist_size) { addr = kprobe_addr(&rp->kp); - if (IS_ERR(addr)) - return PTR_ERR(addr); + if (!addr) + return -EINVAL; for (i = 0; kretprobe_blacklist[i].name != NULL; i++) { if (kretprobe_blacklist[i].addr == addr) diff --git a/trunk/kernel/lockdep.c b/trunk/kernel/lockdep.c index 3956f5149e25..298c9276dfdb 100644 --- a/trunk/kernel/lockdep.c +++ b/trunk/kernel/lockdep.c @@ -2468,9 +2468,6 @@ mark_held_locks(struct task_struct *curr, enum mark_type mark) BUG_ON(usage_bit >= LOCK_USAGE_STATES); - if (hlock_class(hlock)->key == &__lockdep_no_validate__) - continue; - if (!mark_lock(curr, hlock, usage_bit)) return 0; } @@ -2481,10 +2478,15 @@ mark_held_locks(struct task_struct *curr, enum mark_type mark) /* * Hardirqs will be enabled: */ -static void __trace_hardirqs_on_caller(unsigned long ip) +void trace_hardirqs_on_caller(unsigned long ip) { struct task_struct *curr = current; + time_hardirqs_on(CALLER_ADDR0, ip); + + if (unlikely(!debug_locks || current->lockdep_recursion)) + return; + if (DEBUG_LOCKS_WARN_ON(unlikely(early_boot_irqs_disabled))) return; @@ -2500,6 +2502,8 @@ static void __trace_hardirqs_on_caller(unsigned long ip) /* we'll do an OFF -> ON transition: */ curr->hardirqs_enabled = 1; + if (DEBUG_LOCKS_WARN_ON(!irqs_disabled())) + return; if (DEBUG_LOCKS_WARN_ON(current->hardirq_context)) return; /* @@ -2521,21 +2525,6 @@ static void __trace_hardirqs_on_caller(unsigned long ip) curr->hardirq_enable_event = ++curr->irq_events; debug_atomic_inc(hardirqs_on_events); } - -void trace_hardirqs_on_caller(unsigned long ip) -{ - time_hardirqs_on(CALLER_ADDR0, ip); - - if (unlikely(!debug_locks || current->lockdep_recursion)) - return; - - if (DEBUG_LOCKS_WARN_ON(!irqs_disabled())) - return; - - current->lockdep_recursion = 1; - __trace_hardirqs_on_caller(ip); - current->lockdep_recursion = 0; -} EXPORT_SYMBOL(trace_hardirqs_on_caller); void trace_hardirqs_on(void) @@ -2585,7 +2574,7 @@ void trace_softirqs_on(unsigned long ip) { struct task_struct *curr = current; - if (unlikely(!debug_locks || current->lockdep_recursion)) + if (unlikely(!debug_locks)) return; if (DEBUG_LOCKS_WARN_ON(!irqs_disabled())) @@ -2596,7 +2585,6 @@ void trace_softirqs_on(unsigned long ip) return; } - current->lockdep_recursion = 1; /* * We'll do an OFF -> ON transition: */ @@ -2611,7 +2599,6 @@ void trace_softirqs_on(unsigned long ip) */ if (curr->hardirqs_enabled) mark_held_locks(curr, SOFTIRQ); - current->lockdep_recursion = 0; } /* @@ -2621,7 +2608,7 @@ void trace_softirqs_off(unsigned long ip) { struct task_struct *curr = current; - if (unlikely(!debug_locks || current->lockdep_recursion)) + if (unlikely(!debug_locks)) return; if (DEBUG_LOCKS_WARN_ON(!irqs_disabled())) diff --git a/trunk/kernel/module.c b/trunk/kernel/module.c index 04379f92f843..795bdc7f5c3f 100644 --- a/trunk/kernel/module.c +++ b/trunk/kernel/module.c @@ -545,9 +545,9 @@ static void setup_modinfo_##field(struct module *mod, const char *s) \ mod->field = kstrdup(s, GFP_KERNEL); \ } \ static ssize_t show_modinfo_##field(struct module_attribute *mattr, \ - struct module_kobject *mk, char *buffer) \ + struct module *mod, char *buffer) \ { \ - return sprintf(buffer, "%s\n", mk->mod->field); \ + return sprintf(buffer, "%s\n", mod->field); \ } \ static int modinfo_##field##_exists(struct module *mod) \ { \ @@ -902,9 +902,9 @@ void symbol_put_addr(void *addr) EXPORT_SYMBOL_GPL(symbol_put_addr); static ssize_t show_refcnt(struct module_attribute *mattr, - struct module_kobject *mk, char *buffer) + struct module *mod, char *buffer) { - return sprintf(buffer, "%u\n", module_refcount(mk->mod)); + return sprintf(buffer, "%u\n", module_refcount(mod)); } static struct module_attribute refcnt = { @@ -952,11 +952,11 @@ static inline int module_unload_init(struct module *mod) #endif /* CONFIG_MODULE_UNLOAD */ static ssize_t show_initstate(struct module_attribute *mattr, - struct module_kobject *mk, char *buffer) + struct module *mod, char *buffer) { const char *state = "unknown"; - switch (mk->mod->state) { + switch (mod->state) { case MODULE_STATE_LIVE: state = "live"; break; @@ -975,27 +975,10 @@ static struct module_attribute initstate = { .show = show_initstate, }; -static ssize_t store_uevent(struct module_attribute *mattr, - struct module_kobject *mk, - const char *buffer, size_t count) -{ - enum kobject_action action; - - if (kobject_action_type(buffer, count, &action) == 0) - kobject_uevent(&mk->kobj, action); - return count; -} - -struct module_attribute module_uevent = { - .attr = { .name = "uevent", .mode = 0200 }, - .store = store_uevent, -}; - static struct module_attribute *modinfo_attrs[] = { &modinfo_version, &modinfo_srcversion, &initstate, - &module_uevent, #ifdef CONFIG_MODULE_UNLOAD &refcnt, #endif @@ -1204,7 +1187,7 @@ struct module_sect_attrs }; static ssize_t module_sect_show(struct module_attribute *mattr, - struct module_kobject *mk, char *buf) + struct module *mod, char *buf) { struct module_sect_attr *sattr = container_of(mattr, struct module_sect_attr, mattr); @@ -1714,15 +1697,6 @@ static void unset_module_core_ro_nx(struct module *mod) { } static void unset_module_init_ro_nx(struct module *mod) { } #endif -void __weak module_free(struct module *mod, void *module_region) -{ - vfree(module_region); -} - -void __weak module_arch_cleanup(struct module *mod) -{ -} - /* Free a module, remove from lists, etc. */ static void free_module(struct module *mod) { @@ -1877,26 +1851,6 @@ static int simplify_symbols(struct module *mod, const struct load_info *info) return ret; } -int __weak apply_relocate(Elf_Shdr *sechdrs, - const char *strtab, - unsigned int symindex, - unsigned int relsec, - struct module *me) -{ - pr_err("module %s: REL relocation unsupported\n", me->name); - return -ENOEXEC; -} - -int __weak apply_relocate_add(Elf_Shdr *sechdrs, - const char *strtab, - unsigned int symindex, - unsigned int relsec, - struct module *me) -{ - pr_err("module %s: RELA relocation unsupported\n", me->name); - return -ENOEXEC; -} - static int apply_relocations(struct module *mod, const struct load_info *info) { unsigned int i; @@ -2281,11 +2235,6 @@ static void dynamic_debug_remove(struct _ddebug *debug) ddebug_remove_module(debug->modname); } -void * __weak module_alloc(unsigned long size) -{ - return size == 0 ? NULL : vmalloc_exec(size); -} - static void *module_alloc_update_bounds(unsigned long size) { void *ret = module_alloc(size); @@ -2696,14 +2645,6 @@ static void flush_module_icache(const struct module *mod) set_fs(old_fs); } -int __weak module_frob_arch_sections(Elf_Ehdr *hdr, - Elf_Shdr *sechdrs, - char *secstrings, - struct module *mod) -{ - return 0; -} - static struct module *layout_and_allocate(struct load_info *info) { /* Module within temporary copy. */ @@ -2775,13 +2716,6 @@ static void module_deallocate(struct module *mod, struct load_info *info) module_free(mod, mod->module_core); } -int __weak module_finalize(const Elf_Ehdr *hdr, - const Elf_Shdr *sechdrs, - struct module *me) -{ - return 0; -} - static int post_relocation(struct module *mod, const struct load_info *info) { /* Sort exception table now relocations are done. */ diff --git a/trunk/kernel/nsproxy.c b/trunk/kernel/nsproxy.c index 9aeab4b98c64..d6a00f3de15d 100644 --- a/trunk/kernel/nsproxy.c +++ b/trunk/kernel/nsproxy.c @@ -271,8 +271,10 @@ SYSCALL_DEFINE2(setns, int, fd, int, nstype) return err; } -int __init nsproxy_cache_init(void) +static int __init nsproxy_cache_init(void) { nsproxy_cachep = KMEM_CACHE(nsproxy, SLAB_PANIC); return 0; } + +module_init(nsproxy_cache_init); diff --git a/trunk/kernel/params.c b/trunk/kernel/params.c index 22df3e0d142a..ed72e1330862 100644 --- a/trunk/kernel/params.c +++ b/trunk/kernel/params.c @@ -225,8 +225,8 @@ int parse_args(const char *name, int ret; \ \ ret = strtolfn(val, 0, &l); \ - if (ret < 0 || ((type)l != l)) \ - return ret < 0 ? ret : -EINVAL; \ + if (ret == -EINVAL || ((type)l != l)) \ + return -EINVAL; \ *((type *)kp->arg) = l; \ return 0; \ } \ @@ -511,7 +511,7 @@ struct module_param_attrs #define to_param_attr(n) container_of(n, struct param_attribute, mattr) static ssize_t param_attr_show(struct module_attribute *mattr, - struct module_kobject *mk, char *buf) + struct module *mod, char *buf) { int count; struct param_attribute *attribute = to_param_attr(mattr); @@ -531,7 +531,7 @@ static ssize_t param_attr_show(struct module_attribute *mattr, /* sysfs always hands a nul-terminated string in buf. We rely on that. */ static ssize_t param_attr_store(struct module_attribute *mattr, - struct module_kobject *km, + struct module *owner, const char *buf, size_t len) { int err; @@ -730,10 +730,6 @@ static struct module_kobject * __init locate_module_kobject(const char *name) mk->kobj.kset = module_kset; err = kobject_init_and_add(&mk->kobj, &module_ktype, NULL, "%s", name); -#ifdef CONFIG_MODULES - if (!err) - err = sysfs_create_file(&mk->kobj, &module_uevent.attr); -#endif if (err) { kobject_put(&mk->kobj); printk(KERN_ERR @@ -811,7 +807,7 @@ static void __init param_sysfs_builtin(void) } ssize_t __modver_version_show(struct module_attribute *mattr, - struct module_kobject *mk, char *buf) + struct module *mod, char *buf) { struct module_version_attribute *vattr = container_of(mattr, struct module_version_attribute, mattr); @@ -856,7 +852,7 @@ static ssize_t module_attr_show(struct kobject *kobj, if (!attribute->show) return -EIO; - ret = attribute->show(attribute, mk, buf); + ret = attribute->show(attribute, mk->mod, buf); return ret; } @@ -875,7 +871,7 @@ static ssize_t module_attr_store(struct kobject *kobj, if (!attribute->store) return -EIO; - ret = attribute->store(attribute, mk, buf, len); + ret = attribute->store(attribute, mk->mod, buf, len); return ret; } diff --git a/trunk/kernel/pm_qos_params.c b/trunk/kernel/pm_qos_params.c index 37f05d0f0793..6824ca7d4d0c 100644 --- a/trunk/kernel/pm_qos_params.c +++ b/trunk/kernel/pm_qos_params.c @@ -74,7 +74,7 @@ static DEFINE_SPINLOCK(pm_qos_lock); static struct pm_qos_object null_pm_qos; static BLOCKING_NOTIFIER_HEAD(cpu_dma_lat_notifier); static struct pm_qos_object cpu_dma_pm_qos = { - .requests = PLIST_HEAD_INIT(cpu_dma_pm_qos.requests), + .requests = PLIST_HEAD_INIT(cpu_dma_pm_qos.requests, pm_qos_lock), .notifiers = &cpu_dma_lat_notifier, .name = "cpu_dma_latency", .target_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE, @@ -84,7 +84,7 @@ static struct pm_qos_object cpu_dma_pm_qos = { static BLOCKING_NOTIFIER_HEAD(network_lat_notifier); static struct pm_qos_object network_lat_pm_qos = { - .requests = PLIST_HEAD_INIT(network_lat_pm_qos.requests), + .requests = PLIST_HEAD_INIT(network_lat_pm_qos.requests, pm_qos_lock), .notifiers = &network_lat_notifier, .name = "network_latency", .target_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE, @@ -95,7 +95,7 @@ static struct pm_qos_object network_lat_pm_qos = { static BLOCKING_NOTIFIER_HEAD(network_throughput_notifier); static struct pm_qos_object network_throughput_pm_qos = { - .requests = PLIST_HEAD_INIT(network_throughput_pm_qos.requests), + .requests = PLIST_HEAD_INIT(network_throughput_pm_qos.requests, pm_qos_lock), .notifiers = &network_throughput_notifier, .name = "network_throughput", .target_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE, diff --git a/trunk/kernel/printk.c b/trunk/kernel/printk.c index 37dff3429adb..35185392173f 100644 --- a/trunk/kernel/printk.c +++ b/trunk/kernel/printk.c @@ -782,7 +782,7 @@ static inline int can_use_console(unsigned int cpu) static int console_trylock_for_printk(unsigned int cpu) __releases(&logbuf_lock) { - int retval = 0, wake = 0; + int retval = 0; if (console_trylock()) { retval = 1; @@ -795,14 +795,12 @@ static int console_trylock_for_printk(unsigned int cpu) */ if (!can_use_console(cpu)) { console_locked = 0; - wake = 1; + up(&console_sem); retval = 0; } } printk_cpu = UINT_MAX; spin_unlock(&logbuf_lock); - if (wake) - up(&console_sem); return retval; } static const char recursion_bug_msg [] = @@ -1244,7 +1242,7 @@ void console_unlock(void) { unsigned long flags; unsigned _con_start, _log_end; - unsigned wake_klogd = 0, retry = 0; + unsigned wake_klogd = 0; if (console_suspended) { up(&console_sem); @@ -1253,7 +1251,6 @@ void console_unlock(void) console_may_schedule = 0; -again: for ( ; ; ) { spin_lock_irqsave(&logbuf_lock, flags); wake_klogd |= log_start - log_end; @@ -1274,23 +1271,8 @@ void console_unlock(void) if (unlikely(exclusive_console)) exclusive_console = NULL; - spin_unlock(&logbuf_lock); - up(&console_sem); - - /* - * Someone could have filled up the buffer again, so re-check if there's - * something to flush. In case we cannot trylock the console_sem again, - * there's a new owner and the console_unlock() from them will do the - * flush, no worries. - */ - spin_lock(&logbuf_lock); - if (con_start != log_end) - retry = 1; spin_unlock_irqrestore(&logbuf_lock, flags); - if (retry && console_trylock()) - goto again; - if (wake_klogd) wake_up_klogd(); } diff --git a/trunk/kernel/rtmutex.c b/trunk/kernel/rtmutex.c index 255e1662acdb..ab449117aaf2 100644 --- a/trunk/kernel/rtmutex.c +++ b/trunk/kernel/rtmutex.c @@ -890,7 +890,7 @@ void __rt_mutex_init(struct rt_mutex *lock, const char *name) { lock->owner = NULL; raw_spin_lock_init(&lock->wait_lock); - plist_head_init(&lock->wait_list); + plist_head_init_raw(&lock->wait_list, &lock->wait_lock); debug_rt_mutex_init(lock, name); } diff --git a/trunk/kernel/rwsem.c b/trunk/kernel/rwsem.c index 176e5e56ffab..cae050b05f5e 100644 --- a/trunk/kernel/rwsem.c +++ b/trunk/kernel/rwsem.c @@ -117,6 +117,15 @@ void down_read_nested(struct rw_semaphore *sem, int subclass) EXPORT_SYMBOL(down_read_nested); +void down_read_non_owner(struct rw_semaphore *sem) +{ + might_sleep(); + + __down_read(sem); +} + +EXPORT_SYMBOL(down_read_non_owner); + void down_write_nested(struct rw_semaphore *sem, int subclass) { might_sleep(); @@ -127,6 +136,13 @@ void down_write_nested(struct rw_semaphore *sem, int subclass) EXPORT_SYMBOL(down_write_nested); +void up_read_non_owner(struct rw_semaphore *sem) +{ + __up_read(sem); +} + +EXPORT_SYMBOL(up_read_non_owner); + #endif diff --git a/trunk/kernel/sched.c b/trunk/kernel/sched.c index 751a7cc6a5cd..fde6ff903525 100644 --- a/trunk/kernel/sched.c +++ b/trunk/kernel/sched.c @@ -75,9 +75,6 @@ #include #include #include -#ifdef CONFIG_PARAVIRT -#include -#endif #include "sched_cpupri.h" #include "workqueue_sched.h" @@ -127,7 +124,7 @@ static inline int rt_policy(int policy) { - if (policy == SCHED_FIFO || policy == SCHED_RR) + if (unlikely(policy == SCHED_FIFO || policy == SCHED_RR)) return 1; return 0; } @@ -425,7 +422,6 @@ struct rt_rq { */ struct root_domain { atomic_t refcount; - atomic_t rto_count; struct rcu_head rcu; cpumask_var_t span; cpumask_var_t online; @@ -435,6 +431,7 @@ struct root_domain { * one runnable RT task. */ cpumask_var_t rto_mask; + atomic_t rto_count; struct cpupri cpupri; }; @@ -531,12 +528,6 @@ struct rq { #ifdef CONFIG_IRQ_TIME_ACCOUNTING u64 prev_irq_time; #endif -#ifdef CONFIG_PARAVIRT - u64 prev_steal_time; -#endif -#ifdef CONFIG_PARAVIRT_TIME_ACCOUNTING - u64 prev_steal_time_rq; -#endif /* calc_load related fields */ unsigned long calc_load_update; @@ -1577,6 +1568,38 @@ static unsigned long cpu_avg_load_per_task(int cpu) return rq->avg_load_per_task; } +#ifdef CONFIG_FAIR_GROUP_SCHED + +/* + * Compute the cpu's hierarchical load factor for each task group. + * This needs to be done in a top-down fashion because the load of a child + * group is a fraction of its parents load. + */ +static int tg_load_down(struct task_group *tg, void *data) +{ + unsigned long load; + long cpu = (long)data; + + if (!tg->parent) { + load = cpu_rq(cpu)->load.weight; + } else { + load = tg->parent->cfs_rq[cpu]->h_load; + load *= tg->se[cpu]->load.weight; + load /= tg->parent->cfs_rq[cpu]->load.weight + 1; + } + + tg->cfs_rq[cpu]->h_load = load; + + return 0; +} + +static void update_h_load(long cpu) +{ + walk_tg_tree(tg_load_down, tg_nop, (void *)cpu); +} + +#endif + #ifdef CONFIG_PREEMPT static void double_rq_lock(struct rq *rq1, struct rq *rq2); @@ -1930,28 +1953,10 @@ void account_system_vtime(struct task_struct *curr) } EXPORT_SYMBOL_GPL(account_system_vtime); -#endif /* CONFIG_IRQ_TIME_ACCOUNTING */ - -#ifdef CONFIG_PARAVIRT -static inline u64 steal_ticks(u64 steal) -{ - if (unlikely(steal > NSEC_PER_SEC)) - return div_u64(steal, TICK_NSEC); - - return __iter_div_u64_rem(steal, TICK_NSEC, &steal); -} -#endif - static void update_rq_clock_task(struct rq *rq, s64 delta) { -/* - * In theory, the compile should just see 0 here, and optimize out the call - * to sched_rt_avg_update. But I don't trust it... - */ -#if defined(CONFIG_IRQ_TIME_ACCOUNTING) || defined(CONFIG_PARAVIRT_TIME_ACCOUNTING) - s64 steal = 0, irq_delta = 0; -#endif -#ifdef CONFIG_IRQ_TIME_ACCOUNTING + s64 irq_delta; + irq_delta = irq_time_read(cpu_of(rq)) - rq->prev_irq_time; /* @@ -1974,35 +1979,12 @@ static void update_rq_clock_task(struct rq *rq, s64 delta) rq->prev_irq_time += irq_delta; delta -= irq_delta; -#endif -#ifdef CONFIG_PARAVIRT_TIME_ACCOUNTING - if (static_branch((¶virt_steal_rq_enabled))) { - u64 st; - - steal = paravirt_steal_clock(cpu_of(rq)); - steal -= rq->prev_steal_time_rq; - - if (unlikely(steal > delta)) - steal = delta; - - st = steal_ticks(steal); - steal = st * TICK_NSEC; - - rq->prev_steal_time_rq += steal; - - delta -= steal; - } -#endif - rq->clock_task += delta; -#if defined(CONFIG_IRQ_TIME_ACCOUNTING) || defined(CONFIG_PARAVIRT_TIME_ACCOUNTING) - if ((irq_delta + steal) && sched_feat(NONTASK_POWER)) - sched_rt_avg_update(rq, irq_delta + steal); -#endif + if (irq_delta && sched_feat(NONIRQ_POWER)) + sched_rt_avg_update(rq, irq_delta); } -#ifdef CONFIG_IRQ_TIME_ACCOUNTING static int irqtime_account_hi_update(void) { struct cpu_usage_stat *cpustat = &kstat_this_cpu.cpustat; @@ -2037,7 +2019,12 @@ static int irqtime_account_si_update(void) #define sched_clock_irqtime (0) -#endif +static void update_rq_clock_task(struct rq *rq, s64 delta) +{ + rq->clock_task += delta; +} + +#endif /* CONFIG_IRQ_TIME_ACCOUNTING */ #include "sched_idletask.c" #include "sched_fair.c" @@ -2233,7 +2220,7 @@ void set_task_cpu(struct task_struct *p, unsigned int new_cpu) if (task_cpu(p) != new_cpu) { p->se.nr_migrations++; - perf_sw_event(PERF_COUNT_SW_CPU_MIGRATIONS, 1, NULL, 0); + perf_sw_event(PERF_COUNT_SW_CPU_MIGRATIONS, 1, 1, NULL, 0); } __set_task_cpu(p, new_cpu); @@ -2510,7 +2497,7 @@ ttwu_do_wakeup(struct rq *rq, struct task_struct *p, int wake_flags) if (p->sched_class->task_woken) p->sched_class->task_woken(rq, p); - if (rq->idle_stamp) { + if (unlikely(rq->idle_stamp)) { u64 delta = rq->clock - rq->idle_stamp; u64 max = 2*sysctl_sched_migration_cost; @@ -2899,7 +2886,7 @@ void sched_fork(struct task_struct *p) #if defined(CONFIG_SMP) p->on_cpu = 0; #endif -#ifdef CONFIG_PREEMPT_COUNT +#ifdef CONFIG_PREEMPT /* Want to start with kernel preemption disabled. */ task_thread_info(p)->preempt_count = 1; #endif @@ -3890,25 +3877,6 @@ void account_idle_time(cputime_t cputime) cpustat->idle = cputime64_add(cpustat->idle, cputime64); } -static __always_inline bool steal_account_process_tick(void) -{ -#ifdef CONFIG_PARAVIRT - if (static_branch(¶virt_steal_enabled)) { - u64 steal, st = 0; - - steal = paravirt_steal_clock(smp_processor_id()); - steal -= this_rq()->prev_steal_time; - - st = steal_ticks(steal); - this_rq()->prev_steal_time += st * TICK_NSEC; - - account_steal_time(st); - return st; - } -#endif - return false; -} - #ifndef CONFIG_VIRT_CPU_ACCOUNTING #ifdef CONFIG_IRQ_TIME_ACCOUNTING @@ -3940,9 +3908,6 @@ static void irqtime_account_process_tick(struct task_struct *p, int user_tick, cputime64_t tmp = cputime_to_cputime64(cputime_one_jiffy); struct cpu_usage_stat *cpustat = &kstat_this_cpu.cpustat; - if (steal_account_process_tick()) - return; - if (irqtime_account_hi_update()) { cpustat->irq = cputime64_add(cpustat->irq, tmp); } else if (irqtime_account_si_update()) { @@ -3996,9 +3961,6 @@ void account_process_tick(struct task_struct *p, int user_tick) return; } - if (steal_account_process_tick()) - return; - if (user_tick) account_user_time(p, cputime_one_jiffy, one_jiffy_scaled); else if ((p != rq->idle) || (irq_count() != HARDIRQ_OFFSET)) @@ -4376,8 +4338,11 @@ EXPORT_SYMBOL(schedule); static inline bool owner_running(struct mutex *lock, struct task_struct *owner) { + bool ret = false; + + rcu_read_lock(); if (lock->owner != owner) - return false; + goto fail; /* * Ensure we emit the owner->on_cpu, dereference _after_ checking @@ -4387,7 +4352,11 @@ static inline bool owner_running(struct mutex *lock, struct task_struct *owner) */ barrier(); - return owner->on_cpu; + ret = owner->on_cpu; +fail: + rcu_read_unlock(); + + return ret; } /* @@ -4399,21 +4368,21 @@ int mutex_spin_on_owner(struct mutex *lock, struct task_struct *owner) if (!sched_feat(OWNER_SPIN)) return 0; - rcu_read_lock(); while (owner_running(lock, owner)) { if (need_resched()) - break; + return 0; arch_mutex_cpu_relax(); } - rcu_read_unlock(); /* - * We break out the loop above on need_resched() and when the - * owner changed, which is a sign for heavy contention. Return - * success only when lock->owner is NULL. + * If the owner changed to another task there is likely + * heavy contention, stop spinning. */ - return lock->owner == NULL; + if (lock->owner) + return 0; + + return 1; } #endif @@ -7929,10 +7898,17 @@ int in_sched_functions(unsigned long addr) && addr < (unsigned long)__sched_text_end); } -static void init_cfs_rq(struct cfs_rq *cfs_rq) +static void init_cfs_rq(struct cfs_rq *cfs_rq, struct rq *rq) { cfs_rq->tasks_timeline = RB_ROOT; INIT_LIST_HEAD(&cfs_rq->tasks); +#ifdef CONFIG_FAIR_GROUP_SCHED + cfs_rq->rq = rq; + /* allow initial update_cfs_load() to truncate */ +#ifdef CONFIG_SMP + cfs_rq->load_stamp = 1; +#endif +#endif cfs_rq->min_vruntime = (u64)(-(1LL << 20)); #ifndef CONFIG_64BIT cfs_rq->min_vruntime_copy = cfs_rq->min_vruntime; @@ -7952,18 +7928,27 @@ static void init_rt_rq(struct rt_rq *rt_rq, struct rq *rq) /* delimiter for bitsearch: */ __set_bit(MAX_RT_PRIO, array->bitmap); -#if defined CONFIG_SMP +#if defined CONFIG_SMP || defined CONFIG_RT_GROUP_SCHED rt_rq->highest_prio.curr = MAX_RT_PRIO; +#ifdef CONFIG_SMP rt_rq->highest_prio.next = MAX_RT_PRIO; +#endif +#endif +#ifdef CONFIG_SMP rt_rq->rt_nr_migratory = 0; rt_rq->overloaded = 0; - plist_head_init(&rt_rq->pushable_tasks); + plist_head_init_raw(&rt_rq->pushable_tasks, &rq->lock); #endif rt_rq->rt_time = 0; rt_rq->rt_throttled = 0; rt_rq->rt_runtime = 0; raw_spin_lock_init(&rt_rq->rt_runtime_lock); + +#ifdef CONFIG_RT_GROUP_SCHED + rt_rq->rt_nr_boosted = 0; + rt_rq->rq = rq; +#endif } #ifdef CONFIG_FAIR_GROUP_SCHED @@ -7972,17 +7957,11 @@ static void init_tg_cfs_entry(struct task_group *tg, struct cfs_rq *cfs_rq, struct sched_entity *parent) { struct rq *rq = cpu_rq(cpu); - + tg->cfs_rq[cpu] = cfs_rq; + init_cfs_rq(cfs_rq, rq); cfs_rq->tg = tg; - cfs_rq->rq = rq; -#ifdef CONFIG_SMP - /* allow initial update_cfs_load() to truncate */ - cfs_rq->load_stamp = 1; -#endif - tg->cfs_rq[cpu] = cfs_rq; tg->se[cpu] = se; - /* se could be NULL for root_task_group */ if (!se) return; @@ -8005,14 +7984,12 @@ static void init_tg_rt_entry(struct task_group *tg, struct rt_rq *rt_rq, { struct rq *rq = cpu_rq(cpu); - rt_rq->highest_prio.curr = MAX_RT_PRIO; - rt_rq->rt_nr_boosted = 0; - rt_rq->rq = rq; + tg->rt_rq[cpu] = rt_rq; + init_rt_rq(rt_rq, rq); rt_rq->tg = tg; + rt_rq->rt_runtime = tg->rt_bandwidth.rt_runtime; - tg->rt_rq[cpu] = rt_rq; tg->rt_se[cpu] = rt_se; - if (!rt_se) return; @@ -8094,7 +8071,7 @@ void __init sched_init(void) rq->nr_running = 0; rq->calc_load_active = 0; rq->calc_load_update = jiffies + LOAD_FREQ; - init_cfs_rq(&rq->cfs); + init_cfs_rq(&rq->cfs, rq); init_rt_rq(&rq->rt, rq); #ifdef CONFIG_FAIR_GROUP_SCHED root_task_group.shares = root_task_group_load; @@ -8165,7 +8142,7 @@ void __init sched_init(void) #endif #ifdef CONFIG_RT_MUTEXES - plist_head_init(&init_task.pi_waiters); + plist_head_init_raw(&init_task.pi_waiters, &init_task.pi_lock); #endif /* @@ -8208,7 +8185,7 @@ void __init sched_init(void) scheduler_running = 1; } -#ifdef CONFIG_DEBUG_ATOMIC_SLEEP +#ifdef CONFIG_DEBUG_SPINLOCK_SLEEP static inline int preempt_count_equals(int preempt_offset) { int nested = (preempt_count() & ~PREEMPT_ACTIVE) + rcu_preempt_depth(); @@ -8218,6 +8195,7 @@ static inline int preempt_count_equals(int preempt_offset) void __might_sleep(const char *file, int line, int preempt_offset) { +#ifdef in_atomic static unsigned long prev_jiffy; /* ratelimiting */ if ((preempt_count_equals(preempt_offset) && !irqs_disabled()) || @@ -8239,6 +8217,7 @@ void __might_sleep(const char *file, int line, int preempt_offset) if (irqs_disabled()) print_irqtrace_events(current); dump_stack(); +#endif } EXPORT_SYMBOL(__might_sleep); #endif @@ -8397,7 +8376,6 @@ int alloc_fair_sched_group(struct task_group *tg, struct task_group *parent) if (!se) goto err_free_rq; - init_cfs_rq(cfs_rq); init_tg_cfs_entry(tg, cfs_rq, se, i, parent->se[i]); } @@ -8425,7 +8403,7 @@ static inline void unregister_fair_sched_group(struct task_group *tg, int cpu) list_del_leaf_cfs_rq(tg->cfs_rq[cpu]); raw_spin_unlock_irqrestore(&rq->lock, flags); } -#else /* !CONFIG_FAIR_GROUP_SCHED */ +#else /* !CONFG_FAIR_GROUP_SCHED */ static inline void free_fair_sched_group(struct task_group *tg) { } @@ -8446,8 +8424,7 @@ static void free_rt_sched_group(struct task_group *tg) { int i; - if (tg->rt_se) - destroy_rt_bandwidth(&tg->rt_bandwidth); + destroy_rt_bandwidth(&tg->rt_bandwidth); for_each_possible_cpu(i) { if (tg->rt_rq) @@ -8488,8 +8465,6 @@ int alloc_rt_sched_group(struct task_group *tg, struct task_group *parent) if (!rt_se) goto err_free_rq; - init_rt_rq(rt_rq, cpu_rq(i)); - rt_rq->rt_runtime = tg->rt_bandwidth.rt_runtime; init_tg_rt_entry(tg, rt_rq, rt_se, i, parent->rt_se[i]); } diff --git a/trunk/kernel/sched_autogroup.h b/trunk/kernel/sched_autogroup.h index c2f0e7248dca..05577055cfca 100644 --- a/trunk/kernel/sched_autogroup.h +++ b/trunk/kernel/sched_autogroup.h @@ -13,7 +13,6 @@ struct autogroup { int nice; }; -static inline bool task_group_is_autogroup(struct task_group *tg); static inline struct task_group * autogroup_task_group(struct task_struct *p, struct task_group *tg); diff --git a/trunk/kernel/sched_fair.c b/trunk/kernel/sched_fair.c index bc8ee9993814..c768588e180b 100644 --- a/trunk/kernel/sched_fair.c +++ b/trunk/kernel/sched_fair.c @@ -135,6 +135,14 @@ static inline struct cfs_rq *group_cfs_rq(struct sched_entity *grp) return grp->my_q; } +/* Given a group's cfs_rq on one cpu, return its corresponding cfs_rq on + * another cpu ('this_cpu') + */ +static inline struct cfs_rq *cpu_cfs_rq(struct cfs_rq *cfs_rq, int this_cpu) +{ + return cfs_rq->tg->cfs_rq[this_cpu]; +} + static inline void list_add_leaf_cfs_rq(struct cfs_rq *cfs_rq) { if (!cfs_rq->on_list) { @@ -263,6 +271,11 @@ static inline struct cfs_rq *group_cfs_rq(struct sched_entity *grp) return NULL; } +static inline struct cfs_rq *cpu_cfs_rq(struct cfs_rq *cfs_rq, int this_cpu) +{ + return &cpu_rq(this_cpu)->cfs; +} + static inline void list_add_leaf_cfs_rq(struct cfs_rq *cfs_rq) { } @@ -321,6 +334,11 @@ static inline int entity_before(struct sched_entity *a, return (s64)(a->vruntime - b->vruntime) < 0; } +static inline s64 entity_key(struct cfs_rq *cfs_rq, struct sched_entity *se) +{ + return se->vruntime - cfs_rq->min_vruntime; +} + static void update_min_vruntime(struct cfs_rq *cfs_rq) { u64 vruntime = cfs_rq->min_vruntime; @@ -354,6 +372,7 @@ static void __enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se) struct rb_node **link = &cfs_rq->tasks_timeline.rb_node; struct rb_node *parent = NULL; struct sched_entity *entry; + s64 key = entity_key(cfs_rq, se); int leftmost = 1; /* @@ -366,7 +385,7 @@ static void __enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se) * We dont care about collisions. Nodes with * the same key stay together. */ - if (entity_before(se, entry)) { + if (key < entity_key(cfs_rq, entry)) { link = &parent->rb_left; } else { link = &parent->rb_right; @@ -1317,7 +1336,7 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags) } for_each_sched_entity(se) { - cfs_rq = cfs_rq_of(se); + struct cfs_rq *cfs_rq = cfs_rq_of(se); update_cfs_load(cfs_rq, 0); update_cfs_shares(cfs_rq); @@ -1351,16 +1370,13 @@ static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags) */ if (task_sleep && parent_entity(se)) set_next_buddy(parent_entity(se)); - - /* avoid re-evaluating load for this entity */ - se = parent_entity(se); break; } flags |= DEQUEUE_SLEEP; } for_each_sched_entity(se) { - cfs_rq = cfs_rq_of(se); + struct cfs_rq *cfs_rq = cfs_rq_of(se); update_cfs_load(cfs_rq, 0); update_cfs_shares(cfs_rq); @@ -1465,6 +1481,7 @@ static int wake_affine(struct sched_domain *sd, struct task_struct *p, int sync) * effect of the currently running task from the load * of the current CPU: */ + rcu_read_lock(); if (sync) { tg = task_group(current); weight = current->se.load.weight; @@ -1500,6 +1517,7 @@ static int wake_affine(struct sched_domain *sd, struct task_struct *p, int sync) balanced = this_eff_load <= prev_eff_load; } else balanced = true; + rcu_read_unlock(); /* * If the currently running task will sleep within @@ -1903,8 +1921,8 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_ if (!sched_feat(WAKEUP_PREEMPT)) return; + update_curr(cfs_rq); find_matching_se(&se, &pse); - update_curr(cfs_rq_of(se)); BUG_ON(!pse); if (wakeup_preempt_entity(se, pse) == 1) { /* @@ -2213,43 +2231,11 @@ static void update_shares(int cpu) struct rq *rq = cpu_rq(cpu); rcu_read_lock(); - /* - * Iterates the task_group tree in a bottom up fashion, see - * list_add_leaf_cfs_rq() for details. - */ for_each_leaf_cfs_rq(rq, cfs_rq) update_shares_cpu(cfs_rq->tg, cpu); rcu_read_unlock(); } -/* - * Compute the cpu's hierarchical load factor for each task group. - * This needs to be done in a top-down fashion because the load of a child - * group is a fraction of its parents load. - */ -static int tg_load_down(struct task_group *tg, void *data) -{ - unsigned long load; - long cpu = (long)data; - - if (!tg->parent) { - load = cpu_rq(cpu)->load.weight; - } else { - load = tg->parent->cfs_rq[cpu]->h_load; - load *= tg->se[cpu]->load.weight; - load /= tg->parent->cfs_rq[cpu]->load.weight + 1; - } - - tg->cfs_rq[cpu]->h_load = load; - - return 0; -} - -static void update_h_load(long cpu) -{ - walk_tg_tree(tg_load_down, tg_nop, (void *)cpu); -} - static unsigned long load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest, unsigned long max_load_move, @@ -2257,12 +2243,14 @@ load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest, int *all_pinned) { long rem_load_move = max_load_move; - struct cfs_rq *busiest_cfs_rq; + int busiest_cpu = cpu_of(busiest); + struct task_group *tg; rcu_read_lock(); - update_h_load(cpu_of(busiest)); + update_h_load(busiest_cpu); - for_each_leaf_cfs_rq(busiest, busiest_cfs_rq) { + list_for_each_entry_rcu(tg, &task_groups, list) { + struct cfs_rq *busiest_cfs_rq = tg->cfs_rq[busiest_cpu]; unsigned long busiest_h_load = busiest_cfs_rq->h_load; unsigned long busiest_weight = busiest_cfs_rq->load.weight; u64 rem_load, moved_load; diff --git a/trunk/kernel/sched_features.h b/trunk/kernel/sched_features.h index 2e74677cb040..1e7066d76c26 100644 --- a/trunk/kernel/sched_features.h +++ b/trunk/kernel/sched_features.h @@ -61,9 +61,9 @@ SCHED_FEAT(LB_BIAS, 1) SCHED_FEAT(OWNER_SPIN, 1) /* - * Decrement CPU power based on time not spent running tasks + * Decrement CPU power based on irq activity */ -SCHED_FEAT(NONTASK_POWER, 1) +SCHED_FEAT(NONIRQ_POWER, 1) /* * Queue remote wakeups on the target CPU and process them diff --git a/trunk/kernel/sched_rt.c b/trunk/kernel/sched_rt.c index 97540f0c9e47..10d018212bab 100644 --- a/trunk/kernel/sched_rt.c +++ b/trunk/kernel/sched_rt.c @@ -185,23 +185,11 @@ static inline u64 sched_rt_period(struct rt_rq *rt_rq) typedef struct task_group *rt_rq_iter_t; -static inline struct task_group *next_task_group(struct task_group *tg) -{ - do { - tg = list_entry_rcu(tg->list.next, - typeof(struct task_group), list); - } while (&tg->list != &task_groups && task_group_is_autogroup(tg)); - - if (&tg->list == &task_groups) - tg = NULL; - - return tg; -} - -#define for_each_rt_rq(rt_rq, iter, rq) \ - for (iter = container_of(&task_groups, typeof(*iter), list); \ - (iter = next_task_group(iter)) && \ - (rt_rq = iter->rt_rq[cpu_of(rq)]);) +#define for_each_rt_rq(rt_rq, iter, rq) \ + for (iter = list_entry_rcu(task_groups.next, typeof(*iter), list); \ + (&iter->list != &task_groups) && \ + (rt_rq = iter->rt_rq[cpu_of(rq)]); \ + iter = list_entry_rcu(iter->list.next, typeof(*iter), list)) static inline void list_add_leaf_rt_rq(struct rt_rq *rt_rq) { @@ -1138,7 +1126,7 @@ static struct task_struct *_pick_next_task_rt(struct rq *rq) rt_rq = &rq->rt; - if (!rt_rq->rt_nr_running) + if (unlikely(!rt_rq->rt_nr_running)) return NULL; if (rt_rq_throttled(rt_rq)) @@ -1560,7 +1548,7 @@ static int pull_rt_task(struct rq *this_rq) static void pre_schedule_rt(struct rq *rq, struct task_struct *prev) { /* Try to pull RT tasks here if we lower this rq's prio */ - if (rq->rt.highest_prio.curr > prev->prio) + if (unlikely(rt_task(prev)) && rq->rt.highest_prio.curr > prev->prio) pull_rt_task(rq); } diff --git a/trunk/kernel/stacktrace.c b/trunk/kernel/stacktrace.c index d20c6983aad9..eb212f8f8bc8 100644 --- a/trunk/kernel/stacktrace.c +++ b/trunk/kernel/stacktrace.c @@ -26,18 +26,12 @@ void print_stack_trace(struct stack_trace *trace, int spaces) EXPORT_SYMBOL_GPL(print_stack_trace); /* - * Architectures that do not implement save_stack_trace_tsk or - * save_stack_trace_regs get this weak alias and a once-per-bootup warning - * (whenever this facility is utilized - for example by procfs): + * Architectures that do not implement save_stack_trace_tsk get this + * weak alias and a once-per-bootup warning (whenever this facility + * is utilized - for example by procfs): */ __weak void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) { WARN_ONCE(1, KERN_INFO "save_stack_trace_tsk() not implemented yet.\n"); } - -__weak void -save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace) -{ - WARN_ONCE(1, KERN_INFO "save_stack_trace_regs() not implemented yet.\n"); -} diff --git a/trunk/kernel/stop_machine.c b/trunk/kernel/stop_machine.c index c1124752e1d3..e3516b29076c 100644 --- a/trunk/kernel/stop_machine.c +++ b/trunk/kernel/stop_machine.c @@ -136,11 +136,10 @@ void stop_one_cpu_nowait(unsigned int cpu, cpu_stop_fn_t fn, void *arg, static DEFINE_MUTEX(stop_cpus_mutex); static DEFINE_PER_CPU(struct cpu_stop_work, stop_cpus_work); -static void queue_stop_cpus_work(const struct cpumask *cpumask, - cpu_stop_fn_t fn, void *arg, - struct cpu_stop_done *done) +int __stop_cpus(const struct cpumask *cpumask, cpu_stop_fn_t fn, void *arg) { struct cpu_stop_work *work; + struct cpu_stop_done done; unsigned int cpu; /* initialize works and done */ @@ -148,8 +147,9 @@ static void queue_stop_cpus_work(const struct cpumask *cpumask, work = &per_cpu(stop_cpus_work, cpu); work->fn = fn; work->arg = arg; - work->done = done; + work->done = &done; } + cpu_stop_init_done(&done, cpumask_weight(cpumask)); /* * Disable preemption while queueing to avoid getting @@ -161,15 +161,7 @@ static void queue_stop_cpus_work(const struct cpumask *cpumask, cpu_stop_queue_work(&per_cpu(cpu_stopper, cpu), &per_cpu(stop_cpus_work, cpu)); preempt_enable(); -} -static int __stop_cpus(const struct cpumask *cpumask, - cpu_stop_fn_t fn, void *arg) -{ - struct cpu_stop_done done; - - cpu_stop_init_done(&done, cpumask_weight(cpumask)); - queue_stop_cpus_work(cpumask, fn, arg, &done); wait_for_completion(&done.completion); return done.executed ? done.ret : -ENOENT; } @@ -439,15 +431,8 @@ static int stop_machine_cpu_stop(void *data) struct stop_machine_data *smdata = data; enum stopmachine_state curstate = STOPMACHINE_NONE; int cpu = smp_processor_id(), err = 0; - unsigned long flags; bool is_active; - /* - * When called from stop_machine_from_inactive_cpu(), irq might - * already be disabled. Save the state and restore it on exit. - */ - local_save_flags(flags); - if (!smdata->active_cpus) is_active = cpu == cpumask_first(cpu_online_mask); else @@ -475,7 +460,7 @@ static int stop_machine_cpu_stop(void *data) } } while (curstate != STOPMACHINE_EXIT); - local_irq_restore(flags); + local_irq_enable(); return err; } @@ -502,57 +487,4 @@ int stop_machine(int (*fn)(void *), void *data, const struct cpumask *cpus) } EXPORT_SYMBOL_GPL(stop_machine); -/** - * stop_machine_from_inactive_cpu - stop_machine() from inactive CPU - * @fn: the function to run - * @data: the data ptr for the @fn() - * @cpus: the cpus to run the @fn() on (NULL = any online cpu) - * - * This is identical to stop_machine() but can be called from a CPU which - * is not active. The local CPU is in the process of hotplug (so no other - * CPU hotplug can start) and not marked active and doesn't have enough - * context to sleep. - * - * This function provides stop_machine() functionality for such state by - * using busy-wait for synchronization and executing @fn directly for local - * CPU. - * - * CONTEXT: - * Local CPU is inactive. Temporarily stops all active CPUs. - * - * RETURNS: - * 0 if all executions of @fn returned 0, any non zero return value if any - * returned non zero. - */ -int stop_machine_from_inactive_cpu(int (*fn)(void *), void *data, - const struct cpumask *cpus) -{ - struct stop_machine_data smdata = { .fn = fn, .data = data, - .active_cpus = cpus }; - struct cpu_stop_done done; - int ret; - - /* Local CPU must be inactive and CPU hotplug in progress. */ - BUG_ON(cpu_active(raw_smp_processor_id())); - smdata.num_threads = num_active_cpus() + 1; /* +1 for local */ - - /* No proper task established and can't sleep - busy wait for lock. */ - while (!mutex_trylock(&stop_cpus_mutex)) - cpu_relax(); - - /* Schedule work on other CPUs and execute directly for local CPU */ - set_state(&smdata, STOPMACHINE_PREPARE); - cpu_stop_init_done(&done, num_active_cpus()); - queue_stop_cpus_work(cpu_active_mask, stop_machine_cpu_stop, &smdata, - &done); - ret = stop_machine_cpu_stop(&smdata); - - /* Busy wait for completion. */ - while (!completion_done(&done.completion)) - cpu_relax(); - - mutex_unlock(&stop_cpus_mutex); - return ret ?: done.ret; -} - #endif /* CONFIG_STOP_MACHINE */ diff --git a/trunk/kernel/sysctl.c b/trunk/kernel/sysctl.c index 11d65b531e50..f175d98bd355 100644 --- a/trunk/kernel/sysctl.c +++ b/trunk/kernel/sysctl.c @@ -1590,11 +1590,16 @@ void sysctl_head_get(struct ctl_table_header *head) spin_unlock(&sysctl_lock); } +static void free_head(struct rcu_head *rcu) +{ + kfree(container_of(rcu, struct ctl_table_header, rcu)); +} + void sysctl_head_put(struct ctl_table_header *head) { spin_lock(&sysctl_lock); if (!--head->count) - kfree_rcu(head, rcu); + call_rcu(&head->rcu, free_head); spin_unlock(&sysctl_lock); } @@ -1966,10 +1971,10 @@ void unregister_sysctl_table(struct ctl_table_header * header) start_unregistering(header); if (!--header->parent->count) { WARN_ON(1); - kfree_rcu(header->parent, rcu); + call_rcu(&header->parent->rcu, free_head); } if (!--header->count) - kfree_rcu(header, rcu); + call_rcu(&header->rcu, free_head); spin_unlock(&sysctl_lock); } diff --git a/trunk/kernel/time/timekeeping.c b/trunk/kernel/time/timekeeping.c index 2b021b0e8507..342408cf68dd 100644 --- a/trunk/kernel/time/timekeeping.c +++ b/trunk/kernel/time/timekeeping.c @@ -604,12 +604,6 @@ static struct timespec timekeeping_suspend_time; */ static void __timekeeping_inject_sleeptime(struct timespec *delta) { - if (!timespec_valid(delta)) { - printk(KERN_WARNING "__timekeeping_inject_sleeptime: Invalid " - "sleep delta value!\n"); - return; - } - xtime = timespec_add(xtime, *delta); wall_to_monotonic = timespec_sub(wall_to_monotonic, *delta); total_sleep_time = timespec_add(total_sleep_time, *delta); @@ -692,34 +686,12 @@ static void timekeeping_resume(void) static int timekeeping_suspend(void) { unsigned long flags; - struct timespec delta, delta_delta; - static struct timespec old_delta; read_persistent_clock(&timekeeping_suspend_time); write_seqlock_irqsave(&xtime_lock, flags); timekeeping_forward_now(); timekeeping_suspended = 1; - - /* - * To avoid drift caused by repeated suspend/resumes, - * which each can add ~1 second drift error, - * try to compensate so the difference in system time - * and persistent_clock time stays close to constant. - */ - delta = timespec_sub(xtime, timekeeping_suspend_time); - delta_delta = timespec_sub(delta, old_delta); - if (abs(delta_delta.tv_sec) >= 2) { - /* - * if delta_delta is too large, assume time correction - * has occured and set old_delta to the current delta. - */ - old_delta = delta; - } else { - /* Otherwise try to adjust old_system to compensate */ - timekeeping_suspend_time = - timespec_add(timekeeping_suspend_time, delta_delta); - } write_sequnlock_irqrestore(&xtime_lock, flags); clockevents_notify(CLOCK_EVT_NOTIFY_SUSPEND, NULL); diff --git a/trunk/kernel/trace/ftrace.c b/trunk/kernel/trace/ftrace.c index c3e4575e7829..908038f57440 100644 --- a/trunk/kernel/trace/ftrace.c +++ b/trunk/kernel/trace/ftrace.c @@ -32,6 +32,7 @@ #include +#include #include #include "trace_output.h" @@ -81,14 +82,14 @@ static int ftrace_disabled __read_mostly; static DEFINE_MUTEX(ftrace_lock); -static struct ftrace_ops ftrace_list_end __read_mostly = { +static struct ftrace_ops ftrace_list_end __read_mostly = +{ .func = ftrace_stub, }; static struct ftrace_ops *ftrace_global_list __read_mostly = &ftrace_list_end; static struct ftrace_ops *ftrace_ops_list __read_mostly = &ftrace_list_end; ftrace_func_t ftrace_trace_function __read_mostly = ftrace_stub; -static ftrace_func_t __ftrace_trace_function_delay __read_mostly = ftrace_stub; ftrace_func_t __ftrace_trace_function __read_mostly = ftrace_stub; ftrace_func_t ftrace_pid_function __read_mostly = ftrace_stub; static struct ftrace_ops global_ops; @@ -147,11 +148,9 @@ void clear_ftrace_function(void) { ftrace_trace_function = ftrace_stub; __ftrace_trace_function = ftrace_stub; - __ftrace_trace_function_delay = ftrace_stub; ftrace_pid_function = ftrace_stub; } -#undef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST #ifndef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST /* * For those archs that do not test ftrace_trace_stop in their @@ -210,13 +209,8 @@ static void update_ftrace_function(void) #ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST ftrace_trace_function = func; -#else -#ifdef CONFIG_DYNAMIC_FTRACE - /* do not update till all functions have been modified */ - __ftrace_trace_function_delay = func; #else __ftrace_trace_function = func; -#endif ftrace_trace_function = ftrace_test_stop_func; #endif } @@ -791,7 +785,8 @@ static void unregister_ftrace_profiler(void) unregister_ftrace_graph(); } #else -static struct ftrace_ops ftrace_profile_ops __read_mostly = { +static struct ftrace_ops ftrace_profile_ops __read_mostly = +{ .func = function_profile_call, }; @@ -811,10 +806,19 @@ ftrace_profile_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) { unsigned long val; + char buf[64]; /* big enough to hold a number */ int ret; - ret = kstrtoul_from_user(ubuf, cnt, 10, &val); - if (ret) + if (cnt >= sizeof(buf)) + return -EINVAL; + + if (copy_from_user(&buf, ubuf, cnt)) + return -EFAULT; + + buf[cnt] = 0; + + ret = strict_strtoul(buf, 10, &val); + if (ret < 0) return ret; val = !!val; @@ -1178,14 +1182,8 @@ alloc_and_copy_ftrace_hash(int size_bits, struct ftrace_hash *hash) return NULL; } -static void -ftrace_hash_rec_disable(struct ftrace_ops *ops, int filter_hash); -static void -ftrace_hash_rec_enable(struct ftrace_ops *ops, int filter_hash); - static int -ftrace_hash_move(struct ftrace_ops *ops, int enable, - struct ftrace_hash **dst, struct ftrace_hash *src) +ftrace_hash_move(struct ftrace_hash **dst, struct ftrace_hash *src) { struct ftrace_func_entry *entry; struct hlist_node *tp, *tn; @@ -1195,15 +1193,8 @@ ftrace_hash_move(struct ftrace_ops *ops, int enable, unsigned long key; int size = src->count; int bits = 0; - int ret; int i; - /* - * Remove the current set, update the hash and add - * them back. - */ - ftrace_hash_rec_disable(ops, enable); - /* * If the new source is empty, just free dst and assign it * the empty_hash. @@ -1224,10 +1215,9 @@ ftrace_hash_move(struct ftrace_ops *ops, int enable, if (bits > FTRACE_HASH_MAX_BITS) bits = FTRACE_HASH_MAX_BITS; - ret = -ENOMEM; new_hash = alloc_ftrace_hash(bits); if (!new_hash) - goto out; + return -ENOMEM; size = 1 << src->size_bits; for (i = 0; i < size; i++) { @@ -1246,16 +1236,7 @@ ftrace_hash_move(struct ftrace_ops *ops, int enable, rcu_assign_pointer(*dst, new_hash); free_ftrace_hash_rcu(old_hash); - ret = 0; - out: - /* - * Enable regardless of ret: - * On success, we enable the new hash. - * On failure, we re-enable the original hash. - */ - ftrace_hash_rec_enable(ops, enable); - - return ret; + return 0; } /* @@ -1615,12 +1596,6 @@ static int __ftrace_modify_code(void *data) { int *command = data; - /* - * Do not call function tracer while we update the code. - * We are in stop machine, no worrying about races. - */ - function_trace_stop++; - if (*command & FTRACE_ENABLE_CALLS) ftrace_replace_code(1); else if (*command & FTRACE_DISABLE_CALLS) @@ -1634,18 +1609,6 @@ static int __ftrace_modify_code(void *data) else if (*command & FTRACE_STOP_FUNC_RET) ftrace_disable_ftrace_graph_caller(); -#ifndef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST - /* - * For archs that call ftrace_test_stop_func(), we must - * wait till after we update all the function callers - * before we update the callback. This keeps different - * ops that record different functions from corrupting - * each other. - */ - __ftrace_trace_function = __ftrace_trace_function_delay; -#endif - function_trace_stop--; - return 0; } @@ -1781,36 +1744,10 @@ static cycle_t ftrace_update_time; static unsigned long ftrace_update_cnt; unsigned long ftrace_update_tot_cnt; -static int ops_traces_mod(struct ftrace_ops *ops) -{ - struct ftrace_hash *hash; - - hash = ops->filter_hash; - return !!(!hash || !hash->count); -} - static int ftrace_update_code(struct module *mod) { struct dyn_ftrace *p; cycle_t start, stop; - unsigned long ref = 0; - - /* - * When adding a module, we need to check if tracers are - * currently enabled and if they are set to trace all functions. - * If they are, we need to enable the module functions as well - * as update the reference counts for those function records. - */ - if (mod) { - struct ftrace_ops *ops; - - for (ops = ftrace_ops_list; - ops != &ftrace_list_end; ops = ops->next) { - if (ops->flags & FTRACE_OPS_FL_ENABLED && - ops_traces_mod(ops)) - ref++; - } - } start = ftrace_now(raw_smp_processor_id()); ftrace_update_cnt = 0; @@ -1823,7 +1760,7 @@ static int ftrace_update_code(struct module *mod) p = ftrace_new_addrs; ftrace_new_addrs = p->newlist; - p->flags = ref; + p->flags = 0L; /* * Do the initial record conversion from mcount jump @@ -1846,7 +1783,7 @@ static int ftrace_update_code(struct module *mod) * conversion puts the module to the correct state, thus * passing the ftrace_make_call check. */ - if (ftrace_start_up && ref) { + if (ftrace_start_up) { int failed = __ftrace_replace_code(p, 1); if (failed) { ftrace_bug(failed, p->ip); @@ -2470,9 +2407,10 @@ ftrace_match_module_records(struct ftrace_hash *hash, char *buff, char *mod) */ static int -ftrace_mod_callback(struct ftrace_hash *hash, - char *func, char *cmd, char *param, int enable) +ftrace_mod_callback(char *func, char *cmd, char *param, int enable) { + struct ftrace_ops *ops = &global_ops; + struct ftrace_hash *hash; char *mod; int ret = -EINVAL; @@ -2492,6 +2430,11 @@ ftrace_mod_callback(struct ftrace_hash *hash, if (!strlen(mod)) return ret; + if (enable) + hash = ops->filter_hash; + else + hash = ops->notrace_hash; + ret = ftrace_match_module_records(hash, func, mod); if (!ret) ret = -EINVAL; @@ -2817,7 +2760,7 @@ static int ftrace_process_regex(struct ftrace_hash *hash, mutex_lock(&ftrace_cmd_mutex); list_for_each_entry(p, &ftrace_commands, list) { if (strcmp(p->name, command) == 0) { - ret = p->func(hash, func, command, next, enable); + ret = p->func(func, command, next, enable); goto out_unlock; } } @@ -2914,11 +2857,7 @@ ftrace_set_regex(struct ftrace_ops *ops, unsigned char *buf, int len, ftrace_match_records(hash, buf, len); mutex_lock(&ftrace_lock); - ret = ftrace_hash_move(ops, enable, orig_hash, hash); - if (!ret && ops->flags & FTRACE_OPS_FL_ENABLED - && ftrace_enabled) - ftrace_run_update_code(FTRACE_ENABLE_CALLS); - + ret = ftrace_hash_move(orig_hash, hash); mutex_unlock(&ftrace_lock); mutex_unlock(&ftrace_regex_lock); @@ -3101,12 +3040,18 @@ ftrace_regex_release(struct inode *inode, struct file *file) orig_hash = &iter->ops->notrace_hash; mutex_lock(&ftrace_lock); - ret = ftrace_hash_move(iter->ops, filter_hash, - orig_hash, iter->hash); - if (!ret && (iter->ops->flags & FTRACE_OPS_FL_ENABLED) - && ftrace_enabled) - ftrace_run_update_code(FTRACE_ENABLE_CALLS); - + /* + * Remove the current set, update the hash and add + * them back. + */ + ftrace_hash_rec_disable(iter->ops, filter_hash); + ret = ftrace_hash_move(orig_hash, iter->hash); + if (!ret) { + ftrace_hash_rec_enable(iter->ops, filter_hash); + if (iter->ops->flags & FTRACE_OPS_FL_ENABLED + && ftrace_enabled) + ftrace_run_update_code(FTRACE_ENABLE_CALLS); + } mutex_unlock(&ftrace_lock); } free_ftrace_hash(iter->hash); @@ -3385,7 +3330,7 @@ static int ftrace_process_locs(struct module *mod, { unsigned long *p; unsigned long addr; - unsigned long flags = 0; /* Shut up gcc */ + unsigned long flags; mutex_lock(&ftrace_lock); p = start; @@ -3403,18 +3348,12 @@ static int ftrace_process_locs(struct module *mod, } /* - * We only need to disable interrupts on start up - * because we are modifying code that an interrupt - * may execute, and the modification is not atomic. - * But for modules, nothing runs the code we modify - * until we are finished with it, and there's no - * reason to cause large interrupt latencies while we do it. + * Disable interrupts to prevent interrupts from executing + * code that is being modified. */ - if (!mod) - local_irq_save(flags); + local_irq_save(flags); ftrace_update_code(mod); - if (!mod) - local_irq_restore(flags); + local_irq_restore(flags); mutex_unlock(&ftrace_lock); return 0; diff --git a/trunk/kernel/trace/ring_buffer.c b/trunk/kernel/trace/ring_buffer.c index 731201bf4acc..b0c7aa407943 100644 --- a/trunk/kernel/trace/ring_buffer.c +++ b/trunk/kernel/trace/ring_buffer.c @@ -997,21 +997,15 @@ static int rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer, unsigned nr_pages) { struct buffer_page *bpage, *tmp; + unsigned long addr; LIST_HEAD(pages); unsigned i; WARN_ON(!nr_pages); for (i = 0; i < nr_pages; i++) { - struct page *page; - /* - * __GFP_NORETRY flag makes sure that the allocation fails - * gracefully without invoking oom-killer and the system is - * not destabilized. - */ bpage = kzalloc_node(ALIGN(sizeof(*bpage), cache_line_size()), - GFP_KERNEL | __GFP_NORETRY, - cpu_to_node(cpu_buffer->cpu)); + GFP_KERNEL, cpu_to_node(cpu_buffer->cpu)); if (!bpage) goto free_pages; @@ -1019,11 +1013,10 @@ static int rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer, list_add(&bpage->list, &pages); - page = alloc_pages_node(cpu_to_node(cpu_buffer->cpu), - GFP_KERNEL | __GFP_NORETRY, 0); - if (!page) + addr = __get_free_page(GFP_KERNEL); + if (!addr) goto free_pages; - bpage->page = page_address(page); + bpage->page = (void *)addr; rb_init_page(bpage->page); } @@ -1052,7 +1045,7 @@ rb_allocate_cpu_buffer(struct ring_buffer *buffer, int cpu) { struct ring_buffer_per_cpu *cpu_buffer; struct buffer_page *bpage; - struct page *page; + unsigned long addr; int ret; cpu_buffer = kzalloc_node(ALIGN(sizeof(*cpu_buffer), cache_line_size()), @@ -1074,10 +1067,10 @@ rb_allocate_cpu_buffer(struct ring_buffer *buffer, int cpu) rb_check_bpage(cpu_buffer, bpage); cpu_buffer->reader_page = bpage; - page = alloc_pages_node(cpu_to_node(cpu), GFP_KERNEL, 0); - if (!page) + addr = __get_free_page(GFP_KERNEL); + if (!addr) goto fail_free_reader; - bpage->page = page_address(page); + bpage->page = (void *)addr; rb_init_page(bpage->page); INIT_LIST_HEAD(&cpu_buffer->reader_page->list); @@ -1321,6 +1314,7 @@ int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size) unsigned nr_pages, rm_pages, new_pages; struct buffer_page *bpage, *tmp; unsigned long buffer_size; + unsigned long addr; LIST_HEAD(pages); int i, cpu; @@ -1381,24 +1375,16 @@ int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size) for_each_buffer_cpu(buffer, cpu) { for (i = 0; i < new_pages; i++) { - struct page *page; - /* - * __GFP_NORETRY flag makes sure that the allocation - * fails gracefully without invoking oom-killer and - * the system is not destabilized. - */ bpage = kzalloc_node(ALIGN(sizeof(*bpage), cache_line_size()), - GFP_KERNEL | __GFP_NORETRY, - cpu_to_node(cpu)); + GFP_KERNEL, cpu_to_node(cpu)); if (!bpage) goto free_pages; list_add(&bpage->list, &pages); - page = alloc_pages_node(cpu_to_node(cpu), - GFP_KERNEL | __GFP_NORETRY, 0); - if (!page) + addr = __get_free_page(GFP_KERNEL); + if (!addr) goto free_pages; - bpage->page = page_address(page); + bpage->page = (void *)addr; rb_init_page(bpage->page); } } @@ -3744,17 +3730,16 @@ EXPORT_SYMBOL_GPL(ring_buffer_swap_cpu); * Returns: * The page allocated, or NULL on error. */ -void *ring_buffer_alloc_read_page(struct ring_buffer *buffer, int cpu) +void *ring_buffer_alloc_read_page(struct ring_buffer *buffer) { struct buffer_data_page *bpage; - struct page *page; + unsigned long addr; - page = alloc_pages_node(cpu_to_node(cpu), - GFP_KERNEL | __GFP_NORETRY, 0); - if (!page) + addr = __get_free_page(GFP_KERNEL); + if (!addr) return NULL; - bpage = page_address(page); + bpage = (void *)addr; rb_init_page(bpage); @@ -3993,11 +3978,20 @@ rb_simple_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) { unsigned long *p = filp->private_data; + char buf[64]; unsigned long val; int ret; - ret = kstrtoul_from_user(ubuf, cnt, 10, &val); - if (ret) + if (cnt >= sizeof(buf)) + return -EINVAL; + + if (copy_from_user(&buf, ubuf, cnt)) + return -EFAULT; + + buf[cnt] = 0; + + ret = strict_strtoul(buf, 10, &val); + if (ret < 0) return ret; if (val) diff --git a/trunk/kernel/trace/ring_buffer_benchmark.c b/trunk/kernel/trace/ring_buffer_benchmark.c index a5457d577b98..302f8a614635 100644 --- a/trunk/kernel/trace/ring_buffer_benchmark.c +++ b/trunk/kernel/trace/ring_buffer_benchmark.c @@ -106,7 +106,7 @@ static enum event_status read_page(int cpu) int inc; int i; - bpage = ring_buffer_alloc_read_page(buffer, cpu); + bpage = ring_buffer_alloc_read_page(buffer); if (!bpage) return EVENT_DROPPED; diff --git a/trunk/kernel/trace/trace.c b/trunk/kernel/trace/trace.c index e5df02c69b1d..ee9c921d7f21 100644 --- a/trunk/kernel/trace/trace.c +++ b/trunk/kernel/trace/trace.c @@ -343,27 +343,26 @@ unsigned long trace_flags = TRACE_ITER_PRINT_PARENT | TRACE_ITER_PRINTK | static int trace_stop_count; static DEFINE_SPINLOCK(tracing_start_lock); -static void wakeup_work_handler(struct work_struct *work) -{ - wake_up(&trace_wait); -} - -static DECLARE_DELAYED_WORK(wakeup_work, wakeup_work_handler); - /** * trace_wake_up - wake up tasks waiting for trace input * - * Schedules a delayed work to wake up any task that is blocked on the - * trace_wait queue. These is used with trace_poll for tasks polling the - * trace. + * Simply wakes up any task that is blocked on the trace_wait + * queue. These is used with trace_poll for tasks polling the trace. */ void trace_wake_up(void) { - const unsigned long delay = msecs_to_jiffies(2); + int cpu; if (trace_flags & TRACE_ITER_BLOCK) return; - schedule_delayed_work(&wakeup_work, delay); + /* + * The runqueue_is_locked() can fail, but this is the best we + * have for now: + */ + cpu = get_cpu(); + if (!runqueue_is_locked(cpu)) + wake_up(&trace_wait); + put_cpu(); } static int __init set_buf_size(char *str) @@ -425,7 +424,6 @@ static const char *trace_options[] = { "graph-time", "record-cmd", "overwrite", - "disable_on_free", NULL }; @@ -1193,18 +1191,6 @@ void trace_nowake_buffer_unlock_commit(struct ring_buffer *buffer, } EXPORT_SYMBOL_GPL(trace_nowake_buffer_unlock_commit); -void trace_nowake_buffer_unlock_commit_regs(struct ring_buffer *buffer, - struct ring_buffer_event *event, - unsigned long flags, int pc, - struct pt_regs *regs) -{ - ring_buffer_unlock_commit(buffer, event); - - ftrace_trace_stack_regs(buffer, flags, 0, pc, regs); - ftrace_trace_userstack(buffer, flags, pc); -} -EXPORT_SYMBOL_GPL(trace_nowake_buffer_unlock_commit_regs); - void trace_current_buffer_discard_commit(struct ring_buffer *buffer, struct ring_buffer_event *event) { @@ -1248,103 +1234,30 @@ ftrace(struct trace_array *tr, struct trace_array_cpu *data, } #ifdef CONFIG_STACKTRACE - -#define FTRACE_STACK_MAX_ENTRIES (PAGE_SIZE / sizeof(unsigned long)) -struct ftrace_stack { - unsigned long calls[FTRACE_STACK_MAX_ENTRIES]; -}; - -static DEFINE_PER_CPU(struct ftrace_stack, ftrace_stack); -static DEFINE_PER_CPU(int, ftrace_stack_reserve); - static void __ftrace_trace_stack(struct ring_buffer *buffer, unsigned long flags, - int skip, int pc, struct pt_regs *regs) + int skip, int pc) { struct ftrace_event_call *call = &event_kernel_stack; struct ring_buffer_event *event; struct stack_entry *entry; struct stack_trace trace; - int use_stack; - int size = FTRACE_STACK_ENTRIES; - - trace.nr_entries = 0; - trace.skip = skip; - - /* - * Since events can happen in NMIs there's no safe way to - * use the per cpu ftrace_stacks. We reserve it and if an interrupt - * or NMI comes in, it will just have to use the default - * FTRACE_STACK_SIZE. - */ - preempt_disable_notrace(); - - use_stack = ++__get_cpu_var(ftrace_stack_reserve); - /* - * We don't need any atomic variables, just a barrier. - * If an interrupt comes in, we don't care, because it would - * have exited and put the counter back to what we want. - * We just need a barrier to keep gcc from moving things - * around. - */ - barrier(); - if (use_stack == 1) { - trace.entries = &__get_cpu_var(ftrace_stack).calls[0]; - trace.max_entries = FTRACE_STACK_MAX_ENTRIES; - - if (regs) - save_stack_trace_regs(regs, &trace); - else - save_stack_trace(&trace); - - if (trace.nr_entries > size) - size = trace.nr_entries; - } else - /* From now on, use_stack is a boolean */ - use_stack = 0; - - size *= sizeof(unsigned long); event = trace_buffer_lock_reserve(buffer, TRACE_STACK, - sizeof(*entry) + size, flags, pc); + sizeof(*entry), flags, pc); if (!event) - goto out; - entry = ring_buffer_event_data(event); - - memset(&entry->caller, 0, size); - - if (use_stack) - memcpy(&entry->caller, trace.entries, - trace.nr_entries * sizeof(unsigned long)); - else { - trace.max_entries = FTRACE_STACK_ENTRIES; - trace.entries = entry->caller; - if (regs) - save_stack_trace_regs(regs, &trace); - else - save_stack_trace(&trace); - } + return; + entry = ring_buffer_event_data(event); + memset(&entry->caller, 0, sizeof(entry->caller)); - entry->size = trace.nr_entries; + trace.nr_entries = 0; + trace.max_entries = FTRACE_STACK_ENTRIES; + trace.skip = skip; + trace.entries = entry->caller; + save_stack_trace(&trace); if (!filter_check_discard(call, entry, buffer, event)) ring_buffer_unlock_commit(buffer, event); - - out: - /* Again, don't let gcc optimize things here */ - barrier(); - __get_cpu_var(ftrace_stack_reserve)--; - preempt_enable_notrace(); - -} - -void ftrace_trace_stack_regs(struct ring_buffer *buffer, unsigned long flags, - int skip, int pc, struct pt_regs *regs) -{ - if (!(trace_flags & TRACE_ITER_STACKTRACE)) - return; - - __ftrace_trace_stack(buffer, flags, skip, pc, regs); } void ftrace_trace_stack(struct ring_buffer *buffer, unsigned long flags, @@ -1353,13 +1266,13 @@ void ftrace_trace_stack(struct ring_buffer *buffer, unsigned long flags, if (!(trace_flags & TRACE_ITER_STACKTRACE)) return; - __ftrace_trace_stack(buffer, flags, skip, pc, NULL); + __ftrace_trace_stack(buffer, flags, skip, pc); } void __trace_stack(struct trace_array *tr, unsigned long flags, int skip, int pc) { - __ftrace_trace_stack(tr->buffer, flags, skip, pc, NULL); + __ftrace_trace_stack(tr->buffer, flags, skip, pc); } /** @@ -1375,7 +1288,7 @@ void trace_dump_stack(void) local_save_flags(flags); /* skipping 3 traces, seems to get us at the caller of this function */ - __ftrace_trace_stack(global_trace.buffer, flags, 3, preempt_count(), NULL); + __ftrace_trace_stack(global_trace.buffer, flags, 3, preempt_count()); } static DEFINE_PER_CPU(int, user_stack_count); @@ -1623,12 +1536,7 @@ peek_next_entry(struct trace_iterator *iter, int cpu, u64 *ts, ftrace_enable_cpu(); - if (event) { - iter->ent_size = ring_buffer_event_length(event); - return ring_buffer_event_data(event); - } - iter->ent_size = 0; - return NULL; + return event ? ring_buffer_event_data(event) : NULL; } static struct trace_entry * @@ -2143,9 +2051,6 @@ void trace_default_header(struct seq_file *m) { struct trace_iterator *iter = m->private; - if (!(trace_flags & TRACE_ITER_CONTEXT_INFO)) - return; - if (iter->iter_flags & TRACE_FILE_LAT_FMT) { /* print nothing if the buffers are empty */ if (trace_empty(iter)) @@ -2796,11 +2701,20 @@ tracing_ctrl_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) { struct trace_array *tr = filp->private_data; + char buf[64]; unsigned long val; int ret; - ret = kstrtoul_from_user(ubuf, cnt, 10, &val); - if (ret) + if (cnt >= sizeof(buf)) + return -EINVAL; + + if (copy_from_user(&buf, ubuf, cnt)) + return -EFAULT; + + buf[cnt] = 0; + + ret = strict_strtoul(buf, 10, &val); + if (ret < 0) return ret; val = !!val; @@ -2853,7 +2767,7 @@ int tracer_init(struct tracer *t, struct trace_array *tr) return t->init(tr); } -static int __tracing_resize_ring_buffer(unsigned long size) +static int tracing_resize_ring_buffer(unsigned long size) { int ret; @@ -2905,41 +2819,6 @@ static int __tracing_resize_ring_buffer(unsigned long size) return ret; } -static ssize_t tracing_resize_ring_buffer(unsigned long size) -{ - int cpu, ret = size; - - mutex_lock(&trace_types_lock); - - tracing_stop(); - - /* disable all cpu buffers */ - for_each_tracing_cpu(cpu) { - if (global_trace.data[cpu]) - atomic_inc(&global_trace.data[cpu]->disabled); - if (max_tr.data[cpu]) - atomic_inc(&max_tr.data[cpu]->disabled); - } - - if (size != global_trace.entries) - ret = __tracing_resize_ring_buffer(size); - - if (ret < 0) - ret = -ENOMEM; - - for_each_tracing_cpu(cpu) { - if (global_trace.data[cpu]) - atomic_dec(&global_trace.data[cpu]->disabled); - if (max_tr.data[cpu]) - atomic_dec(&max_tr.data[cpu]->disabled); - } - - tracing_start(); - mutex_unlock(&trace_types_lock); - - return ret; -} - /** * tracing_update_buffers - used by tracing facility to expand ring buffers @@ -2957,7 +2836,7 @@ int tracing_update_buffers(void) mutex_lock(&trace_types_lock); if (!ring_buffer_expanded) - ret = __tracing_resize_ring_buffer(trace_buf_size); + ret = tracing_resize_ring_buffer(trace_buf_size); mutex_unlock(&trace_types_lock); return ret; @@ -2981,7 +2860,7 @@ static int tracing_set_tracer(const char *buf) mutex_lock(&trace_types_lock); if (!ring_buffer_expanded) { - ret = __tracing_resize_ring_buffer(trace_buf_size); + ret = tracing_resize_ring_buffer(trace_buf_size); if (ret < 0) goto out; ret = 0; @@ -3087,11 +2966,20 @@ tracing_max_lat_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) { unsigned long *ptr = filp->private_data; + char buf[64]; unsigned long val; int ret; - ret = kstrtoul_from_user(ubuf, cnt, 10, &val); - if (ret) + if (cnt >= sizeof(buf)) + return -EINVAL; + + if (copy_from_user(&buf, ubuf, cnt)) + return -EFAULT; + + buf[cnt] = 0; + + ret = strict_strtoul(buf, 10, &val); + if (ret < 0) return ret; *ptr = val * 1000; @@ -3546,52 +3434,65 @@ tracing_entries_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) { unsigned long val; - int ret; + char buf[64]; + int ret, cpu; - ret = kstrtoul_from_user(ubuf, cnt, 10, &val); - if (ret) + if (cnt >= sizeof(buf)) + return -EINVAL; + + if (copy_from_user(&buf, ubuf, cnt)) + return -EFAULT; + + buf[cnt] = 0; + + ret = strict_strtoul(buf, 10, &val); + if (ret < 0) return ret; /* must have at least 1 entry */ if (!val) return -EINVAL; - /* value is in KB */ - val <<= 10; + mutex_lock(&trace_types_lock); - ret = tracing_resize_ring_buffer(val); - if (ret < 0) - return ret; + tracing_stop(); - *ppos += cnt; + /* disable all cpu buffers */ + for_each_tracing_cpu(cpu) { + if (global_trace.data[cpu]) + atomic_inc(&global_trace.data[cpu]->disabled); + if (max_tr.data[cpu]) + atomic_inc(&max_tr.data[cpu]->disabled); + } - return cnt; -} + /* value is in KB */ + val <<= 10; -static ssize_t -tracing_free_buffer_write(struct file *filp, const char __user *ubuf, - size_t cnt, loff_t *ppos) -{ - /* - * There is no need to read what the user has written, this function - * is just to make sure that there is no error when "echo" is used - */ + if (val != global_trace.entries) { + ret = tracing_resize_ring_buffer(val); + if (ret < 0) { + cnt = ret; + goto out; + } + } *ppos += cnt; - return cnt; -} + /* If check pages failed, return ENOMEM */ + if (tracing_disabled) + cnt = -ENOMEM; + out: + for_each_tracing_cpu(cpu) { + if (global_trace.data[cpu]) + atomic_dec(&global_trace.data[cpu]->disabled); + if (max_tr.data[cpu]) + atomic_dec(&max_tr.data[cpu]->disabled); + } -static int -tracing_free_buffer_release(struct inode *inode, struct file *filp) -{ - /* disable tracing ? */ - if (trace_flags & TRACE_ITER_STOP_ON_FREE) - tracing_off(); - /* resize the ring buffer to 0 */ - tracing_resize_ring_buffer(0); + tracing_start(); + mutex_unlock(&trace_types_lock); - return 0; + return cnt; } static int mark_printk(const char *fmt, ...) @@ -3739,11 +3640,6 @@ static const struct file_operations tracing_entries_fops = { .llseek = generic_file_llseek, }; -static const struct file_operations tracing_free_buffer_fops = { - .write = tracing_free_buffer_write, - .release = tracing_free_buffer_release, -}; - static const struct file_operations tracing_mark_fops = { .open = tracing_open_generic, .write = tracing_mark_write, @@ -3800,7 +3696,7 @@ tracing_buffers_read(struct file *filp, char __user *ubuf, return 0; if (!info->spare) - info->spare = ring_buffer_alloc_read_page(info->tr->buffer, info->cpu); + info->spare = ring_buffer_alloc_read_page(info->tr->buffer); if (!info->spare) return -ENOMEM; @@ -3957,7 +3853,7 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos, ref->ref = 1; ref->buffer = info->tr->buffer; - ref->page = ring_buffer_alloc_read_page(ref->buffer, info->cpu); + ref->page = ring_buffer_alloc_read_page(ref->buffer); if (!ref->page) { kfree(ref); break; @@ -3966,7 +3862,8 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos, r = ring_buffer_read_page(ref->buffer, &ref->page, len, info->cpu, 1); if (r < 0) { - ring_buffer_free_read_page(ref->buffer, ref->page); + ring_buffer_free_read_page(ref->buffer, + ref->page); kfree(ref); break; } @@ -4202,10 +4099,19 @@ trace_options_write(struct file *filp, const char __user *ubuf, size_t cnt, { struct trace_option_dentry *topt = filp->private_data; unsigned long val; + char buf[64]; int ret; - ret = kstrtoul_from_user(ubuf, cnt, 10, &val); - if (ret) + if (cnt >= sizeof(buf)) + return -EINVAL; + + if (copy_from_user(&buf, ubuf, cnt)) + return -EFAULT; + + buf[cnt] = 0; + + ret = strict_strtoul(buf, 10, &val); + if (ret < 0) return ret; if (val != 0 && val != 1) @@ -4253,11 +4159,20 @@ trace_options_core_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) { long index = (long)filp->private_data; + char buf[64]; unsigned long val; int ret; - ret = kstrtoul_from_user(ubuf, cnt, 10, &val); - if (ret) + if (cnt >= sizeof(buf)) + return -EINVAL; + + if (copy_from_user(&buf, ubuf, cnt)) + return -EFAULT; + + buf[cnt] = 0; + + ret = strict_strtoul(buf, 10, &val); + if (ret < 0) return ret; if (val != 0 && val != 1) @@ -4450,9 +4365,6 @@ static __init int tracer_init_debugfs(void) trace_create_file("buffer_size_kb", 0644, d_tracer, &global_trace, &tracing_entries_fops); - trace_create_file("free_buffer", 0644, d_tracer, - &global_trace, &tracing_free_buffer_fops); - trace_create_file("trace_marker", 0220, d_tracer, NULL, &tracing_mark_fops); diff --git a/trunk/kernel/trace/trace.h b/trunk/kernel/trace/trace.h index 3f381d0b20a8..229f8591f61d 100644 --- a/trunk/kernel/trace/trace.h +++ b/trunk/kernel/trace/trace.h @@ -278,29 +278,6 @@ struct tracer { }; -/* Only current can touch trace_recursion */ -#define trace_recursion_inc() do { (current)->trace_recursion++; } while (0) -#define trace_recursion_dec() do { (current)->trace_recursion--; } while (0) - -/* Ring buffer has the 10 LSB bits to count */ -#define trace_recursion_buffer() ((current)->trace_recursion & 0x3ff) - -/* for function tracing recursion */ -#define TRACE_INTERNAL_BIT (1<<11) -#define TRACE_GLOBAL_BIT (1<<12) -/* - * Abuse of the trace_recursion. - * As we need a way to maintain state if we are tracing the function - * graph in irq because we want to trace a particular function that - * was called in irq context but we have irq tracing off. Since this - * can only be modified by current, we can reuse trace_recursion. - */ -#define TRACE_IRQ_BIT (1<<13) - -#define trace_recursion_set(bit) do { (current)->trace_recursion |= (bit); } while (0) -#define trace_recursion_clear(bit) do { (current)->trace_recursion &= ~(bit); } while (0) -#define trace_recursion_test(bit) ((current)->trace_recursion & (bit)) - #define TRACE_PIPE_ALL_CPU -1 int tracer_init(struct tracer *t, struct trace_array *tr); @@ -412,9 +389,6 @@ void update_max_tr_single(struct trace_array *tr, void ftrace_trace_stack(struct ring_buffer *buffer, unsigned long flags, int skip, int pc); -void ftrace_trace_stack_regs(struct ring_buffer *buffer, unsigned long flags, - int skip, int pc, struct pt_regs *regs); - void ftrace_trace_userstack(struct ring_buffer *buffer, unsigned long flags, int pc); @@ -426,12 +400,6 @@ static inline void ftrace_trace_stack(struct ring_buffer *buffer, { } -static inline void ftrace_trace_stack_regs(struct ring_buffer *buffer, - unsigned long flags, int skip, - int pc, struct pt_regs *regs) -{ -} - static inline void ftrace_trace_userstack(struct ring_buffer *buffer, unsigned long flags, int pc) { @@ -539,18 +507,8 @@ static inline int ftrace_graph_addr(unsigned long addr) return 1; for (i = 0; i < ftrace_graph_count; i++) { - if (addr == ftrace_graph_funcs[i]) { - /* - * If no irqs are to be traced, but a set_graph_function - * is set, and called by an interrupt handler, we still - * want to trace it. - */ - if (in_irq()) - trace_recursion_set(TRACE_IRQ_BIT); - else - trace_recursion_clear(TRACE_IRQ_BIT); + if (addr == ftrace_graph_funcs[i]) return 1; - } } return 0; @@ -651,7 +609,6 @@ enum trace_iterator_flags { TRACE_ITER_GRAPH_TIME = 0x80000, TRACE_ITER_RECORD_CMD = 0x100000, TRACE_ITER_OVERWRITE = 0x200000, - TRACE_ITER_STOP_ON_FREE = 0x400000, }; /* @@ -720,7 +677,6 @@ struct event_subsystem { struct dentry *entry; struct event_filter *filter; int nr_events; - int ref_count; }; #define FILTER_PRED_INVALID ((unsigned short)-1) @@ -828,4 +784,19 @@ extern const char *__stop___trace_bprintk_fmt[]; FTRACE_ENTRY(call, struct_name, id, PARAMS(tstruct), PARAMS(print)) #include "trace_entries.h" +/* Only current can touch trace_recursion */ +#define trace_recursion_inc() do { (current)->trace_recursion++; } while (0) +#define trace_recursion_dec() do { (current)->trace_recursion--; } while (0) + +/* Ring buffer has the 10 LSB bits to count */ +#define trace_recursion_buffer() ((current)->trace_recursion & 0x3ff) + +/* for function tracing recursion */ +#define TRACE_INTERNAL_BIT (1<<11) +#define TRACE_GLOBAL_BIT (1<<12) + +#define trace_recursion_set(bit) do { (current)->trace_recursion |= (bit); } while (0) +#define trace_recursion_clear(bit) do { (current)->trace_recursion &= ~(bit); } while (0) +#define trace_recursion_test(bit) ((current)->trace_recursion & (bit)) + #endif /* _LINUX_KERNEL_TRACE_H */ diff --git a/trunk/kernel/trace/trace_entries.h b/trunk/kernel/trace/trace_entries.h index 93365907f219..e32744c84d94 100644 --- a/trunk/kernel/trace/trace_entries.h +++ b/trunk/kernel/trace/trace_entries.h @@ -161,8 +161,7 @@ FTRACE_ENTRY(kernel_stack, stack_entry, TRACE_STACK, F_STRUCT( - __field( int, size ) - __dynamic_array(unsigned long, caller ) + __array( unsigned long, caller, FTRACE_STACK_ENTRIES ) ), F_printk("\t=> (%08lx)\n\t=> (%08lx)\n\t=> (%08lx)\n\t=> (%08lx)\n" diff --git a/trunk/kernel/trace/trace_events.c b/trunk/kernel/trace/trace_events.c index 581876f9f387..686ec399f2a8 100644 --- a/trunk/kernel/trace/trace_events.c +++ b/trunk/kernel/trace/trace_events.c @@ -244,35 +244,6 @@ static void ftrace_clear_events(void) mutex_unlock(&event_mutex); } -static void __put_system(struct event_subsystem *system) -{ - struct event_filter *filter = system->filter; - - WARN_ON_ONCE(system->ref_count == 0); - if (--system->ref_count) - return; - - if (filter) { - kfree(filter->filter_string); - kfree(filter); - } - kfree(system->name); - kfree(system); -} - -static void __get_system(struct event_subsystem *system) -{ - WARN_ON_ONCE(system->ref_count == 0); - system->ref_count++; -} - -static void put_system(struct event_subsystem *system) -{ - mutex_lock(&event_mutex); - __put_system(system); - mutex_unlock(&event_mutex); -} - /* * __ftrace_set_clr_event(NULL, NULL, NULL, set) will set/unset all events. */ @@ -515,11 +486,20 @@ event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) { struct ftrace_event_call *call = filp->private_data; + char buf[64]; unsigned long val; int ret; - ret = kstrtoul_from_user(ubuf, cnt, 10, &val); - if (ret) + if (cnt >= sizeof(buf)) + return -EINVAL; + + if (copy_from_user(&buf, ubuf, cnt)) + return -EFAULT; + + buf[cnt] = 0; + + ret = strict_strtoul(buf, 10, &val); + if (ret < 0) return ret; ret = tracing_update_buffers(); @@ -548,7 +528,7 @@ system_enable_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) { const char set_to_char[4] = { '?', '0', '1', 'X' }; - struct event_subsystem *system = filp->private_data; + const char *system = filp->private_data; struct ftrace_event_call *call; char buf[2]; int set = 0; @@ -559,7 +539,7 @@ system_enable_read(struct file *filp, char __user *ubuf, size_t cnt, if (!call->name || !call->class || !call->class->reg) continue; - if (system && strcmp(call->class->system, system->name) != 0) + if (system && strcmp(call->class->system, system) != 0) continue; /* @@ -589,13 +569,21 @@ static ssize_t system_enable_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) { - struct event_subsystem *system = filp->private_data; - const char *name = NULL; + const char *system = filp->private_data; unsigned long val; + char buf[64]; ssize_t ret; - ret = kstrtoul_from_user(ubuf, cnt, 10, &val); - if (ret) + if (cnt >= sizeof(buf)) + return -EINVAL; + + if (copy_from_user(&buf, ubuf, cnt)) + return -EFAULT; + + buf[cnt] = 0; + + ret = strict_strtoul(buf, 10, &val); + if (ret < 0) return ret; ret = tracing_update_buffers(); @@ -605,14 +593,7 @@ system_enable_write(struct file *filp, const char __user *ubuf, size_t cnt, if (val != 0 && val != 1) return -EINVAL; - /* - * Opening of "enable" adds a ref count to system, - * so the name is safe to use. - */ - if (system) - name = system->name; - - ret = __ftrace_set_clr_event(NULL, name, NULL, val); + ret = __ftrace_set_clr_event(NULL, system, NULL, val); if (ret) goto out; @@ -845,52 +826,6 @@ event_filter_write(struct file *filp, const char __user *ubuf, size_t cnt, return cnt; } -static LIST_HEAD(event_subsystems); - -static int subsystem_open(struct inode *inode, struct file *filp) -{ - struct event_subsystem *system = NULL; - int ret; - - if (!inode->i_private) - goto skip_search; - - /* Make sure the system still exists */ - mutex_lock(&event_mutex); - list_for_each_entry(system, &event_subsystems, list) { - if (system == inode->i_private) { - /* Don't open systems with no events */ - if (!system->nr_events) { - system = NULL; - break; - } - __get_system(system); - break; - } - } - mutex_unlock(&event_mutex); - - if (system != inode->i_private) - return -ENODEV; - - skip_search: - ret = tracing_open_generic(inode, filp); - if (ret < 0 && system) - put_system(system); - - return ret; -} - -static int subsystem_release(struct inode *inode, struct file *file) -{ - struct event_subsystem *system = inode->i_private; - - if (system) - put_system(system); - - return 0; -} - static ssize_t subsystem_filter_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) @@ -1028,19 +963,17 @@ static const struct file_operations ftrace_event_filter_fops = { }; static const struct file_operations ftrace_subsystem_filter_fops = { - .open = subsystem_open, + .open = tracing_open_generic, .read = subsystem_filter_read, .write = subsystem_filter_write, .llseek = default_llseek, - .release = subsystem_release, }; static const struct file_operations ftrace_system_enable_fops = { - .open = subsystem_open, + .open = tracing_open_generic, .read = system_enable_read, .write = system_enable_write, .llseek = default_llseek, - .release = subsystem_release, }; static const struct file_operations ftrace_show_header_fops = { @@ -1069,6 +1002,8 @@ static struct dentry *event_trace_events_dir(void) return d_events; } +static LIST_HEAD(event_subsystems); + static struct dentry * event_subsystem_dir(const char *name, struct dentry *d_events) { @@ -1078,7 +1013,6 @@ event_subsystem_dir(const char *name, struct dentry *d_events) /* First see if we did not already create this dir */ list_for_each_entry(system, &event_subsystems, list) { if (strcmp(system->name, name) == 0) { - __get_system(system); system->nr_events++; return system->entry; } @@ -1101,7 +1035,6 @@ event_subsystem_dir(const char *name, struct dentry *d_events) } system->nr_events = 1; - system->ref_count = 1; system->name = kstrdup(name, GFP_KERNEL); if (!system->name) { debugfs_remove(system->entry); @@ -1129,7 +1062,8 @@ event_subsystem_dir(const char *name, struct dentry *d_events) "'%s/filter' entry\n", name); } - trace_create_file("enable", 0644, system->entry, system, + trace_create_file("enable", 0644, system->entry, + (void *)system->name, &ftrace_system_enable_fops); return system->entry; @@ -1250,9 +1184,16 @@ static void remove_subsystem_dir(const char *name) list_for_each_entry(system, &event_subsystems, list) { if (strcmp(system->name, name) == 0) { if (!--system->nr_events) { + struct event_filter *filter = system->filter; + debugfs_remove_recursive(system->entry); list_del(&system->list); - __put_system(system); + if (filter) { + kfree(filter->filter_string); + kfree(filter); + } + kfree(system->name); + kfree(system); } break; } diff --git a/trunk/kernel/trace/trace_events_filter.c b/trunk/kernel/trace/trace_events_filter.c index 256764ecccd6..8008ddcfbf20 100644 --- a/trunk/kernel/trace/trace_events_filter.c +++ b/trunk/kernel/trace/trace_events_filter.c @@ -1886,12 +1886,6 @@ int apply_subsystem_event_filter(struct event_subsystem *system, mutex_lock(&event_mutex); - /* Make sure the system still has events */ - if (!system->nr_events) { - err = -ENODEV; - goto out_unlock; - } - if (!strcmp(strstrip(filter_string), "0")) { filter_free_subsystem_preds(system); remove_filter_string(system->filter); diff --git a/trunk/kernel/trace/trace_functions.c b/trunk/kernel/trace/trace_functions.c index c7b0c6a7db09..8d0e1cc4e974 100644 --- a/trunk/kernel/trace/trace_functions.c +++ b/trunk/kernel/trace/trace_functions.c @@ -324,8 +324,7 @@ ftrace_trace_onoff_unreg(char *glob, char *cmd, char *param) } static int -ftrace_trace_onoff_callback(struct ftrace_hash *hash, - char *glob, char *cmd, char *param, int enable) +ftrace_trace_onoff_callback(char *glob, char *cmd, char *param, int enable) { struct ftrace_probe_ops *ops; void *count = (void *)-1; diff --git a/trunk/kernel/trace/trace_functions_graph.c b/trunk/kernel/trace/trace_functions_graph.c index a7d2a4c653d8..962cdb24ed81 100644 --- a/trunk/kernel/trace/trace_functions_graph.c +++ b/trunk/kernel/trace/trace_functions_graph.c @@ -74,20 +74,6 @@ static struct tracer_flags tracer_flags = { static struct trace_array *graph_array; -/* - * DURATION column is being also used to display IRQ signs, - * following values are used by print_graph_irq and others - * to fill in space into DURATION column. - */ -enum { - DURATION_FILL_FULL = -1, - DURATION_FILL_START = -2, - DURATION_FILL_END = -3, -}; - -static enum print_line_t -print_graph_duration(unsigned long long duration, struct trace_seq *s, - u32 flags); /* Add a function return address to the trace stack on thread info.*/ int @@ -227,7 +213,7 @@ int __trace_graph_entry(struct trace_array *tr, static inline int ftrace_graph_ignore_irqs(void) { - if (!ftrace_graph_skip_irqs || trace_recursion_test(TRACE_IRQ_BIT)) + if (!ftrace_graph_skip_irqs) return 0; return in_irq(); @@ -591,6 +577,32 @@ get_return_for_leaf(struct trace_iterator *iter, return next; } +/* Signal a overhead of time execution to the output */ +static int +print_graph_overhead(unsigned long long duration, struct trace_seq *s, + u32 flags) +{ + /* If duration disappear, we don't need anything */ + if (!(flags & TRACE_GRAPH_PRINT_DURATION)) + return 1; + + /* Non nested entry or return */ + if (duration == -1) + return trace_seq_printf(s, " "); + + if (flags & TRACE_GRAPH_PRINT_OVERHEAD) { + /* Duration exceeded 100 msecs */ + if (duration > 100000ULL) + return trace_seq_printf(s, "! "); + + /* Duration exceeded 10 msecs */ + if (duration > 10000ULL) + return trace_seq_printf(s, "+ "); + } + + return trace_seq_printf(s, " "); +} + static int print_graph_abs_time(u64 t, struct trace_seq *s) { unsigned long usecs_rem; @@ -613,36 +625,34 @@ print_graph_irq(struct trace_iterator *iter, unsigned long addr, addr >= (unsigned long)__irqentry_text_end) return TRACE_TYPE_UNHANDLED; - if (trace_flags & TRACE_ITER_CONTEXT_INFO) { - /* Absolute time */ - if (flags & TRACE_GRAPH_PRINT_ABS_TIME) { - ret = print_graph_abs_time(iter->ts, s); - if (!ret) - return TRACE_TYPE_PARTIAL_LINE; - } + /* Absolute time */ + if (flags & TRACE_GRAPH_PRINT_ABS_TIME) { + ret = print_graph_abs_time(iter->ts, s); + if (!ret) + return TRACE_TYPE_PARTIAL_LINE; + } - /* Cpu */ - if (flags & TRACE_GRAPH_PRINT_CPU) { - ret = print_graph_cpu(s, cpu); - if (ret == TRACE_TYPE_PARTIAL_LINE) - return TRACE_TYPE_PARTIAL_LINE; - } + /* Cpu */ + if (flags & TRACE_GRAPH_PRINT_CPU) { + ret = print_graph_cpu(s, cpu); + if (ret == TRACE_TYPE_PARTIAL_LINE) + return TRACE_TYPE_PARTIAL_LINE; + } - /* Proc */ - if (flags & TRACE_GRAPH_PRINT_PROC) { - ret = print_graph_proc(s, pid); - if (ret == TRACE_TYPE_PARTIAL_LINE) - return TRACE_TYPE_PARTIAL_LINE; - ret = trace_seq_printf(s, " | "); - if (!ret) - return TRACE_TYPE_PARTIAL_LINE; - } + /* Proc */ + if (flags & TRACE_GRAPH_PRINT_PROC) { + ret = print_graph_proc(s, pid); + if (ret == TRACE_TYPE_PARTIAL_LINE) + return TRACE_TYPE_PARTIAL_LINE; + ret = trace_seq_printf(s, " | "); + if (!ret) + return TRACE_TYPE_PARTIAL_LINE; } /* No overhead */ - ret = print_graph_duration(DURATION_FILL_START, s, flags); - if (ret != TRACE_TYPE_HANDLED) - return ret; + ret = print_graph_overhead(-1, s, flags); + if (!ret) + return TRACE_TYPE_PARTIAL_LINE; if (type == TRACE_GRAPH_ENT) ret = trace_seq_printf(s, "==========>"); @@ -652,10 +662,9 @@ print_graph_irq(struct trace_iterator *iter, unsigned long addr, if (!ret) return TRACE_TYPE_PARTIAL_LINE; - ret = print_graph_duration(DURATION_FILL_END, s, flags); - if (ret != TRACE_TYPE_HANDLED) - return ret; - + /* Don't close the duration column if haven't one */ + if (flags & TRACE_GRAPH_PRINT_DURATION) + trace_seq_printf(s, " |"); ret = trace_seq_printf(s, "\n"); if (!ret) @@ -707,49 +716,9 @@ trace_print_graph_duration(unsigned long long duration, struct trace_seq *s) } static enum print_line_t -print_graph_duration(unsigned long long duration, struct trace_seq *s, - u32 flags) +print_graph_duration(unsigned long long duration, struct trace_seq *s) { - int ret = -1; - - if (!(flags & TRACE_GRAPH_PRINT_DURATION) || - !(trace_flags & TRACE_ITER_CONTEXT_INFO)) - return TRACE_TYPE_HANDLED; - - /* No real adata, just filling the column with spaces */ - switch (duration) { - case DURATION_FILL_FULL: - ret = trace_seq_printf(s, " | "); - return ret ? TRACE_TYPE_HANDLED : TRACE_TYPE_PARTIAL_LINE; - case DURATION_FILL_START: - ret = trace_seq_printf(s, " "); - return ret ? TRACE_TYPE_HANDLED : TRACE_TYPE_PARTIAL_LINE; - case DURATION_FILL_END: - ret = trace_seq_printf(s, " |"); - return ret ? TRACE_TYPE_HANDLED : TRACE_TYPE_PARTIAL_LINE; - } - - /* Signal a overhead of time execution to the output */ - if (flags & TRACE_GRAPH_PRINT_OVERHEAD) { - /* Duration exceeded 100 msecs */ - if (duration > 100000ULL) - ret = trace_seq_printf(s, "! "); - /* Duration exceeded 10 msecs */ - else if (duration > 10000ULL) - ret = trace_seq_printf(s, "+ "); - } - - /* - * The -1 means we either did not exceed the duration tresholds - * or we dont want to print out the overhead. Either way we need - * to fill out the space. - */ - if (ret == -1) - ret = trace_seq_printf(s, " "); - - /* Catching here any failure happenned above */ - if (!ret) - return TRACE_TYPE_PARTIAL_LINE; + int ret; ret = trace_print_graph_duration(duration, s); if (ret != TRACE_TYPE_HANDLED) @@ -798,11 +767,18 @@ print_graph_entry_leaf(struct trace_iterator *iter, cpu_data->enter_funcs[call->depth] = 0; } - /* Overhead and duration */ - ret = print_graph_duration(duration, s, flags); - if (ret == TRACE_TYPE_PARTIAL_LINE) + /* Overhead */ + ret = print_graph_overhead(duration, s, flags); + if (!ret) return TRACE_TYPE_PARTIAL_LINE; + /* Duration */ + if (flags & TRACE_GRAPH_PRINT_DURATION) { + ret = print_graph_duration(duration, s); + if (ret == TRACE_TYPE_PARTIAL_LINE) + return TRACE_TYPE_PARTIAL_LINE; + } + /* Function */ for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++) { ret = trace_seq_printf(s, " "); @@ -839,10 +815,17 @@ print_graph_entry_nested(struct trace_iterator *iter, cpu_data->enter_funcs[call->depth] = call->func; } + /* No overhead */ + ret = print_graph_overhead(-1, s, flags); + if (!ret) + return TRACE_TYPE_PARTIAL_LINE; + /* No time */ - ret = print_graph_duration(DURATION_FILL_FULL, s, flags); - if (ret != TRACE_TYPE_HANDLED) - return ret; + if (flags & TRACE_GRAPH_PRINT_DURATION) { + ret = trace_seq_printf(s, " | "); + if (!ret) + return TRACE_TYPE_PARTIAL_LINE; + } /* Function */ for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++) { @@ -882,9 +865,6 @@ print_graph_prologue(struct trace_iterator *iter, struct trace_seq *s, return TRACE_TYPE_PARTIAL_LINE; } - if (!(trace_flags & TRACE_ITER_CONTEXT_INFO)) - return 0; - /* Absolute time */ if (flags & TRACE_GRAPH_PRINT_ABS_TIME) { ret = print_graph_abs_time(iter->ts, s); @@ -1098,11 +1078,18 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s, if (print_graph_prologue(iter, s, 0, 0, flags)) return TRACE_TYPE_PARTIAL_LINE; - /* Overhead and duration */ - ret = print_graph_duration(duration, s, flags); - if (ret == TRACE_TYPE_PARTIAL_LINE) + /* Overhead */ + ret = print_graph_overhead(duration, s, flags); + if (!ret) return TRACE_TYPE_PARTIAL_LINE; + /* Duration */ + if (flags & TRACE_GRAPH_PRINT_DURATION) { + ret = print_graph_duration(duration, s); + if (ret == TRACE_TYPE_PARTIAL_LINE) + return TRACE_TYPE_PARTIAL_LINE; + } + /* Closing brace */ for (i = 0; i < trace->depth * TRACE_GRAPH_INDENT; i++) { ret = trace_seq_printf(s, " "); @@ -1159,10 +1146,17 @@ print_graph_comment(struct trace_seq *s, struct trace_entry *ent, if (print_graph_prologue(iter, s, 0, 0, flags)) return TRACE_TYPE_PARTIAL_LINE; + /* No overhead */ + ret = print_graph_overhead(-1, s, flags); + if (!ret) + return TRACE_TYPE_PARTIAL_LINE; + /* No time */ - ret = print_graph_duration(DURATION_FILL_FULL, s, flags); - if (ret != TRACE_TYPE_HANDLED) - return ret; + if (flags & TRACE_GRAPH_PRINT_DURATION) { + ret = trace_seq_printf(s, " | "); + if (!ret) + return TRACE_TYPE_PARTIAL_LINE; + } /* Indentation */ if (depth > 0) @@ -1213,7 +1207,7 @@ print_graph_comment(struct trace_seq *s, struct trace_entry *ent, enum print_line_t -print_graph_function_flags(struct trace_iterator *iter, u32 flags) +__print_graph_function_flags(struct trace_iterator *iter, u32 flags) { struct ftrace_graph_ent_entry *field; struct fgraph_data *data = iter->private; @@ -1276,7 +1270,18 @@ print_graph_function_flags(struct trace_iterator *iter, u32 flags) static enum print_line_t print_graph_function(struct trace_iterator *iter) { - return print_graph_function_flags(iter, tracer_flags.val); + return __print_graph_function_flags(iter, tracer_flags.val); +} + +enum print_line_t print_graph_function_flags(struct trace_iterator *iter, + u32 flags) +{ + if (trace_flags & TRACE_ITER_LATENCY_FMT) + flags |= TRACE_GRAPH_PRINT_DURATION; + else + flags |= TRACE_GRAPH_PRINT_ABS_TIME; + + return __print_graph_function_flags(iter, flags); } static enum print_line_t @@ -1304,7 +1309,8 @@ static void print_lat_header(struct seq_file *s, u32 flags) seq_printf(s, "#%.*s / _----=> need-resched \n", size, spaces); seq_printf(s, "#%.*s| / _---=> hardirq/softirq \n", size, spaces); seq_printf(s, "#%.*s|| / _--=> preempt-depth \n", size, spaces); - seq_printf(s, "#%.*s||| / \n", size, spaces); + seq_printf(s, "#%.*s||| / _-=> lock-depth \n", size, spaces); + seq_printf(s, "#%.*s|||| / \n", size, spaces); } static void __print_graph_headers_flags(struct seq_file *s, u32 flags) @@ -1323,7 +1329,7 @@ static void __print_graph_headers_flags(struct seq_file *s, u32 flags) if (flags & TRACE_GRAPH_PRINT_PROC) seq_printf(s, " TASK/PID "); if (lat) - seq_printf(s, "||||"); + seq_printf(s, "|||||"); if (flags & TRACE_GRAPH_PRINT_DURATION) seq_printf(s, " DURATION "); seq_printf(s, " FUNCTION CALLS\n"); @@ -1337,7 +1343,7 @@ static void __print_graph_headers_flags(struct seq_file *s, u32 flags) if (flags & TRACE_GRAPH_PRINT_PROC) seq_printf(s, " | | "); if (lat) - seq_printf(s, "||||"); + seq_printf(s, "|||||"); if (flags & TRACE_GRAPH_PRINT_DURATION) seq_printf(s, " | | "); seq_printf(s, " | | | |\n"); @@ -1352,16 +1358,15 @@ void print_graph_headers_flags(struct seq_file *s, u32 flags) { struct trace_iterator *iter = s->private; - if (!(trace_flags & TRACE_ITER_CONTEXT_INFO)) - return; - if (trace_flags & TRACE_ITER_LATENCY_FMT) { /* print nothing if the buffers are empty */ if (trace_empty(iter)) return; print_trace_header(s, iter); - } + flags |= TRACE_GRAPH_PRINT_DURATION; + } else + flags |= TRACE_GRAPH_PRINT_ABS_TIME; __print_graph_headers_flags(s, flags); } diff --git a/trunk/kernel/trace/trace_irqsoff.c b/trunk/kernel/trace/trace_irqsoff.c index 667aa8cc0cfc..c77424be284d 100644 --- a/trunk/kernel/trace/trace_irqsoff.c +++ b/trunk/kernel/trace/trace_irqsoff.c @@ -226,9 +226,7 @@ static void irqsoff_trace_close(struct trace_iterator *iter) } #define GRAPH_TRACER_FLAGS (TRACE_GRAPH_PRINT_CPU | \ - TRACE_GRAPH_PRINT_PROC | \ - TRACE_GRAPH_PRINT_ABS_TIME | \ - TRACE_GRAPH_PRINT_DURATION) + TRACE_GRAPH_PRINT_PROC) static enum print_line_t irqsoff_print_line(struct trace_iterator *iter) { diff --git a/trunk/kernel/trace/trace_kprobe.c b/trunk/kernel/trace/trace_kprobe.c index 5fb3697bf0e5..27d13b36b8be 100644 --- a/trunk/kernel/trace/trace_kprobe.c +++ b/trunk/kernel/trace/trace_kprobe.c @@ -343,14 +343,6 @@ DEFINE_BASIC_FETCH_FUNCS(deref) DEFINE_FETCH_deref(string) DEFINE_FETCH_deref(string_size) -static __kprobes void update_deref_fetch_param(struct deref_fetch_param *data) -{ - if (CHECK_FETCH_FUNCS(deref, data->orig.fn)) - update_deref_fetch_param(data->orig.data); - else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn)) - update_symbol_cache(data->orig.data); -} - static __kprobes void free_deref_fetch_param(struct deref_fetch_param *data) { if (CHECK_FETCH_FUNCS(deref, data->orig.fn)) @@ -384,19 +376,6 @@ DEFINE_BASIC_FETCH_FUNCS(bitfield) #define fetch_bitfield_string NULL #define fetch_bitfield_string_size NULL -static __kprobes void -update_bitfield_fetch_param(struct bitfield_fetch_param *data) -{ - /* - * Don't check the bitfield itself, because this must be the - * last fetch function. - */ - if (CHECK_FETCH_FUNCS(deref, data->orig.fn)) - update_deref_fetch_param(data->orig.data); - else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn)) - update_symbol_cache(data->orig.data); -} - static __kprobes void free_bitfield_fetch_param(struct bitfield_fetch_param *data) { @@ -410,7 +389,6 @@ free_bitfield_fetch_param(struct bitfield_fetch_param *data) free_symbol_cache(data->orig.data); kfree(data); } - /* Default (unsigned long) fetch type */ #define __DEFAULT_FETCH_TYPE(t) u##t #define _DEFAULT_FETCH_TYPE(t) __DEFAULT_FETCH_TYPE(t) @@ -558,7 +536,6 @@ struct probe_arg { /* Flags for trace_probe */ #define TP_FLAG_TRACE 1 #define TP_FLAG_PROFILE 2 -#define TP_FLAG_REGISTERED 4 struct trace_probe { struct list_head list; @@ -578,49 +555,16 @@ struct trace_probe { (sizeof(struct probe_arg) * (n))) -static __kprobes int trace_probe_is_return(struct trace_probe *tp) +static __kprobes int probe_is_return(struct trace_probe *tp) { return tp->rp.handler != NULL; } -static __kprobes const char *trace_probe_symbol(struct trace_probe *tp) +static __kprobes const char *probe_symbol(struct trace_probe *tp) { return tp->symbol ? tp->symbol : "unknown"; } -static __kprobes unsigned long trace_probe_offset(struct trace_probe *tp) -{ - return tp->rp.kp.offset; -} - -static __kprobes bool trace_probe_is_enabled(struct trace_probe *tp) -{ - return !!(tp->flags & (TP_FLAG_TRACE | TP_FLAG_PROFILE)); -} - -static __kprobes bool trace_probe_is_registered(struct trace_probe *tp) -{ - return !!(tp->flags & TP_FLAG_REGISTERED); -} - -static __kprobes bool trace_probe_has_gone(struct trace_probe *tp) -{ - return !!(kprobe_gone(&tp->rp.kp)); -} - -static __kprobes bool trace_probe_within_module(struct trace_probe *tp, - struct module *mod) -{ - int len = strlen(mod->name); - const char *name = trace_probe_symbol(tp); - return strncmp(mod->name, name, len) == 0 && name[len] == ':'; -} - -static __kprobes bool trace_probe_is_on_module(struct trace_probe *tp) -{ - return !!strchr(trace_probe_symbol(tp), ':'); -} - static int register_probe_event(struct trace_probe *tp); static void unregister_probe_event(struct trace_probe *tp); @@ -702,16 +646,6 @@ static struct trace_probe *alloc_trace_probe(const char *group, return ERR_PTR(ret); } -static void update_probe_arg(struct probe_arg *arg) -{ - if (CHECK_FETCH_FUNCS(bitfield, arg->fetch.fn)) - update_bitfield_fetch_param(arg->fetch.data); - else if (CHECK_FETCH_FUNCS(deref, arg->fetch.fn)) - update_deref_fetch_param(arg->fetch.data); - else if (CHECK_FETCH_FUNCS(symbol, arg->fetch.fn)) - update_symbol_cache(arg->fetch.data); -} - static void free_probe_arg(struct probe_arg *arg) { if (CHECK_FETCH_FUNCS(bitfield, arg->fetch.fn)) @@ -737,7 +671,7 @@ static void free_trace_probe(struct trace_probe *tp) kfree(tp); } -static struct trace_probe *find_trace_probe(const char *event, +static struct trace_probe *find_probe_event(const char *event, const char *group) { struct trace_probe *tp; @@ -749,96 +683,13 @@ static struct trace_probe *find_trace_probe(const char *event, return NULL; } -/* Enable trace_probe - @flag must be TP_FLAG_TRACE or TP_FLAG_PROFILE */ -static int enable_trace_probe(struct trace_probe *tp, int flag) -{ - int ret = 0; - - tp->flags |= flag; - if (trace_probe_is_enabled(tp) && trace_probe_is_registered(tp) && - !trace_probe_has_gone(tp)) { - if (trace_probe_is_return(tp)) - ret = enable_kretprobe(&tp->rp); - else - ret = enable_kprobe(&tp->rp.kp); - } - - return ret; -} - -/* Disable trace_probe - @flag must be TP_FLAG_TRACE or TP_FLAG_PROFILE */ -static void disable_trace_probe(struct trace_probe *tp, int flag) -{ - tp->flags &= ~flag; - if (!trace_probe_is_enabled(tp) && trace_probe_is_registered(tp)) { - if (trace_probe_is_return(tp)) - disable_kretprobe(&tp->rp); - else - disable_kprobe(&tp->rp.kp); - } -} - -/* Internal register function - just handle k*probes and flags */ -static int __register_trace_probe(struct trace_probe *tp) -{ - int i, ret; - - if (trace_probe_is_registered(tp)) - return -EINVAL; - - for (i = 0; i < tp->nr_args; i++) - update_probe_arg(&tp->args[i]); - - /* Set/clear disabled flag according to tp->flag */ - if (trace_probe_is_enabled(tp)) - tp->rp.kp.flags &= ~KPROBE_FLAG_DISABLED; - else - tp->rp.kp.flags |= KPROBE_FLAG_DISABLED; - - if (trace_probe_is_return(tp)) - ret = register_kretprobe(&tp->rp); - else - ret = register_kprobe(&tp->rp.kp); - - if (ret == 0) - tp->flags |= TP_FLAG_REGISTERED; - else { - pr_warning("Could not insert probe at %s+%lu: %d\n", - trace_probe_symbol(tp), trace_probe_offset(tp), ret); - if (ret == -ENOENT && trace_probe_is_on_module(tp)) { - pr_warning("This probe might be able to register after" - "target module is loaded. Continue.\n"); - ret = 0; - } else if (ret == -EILSEQ) { - pr_warning("Probing address(0x%p) is not an " - "instruction boundary.\n", - tp->rp.kp.addr); - ret = -EINVAL; - } - } - - return ret; -} - -/* Internal unregister function - just handle k*probes and flags */ -static void __unregister_trace_probe(struct trace_probe *tp) -{ - if (trace_probe_is_registered(tp)) { - if (trace_probe_is_return(tp)) - unregister_kretprobe(&tp->rp); - else - unregister_kprobe(&tp->rp.kp); - tp->flags &= ~TP_FLAG_REGISTERED; - /* Cleanup kprobe for reuse */ - if (tp->rp.kp.symbol_name) - tp->rp.kp.addr = NULL; - } -} - /* Unregister a trace_probe and probe_event: call with locking probe_lock */ static void unregister_trace_probe(struct trace_probe *tp) { - __unregister_trace_probe(tp); + if (probe_is_return(tp)) + unregister_kretprobe(&tp->rp); + else + unregister_kprobe(&tp->rp.kp); list_del(&tp->list); unregister_probe_event(tp); } @@ -851,65 +702,41 @@ static int register_trace_probe(struct trace_probe *tp) mutex_lock(&probe_lock); - /* Delete old (same name) event if exist */ - old_tp = find_trace_probe(tp->call.name, tp->call.class->system); + /* register as an event */ + old_tp = find_probe_event(tp->call.name, tp->call.class->system); if (old_tp) { + /* delete old event */ unregister_trace_probe(old_tp); free_trace_probe(old_tp); } - - /* Register new event */ ret = register_probe_event(tp); if (ret) { pr_warning("Failed to register probe event(%d)\n", ret); goto end; } - /* Register k*probe */ - ret = __register_trace_probe(tp); - if (ret < 0) - unregister_probe_event(tp); + tp->rp.kp.flags |= KPROBE_FLAG_DISABLED; + if (probe_is_return(tp)) + ret = register_kretprobe(&tp->rp); else - list_add_tail(&tp->list, &probe_list); + ret = register_kprobe(&tp->rp.kp); + if (ret) { + pr_warning("Could not insert probe(%d)\n", ret); + if (ret == -EILSEQ) { + pr_warning("Probing address(0x%p) is not an " + "instruction boundary.\n", + tp->rp.kp.addr); + ret = -EINVAL; + } + unregister_probe_event(tp); + } else + list_add_tail(&tp->list, &probe_list); end: mutex_unlock(&probe_lock); return ret; } -/* Module notifier call back, checking event on the module */ -static int trace_probe_module_callback(struct notifier_block *nb, - unsigned long val, void *data) -{ - struct module *mod = data; - struct trace_probe *tp; - int ret; - - if (val != MODULE_STATE_COMING) - return NOTIFY_DONE; - - /* Update probes on coming module */ - mutex_lock(&probe_lock); - list_for_each_entry(tp, &probe_list, list) { - if (trace_probe_within_module(tp, mod)) { - __unregister_trace_probe(tp); - ret = __register_trace_probe(tp); - if (ret) - pr_warning("Failed to re-register probe %s on" - "%s: %d\n", - tp->call.name, mod->name, ret); - } - } - mutex_unlock(&probe_lock); - - return NOTIFY_DONE; -} - -static struct notifier_block trace_probe_module_nb = { - .notifier_call = trace_probe_module_callback, - .priority = 1 /* Invoked after kprobe module callback */ -}; - /* Split symbol and offset. */ static int split_symbol_offset(char *symbol, unsigned long *offset) { @@ -1135,8 +962,8 @@ static int create_trace_probe(int argc, char **argv) { /* * Argument syntax: - * - Add kprobe: p[:[GRP/]EVENT] [MOD:]KSYM[+OFFS]|KADDR [FETCHARGS] - * - Add kretprobe: r[:[GRP/]EVENT] [MOD:]KSYM[+0] [FETCHARGS] + * - Add kprobe: p[:[GRP/]EVENT] KSYM[+OFFS]|KADDR [FETCHARGS] + * - Add kretprobe: r[:[GRP/]EVENT] KSYM[+0] [FETCHARGS] * Fetch args: * $retval : fetch return value * $stack : fetch stack address @@ -1198,7 +1025,7 @@ static int create_trace_probe(int argc, char **argv) return -EINVAL; } mutex_lock(&probe_lock); - tp = find_trace_probe(event, group); + tp = find_probe_event(event, group); if (!tp) { mutex_unlock(&probe_lock); pr_info("Event %s/%s doesn't exist.\n", group, event); @@ -1317,7 +1144,7 @@ static int create_trace_probe(int argc, char **argv) return ret; } -static void release_all_trace_probes(void) +static void cleanup_all_probes(void) { struct trace_probe *tp; @@ -1331,6 +1158,7 @@ static void release_all_trace_probes(void) mutex_unlock(&probe_lock); } + /* Probes listing interfaces */ static void *probes_seq_start(struct seq_file *m, loff_t *pos) { @@ -1353,16 +1181,15 @@ static int probes_seq_show(struct seq_file *m, void *v) struct trace_probe *tp = v; int i; - seq_printf(m, "%c", trace_probe_is_return(tp) ? 'r' : 'p'); + seq_printf(m, "%c", probe_is_return(tp) ? 'r' : 'p'); seq_printf(m, ":%s/%s", tp->call.class->system, tp->call.name); if (!tp->symbol) seq_printf(m, " 0x%p", tp->rp.kp.addr); else if (tp->rp.kp.offset) - seq_printf(m, " %s+%u", trace_probe_symbol(tp), - tp->rp.kp.offset); + seq_printf(m, " %s+%u", probe_symbol(tp), tp->rp.kp.offset); else - seq_printf(m, " %s", trace_probe_symbol(tp)); + seq_printf(m, " %s", probe_symbol(tp)); for (i = 0; i < tp->nr_args; i++) seq_printf(m, " %s=%s", tp->args[i].name, tp->args[i].comm); @@ -1382,7 +1209,7 @@ static int probes_open(struct inode *inode, struct file *file) { if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) - release_all_trace_probes(); + cleanup_all_probes(); return seq_open(file, &probes_seq_op); } @@ -1570,8 +1397,7 @@ static __kprobes void kprobe_trace_func(struct kprobe *kp, struct pt_regs *regs) store_trace_args(sizeof(*entry), tp, regs, (u8 *)&entry[1], dsize); if (!filter_current_check_discard(buffer, call, entry, event)) - trace_nowake_buffer_unlock_commit_regs(buffer, event, - irq_flags, pc, regs); + trace_nowake_buffer_unlock_commit(buffer, event, irq_flags, pc); } /* Kretprobe handler */ @@ -1603,8 +1429,7 @@ static __kprobes void kretprobe_trace_func(struct kretprobe_instance *ri, store_trace_args(sizeof(*entry), tp, regs, (u8 *)&entry[1], dsize); if (!filter_current_check_discard(buffer, call, entry, event)) - trace_nowake_buffer_unlock_commit_regs(buffer, event, - irq_flags, pc, regs); + trace_nowake_buffer_unlock_commit(buffer, event, irq_flags, pc); } /* Event entry printers */ @@ -1686,6 +1511,30 @@ print_kretprobe_event(struct trace_iterator *iter, int flags, return TRACE_TYPE_PARTIAL_LINE; } +static int probe_event_enable(struct ftrace_event_call *call) +{ + struct trace_probe *tp = (struct trace_probe *)call->data; + + tp->flags |= TP_FLAG_TRACE; + if (probe_is_return(tp)) + return enable_kretprobe(&tp->rp); + else + return enable_kprobe(&tp->rp.kp); +} + +static void probe_event_disable(struct ftrace_event_call *call) +{ + struct trace_probe *tp = (struct trace_probe *)call->data; + + tp->flags &= ~TP_FLAG_TRACE; + if (!(tp->flags & (TP_FLAG_TRACE | TP_FLAG_PROFILE))) { + if (probe_is_return(tp)) + disable_kretprobe(&tp->rp); + else + disable_kprobe(&tp->rp.kp); + } +} + #undef DEFINE_FIELD #define DEFINE_FIELD(type, item, name, is_signed) \ do { \ @@ -1747,7 +1596,7 @@ static int __set_print_fmt(struct trace_probe *tp, char *buf, int len) const char *fmt, *arg; - if (!trace_probe_is_return(tp)) { + if (!probe_is_return(tp)) { fmt = "(%lx)"; arg = "REC->" FIELD_STRING_IP; } else { @@ -1864,25 +1713,49 @@ static __kprobes void kretprobe_perf_func(struct kretprobe_instance *ri, head = this_cpu_ptr(call->perf_events); perf_trace_buf_submit(entry, size, rctx, entry->ret_ip, 1, regs, head); } + +static int probe_perf_enable(struct ftrace_event_call *call) +{ + struct trace_probe *tp = (struct trace_probe *)call->data; + + tp->flags |= TP_FLAG_PROFILE; + + if (probe_is_return(tp)) + return enable_kretprobe(&tp->rp); + else + return enable_kprobe(&tp->rp.kp); +} + +static void probe_perf_disable(struct ftrace_event_call *call) +{ + struct trace_probe *tp = (struct trace_probe *)call->data; + + tp->flags &= ~TP_FLAG_PROFILE; + + if (!(tp->flags & TP_FLAG_TRACE)) { + if (probe_is_return(tp)) + disable_kretprobe(&tp->rp); + else + disable_kprobe(&tp->rp.kp); + } +} #endif /* CONFIG_PERF_EVENTS */ static __kprobes int kprobe_register(struct ftrace_event_call *event, enum trace_reg type) { - struct trace_probe *tp = (struct trace_probe *)event->data; - switch (type) { case TRACE_REG_REGISTER: - return enable_trace_probe(tp, TP_FLAG_TRACE); + return probe_event_enable(event); case TRACE_REG_UNREGISTER: - disable_trace_probe(tp, TP_FLAG_TRACE); + probe_event_disable(event); return 0; #ifdef CONFIG_PERF_EVENTS case TRACE_REG_PERF_REGISTER: - return enable_trace_probe(tp, TP_FLAG_PROFILE); + return probe_perf_enable(event); case TRACE_REG_PERF_UNREGISTER: - disable_trace_probe(tp, TP_FLAG_PROFILE); + probe_perf_disable(event); return 0; #endif } @@ -1932,7 +1805,7 @@ static int register_probe_event(struct trace_probe *tp) /* Initialize ftrace_event_call */ INIT_LIST_HEAD(&call->class->fields); - if (trace_probe_is_return(tp)) { + if (probe_is_return(tp)) { call->event.funcs = &kretprobe_funcs; call->class->define_fields = kretprobe_event_define_fields; } else { @@ -1971,9 +1844,6 @@ static __init int init_kprobe_trace(void) struct dentry *d_tracer; struct dentry *entry; - if (register_module_notifier(&trace_probe_module_nb)) - return -EINVAL; - d_tracer = tracing_init_dentry(); if (!d_tracer) return 0; @@ -2027,12 +1897,12 @@ static __init int kprobe_trace_self_tests_init(void) warn++; } else { /* Enable trace point */ - tp = find_trace_probe("testprobe", KPROBE_EVENT_SYSTEM); + tp = find_probe_event("testprobe", KPROBE_EVENT_SYSTEM); if (WARN_ON_ONCE(tp == NULL)) { pr_warning("error on getting new probe.\n"); warn++; } else - enable_trace_probe(tp, TP_FLAG_TRACE); + probe_event_enable(&tp->call); } ret = command_trace_probe("r:testprobe2 kprobe_trace_selftest_target " @@ -2042,12 +1912,12 @@ static __init int kprobe_trace_self_tests_init(void) warn++; } else { /* Enable trace point */ - tp = find_trace_probe("testprobe2", KPROBE_EVENT_SYSTEM); + tp = find_probe_event("testprobe2", KPROBE_EVENT_SYSTEM); if (WARN_ON_ONCE(tp == NULL)) { pr_warning("error on getting new probe.\n"); warn++; } else - enable_trace_probe(tp, TP_FLAG_TRACE); + probe_event_enable(&tp->call); } if (warn) @@ -2068,7 +1938,7 @@ static __init int kprobe_trace_self_tests_init(void) } end: - release_all_trace_probes(); + cleanup_all_probes(); if (warn) pr_cont("NG: Some tests are failed. Please check them.\n"); else diff --git a/trunk/kernel/trace/trace_output.c b/trunk/kernel/trace/trace_output.c index 51999309a6cf..e37de492a9e1 100644 --- a/trunk/kernel/trace/trace_output.c +++ b/trunk/kernel/trace/trace_output.c @@ -1107,20 +1107,19 @@ static enum print_line_t trace_stack_print(struct trace_iterator *iter, { struct stack_entry *field; struct trace_seq *s = &iter->seq; - unsigned long *p; - unsigned long *end; + int i; trace_assign_type(field, iter->ent); - end = (unsigned long *)((long)iter->ent + iter->ent_size); if (!trace_seq_puts(s, "\n")) goto partial; - - for (p = field->caller; p && *p != ULONG_MAX && p < end; p++) { + for (i = 0; i < FTRACE_STACK_ENTRIES; i++) { + if (!field->caller[i] || (field->caller[i] == ULONG_MAX)) + break; if (!trace_seq_puts(s, " => ")) goto partial; - if (!seq_print_ip_sym(s, *p, flags)) + if (!seq_print_ip_sym(s, field->caller[i], flags)) goto partial; if (!trace_seq_puts(s, "\n")) goto partial; diff --git a/trunk/kernel/trace/trace_sched_wakeup.c b/trunk/kernel/trace/trace_sched_wakeup.c index e4a70c0c71b6..f029dd4fd2ca 100644 --- a/trunk/kernel/trace/trace_sched_wakeup.c +++ b/trunk/kernel/trace/trace_sched_wakeup.c @@ -227,9 +227,7 @@ static void wakeup_trace_close(struct trace_iterator *iter) graph_trace_close(iter); } -#define GRAPH_TRACER_FLAGS (TRACE_GRAPH_PRINT_PROC | \ - TRACE_GRAPH_PRINT_ABS_TIME | \ - TRACE_GRAPH_PRINT_DURATION) +#define GRAPH_TRACER_FLAGS (TRACE_GRAPH_PRINT_PROC) static enum print_line_t wakeup_print_line(struct trace_iterator *iter) { diff --git a/trunk/kernel/trace/trace_stack.c b/trunk/kernel/trace/trace_stack.c index 77575b386d97..b0b53b8e4c25 100644 --- a/trunk/kernel/trace/trace_stack.c +++ b/trunk/kernel/trace/trace_stack.c @@ -156,11 +156,20 @@ stack_max_size_write(struct file *filp, const char __user *ubuf, { long *ptr = filp->private_data; unsigned long val, flags; + char buf[64]; int ret; int cpu; - ret = kstrtoul_from_user(ubuf, count, 10, &val); - if (ret) + if (count >= sizeof(buf)) + return -EINVAL; + + if (copy_from_user(&buf, ubuf, count)) + return -EFAULT; + + buf[count] = 0; + + ret = strict_strtoul(buf, 10, &val); + if (ret < 0) return ret; local_irq_save(flags); diff --git a/trunk/kernel/watchdog.c b/trunk/kernel/watchdog.c index 36491cd5b7d4..3d0c56ad4792 100644 --- a/trunk/kernel/watchdog.c +++ b/trunk/kernel/watchdog.c @@ -200,7 +200,6 @@ static int is_softlockup(unsigned long touch_ts) } #ifdef CONFIG_HARDLOCKUP_DETECTOR - static struct perf_event_attr wd_hw_attr = { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES, @@ -210,7 +209,7 @@ static struct perf_event_attr wd_hw_attr = { }; /* Callback function for perf event subsystem */ -static void watchdog_overflow_callback(struct perf_event *event, +static void watchdog_overflow_callback(struct perf_event *event, int nmi, struct perf_sample_data *data, struct pt_regs *regs) { @@ -369,11 +368,10 @@ static int watchdog_nmi_enable(int cpu) if (event != NULL) goto out_enable; + /* Try to register using hardware perf events */ wd_attr = &wd_hw_attr; wd_attr->sample_period = hw_nmi_get_sample_period(watchdog_thresh); - - /* Try to register using hardware perf events */ - event = perf_event_create_kernel_counter(wd_attr, cpu, NULL, watchdog_overflow_callback, NULL); + event = perf_event_create_kernel_counter(wd_attr, cpu, NULL, watchdog_overflow_callback); if (!IS_ERR(event)) { printk(KERN_INFO "NMI watchdog enabled, takes one hw-pmu counter.\n"); goto out_save; diff --git a/trunk/lib/Kconfig.debug b/trunk/lib/Kconfig.debug index c0cb9c4bc46d..dd373c8ee943 100644 --- a/trunk/lib/Kconfig.debug +++ b/trunk/lib/Kconfig.debug @@ -227,7 +227,7 @@ config BOOTPARAM_SOFTLOCKUP_PANIC_VALUE config DETECT_HUNG_TASK bool "Detect Hung Tasks" depends on DEBUG_KERNEL - default LOCKUP_DETECTOR + default DETECT_SOFTLOCKUP help Say Y here to enable the kernel to detect "hung tasks", which are bugs that cause the task to be stuck in @@ -648,15 +648,12 @@ config TRACE_IRQFLAGS Enables hooks to interrupt enabling and disabling for either tracing or lock debugging. -config DEBUG_ATOMIC_SLEEP - bool "Sleep inside atomic section checking" - select PREEMPT_COUNT +config DEBUG_SPINLOCK_SLEEP + bool "Spinlock debugging: sleep-inside-spinlock checking" depends on DEBUG_KERNEL help If you say Y here, various routines which may sleep will become very - noisy if they are called inside atomic sections: when a spinlock is - held, inside an rcu read side critical section, inside preempt disabled - sections, inside an interrupt, etc... + noisy if they are called with a spinlock held. config DEBUG_LOCKING_API_SELFTESTS bool "Locking API boot-time self-tests" @@ -869,7 +866,7 @@ config BOOT_PRINTK_DELAY system, and then set "lpj=M" before setting "boot_delay=N". NOTE: Using this option may adversely affect SMP systems. I.e., processors other than the first one may not boot up. - BOOT_PRINTK_DELAY also may cause LOCKUP_DETECTOR to detect + BOOT_PRINTK_DELAY also may cause DETECT_SOFTLOCKUP to detect what it believes to be lockup conditions. config RCU_TORTURE_TEST diff --git a/trunk/lib/iomap.c b/trunk/lib/iomap.c index 5dbcb4b2d864..d32229385151 100644 --- a/trunk/lib/iomap.c +++ b/trunk/lib/iomap.c @@ -224,7 +224,6 @@ EXPORT_SYMBOL(iowrite8_rep); EXPORT_SYMBOL(iowrite16_rep); EXPORT_SYMBOL(iowrite32_rep); -#ifdef CONFIG_HAS_IOPORT /* Create a virtual mapping cookie for an IO port range */ void __iomem *ioport_map(unsigned long port, unsigned int nr) { @@ -239,9 +238,7 @@ void ioport_unmap(void __iomem *addr) } EXPORT_SYMBOL(ioport_map); EXPORT_SYMBOL(ioport_unmap); -#endif /* CONFIG_HAS_IOPORT */ -#ifdef CONFIG_PCI /** * pci_iomap - create a virtual mapping cookie for a PCI BAR * @dev: PCI device that owns the BAR @@ -283,4 +280,3 @@ void pci_iounmap(struct pci_dev *dev, void __iomem * addr) } EXPORT_SYMBOL(pci_iomap); EXPORT_SYMBOL(pci_iounmap); -#endif /* CONFIG_PCI */ diff --git a/trunk/lib/plist.c b/trunk/lib/plist.c index a0a4da489c22..0ae7e6431726 100644 --- a/trunk/lib/plist.c +++ b/trunk/lib/plist.c @@ -56,6 +56,11 @@ static void plist_check_list(struct list_head *top) static void plist_check_head(struct plist_head *head) { + WARN_ON(head != &test_head && !head->rawlock && !head->spinlock); + if (head->rawlock) + WARN_ON_SMP(!raw_spin_is_locked(head->rawlock)); + if (head->spinlock) + WARN_ON_SMP(!spin_is_locked(head->spinlock)); if (!plist_head_empty(head)) plist_check_list(&plist_first(head)->prio_list); plist_check_list(&head->node_list); @@ -175,7 +180,7 @@ static int __init plist_test(void) unsigned int r = local_clock(); printk(KERN_INFO "start plist test\n"); - plist_head_init(&test_head); + plist_head_init(&test_head, NULL); for (i = 0; i < ARRAY_SIZE(test_node); i++) plist_node_init(test_node + i, 0); diff --git a/trunk/lib/xz/xz_private.h b/trunk/lib/xz/xz_private.h index 482b90f363fe..a65633e06962 100644 --- a/trunk/lib/xz/xz_private.h +++ b/trunk/lib/xz/xz_private.h @@ -12,7 +12,7 @@ #ifdef __KERNEL__ # include -# include +# include # include /* XZ_PREBOOT may be defined only via decompress_unxz.c. */ # ifndef XZ_PREBOOT diff --git a/trunk/mm/filemap.c b/trunk/mm/filemap.c index f820e600f1ad..a8251a8d3457 100644 --- a/trunk/mm/filemap.c +++ b/trunk/mm/filemap.c @@ -78,6 +78,9 @@ * ->i_mutex (generic_file_buffered_write) * ->mmap_sem (fault_in_pages_readable->do_page_fault) * + * ->i_mutex + * ->i_alloc_sem (various) + * * inode_wb_list_lock * sb_lock (fs/fs-writeback.c) * ->mapping->tree_lock (__sync_single_inode) diff --git a/trunk/mm/madvise.c b/trunk/mm/madvise.c index 74bf193eff04..2221491ed503 100644 --- a/trunk/mm/madvise.c +++ b/trunk/mm/madvise.c @@ -218,7 +218,7 @@ static long madvise_remove(struct vm_area_struct *vma, endoff = (loff_t)(end - vma->vm_start - 1) + ((loff_t)vma->vm_pgoff << PAGE_SHIFT); - /* vmtruncate_range needs to take i_mutex */ + /* vmtruncate_range needs to take i_mutex and i_alloc_sem */ up_read(¤t->mm->mmap_sem); error = vmtruncate_range(mapping->host, offset, endoff); down_read(¤t->mm->mmap_sem); diff --git a/trunk/mm/page_alloc.c b/trunk/mm/page_alloc.c index 9119faae6e6a..4e8985acdab8 100644 --- a/trunk/mm/page_alloc.c +++ b/trunk/mm/page_alloc.c @@ -4585,60 +4585,6 @@ void __init sort_node_map(void) cmp_node_active_region, NULL); } -/** - * node_map_pfn_alignment - determine the maximum internode alignment - * - * This function should be called after node map is populated and sorted. - * It calculates the maximum power of two alignment which can distinguish - * all the nodes. - * - * For example, if all nodes are 1GiB and aligned to 1GiB, the return value - * would indicate 1GiB alignment with (1 << (30 - PAGE_SHIFT)). If the - * nodes are shifted by 256MiB, 256MiB. Note that if only the last node is - * shifted, 1GiB is enough and this function will indicate so. - * - * This is used to test whether pfn -> nid mapping of the chosen memory - * model has fine enough granularity to avoid incorrect mapping for the - * populated node map. - * - * Returns the determined alignment in pfn's. 0 if there is no alignment - * requirement (single node). - */ -unsigned long __init node_map_pfn_alignment(void) -{ - unsigned long accl_mask = 0, last_end = 0; - int last_nid = -1; - int i; - - for_each_active_range_index_in_nid(i, MAX_NUMNODES) { - int nid = early_node_map[i].nid; - unsigned long start = early_node_map[i].start_pfn; - unsigned long end = early_node_map[i].end_pfn; - unsigned long mask; - - if (!start || last_nid < 0 || last_nid == nid) { - last_nid = nid; - last_end = end; - continue; - } - - /* - * Start with a mask granular enough to pin-point to the - * start pfn and tick off bits one-by-one until it becomes - * too coarse to separate the current node from the last. - */ - mask = ~((1 << __ffs(start)) - 1); - while (mask && last_end <= (start & (mask << 1))) - mask <<= 1; - - /* accumulate all internode masks */ - accl_mask |= mask; - } - - /* convert mask to number of pages */ - return ~accl_mask + 1; -} - /* Find the lowest pfn for a node */ static unsigned long __init find_min_pfn_for_node(int nid) { diff --git a/trunk/mm/rmap.c b/trunk/mm/rmap.c index 9701574bb67a..23295f65ae43 100644 --- a/trunk/mm/rmap.c +++ b/trunk/mm/rmap.c @@ -21,6 +21,7 @@ * Lock ordering in mm: * * inode->i_mutex (while writing or truncating, not reading or faulting) + * inode->i_alloc_sem (vmtruncate_range) * mm->mmap_sem * page->flags PG_locked (lock_page) * mapping->i_mmap_mutex @@ -869,11 +870,11 @@ int page_referenced(struct page *page, vm_flags); if (we_locked) unlock_page(page); - - if (page_test_and_clear_young(page_to_pfn(page))) - referenced++; } out: + if (page_test_and_clear_young(page_to_pfn(page))) + referenced++; + return referenced; } diff --git a/trunk/mm/swapfile.c b/trunk/mm/swapfile.c index 1b8c33907242..ff8dc1a18cb4 100644 --- a/trunk/mm/swapfile.c +++ b/trunk/mm/swapfile.c @@ -1681,14 +1681,19 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) } #ifdef CONFIG_PROC_FS +struct proc_swaps { + struct seq_file seq; + int event; +}; + static unsigned swaps_poll(struct file *file, poll_table *wait) { - struct seq_file *seq = file->private_data; + struct proc_swaps *s = file->private_data; poll_wait(file, &proc_poll_wait, wait); - if (seq->poll_event != atomic_read(&proc_poll_event)) { - seq->poll_event = atomic_read(&proc_poll_event); + if (s->event != atomic_read(&proc_poll_event)) { + s->event = atomic_read(&proc_poll_event); return POLLIN | POLLRDNORM | POLLERR | POLLPRI; } @@ -1778,16 +1783,24 @@ static const struct seq_operations swaps_op = { static int swaps_open(struct inode *inode, struct file *file) { - struct seq_file *seq; + struct proc_swaps *s; int ret; + s = kmalloc(sizeof(struct proc_swaps), GFP_KERNEL); + if (!s) + return -ENOMEM; + + file->private_data = s; + ret = seq_open(file, &swaps_op); - if (ret) + if (ret) { + kfree(s); return ret; + } - seq = file->private_data; - seq->poll_event = atomic_read(&proc_poll_event); - return 0; + s->seq.private = s; + s->event = atomic_read(&proc_poll_event); + return ret; } static const struct file_operations proc_swaps_operations = { diff --git a/trunk/mm/truncate.c b/trunk/mm/truncate.c index 003c6c685fc8..e13f22efaad7 100644 --- a/trunk/mm/truncate.c +++ b/trunk/mm/truncate.c @@ -622,11 +622,12 @@ int vmtruncate_range(struct inode *inode, loff_t offset, loff_t end) return -ENOSYS; mutex_lock(&inode->i_mutex); - inode_dio_wait(inode); + down_write(&inode->i_alloc_sem); unmap_mapping_range(mapping, offset, (end - offset), 1); inode->i_op->truncate_range(inode, offset, end); /* unmap again to remove racily COWed private pages */ unmap_mapping_range(mapping, offset, (end - offset), 1); + up_write(&inode->i_alloc_sem); mutex_unlock(&inode->i_mutex); return 0; diff --git a/trunk/mm/vmalloc.c b/trunk/mm/vmalloc.c index ab8494cde007..1d34d75366a7 100644 --- a/trunk/mm/vmalloc.c +++ b/trunk/mm/vmalloc.c @@ -452,6 +452,13 @@ static struct vmap_area *alloc_vmap_area(unsigned long size, return ERR_PTR(-EBUSY); } +static void rcu_free_va(struct rcu_head *head) +{ + struct vmap_area *va = container_of(head, struct vmap_area, rcu_head); + + kfree(va); +} + static void __free_vmap_area(struct vmap_area *va) { BUG_ON(RB_EMPTY_NODE(&va->rb_node)); @@ -484,7 +491,7 @@ static void __free_vmap_area(struct vmap_area *va) if (va->va_end > VMALLOC_START && va->va_end <= VMALLOC_END) vmap_area_pcpu_hole = max(vmap_area_pcpu_hole, va->va_end); - kfree_rcu(va, rcu_head); + call_rcu(&va->rcu_head, rcu_free_va); } /* @@ -830,6 +837,13 @@ static struct vmap_block *new_vmap_block(gfp_t gfp_mask) return vb; } +static void rcu_free_vb(struct rcu_head *head) +{ + struct vmap_block *vb = container_of(head, struct vmap_block, rcu_head); + + kfree(vb); +} + static void free_vmap_block(struct vmap_block *vb) { struct vmap_block *tmp; @@ -842,7 +856,7 @@ static void free_vmap_block(struct vmap_block *vb) BUG_ON(tmp != vb); free_vmap_area_noflush(vb->va); - kfree_rcu(vb, rcu_head); + call_rcu(&vb->rcu_head, rcu_free_vb); } static void purge_fragmented_blocks(int cpu) diff --git a/trunk/mm/vmscan.c b/trunk/mm/vmscan.c index febbc044e792..d036e59d302b 100644 --- a/trunk/mm/vmscan.c +++ b/trunk/mm/vmscan.c @@ -250,90 +250,49 @@ unsigned long shrink_slab(struct shrink_control *shrink, unsigned long long delta; unsigned long total_scan; unsigned long max_pass; - int shrink_ret = 0; - long nr; - long new_nr; - long batch_size = shrinker->batch ? shrinker->batch - : SHRINK_BATCH; - /* - * copy the current shrinker scan count into a local variable - * and zero it so that other concurrent shrinker invocations - * don't also do this scanning work. - */ - do { - nr = shrinker->nr; - } while (cmpxchg(&shrinker->nr, nr, 0) != nr); - - total_scan = nr; max_pass = do_shrinker_shrink(shrinker, shrink, 0); delta = (4 * nr_pages_scanned) / shrinker->seeks; delta *= max_pass; do_div(delta, lru_pages + 1); - total_scan += delta; - if (total_scan < 0) { + shrinker->nr += delta; + if (shrinker->nr < 0) { printk(KERN_ERR "shrink_slab: %pF negative objects to " "delete nr=%ld\n", - shrinker->shrink, total_scan); - total_scan = max_pass; + shrinker->shrink, shrinker->nr); + shrinker->nr = max_pass; } - /* - * We need to avoid excessive windup on filesystem shrinkers - * due to large numbers of GFP_NOFS allocations causing the - * shrinkers to return -1 all the time. This results in a large - * nr being built up so when a shrink that can do some work - * comes along it empties the entire cache due to nr >>> - * max_pass. This is bad for sustaining a working set in - * memory. - * - * Hence only allow the shrinker to scan the entire cache when - * a large delta change is calculated directly. - */ - if (delta < max_pass / 4) - total_scan = min(total_scan, max_pass / 2); - /* * Avoid risking looping forever due to too large nr value: * never try to free more than twice the estimate number of * freeable entries. */ - if (total_scan > max_pass * 2) - total_scan = max_pass * 2; + if (shrinker->nr > max_pass * 2) + shrinker->nr = max_pass * 2; - trace_mm_shrink_slab_start(shrinker, shrink, nr, - nr_pages_scanned, lru_pages, - max_pass, delta, total_scan); + total_scan = shrinker->nr; + shrinker->nr = 0; - while (total_scan >= batch_size) { + while (total_scan >= SHRINK_BATCH) { + long this_scan = SHRINK_BATCH; + int shrink_ret; int nr_before; nr_before = do_shrinker_shrink(shrinker, shrink, 0); shrink_ret = do_shrinker_shrink(shrinker, shrink, - batch_size); + this_scan); if (shrink_ret == -1) break; if (shrink_ret < nr_before) ret += nr_before - shrink_ret; - count_vm_events(SLABS_SCANNED, batch_size); - total_scan -= batch_size; + count_vm_events(SLABS_SCANNED, this_scan); + total_scan -= this_scan; cond_resched(); } - /* - * move the unused scan count back into the shrinker in a - * manner that handles concurrent updates. If we exhausted the - * scan, there is no need to do an update. - */ - do { - nr = shrinker->nr; - new_nr = total_scan + nr; - if (total_scan <= 0) - break; - } while (cmpxchg(&shrinker->nr, nr, new_nr) != nr); - - trace_mm_shrink_slab_end(shrinker, shrink_ret, nr, new_nr); + shrinker->nr += total_scan; } up_read(&shrinker_rwsem); out: diff --git a/trunk/net/9p/client.c b/trunk/net/9p/client.c index 0505a03c374c..9e3b0e640da1 100644 --- a/trunk/net/9p/client.c +++ b/trunk/net/9p/client.c @@ -72,22 +72,23 @@ inline int p9_is_proto_dotu(struct p9_client *clnt) EXPORT_SYMBOL(p9_is_proto_dotu); /* Interpret mount option for protocol version */ -static int get_protocol_version(char *s) +static int get_protocol_version(const substring_t *name) { int version = -EINVAL; - if (!strcmp(s, "9p2000")) { + if (!strncmp("9p2000", name->from, name->to-name->from)) { version = p9_proto_legacy; P9_DPRINTK(P9_DEBUG_9P, "Protocol version: Legacy\n"); - } else if (!strcmp(s, "9p2000.u")) { + } else if (!strncmp("9p2000.u", name->from, name->to-name->from)) { version = p9_proto_2000u; P9_DPRINTK(P9_DEBUG_9P, "Protocol version: 9P2000.u\n"); - } else if (!strcmp(s, "9p2000.L")) { + } else if (!strncmp("9p2000.L", name->from, name->to-name->from)) { version = p9_proto_2000L; P9_DPRINTK(P9_DEBUG_9P, "Protocol version: 9P2000.L\n"); - } else - printk(KERN_INFO "9p: Unknown protocol version %s.\n", s); - + } else { + P9_DPRINTK(P9_DEBUG_ERROR, "Unknown protocol version %s. ", + name->from); + } return version; } @@ -105,7 +106,6 @@ static int parse_opts(char *opts, struct p9_client *clnt) char *p; substring_t args[MAX_OPT_ARGS]; int option; - char *s; int ret = 0; clnt->proto_version = p9_proto_2000u; @@ -141,41 +141,22 @@ static int parse_opts(char *opts, struct p9_client *clnt) clnt->msize = option; break; case Opt_trans: - s = match_strdup(&args[0]); - if (!s) { - ret = -ENOMEM; + clnt->trans_mod = v9fs_get_trans_by_name(&args[0]); + if(clnt->trans_mod == NULL) { P9_DPRINTK(P9_DEBUG_ERROR, - "problem allocating copy of trans arg\n"); - goto free_and_return; - } - clnt->trans_mod = v9fs_get_trans_by_name(s); - if (clnt->trans_mod == NULL) { - printk(KERN_INFO - "9p: Could not find " - "request transport: %s\n", s); + "Could not find request transport: %s\n", + (char *) &args[0]); ret = -EINVAL; - kfree(s); goto free_and_return; } - kfree(s); break; case Opt_legacy: clnt->proto_version = p9_proto_legacy; break; case Opt_version: - s = match_strdup(&args[0]); - if (!s) { - ret = -ENOMEM; - P9_DPRINTK(P9_DEBUG_ERROR, - "problem allocating copy of version arg\n"); + ret = get_protocol_version(&args[0]); + if (ret == -EINVAL) goto free_and_return; - } - ret = get_protocol_version(s); - if (ret == -EINVAL) { - kfree(s); - goto free_and_return; - } - kfree(s); clnt->proto_version = ret; break; default: @@ -299,8 +280,7 @@ struct p9_req_t *p9_tag_lookup(struct p9_client *c, u16 tag) * buffer to read the data into */ tag++; - if(tag >= c->max_tag) - return NULL; + BUG_ON(tag >= c->max_tag); row = tag / P9_ROW_MAXTAG; col = tag % P9_ROW_MAXTAG; @@ -769,7 +749,7 @@ static int p9_client_version(struct p9_client *c) err = p9pdu_readf(req->rc, c->proto_version, "ds", &msize, &version); if (err) { P9_DPRINTK(P9_DEBUG_9P, "version error %d\n", err); - P9_DUMP_PKT(1, req->rc); + p9pdu_dump(1, req->rc); goto error; } @@ -841,8 +821,8 @@ struct p9_client *p9_client_create(const char *dev_name, char *options) if (err) goto destroy_fidpool; - if (clnt->msize > clnt->trans_mod->maxsize) - clnt->msize = clnt->trans_mod->maxsize; + if ((clnt->msize+P9_IOHDRSZ) > clnt->trans_mod->maxsize) + clnt->msize = clnt->trans_mod->maxsize-P9_IOHDRSZ; err = p9_client_version(clnt); if (err) @@ -931,7 +911,7 @@ struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, err = p9pdu_readf(req->rc, clnt->proto_version, "Q", &qid); if (err) { - P9_DUMP_PKT(1, req->rc); + p9pdu_dump(1, req->rc); p9_free_req(clnt, req); goto error; } @@ -991,7 +971,7 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, uint16_t nwname, err = p9pdu_readf(req->rc, clnt->proto_version, "R", &nwqids, &wqids); if (err) { - P9_DUMP_PKT(1, req->rc); + p9pdu_dump(1, req->rc); p9_free_req(clnt, req); goto clunk_fid; } @@ -1058,7 +1038,7 @@ int p9_client_open(struct p9_fid *fid, int mode) err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", &qid, &iounit); if (err) { - P9_DUMP_PKT(1, req->rc); + p9pdu_dump(1, req->rc); goto free_and_error; } @@ -1101,7 +1081,7 @@ int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode, err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", qid, &iounit); if (err) { - P9_DUMP_PKT(1, req->rc); + p9pdu_dump(1, req->rc); goto free_and_error; } @@ -1146,7 +1126,7 @@ int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode, err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", &qid, &iounit); if (err) { - P9_DUMP_PKT(1, req->rc); + p9pdu_dump(1, req->rc); goto free_and_error; } @@ -1185,7 +1165,7 @@ int p9_client_symlink(struct p9_fid *dfid, char *name, char *symtgt, gid_t gid, err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid); if (err) { - P9_DUMP_PKT(1, req->rc); + p9pdu_dump(1, req->rc); goto free_and_error; } @@ -1269,11 +1249,9 @@ int p9_client_clunk(struct p9_fid *fid) P9_DPRINTK(P9_DEBUG_9P, "<<< RCLUNK fid %d\n", fid->fid); p9_free_req(clnt, req); -error: - /* - * Fid is not valid even after a failed clunk - */ p9_fid_destroy(fid); + +error: return err; } EXPORT_SYMBOL(p9_client_clunk); @@ -1303,29 +1281,6 @@ int p9_client_remove(struct p9_fid *fid) } EXPORT_SYMBOL(p9_client_remove); -int p9_client_unlinkat(struct p9_fid *dfid, const char *name, int flags) -{ - int err = 0; - struct p9_req_t *req; - struct p9_client *clnt; - - P9_DPRINTK(P9_DEBUG_9P, ">>> TUNLINKAT fid %d %s %d\n", - dfid->fid, name, flags); - - clnt = dfid->clnt; - req = p9_client_rpc(clnt, P9_TUNLINKAT, "dsd", dfid->fid, name, flags); - if (IS_ERR(req)) { - err = PTR_ERR(req); - goto error; - } - P9_DPRINTK(P9_DEBUG_9P, "<<< RUNLINKAT fid %d %s\n", dfid->fid, name); - - p9_free_req(clnt, req); -error: - return err; -} -EXPORT_SYMBOL(p9_client_unlinkat); - int p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, u32 count) @@ -1363,12 +1318,11 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, err = p9pdu_readf(req->rc, clnt->proto_version, "D", &count, &dataptr); if (err) { - P9_DUMP_PKT(1, req->rc); + p9pdu_dump(1, req->rc); goto free_and_error; } P9_DPRINTK(P9_DEBUG_9P, "<<< RREAD count %d\n", count); - P9_DUMP_PKT(1, req->rc); if (!req->tc->pbuf_size) { if (data) { @@ -1432,7 +1386,7 @@ p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, err = p9pdu_readf(req->rc, clnt->proto_version, "d", &count); if (err) { - P9_DUMP_PKT(1, req->rc); + p9pdu_dump(1, req->rc); goto free_and_error; } @@ -1472,7 +1426,7 @@ struct p9_wstat *p9_client_stat(struct p9_fid *fid) err = p9pdu_readf(req->rc, clnt->proto_version, "wS", &ignored, ret); if (err) { - P9_DUMP_PKT(1, req->rc); + p9pdu_dump(1, req->rc); p9_free_req(clnt, req); goto error; } @@ -1523,7 +1477,7 @@ struct p9_stat_dotl *p9_client_getattr_dotl(struct p9_fid *fid, err = p9pdu_readf(req->rc, clnt->proto_version, "A", ret); if (err) { - P9_DUMP_PKT(1, req->rc); + p9pdu_dump(1, req->rc); p9_free_req(clnt, req); goto error; } @@ -1671,7 +1625,7 @@ int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb) &sb->bsize, &sb->blocks, &sb->bfree, &sb->bavail, &sb->files, &sb->ffree, &sb->fsid, &sb->namelen); if (err) { - P9_DUMP_PKT(1, req->rc); + p9pdu_dump(1, req->rc); p9_free_req(clnt, req); goto error; } @@ -1689,8 +1643,7 @@ int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb) } EXPORT_SYMBOL(p9_client_statfs); -int p9_client_rename(struct p9_fid *fid, - struct p9_fid *newdirfid, const char *name) +int p9_client_rename(struct p9_fid *fid, struct p9_fid *newdirfid, char *name) { int err; struct p9_req_t *req; @@ -1717,36 +1670,6 @@ int p9_client_rename(struct p9_fid *fid, } EXPORT_SYMBOL(p9_client_rename); -int p9_client_renameat(struct p9_fid *olddirfid, const char *old_name, - struct p9_fid *newdirfid, const char *new_name) -{ - int err; - struct p9_req_t *req; - struct p9_client *clnt; - - err = 0; - clnt = olddirfid->clnt; - - P9_DPRINTK(P9_DEBUG_9P, ">>> TRENAMEAT olddirfid %d old name %s" - " newdirfid %d new name %s\n", olddirfid->fid, old_name, - newdirfid->fid, new_name); - - req = p9_client_rpc(clnt, P9_TRENAMEAT, "dsds", olddirfid->fid, - old_name, newdirfid->fid, new_name); - if (IS_ERR(req)) { - err = PTR_ERR(req); - goto error; - } - - P9_DPRINTK(P9_DEBUG_9P, "<<< RRENAMEAT newdirfid %d new name %s\n", - newdirfid->fid, new_name); - - p9_free_req(clnt, req); -error: - return err; -} -EXPORT_SYMBOL(p9_client_renameat); - /* * An xattrwalk without @attr_name gives the fid for the lisxattr namespace */ @@ -1778,7 +1701,7 @@ struct p9_fid *p9_client_xattrwalk(struct p9_fid *file_fid, } err = p9pdu_readf(req->rc, clnt->proto_version, "q", attr_size); if (err) { - P9_DUMP_PKT(1, req->rc); + p9pdu_dump(1, req->rc); p9_free_req(clnt, req); goto clunk_fid; } @@ -1857,7 +1780,7 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) err = p9pdu_readf(req->rc, clnt->proto_version, "D", &count, &dataptr); if (err) { - P9_DUMP_PKT(1, req->rc); + p9pdu_dump(1, req->rc); goto free_and_error; } @@ -1894,7 +1817,7 @@ int p9_client_mknod_dotl(struct p9_fid *fid, char *name, int mode, err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid); if (err) { - P9_DUMP_PKT(1, req->rc); + p9pdu_dump(1, req->rc); goto error; } P9_DPRINTK(P9_DEBUG_9P, "<<< RMKNOD qid %x.%llx.%x\n", qid->type, @@ -1925,7 +1848,7 @@ int p9_client_mkdir_dotl(struct p9_fid *fid, char *name, int mode, err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid); if (err) { - P9_DUMP_PKT(1, req->rc); + p9pdu_dump(1, req->rc); goto error; } P9_DPRINTK(P9_DEBUG_9P, "<<< RMKDIR qid %x.%llx.%x\n", qid->type, @@ -1960,7 +1883,7 @@ int p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status) err = p9pdu_readf(req->rc, clnt->proto_version, "b", status); if (err) { - P9_DUMP_PKT(1, req->rc); + p9pdu_dump(1, req->rc); goto error; } P9_DPRINTK(P9_DEBUG_9P, "<<< RLOCK status %i\n", *status); @@ -1993,7 +1916,7 @@ int p9_client_getlock_dotl(struct p9_fid *fid, struct p9_getlock *glock) &glock->start, &glock->length, &glock->proc_id, &glock->client_id); if (err) { - P9_DUMP_PKT(1, req->rc); + p9pdu_dump(1, req->rc); goto error; } P9_DPRINTK(P9_DEBUG_9P, "<<< RGETLOCK type %i start %lld length %lld " @@ -2021,7 +1944,7 @@ int p9_client_readlink(struct p9_fid *fid, char **target) err = p9pdu_readf(req->rc, clnt->proto_version, "s", target); if (err) { - P9_DUMP_PKT(1, req->rc); + p9pdu_dump(1, req->rc); goto error; } P9_DPRINTK(P9_DEBUG_9P, "<<< RREADLINK target %s\n", *target); diff --git a/trunk/net/9p/mod.c b/trunk/net/9p/mod.c index 2664d1292291..72c398275051 100644 --- a/trunk/net/9p/mod.c +++ b/trunk/net/9p/mod.c @@ -80,14 +80,14 @@ EXPORT_SYMBOL(v9fs_unregister_trans); * @name: string identifying transport * */ -struct p9_trans_module *v9fs_get_trans_by_name(char *s) +struct p9_trans_module *v9fs_get_trans_by_name(const substring_t *name) { struct p9_trans_module *t, *found = NULL; spin_lock(&v9fs_trans_lock); list_for_each_entry(t, &v9fs_trans_list, list) - if (strcmp(t->name, s) == 0 && + if (strncmp(t->name, name->from, name->to-name->from) == 0 && try_module_get(t->owner)) { found = t; break; diff --git a/trunk/net/9p/protocol.c b/trunk/net/9p/protocol.c index df58375ea6b3..a873277cb996 100644 --- a/trunk/net/9p/protocol.c +++ b/trunk/net/9p/protocol.c @@ -44,24 +44,30 @@ p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...); void p9pdu_dump(int way, struct p9_fcall *pdu) { - int len = pdu->size; - - if ((p9_debug_level & P9_DEBUG_VPKT) != P9_DEBUG_VPKT) { - if ((p9_debug_level & P9_DEBUG_PKT) == P9_DEBUG_PKT) { - if (len > 32) - len = 32; - } else { - /* shouldn't happen */ - return; - } + int i, n; + u8 *data = pdu->sdata; + int datalen = pdu->size; + char buf[255]; + int buflen = 255; + + i = n = 0; + if (datalen > (buflen-16)) + datalen = buflen-16; + while (i < datalen) { + n += scnprintf(buf + n, buflen - n, "%02x ", data[i]); + if (i%4 == 3) + n += scnprintf(buf + n, buflen - n, " "); + if (i%32 == 31) + n += scnprintf(buf + n, buflen - n, "\n"); + + i++; } + n += scnprintf(buf + n, buflen - n, "\n"); if (way) - print_hex_dump_bytes("[9P] ", DUMP_PREFIX_OFFSET, pdu->sdata, - len); + P9_DPRINTK(P9_DEBUG_PKT, "[[[(%d) %s\n", datalen, buf); else - print_hex_dump_bytes("]9P[ ", DUMP_PREFIX_OFFSET, pdu->sdata, - len); + P9_DPRINTK(P9_DEBUG_PKT, "]]](%d) %s\n", datalen, buf); } #else void @@ -604,7 +610,7 @@ int p9stat_read(char *buf, int len, struct p9_wstat *st, int proto_version) ret = p9pdu_readf(&fake_pdu, proto_version, "S", st); if (ret) { P9_DPRINTK(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret); - P9_DUMP_PKT(0, &fake_pdu); + p9pdu_dump(1, &fake_pdu); } return ret; @@ -626,7 +632,11 @@ int p9pdu_finalize(struct p9_fcall *pdu) err = p9pdu_writef(pdu, 0, "d", size); pdu->size = size; - P9_DUMP_PKT(0, pdu); +#ifdef CONFIG_NET_9P_DEBUG + if ((p9_debug_level & P9_DEBUG_PKT) == P9_DEBUG_PKT) + p9pdu_dump(0, pdu); +#endif + P9_DPRINTK(P9_DEBUG_9P, ">>> size=%d type: %d tag: %d\n", pdu->size, pdu->id, pdu->tag); @@ -659,7 +669,7 @@ int p9dirent_read(char *buf, int len, struct p9_dirent *dirent, &dirent->d_off, &dirent->d_type, &nameptr); if (ret) { P9_DPRINTK(P9_DEBUG_9P, "<<< p9dirent_read failed: %d\n", ret); - P9_DUMP_PKT(1, &fake_pdu); + p9pdu_dump(1, &fake_pdu); goto out; } diff --git a/trunk/net/9p/trans_virtio.c b/trunk/net/9p/trans_virtio.c index 175b5135bdcf..244e70742183 100644 --- a/trunk/net/9p/trans_virtio.c +++ b/trunk/net/9p/trans_virtio.c @@ -367,7 +367,7 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req) in += inp; } else { in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM, rdata, - req->rc->capacity); + client->msize); } err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc); @@ -592,7 +592,7 @@ static struct p9_trans_module p9_virtio_trans = { .close = p9_virtio_close, .request = p9_virtio_request, .cancel = p9_virtio_cancel, - .maxsize = PAGE_SIZE*VIRTQUEUE_NUM, + .maxsize = PAGE_SIZE*16, .pref = P9_TRANS_PREF_PAYLOAD_SEP, .def = 0, .owner = THIS_MODULE, diff --git a/trunk/net/iucv/iucv.c b/trunk/net/iucv/iucv.c index f2b713847b45..7f9124914b13 100644 --- a/trunk/net/iucv/iucv.c +++ b/trunk/net/iucv/iucv.c @@ -1988,13 +1988,12 @@ static int __init iucv_init(void) rc = -EPROTONOSUPPORT; goto out; } - ctl_set_bit(0, 1); rc = iucv_query_maxconn(); if (rc) - goto out_ctl; + goto out; rc = register_external_interrupt(0x4000, iucv_external_interrupt); if (rc) - goto out_ctl; + goto out; iucv_root = root_device_register("iucv"); if (IS_ERR(iucv_root)) { rc = PTR_ERR(iucv_root); @@ -2056,8 +2055,6 @@ static int __init iucv_init(void) root_device_unregister(iucv_root); out_int: unregister_external_interrupt(0x4000, iucv_external_interrupt); -out_ctl: - ctl_clear_bit(0, 1); out: return rc; } diff --git a/trunk/net/netfilter/xt_RATEEST.c b/trunk/net/netfilter/xt_RATEEST.c index f264032b8c56..de079abd5bc8 100644 --- a/trunk/net/netfilter/xt_RATEEST.c +++ b/trunk/net/netfilter/xt_RATEEST.c @@ -60,6 +60,11 @@ struct xt_rateest *xt_rateest_lookup(const char *name) } EXPORT_SYMBOL_GPL(xt_rateest_lookup); +static void xt_rateest_free_rcu(struct rcu_head *head) +{ + kfree(container_of(head, struct xt_rateest, rcu)); +} + void xt_rateest_put(struct xt_rateest *est) { mutex_lock(&xt_rateest_mutex); @@ -70,7 +75,7 @@ void xt_rateest_put(struct xt_rateest *est) * gen_estimator est_timer() might access est->lock or bstats, * wait a RCU grace period before freeing 'est' */ - kfree_rcu(est, rcu); + call_rcu(&est->rcu, xt_rateest_free_rcu); } mutex_unlock(&xt_rateest_mutex); } @@ -183,6 +188,7 @@ static int __init xt_rateest_tg_init(void) static void __exit xt_rateest_tg_fini(void) { xt_unregister_target(&xt_rateest_tg_reg); + rcu_barrier(); /* Wait for completion of call_rcu()'s (xt_rateest_free_rcu) */ } diff --git a/trunk/net/sunrpc/clnt.c b/trunk/net/sunrpc/clnt.c index c50818f0473b..7389b7da3a8d 100644 --- a/trunk/net/sunrpc/clnt.c +++ b/trunk/net/sunrpc/clnt.c @@ -97,7 +97,8 @@ static int rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name) { static uint32_t clntid; - struct path path, dir; + struct nameidata nd; + struct path path; char name[15]; struct qstr q = { .name = name, @@ -112,7 +113,7 @@ rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name) path.mnt = rpc_get_mount(); if (IS_ERR(path.mnt)) return PTR_ERR(path.mnt); - error = vfs_path_lookup(path.mnt->mnt_root, path.mnt, dir_name, 0, &dir); + error = vfs_path_lookup(path.mnt->mnt_root, path.mnt, dir_name, 0, &nd); if (error) goto err; @@ -120,7 +121,7 @@ rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name) q.len = snprintf(name, sizeof(name), "clnt%x", (unsigned int)clntid++); name[sizeof(name) - 1] = '\0'; q.hash = full_name_hash(q.name, q.len); - path.dentry = rpc_create_client_dir(dir.dentry, &q, clnt); + path.dentry = rpc_create_client_dir(nd.path.dentry, &q, clnt); if (!IS_ERR(path.dentry)) break; error = PTR_ERR(path.dentry); @@ -131,11 +132,11 @@ rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name) goto err_path_put; } } - path_put(&dir); + path_put(&nd.path); clnt->cl_path = path; return 0; err_path_put: - path_put(&dir); + path_put(&nd.path); err: rpc_put_mount(); return error; diff --git a/trunk/net/unix/af_unix.c b/trunk/net/unix/af_unix.c index ec68e1c05b85..0722a25a3a33 100644 --- a/trunk/net/unix/af_unix.c +++ b/trunk/net/unix/af_unix.c @@ -808,9 +808,8 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) struct net *net = sock_net(sk); struct unix_sock *u = unix_sk(sk); struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr; - char *sun_path = sunaddr->sun_path; struct dentry *dentry = NULL; - struct path path; + struct nameidata nd; int err; unsigned hash; struct unix_address *addr; @@ -846,44 +845,48 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) addr->hash = hash ^ sk->sk_type; atomic_set(&addr->refcnt, 1); - if (sun_path[0]) { + if (sunaddr->sun_path[0]) { unsigned int mode; err = 0; /* * Get the parent directory, calculate the hash for last * component. */ - dentry = kern_path_create(AT_FDCWD, sun_path, &path, 0); + err = kern_path_parent(sunaddr->sun_path, &nd); + if (err) + goto out_mknod_parent; + + dentry = lookup_create(&nd, 0); err = PTR_ERR(dentry); if (IS_ERR(dentry)) - goto out_mknod_parent; + goto out_mknod_unlock; /* * All right, let's create it. */ mode = S_IFSOCK | (SOCK_INODE(sock)->i_mode & ~current_umask()); - err = mnt_want_write(path.mnt); + err = mnt_want_write(nd.path.mnt); if (err) goto out_mknod_dput; - err = security_path_mknod(&path, dentry, mode, 0); + err = security_path_mknod(&nd.path, dentry, mode, 0); if (err) goto out_mknod_drop_write; - err = vfs_mknod(path.dentry->d_inode, dentry, mode, 0); + err = vfs_mknod(nd.path.dentry->d_inode, dentry, mode, 0); out_mknod_drop_write: - mnt_drop_write(path.mnt); + mnt_drop_write(nd.path.mnt); if (err) goto out_mknod_dput; - mutex_unlock(&path.dentry->d_inode->i_mutex); - dput(path.dentry); - path.dentry = dentry; + mutex_unlock(&nd.path.dentry->d_inode->i_mutex); + dput(nd.path.dentry); + nd.path.dentry = dentry; addr->hash = UNIX_HASH_SIZE; } spin_lock(&unix_table_lock); - if (!sun_path[0]) { + if (!sunaddr->sun_path[0]) { err = -EADDRINUSE; if (__unix_find_socket_byname(net, sunaddr, addr_len, sk->sk_type, hash)) { @@ -894,8 +897,8 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) list = &unix_socket_table[addr->hash]; } else { list = &unix_socket_table[dentry->d_inode->i_ino & (UNIX_HASH_SIZE-1)]; - u->dentry = path.dentry; - u->mnt = path.mnt; + u->dentry = nd.path.dentry; + u->mnt = nd.path.mnt; } err = 0; @@ -912,8 +915,9 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) out_mknod_dput: dput(dentry); - mutex_unlock(&path.dentry->d_inode->i_mutex); - path_put(&path); +out_mknod_unlock: + mutex_unlock(&nd.path.dentry->d_inode->i_mutex); + path_put(&nd.path); out_mknod_parent: if (err == -EEXIST) err = -EADDRINUSE; diff --git a/trunk/samples/hw_breakpoint/data_breakpoint.c b/trunk/samples/hw_breakpoint/data_breakpoint.c index ef7f32291852..063653955f9f 100644 --- a/trunk/samples/hw_breakpoint/data_breakpoint.c +++ b/trunk/samples/hw_breakpoint/data_breakpoint.c @@ -41,7 +41,7 @@ module_param_string(ksym, ksym_name, KSYM_NAME_LEN, S_IRUGO); MODULE_PARM_DESC(ksym, "Kernel symbol to monitor; this module will report any" " write operations on the kernel symbol"); -static void sample_hbp_handler(struct perf_event *bp, +static void sample_hbp_handler(struct perf_event *bp, int nmi, struct perf_sample_data *data, struct pt_regs *regs) { @@ -60,7 +60,7 @@ static int __init hw_break_module_init(void) attr.bp_len = HW_BREAKPOINT_LEN_4; attr.bp_type = HW_BREAKPOINT_W | HW_BREAKPOINT_R; - sample_hbp = register_wide_hw_breakpoint(&attr, sample_hbp_handler, NULL); + sample_hbp = register_wide_hw_breakpoint(&attr, sample_hbp_handler); if (IS_ERR((void __force *)sample_hbp)) { ret = PTR_ERR((void __force *)sample_hbp); goto fail; diff --git a/trunk/scripts/mod/modpost.c b/trunk/scripts/mod/modpost.c index a509ff8f32fa..413c53693e62 100644 --- a/trunk/scripts/mod/modpost.c +++ b/trunk/scripts/mod/modpost.c @@ -254,28 +254,6 @@ static enum export export_no(const char *s) return export_unknown; } -static const char *sec_name(struct elf_info *elf, int secindex); - -#define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0) - -static enum export export_from_secname(struct elf_info *elf, unsigned int sec) -{ - const char *secname = sec_name(elf, sec); - - if (strstarts(secname, "___ksymtab+")) - return export_plain; - else if (strstarts(secname, "___ksymtab_unused+")) - return export_unused; - else if (strstarts(secname, "___ksymtab_gpl+")) - return export_gpl; - else if (strstarts(secname, "___ksymtab_unused_gpl+")) - return export_unused_gpl; - else if (strstarts(secname, "___ksymtab_gpl_future+")) - return export_gpl_future; - else - return export_unknown; -} - static enum export export_from_sec(struct elf_info *elf, unsigned int sec) { if (sec == elf->export_sec) @@ -585,12 +563,7 @@ static void handle_modversions(struct module *mod, struct elf_info *info, Elf_Sym *sym, const char *symname) { unsigned int crc; - enum export export; - - if (!is_vmlinux(mod->name) && strncmp(symname, "__ksymtab", 9) == 0) - export = export_from_secname(info, get_secindex(info, sym)); - else - export = export_from_sec(info, get_secindex(info, sym)); + enum export export = export_from_sec(info, get_secindex(info, sym)); switch (sym->st_shndx) { case SHN_COMMON: diff --git a/trunk/security/capability.c b/trunk/security/capability.c index 2984ea4f776f..bbb51156261b 100644 --- a/trunk/security/capability.c +++ b/trunk/security/capability.c @@ -181,7 +181,7 @@ static int cap_inode_follow_link(struct dentry *dentry, return 0; } -static int cap_inode_permission(struct inode *inode, int mask) +static int cap_inode_permission(struct inode *inode, int mask, unsigned flags) { return 0; } diff --git a/trunk/security/device_cgroup.c b/trunk/security/device_cgroup.c index 4450fbeec411..1be68269e1c2 100644 --- a/trunk/security/device_cgroup.c +++ b/trunk/security/device_cgroup.c @@ -125,6 +125,14 @@ static int dev_whitelist_add(struct dev_cgroup *dev_cgroup, return 0; } +static void whitelist_item_free(struct rcu_head *rcu) +{ + struct dev_whitelist_item *item; + + item = container_of(rcu, struct dev_whitelist_item, rcu); + kfree(item); +} + /* * called under devcgroup_mutex */ @@ -147,7 +155,7 @@ static void dev_whitelist_rm(struct dev_cgroup *dev_cgroup, walk->access &= ~wh->access; if (!walk->access) { list_del_rcu(&walk->list); - kfree_rcu(walk, rcu); + call_rcu(&walk->rcu, whitelist_item_free); } } } diff --git a/trunk/security/security.c b/trunk/security/security.c index 0e4fccfef12c..4ba6d4cc061f 100644 --- a/trunk/security/security.c +++ b/trunk/security/security.c @@ -518,7 +518,14 @@ int security_inode_permission(struct inode *inode, int mask) { if (unlikely(IS_PRIVATE(inode))) return 0; - return security_ops->inode_permission(inode, mask); + return security_ops->inode_permission(inode, mask, 0); +} + +int security_inode_exec_permission(struct inode *inode, unsigned int flags) +{ + if (unlikely(IS_PRIVATE(inode))) + return 0; + return security_ops->inode_permission(inode, MAY_EXEC, flags); } int security_inode_setattr(struct dentry *dentry, struct iattr *attr) diff --git a/trunk/security/selinux/avc.c b/trunk/security/selinux/avc.c index dca1c22d9276..d515b2128a4e 100644 --- a/trunk/security/selinux/avc.c +++ b/trunk/security/selinux/avc.c @@ -527,7 +527,7 @@ int avc_audit(u32 ssid, u32 tsid, * happened a little later. */ if ((a->type == LSM_AUDIT_DATA_INODE) && - (flags & MAY_NOT_BLOCK)) + (flags & IPERM_FLAG_RCU)) return -ECHILD; a->selinux_audit_data.tclass = tclass; diff --git a/trunk/security/selinux/hooks.c b/trunk/security/selinux/hooks.c index 9f4c77dca35f..422515509f3d 100644 --- a/trunk/security/selinux/hooks.c +++ b/trunk/security/selinux/hooks.c @@ -2659,13 +2659,12 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *na return dentry_has_perm(cred, dentry, FILE__READ); } -static int selinux_inode_permission(struct inode *inode, int mask) +static int selinux_inode_permission(struct inode *inode, int mask, unsigned flags) { const struct cred *cred = current_cred(); struct common_audit_data ad; u32 perms; bool from_access; - unsigned flags = mask & MAY_NOT_BLOCK; from_access = mask & MAY_ACCESS; mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND); diff --git a/trunk/security/selinux/netnode.c b/trunk/security/selinux/netnode.c index 8b691a863186..3618251d0fdb 100644 --- a/trunk/security/selinux/netnode.c +++ b/trunk/security/selinux/netnode.c @@ -68,6 +68,22 @@ static LIST_HEAD(sel_netnode_list); static DEFINE_SPINLOCK(sel_netnode_lock); static struct sel_netnode_bkt sel_netnode_hash[SEL_NETNODE_HASH_SIZE]; +/** + * sel_netnode_free - Frees a node entry + * @p: the entry's RCU field + * + * Description: + * This function is designed to be used as a callback to the call_rcu() + * function so that memory allocated to a hash table node entry can be + * released safely. + * + */ +static void sel_netnode_free(struct rcu_head *p) +{ + struct sel_netnode *node = container_of(p, struct sel_netnode, rcu); + kfree(node); +} + /** * sel_netnode_hashfn_ipv4 - IPv4 hashing function for the node table * @addr: IPv4 address @@ -177,7 +193,7 @@ static void sel_netnode_insert(struct sel_netnode *node) rcu_dereference(sel_netnode_hash[idx].list.prev), struct sel_netnode, list); list_del_rcu(&tail->list); - kfree_rcu(tail, rcu); + call_rcu(&tail->rcu, sel_netnode_free); } else sel_netnode_hash[idx].size++; } @@ -290,7 +306,7 @@ static void sel_netnode_flush(void) list_for_each_entry_safe(node, node_tmp, &sel_netnode_hash[idx].list, list) { list_del_rcu(&node->list); - kfree_rcu(node, rcu); + call_rcu(&node->rcu, sel_netnode_free); } sel_netnode_hash[idx].size = 0; } diff --git a/trunk/security/selinux/netport.c b/trunk/security/selinux/netport.c index ae76e298de7d..cfe2d72d3fb7 100644 --- a/trunk/security/selinux/netport.c +++ b/trunk/security/selinux/netport.c @@ -67,6 +67,22 @@ static LIST_HEAD(sel_netport_list); static DEFINE_SPINLOCK(sel_netport_lock); static struct sel_netport_bkt sel_netport_hash[SEL_NETPORT_HASH_SIZE]; +/** + * sel_netport_free - Frees a port entry + * @p: the entry's RCU field + * + * Description: + * This function is designed to be used as a callback to the call_rcu() + * function so that memory allocated to a hash table port entry can be + * released safely. + * + */ +static void sel_netport_free(struct rcu_head *p) +{ + struct sel_netport *port = container_of(p, struct sel_netport, rcu); + kfree(port); +} + /** * sel_netport_hashfn - Hashing function for the port table * @pnum: port number @@ -126,7 +142,7 @@ static void sel_netport_insert(struct sel_netport *port) rcu_dereference(sel_netport_hash[idx].list.prev), struct sel_netport, list); list_del_rcu(&tail->list); - kfree_rcu(tail, rcu); + call_rcu(&tail->rcu, sel_netport_free); } else sel_netport_hash[idx].size++; } @@ -225,7 +241,7 @@ static void sel_netport_flush(void) list_for_each_entry_safe(port, port_tmp, &sel_netport_hash[idx].list, list) { list_del_rcu(&port->list); - kfree_rcu(port, rcu); + call_rcu(&port->rcu, sel_netport_free); } sel_netport_hash[idx].size = 0; } diff --git a/trunk/security/smack/smack_lsm.c b/trunk/security/smack/smack_lsm.c index f375eb2e1957..9831a39c11f6 100644 --- a/trunk/security/smack/smack_lsm.c +++ b/trunk/security/smack/smack_lsm.c @@ -689,10 +689,9 @@ static int smack_inode_rename(struct inode *old_inode, * * Returns 0 if access is permitted, -EACCES otherwise */ -static int smack_inode_permission(struct inode *inode, int mask) +static int smack_inode_permission(struct inode *inode, int mask, unsigned flags) { struct smk_audit_info ad; - int no_block = mask & MAY_NOT_BLOCK; mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND); /* @@ -702,7 +701,7 @@ static int smack_inode_permission(struct inode *inode, int mask) return 0; /* May be droppable after audit */ - if (no_block) + if (flags & IPERM_FLAG_RCU) return -ECHILD; smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE); smk_ad_setfield_u_fs_inode(&ad, inode); diff --git a/trunk/security/tomoyo/realpath.c b/trunk/security/tomoyo/realpath.c index 8d95e91c9fc4..d1e05b047715 100644 --- a/trunk/security/tomoyo/realpath.c +++ b/trunk/security/tomoyo/realpath.c @@ -103,7 +103,7 @@ char *tomoyo_realpath_from_path(struct path *path) if (!buf) break; /* Get better name for socket. */ - if (dentry->d_sb->s_magic == SOCKFS_MAGIC) { + if (dentry->d_sb && dentry->d_sb->s_magic == SOCKFS_MAGIC) { struct inode *inode = dentry->d_inode; struct socket *sock = inode ? SOCKET_I(inode) : NULL; struct sock *sk = sock ? sock->sk : NULL; diff --git a/trunk/sound/core/rawmidi.c b/trunk/sound/core/rawmidi.c index 849a0ed95054..cbbed0db9e56 100644 --- a/trunk/sound/core/rawmidi.c +++ b/trunk/sound/core/rawmidi.c @@ -92,12 +92,16 @@ static inline int snd_rawmidi_ready_append(struct snd_rawmidi_substream *substre (!substream->append || runtime->avail >= count); } -static void snd_rawmidi_input_event_work(struct work_struct *work) +static void snd_rawmidi_input_event_tasklet(unsigned long data) { - struct snd_rawmidi_runtime *runtime = - container_of(work, struct snd_rawmidi_runtime, event_work); - if (runtime->event) - runtime->event(runtime->substream); + struct snd_rawmidi_substream *substream = (struct snd_rawmidi_substream *)data; + substream->runtime->event(substream); +} + +static void snd_rawmidi_output_trigger_tasklet(unsigned long data) +{ + struct snd_rawmidi_substream *substream = (struct snd_rawmidi_substream *)data; + substream->ops->trigger(substream, 1); } static int snd_rawmidi_runtime_create(struct snd_rawmidi_substream *substream) @@ -106,10 +110,16 @@ static int snd_rawmidi_runtime_create(struct snd_rawmidi_substream *substream) if ((runtime = kzalloc(sizeof(*runtime), GFP_KERNEL)) == NULL) return -ENOMEM; - runtime->substream = substream; spin_lock_init(&runtime->lock); init_waitqueue_head(&runtime->sleep); - INIT_WORK(&runtime->event_work, snd_rawmidi_input_event_work); + if (substream->stream == SNDRV_RAWMIDI_STREAM_INPUT) + tasklet_init(&runtime->tasklet, + snd_rawmidi_input_event_tasklet, + (unsigned long)substream); + else + tasklet_init(&runtime->tasklet, + snd_rawmidi_output_trigger_tasklet, + (unsigned long)substream); runtime->event = NULL; runtime->buffer_size = PAGE_SIZE; runtime->avail_min = 1; @@ -140,7 +150,12 @@ static inline void snd_rawmidi_output_trigger(struct snd_rawmidi_substream *subs { if (!substream->opened) return; - substream->ops->trigger(substream, up); + if (up) { + tasklet_schedule(&substream->runtime->tasklet); + } else { + tasklet_kill(&substream->runtime->tasklet); + substream->ops->trigger(substream, 0); + } } static void snd_rawmidi_input_trigger(struct snd_rawmidi_substream *substream, int up) @@ -148,8 +163,8 @@ static void snd_rawmidi_input_trigger(struct snd_rawmidi_substream *substream, i if (!substream->opened) return; substream->ops->trigger(substream, up); - if (!up) - cancel_work_sync(&substream->runtime->event_work); + if (!up && substream->runtime->event) + tasklet_kill(&substream->runtime->tasklet); } int snd_rawmidi_drop_output(struct snd_rawmidi_substream *substream) @@ -626,10 +641,10 @@ int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream, return -EINVAL; } if (params->buffer_size != runtime->buffer_size) { - newbuf = krealloc(runtime->buffer, params->buffer_size, - GFP_KERNEL); + newbuf = kmalloc(params->buffer_size, GFP_KERNEL); if (!newbuf) return -ENOMEM; + kfree(runtime->buffer); runtime->buffer = newbuf; runtime->buffer_size = params->buffer_size; runtime->avail = runtime->buffer_size; @@ -653,10 +668,10 @@ int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream, return -EINVAL; } if (params->buffer_size != runtime->buffer_size) { - newbuf = krealloc(runtime->buffer, params->buffer_size, - GFP_KERNEL); + newbuf = kmalloc(params->buffer_size, GFP_KERNEL); if (!newbuf) return -ENOMEM; + kfree(runtime->buffer); runtime->buffer = newbuf; runtime->buffer_size = params->buffer_size; } @@ -911,7 +926,7 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream, } if (result > 0) { if (runtime->event) - schedule_work(&runtime->event_work); + tasklet_schedule(&runtime->tasklet); else if (snd_rawmidi_ready(substream)) wake_up(&runtime->sleep); } diff --git a/trunk/sound/drivers/pcsp/pcsp.h b/trunk/sound/drivers/pcsp/pcsp.h index fc7a2dc410a1..4ff6c8cc5077 100644 --- a/trunk/sound/drivers/pcsp/pcsp.h +++ b/trunk/sound/drivers/pcsp/pcsp.h @@ -10,8 +10,14 @@ #define __PCSP_H__ #include -#include #include +#if defined(CONFIG_MIPS) || defined(CONFIG_X86) +/* Use the global PIT lock ! */ +#include +#else +#include +static DEFINE_RAW_SPINLOCK(i8253_lock); +#endif #define PCSP_SOUND_VERSION 0x400 /* read 4.00 */ #define PCSP_DEBUG 0 diff --git a/trunk/sound/firewire/speakers.c b/trunk/sound/firewire/speakers.c index 3fc257da180c..5466de8527bd 100644 --- a/trunk/sound/firewire/speakers.c +++ b/trunk/sound/firewire/speakers.c @@ -171,7 +171,7 @@ static int fwspk_open(struct snd_pcm_substream *substream) err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, - 5000, UINT_MAX); + 5000, 8192000); if (err < 0) return err; diff --git a/trunk/sound/pci/ad1889.c b/trunk/sound/pci/ad1889.c index 201503673f25..d8f6fd65ebbb 100644 --- a/trunk/sound/pci/ad1889.c +++ b/trunk/sound/pci/ad1889.c @@ -944,7 +944,7 @@ snd_ad1889_create(struct snd_card *card, spin_lock_init(&chip->lock); /* only now can we call ad1889_free */ if (request_irq(pci->irq, snd_ad1889_interrupt, - IRQF_SHARED, KBUILD_MODNAME, chip)) { + IRQF_SHARED, card->driver, chip)) { printk(KERN_ERR PFX "cannot obtain IRQ %d\n", pci->irq); snd_ad1889_free(chip); return -EBUSY; @@ -1055,7 +1055,7 @@ static DEFINE_PCI_DEVICE_TABLE(snd_ad1889_ids) = { MODULE_DEVICE_TABLE(pci, snd_ad1889_ids); static struct pci_driver ad1889_pci_driver = { - .name = KBUILD_MODNAME, + .name = "AD1889 Audio", .id_table = snd_ad1889_ids, .probe = snd_ad1889_probe, .remove = __devexit_p(snd_ad1889_remove), diff --git a/trunk/sound/pci/ali5451/ali5451.c b/trunk/sound/pci/ali5451/ali5451.c index b444b74d9dcf..5c6e322a48f0 100644 --- a/trunk/sound/pci/ali5451/ali5451.c +++ b/trunk/sound/pci/ali5451/ali5451.c @@ -2090,7 +2090,7 @@ static int __devinit snd_ali_resources(struct snd_ali *codec) codec->port = pci_resource_start(codec->pci, 0); if (request_irq(codec->pci->irq, snd_ali_card_interrupt, - IRQF_SHARED, KBUILD_MODNAME, codec)) { + IRQF_SHARED, "ALI 5451", codec)) { snd_printk(KERN_ERR "Unable to request irq.\n"); return -EBUSY; } @@ -2295,7 +2295,7 @@ static void __devexit snd_ali_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "ALI 5451", .id_table = snd_ali_ids, .probe = snd_ali_probe, .remove = __devexit_p(snd_ali_remove), diff --git a/trunk/sound/pci/als300.c b/trunk/sound/pci/als300.c index 736c8e93db1f..d7653cb7ac60 100644 --- a/trunk/sound/pci/als300.c +++ b/trunk/sound/pci/als300.c @@ -722,7 +722,7 @@ static int __devinit snd_als300_create(struct snd_card *card, irq_handler = snd_als300_interrupt; if (request_irq(pci->irq, irq_handler, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + card->shortname, chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_als300_free(chip); return -EBUSY; @@ -846,7 +846,7 @@ static int __devinit snd_als300_probe(struct pci_dev *pci, } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "ALS300", .id_table = snd_als300_ids, .probe = snd_als300_probe, .remove = __devexit_p(snd_als300_remove), diff --git a/trunk/sound/pci/als4000.c b/trunk/sound/pci/als4000.c index a9c1af33f276..0e247cb90ecc 100644 --- a/trunk/sound/pci/als4000.c +++ b/trunk/sound/pci/als4000.c @@ -1036,7 +1036,7 @@ static int snd_als4000_resume(struct pci_dev *pci) static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "ALS4000", .id_table = snd_als4000_ids, .probe = snd_card_als4000_probe, .remove = __devexit_p(snd_card_als4000_remove), diff --git a/trunk/sound/pci/asihpi/asihpi.c b/trunk/sound/pci/asihpi/asihpi.c index b941d2541dda..e3569bdd3b64 100644 --- a/trunk/sound/pci/asihpi/asihpi.c +++ b/trunk/sound/pci/asihpi/asihpi.c @@ -49,21 +49,19 @@ MODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx"); #if defined CONFIG_SND_DEBUG /* copied from pcm_lib.c, hope later patch will make that version public and this copy can be removed */ -static inline void -snd_pcm_debug_name(struct snd_pcm_substream *substream, char *buf, size_t size) +static void pcm_debug_name(struct snd_pcm_substream *substream, + char *name, size_t len) { - snprintf(buf, size, "pcmC%dD%d%c:%d", + snprintf(name, len, "pcmC%dD%d%c:%d", substream->pcm->card->number, substream->pcm->device, substream->stream ? 'c' : 'p', substream->number); } +#define DEBUG_NAME(substream, name) char name[16]; pcm_debug_name(substream, name, sizeof(name)) #else -static inline void -snd_pcm_debug_name(struct snd_pcm_substream *substream, char *buf, size_t size) -{ - *buf = 0; -} +#define pcm_debug_name(s, n, l) do { } while (0) +#define DEBUG_NAME(name, substream) do { } while (0) #endif #if defined CONFIG_SND_DEBUG_VERBOSE @@ -306,8 +304,7 @@ static u16 handle_error(u16 err, int line, char *filename) static void print_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *p) { - char name[16]; - snd_pcm_debug_name(substream, name, sizeof(name)); + DEBUG_NAME(substream, name); snd_printd("%s HWPARAMS\n", name); snd_printd(" samplerate %d Hz\n", params_rate(p)); snd_printd(" channels %d\n", params_channels(p)); @@ -579,9 +576,8 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, struct snd_card_asihpi *card = snd_pcm_substream_chip(substream); struct snd_pcm_substream *s; u16 e; - char name[16]; + DEBUG_NAME(substream, name); - snd_pcm_debug_name(substream, name, sizeof(name)); snd_printdd("%s trigger\n", name); switch (cmd) { @@ -745,9 +741,7 @@ static void snd_card_asihpi_timer_function(unsigned long data) int loops = 0; u16 state; u32 buffer_size, bytes_avail, samples_played, on_card_bytes; - char name[16]; - - snd_pcm_debug_name(substream, name, sizeof(name)); + DEBUG_NAME(substream, name); snd_printdd("%s snd_card_asihpi_timer_function\n", name); @@ -1329,12 +1323,10 @@ static const char * const asihpi_src_names[] = { "RF", "Clock", "Bitstream", - "Mic", - "Net", + "Microphone", + "Cobranet", "Analog", "Adapter", - "RTP", - "GPI", }; compile_time_assert( @@ -1349,10 +1341,8 @@ static const char * const asihpi_dst_names[] = { "Digital", "RF", "Speaker", - "Net", - "Analog", - "RTP", - "GPO", + "Cobranet Out", + "Analog" }; compile_time_assert( @@ -1486,40 +1476,11 @@ static int snd_asihpi_volume_put(struct snd_kcontrol *kcontrol, static const DECLARE_TLV_DB_SCALE(db_scale_100, -10000, VOL_STEP_mB, 0); -#define snd_asihpi_volume_mute_info snd_ctl_boolean_mono_info - -static int snd_asihpi_volume_mute_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - u32 h_control = kcontrol->private_value; - u32 mute; - - hpi_handle_error(hpi_volume_get_mute(h_control, &mute)); - ucontrol->value.integer.value[0] = mute ? 0 : 1; - - return 0; -} - -static int snd_asihpi_volume_mute_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - u32 h_control = kcontrol->private_value; - int change = 1; - /* HPI currently only supports all or none muting of multichannel volume - ALSA Switch element has opposite sense to HPI mute: on==unmuted, off=muted - */ - int mute = ucontrol->value.integer.value[0] ? 0 : HPI_BITMASK_ALL_CHANNELS; - hpi_handle_error(hpi_volume_set_mute(h_control, mute)); - return change; -} - static int __devinit snd_asihpi_volume_add(struct snd_card_asihpi *asihpi, struct hpi_control *hpi_ctl) { struct snd_card *card = asihpi->card; struct snd_kcontrol_new snd_control; - int err; - u32 mute; asihpi_ctl_init(&snd_control, hpi_ctl, "Volume"); snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | @@ -1529,19 +1490,7 @@ static int __devinit snd_asihpi_volume_add(struct snd_card_asihpi *asihpi, snd_control.put = snd_asihpi_volume_put; snd_control.tlv.p = db_scale_100; - err = ctl_add(card, &snd_control, asihpi); - if (err) - return err; - - if (hpi_volume_get_mute(hpi_ctl->h_control, &mute) == 0) { - asihpi_ctl_init(&snd_control, hpi_ctl, "Switch"); - snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE; - snd_control.info = snd_asihpi_volume_mute_info; - snd_control.get = snd_asihpi_volume_mute_get; - snd_control.put = snd_asihpi_volume_mute_put; - err = ctl_add(card, &snd_control, asihpi); - } - return err; + return ctl_add(card, &snd_control, asihpi); } /*------------------------------------------------------------ @@ -2974,7 +2923,7 @@ static DEFINE_PCI_DEVICE_TABLE(asihpi_pci_tbl) = { MODULE_DEVICE_TABLE(pci, asihpi_pci_tbl); static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "asihpi", .id_table = asihpi_pci_tbl, .probe = snd_asihpi_probe, .remove = __devexit_p(snd_asihpi_remove), diff --git a/trunk/sound/pci/asihpi/hpi.h b/trunk/sound/pci/asihpi/hpi.h index f20727288994..255429c32c1c 100644 --- a/trunk/sound/pci/asihpi/hpi.h +++ b/trunk/sound/pci/asihpi/hpi.h @@ -1,7 +1,7 @@ /****************************************************************************** AudioScience HPI driver - Copyright (C) 1997-2011 AudioScience Inc. + Copyright (C) 1997-2010 AudioScience Inc. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as @@ -42,11 +42,12 @@ i.e 3.05.02 is a development version #define HPI_VER_MINOR(v) ((int)((v >> 8) & 0xFF)) #define HPI_VER_RELEASE(v) ((int)(v & 0xFF)) -#define HPI_VER HPI_VERSION_CONSTRUCTOR(4L, 8, 0) -#define HPI_VER_STRING "4.08.00" +/* Use single digits for versions less that 10 to avoid octal. */ +#define HPI_VER HPI_VERSION_CONSTRUCTOR(4L, 6, 0) +#define HPI_VER_STRING "4.06.00" /* Library version as documented in hpi-api-versions.txt */ -#define HPI_LIB_VER HPI_VERSION_CONSTRUCTOR(10, 0, 0) +#define HPI_LIB_VER HPI_VERSION_CONSTRUCTOR(9, 0, 0) #include #define HPI_BUILD_EXCLUDE_DEPRECATED @@ -210,12 +211,8 @@ enum HPI_SOURCENODES { HPI_SOURCENODE_COBRANET = 109, HPI_SOURCENODE_ANALOG = 110, /**< analog input node. */ HPI_SOURCENODE_ADAPTER = 111, /**< adapter node. */ - /** RTP stream input node - This node is a destination for - packets of RTP audio samples from other devices. */ - HPI_SOURCENODE_RTP_DESTINATION = 112, - HPI_SOURCENODE_GP_IN = 113, /**< general purpose input. */ /* !!!Update this AND hpidebug.h if you add a new sourcenode type!!! */ - HPI_SOURCENODE_LAST_INDEX = 113 /**< largest ID */ + HPI_SOURCENODE_LAST_INDEX = 111 /**< largest ID */ /* AX6 max sourcenode types = 15 */ }; @@ -231,7 +228,7 @@ enum HPI_DESTNODES { HPI_DESTNODE_NONE = 200, /** In Stream (Record) node. */ HPI_DESTNODE_ISTREAM = 201, - HPI_DESTNODE_LINEOUT = 202, /**< line out node. */ + HPI_DESTNODE_LINEOUT = 202, /**< line out node. */ HPI_DESTNODE_AESEBU_OUT = 203, /**< AES/EBU output node. */ HPI_DESTNODE_RF = 204, /**< RF output node. */ HPI_DESTNODE_SPEAKER = 205, /**< speaker output node. */ @@ -239,12 +236,9 @@ enum HPI_DESTNODES { Audio samples from the device are sent out on the Cobranet network.*/ HPI_DESTNODE_COBRANET = 206, HPI_DESTNODE_ANALOG = 207, /**< analog output node. */ - /** RTP stream output node - This node is a source for - packets of RTP audio samples that are sent to other devices. */ - HPI_DESTNODE_RTP_SOURCE = 208, - HPI_DESTNODE_GP_OUT = 209, /**< general purpose output node. */ + /* !!!Update this AND hpidebug.h if you add a new destnode type!!! */ - HPI_DESTNODE_LAST_INDEX = 209 /**< largest ID */ + HPI_DESTNODE_LAST_INDEX = 207 /**< largest ID */ /* AX6 max destnode types = 15 */ }; diff --git a/trunk/sound/pci/asihpi/hpi6000.c b/trunk/sound/pci/asihpi/hpi6000.c index 3cc6f11c20aa..df4aed5295dd 100644 --- a/trunk/sound/pci/asihpi/hpi6000.c +++ b/trunk/sound/pci/asihpi/hpi6000.c @@ -359,7 +359,7 @@ void HPI_6000(struct hpi_message *phm, struct hpi_response *phr) HPI_ERROR_PROCESSING_MESSAGE); switch (phm->type) { - case HPI_TYPE_REQUEST: + case HPI_TYPE_MESSAGE: switch (phm->object) { case HPI_OBJ_SUBSYSTEM: subsys_message(phm, phr); @@ -538,7 +538,7 @@ static short create_adapter_obj(struct hpi_adapter_obj *pao, HPI_DEBUG_LOG(VERBOSE, "send ADAPTER_GET_INFO\n"); memset(&hm, 0, sizeof(hm)); - hm.type = HPI_TYPE_REQUEST; + hm.type = HPI_TYPE_MESSAGE; hm.size = sizeof(struct hpi_message); hm.object = HPI_OBJ_ADAPTER; hm.function = HPI_ADAPTER_GET_INFO; @@ -946,8 +946,11 @@ static short hpi6000_adapter_boot_load_dsp(struct hpi_adapter_obj *pao, } /* write the DSP code down into the DSPs memory */ - error = hpi_dsp_code_open(boot_load_family, pao->pci.pci_dev, - &dsp_code, pos_error_code); + /*HpiDspCode_Open(nBootLoadFamily,&DspCode,pdwOsErrorCode); */ + dsp_code.ps_dev = pao->pci.pci_dev; + + error = hpi_dsp_code_open(boot_load_family, &dsp_code, + pos_error_code); if (error) return error; diff --git a/trunk/sound/pci/asihpi/hpi6205.c b/trunk/sound/pci/asihpi/hpi6205.c index e041a6ae1c5a..9d5df54a6b46 100644 --- a/trunk/sound/pci/asihpi/hpi6205.c +++ b/trunk/sound/pci/asihpi/hpi6205.c @@ -373,7 +373,6 @@ static void instream_message(struct hpi_adapter_obj *pao, /** Entry point to this HPI backend * All calls to the HPI start here */ -static void _HPI_6205(struct hpi_adapter_obj *pao, struct hpi_message *phm, struct hpi_response *phr) { @@ -393,7 +392,7 @@ void _HPI_6205(struct hpi_adapter_obj *pao, struct hpi_message *phm, HPI_DEBUG_LOG(VERBOSE, "start of switch\n"); switch (phm->type) { - case HPI_TYPE_REQUEST: + case HPI_TYPE_MESSAGE: switch (phm->object) { case HPI_OBJ_SUBSYSTEM: subsys_message(pao, phm, phr); @@ -403,6 +402,7 @@ void _HPI_6205(struct hpi_adapter_obj *pao, struct hpi_message *phm, adapter_message(pao, phm, phr); break; + case HPI_OBJ_CONTROLEX: case HPI_OBJ_CONTROL: control_message(pao, phm, phr); break; @@ -634,12 +634,11 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao, HPI_DEBUG_LOG(VERBOSE, "init ADAPTER_GET_INFO\n"); memset(&hm, 0, sizeof(hm)); - /* wAdapterIndex == version == 0 */ - hm.type = HPI_TYPE_REQUEST; + hm.type = HPI_TYPE_MESSAGE; hm.size = sizeof(hm); hm.object = HPI_OBJ_ADAPTER; hm.function = HPI_ADAPTER_GET_INFO; - + hm.adapter_index = 0; memset(&hr, 0, sizeof(hr)); hr.size = sizeof(hr); @@ -659,6 +658,9 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao, hr.u.ax.info.num_outstreams + hr.u.ax.info.num_instreams; + hpios_locked_mem_prepare((max_streams * 6) / 10, max_streams, + 65536, pao->pci.pci_dev); + HPI_DEBUG_LOG(VERBOSE, "got adapter info type %x index %d serial %d\n", hr.u.ax.info.adapter_type, hr.u.ax.info.adapter_index, @@ -707,6 +709,9 @@ static void delete_adapter_obj(struct hpi_adapter_obj *pao) [i]); phw->outstream_host_buffer_size[i] = 0; } + + hpios_locked_mem_unprepare(pao->pci.pci_dev); + kfree(phw); } @@ -1366,8 +1371,9 @@ static u16 adapter_boot_load_dsp(struct hpi_adapter_obj *pao, return err; /* write the DSP code down into the DSPs memory */ - err = hpi_dsp_code_open(boot_code_id[dsp], pao->pci.pci_dev, - &dsp_code, pos_error_code); + dsp_code.ps_dev = pao->pci.pci_dev; + err = hpi_dsp_code_open(boot_code_id[dsp], &dsp_code, + pos_error_code); if (err) return err; @@ -2078,13 +2084,13 @@ static u16 message_response_sequence(struct hpi_adapter_obj *pao, u16 err = 0; message_count++; - if (phm->size > sizeof(interface->u.message_buffer)) { + if (phm->size > sizeof(interface->u)) { phr->error = HPI_ERROR_MESSAGE_BUFFER_TOO_SMALL; - phr->specific_error = sizeof(interface->u.message_buffer); + phr->specific_error = sizeof(interface->u); phr->size = sizeof(struct hpi_response_header); HPI_DEBUG_LOG(ERROR, "message len %d too big for buffer %zd \n", phm->size, - sizeof(interface->u.message_buffer)); + sizeof(interface->u)); return 0; } @@ -2116,19 +2122,18 @@ static u16 message_response_sequence(struct hpi_adapter_obj *pao, /* read the result */ if (time_out) { - if (interface->u.response_buffer.response.size <= phr->size) + if (interface->u.response_buffer.size <= phr->size) memcpy(phr, &interface->u.response_buffer, - interface->u.response_buffer.response.size); + interface->u.response_buffer.size); else { HPI_DEBUG_LOG(ERROR, "response len %d too big for buffer %d\n", - interface->u.response_buffer.response.size, - phr->size); + interface->u.response_buffer.size, phr->size); memcpy(phr, &interface->u.response_buffer, sizeof(struct hpi_response_header)); phr->error = HPI_ERROR_RESPONSE_BUFFER_TOO_SMALL; phr->specific_error = - interface->u.response_buffer.response.size; + interface->u.response_buffer.size; phr->size = sizeof(struct hpi_response_header); } } @@ -2197,6 +2202,23 @@ static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm, phm->u.d.u.data.data_size, H620_HIF_GET_DATA); break; + case HPI_CONTROL_SET_STATE: + if (phm->object == HPI_OBJ_CONTROLEX + && phm->u.cx.attribute == HPI_COBRANET_SET_DATA) + err = hpi6205_transfer_data(pao, + phm->u.cx.u.cobranet_bigdata.pb_data, + phm->u.cx.u.cobranet_bigdata.byte_count, + H620_HIF_SEND_DATA); + break; + + case HPI_CONTROL_GET_STATE: + if (phm->object == HPI_OBJ_CONTROLEX + && phm->u.cx.attribute == HPI_COBRANET_GET_DATA) + err = hpi6205_transfer_data(pao, + phm->u.cx.u.cobranet_bigdata.pb_data, + phr->u.cx.u.cobranet_data.byte_count, + H620_HIF_GET_DATA); + break; } phr->error = err; diff --git a/trunk/sound/pci/asihpi/hpi6205.h b/trunk/sound/pci/asihpi/hpi6205.h index ec0827b633a6..df2f02c0c7b4 100644 --- a/trunk/sound/pci/asihpi/hpi6205.h +++ b/trunk/sound/pci/asihpi/hpi6205.h @@ -1,7 +1,7 @@ /***************************************************************************** AudioScience HPI driver - Copyright (C) 1997-2011 AudioScience Inc. + Copyright (C) 1997-2010 AudioScience Inc. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as @@ -70,28 +70,15 @@ The Host located memory buffer that the 6205 will bus master in and out of. ************************************************************/ #define HPI6205_SIZEOF_DATA (16*1024) - -struct message_buffer_6205 { - struct hpi_message message; - char data[256]; -}; - -struct response_buffer_6205 { - struct hpi_response response; - char data[256]; -}; - -union buffer_6205 { - struct message_buffer_6205 message_buffer; - struct response_buffer_6205 response_buffer; - u8 b_data[HPI6205_SIZEOF_DATA]; -}; - struct bus_master_interface { u32 host_cmd; u32 dsp_ack; u32 transfer_size_in_bytes; - union buffer_6205 u; + union { + struct hpi_message_header message_buffer; + struct hpi_response_header response_buffer; + u8 b_data[HPI6205_SIZEOF_DATA]; + } u; struct controlcache_6205 control_cache; struct async_event_buffer_6205 async_buffer; struct hpi_hostbuffer_status diff --git a/trunk/sound/pci/asihpi/hpi_internal.h b/trunk/sound/pci/asihpi/hpi_internal.h index d497030c160f..bf5eced76bac 100644 --- a/trunk/sound/pci/asihpi/hpi_internal.h +++ b/trunk/sound/pci/asihpi/hpi_internal.h @@ -1,7 +1,7 @@ /****************************************************************************** AudioScience HPI driver - Copyright (C) 1997-2011 AudioScience Inc. + Copyright (C) 1997-2010 AudioScience Inc. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as @@ -32,6 +32,12 @@ HPI internal definitions #include "hpios.h" /* physical memory allocation */ +void hpios_locked_mem_init(void + ); +void hpios_locked_mem_free_all(void + ); +#define hpios_locked_mem_prepare(a, b, c, d); +#define hpios_locked_mem_unprepare(a) /** Allocate and map an area of locked memory for bus master DMA operations. @@ -220,8 +226,8 @@ enum HPI_CONTROL_ATTRIBUTES { HPI_COBRANET_SET = HPI_CTL_ATTR(COBRANET, 1), HPI_COBRANET_GET = HPI_CTL_ATTR(COBRANET, 2), - /*HPI_COBRANET_SET_DATA = HPI_CTL_ATTR(COBRANET, 3), */ - /*HPI_COBRANET_GET_DATA = HPI_CTL_ATTR(COBRANET, 4), */ + HPI_COBRANET_SET_DATA = HPI_CTL_ATTR(COBRANET, 3), + HPI_COBRANET_GET_DATA = HPI_CTL_ATTR(COBRANET, 4), HPI_COBRANET_GET_STATUS = HPI_CTL_ATTR(COBRANET, 5), HPI_COBRANET_SEND_PACKET = HPI_CTL_ATTR(COBRANET, 6), HPI_COBRANET_GET_PACKET = HPI_CTL_ATTR(COBRANET, 7), @@ -358,12 +364,10 @@ Used in DLL to indicate device not present #define HPI_ADAPTER_ASI(f) (f) enum HPI_MESSAGE_TYPES { - HPI_TYPE_REQUEST = 1, + HPI_TYPE_MESSAGE = 1, HPI_TYPE_RESPONSE = 2, HPI_TYPE_DATA = 3, - HPI_TYPE_SSX2BYPASS_MESSAGE = 4, - HPI_TYPE_COMMAND = 5, - HPI_TYPE_NOTIFICATION = 6 + HPI_TYPE_SSX2BYPASS_MESSAGE = 4 }; enum HPI_OBJECT_TYPES { @@ -379,7 +383,7 @@ enum HPI_OBJECT_TYPES { HPI_OBJ_WATCHDOG = 10, HPI_OBJ_CLOCK = 11, HPI_OBJ_PROFILE = 12, - /* HPI_ OBJ_ CONTROLEX = 13, */ + HPI_OBJ_CONTROLEX = 13, HPI_OBJ_ASYNCEVENT = 14 #define HPI_OBJ_MAXINDEX 14 }; @@ -604,7 +608,7 @@ struct hpi_data_compat32 { #endif struct hpi_buffer { - /** placeholder for backward compatibility (see dwBufferSize) */ + /** placehoder for backward compatibility (see dwBufferSize) */ struct hpi_msg_format reserved; u32 command; /**< HPI_BUFFER_CMD_xxx*/ u32 pci_address; /**< PCI physical address of buffer for DSP DMA */ @@ -908,13 +912,95 @@ union hpi_control_union_res { u32 remaining_chars; } chars8; char c_data12[12]; +}; + +/* HPI_CONTROLX_STRUCTURES */ + +/* Message */ + +/** Used for all HMI variables where max length <= 8 bytes +*/ +struct hpi_controlx_msg_cobranet_data { + u32 hmi_address; + u32 byte_count; + u32 data[2]; +}; + +/** Used for string data, and for packet bridge +*/ +struct hpi_controlx_msg_cobranet_bigdata { + u32 hmi_address; + u32 byte_count; + u8 *pb_data; +#ifndef HPI64BIT + u32 padding; +#endif +}; + +/** Used for PADS control reading of string fields. +*/ +struct hpi_controlx_msg_pad_data { + u32 field; + u32 byte_count; + u8 *pb_data; +#ifndef HPI64BIT + u32 padding; +#endif +}; + +/** Used for generic data +*/ + +struct hpi_controlx_msg_generic { + u32 param1; + u32 param2; +}; + +struct hpi_controlx_msg { + u16 attribute; /* control attribute or property */ + u16 saved_index; union { - struct { - u32 status; - u32 readable_size; - u32 writeable_size; - } status; - } cobranet; + struct hpi_controlx_msg_cobranet_data cobranet_data; + struct hpi_controlx_msg_cobranet_bigdata cobranet_bigdata; + struct hpi_controlx_msg_generic generic; + struct hpi_controlx_msg_pad_data pad_data; + /*struct param_value universal_value; */ + /* nothing extra to send for status read */ + } u; +}; + +/* Response */ +/** +*/ +struct hpi_controlx_res_cobranet_data { + u32 byte_count; + u32 data[2]; +}; + +struct hpi_controlx_res_cobranet_bigdata { + u32 byte_count; +}; + +struct hpi_controlx_res_cobranet_status { + u32 status; + u32 readable_size; + u32 writeable_size; +}; + +struct hpi_controlx_res_generic { + u32 param1; + u32 param2; +}; + +struct hpi_controlx_res { + union { + struct hpi_controlx_res_cobranet_bigdata cobranet_bigdata; + struct hpi_controlx_res_cobranet_data cobranet_data; + struct hpi_controlx_res_cobranet_status cobranet_status; + struct hpi_controlx_res_generic generic; + /*struct param_info universal_info; */ + /*struct param_value universal_value; */ + } u; }; struct hpi_nvmemory_msg { @@ -1040,6 +1126,7 @@ struct hpi_message { /* identical to struct hpi_control_msg, but field naming is improved */ struct hpi_control_union_msg cu; + struct hpi_controlx_msg cx; /* extended mixer control; */ struct hpi_nvmemory_msg n; struct hpi_gpio_msg l; /* digital i/o */ struct hpi_watchdog_msg w; @@ -1064,7 +1151,7 @@ struct hpi_message { sizeof(struct hpi_message_header) + sizeof(struct hpi_watchdog_msg),\ sizeof(struct hpi_message_header) + sizeof(struct hpi_clock_msg),\ sizeof(struct hpi_message_header) + sizeof(struct hpi_profile_msg),\ - sizeof(struct hpi_message_header), /* controlx obj removed */ \ + sizeof(struct hpi_message_header) + sizeof(struct hpi_controlx_msg),\ sizeof(struct hpi_message_header) + sizeof(struct hpi_async_msg) \ } @@ -1101,6 +1188,7 @@ struct hpi_response { struct hpi_control_res c; /* mixer control; */ /* identical to hpi_control_res, but field naming is improved */ union hpi_control_union_res cu; + struct hpi_controlx_res cx; /* extended mixer control; */ struct hpi_nvmemory_res n; struct hpi_gpio_res l; /* digital i/o */ struct hpi_watchdog_res w; @@ -1125,7 +1213,7 @@ struct hpi_response { sizeof(struct hpi_response_header) + sizeof(struct hpi_watchdog_res),\ sizeof(struct hpi_response_header) + sizeof(struct hpi_clock_res),\ sizeof(struct hpi_response_header) + sizeof(struct hpi_profile_res),\ - sizeof(struct hpi_response_header), /* controlx obj removed */ \ + sizeof(struct hpi_response_header) + sizeof(struct hpi_controlx_res),\ sizeof(struct hpi_response_header) + sizeof(struct hpi_async_res) \ } @@ -1220,30 +1308,6 @@ struct hpi_res_adapter_debug_read { u8 bytes[256]; }; -struct hpi_msg_cobranet_hmi { - u16 attribute; - u16 padding; - u32 hmi_address; - u32 byte_count; -}; - -struct hpi_msg_cobranet_hmiwrite { - struct hpi_message_header h; - struct hpi_msg_cobranet_hmi p; - u8 bytes[256]; -}; - -struct hpi_msg_cobranet_hmiread { - struct hpi_message_header h; - struct hpi_msg_cobranet_hmi p; -}; - -struct hpi_res_cobranet_hmiread { - struct hpi_response_header h; - u32 byte_count; - u8 bytes[256]; -}; - #if 1 #define hpi_message_header_v1 hpi_message_header #define hpi_response_header_v1 hpi_response_header @@ -1274,6 +1338,7 @@ struct hpi_msg_payload_v0 { union hpi_mixerx_msg mx; struct hpi_control_msg c; struct hpi_control_union_msg cu; + struct hpi_controlx_msg cx; struct hpi_nvmemory_msg n; struct hpi_gpio_msg l; struct hpi_watchdog_msg w; @@ -1293,6 +1358,7 @@ struct hpi_res_payload_v0 { union hpi_mixerx_res mx; struct hpi_control_res c; union hpi_control_union_res cu; + struct hpi_controlx_res cx; struct hpi_nvmemory_res n; struct hpi_gpio_res l; struct hpi_watchdog_res w; @@ -1427,6 +1493,12 @@ struct hpi_control_cache_microphone { char temp_padding[6]; }; +struct hpi_control_cache_generic { + struct hpi_control_cache_info i; + u32 dw1; + u32 dw2; +}; + struct hpi_control_cache_single { union { struct hpi_control_cache_info i; @@ -1442,6 +1514,7 @@ struct hpi_control_cache_single { struct hpi_control_cache_silencedetector silence; struct hpi_control_cache_sampleclock clk; struct hpi_control_cache_microphone microphone; + struct hpi_control_cache_generic generic; } u; }; diff --git a/trunk/sound/pci/asihpi/hpicmn.c b/trunk/sound/pci/asihpi/hpicmn.c index 65b7ca13115b..b15a02e91f82 100644 --- a/trunk/sound/pci/asihpi/hpicmn.c +++ b/trunk/sound/pci/asihpi/hpicmn.c @@ -57,7 +57,7 @@ u16 hpi_validate_response(struct hpi_message *phm, struct hpi_response *phr) } if (phr->function != phm->function) { - HPI_DEBUG_LOG(ERROR, "header function %d invalid\n", + HPI_DEBUG_LOG(ERROR, "header type %d invalid\n", phr->function); return HPI_ERROR_INVALID_RESPONSE; } @@ -315,7 +315,8 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache, short found = 1; struct hpi_control_cache_info *pI; struct hpi_control_cache_single *pC; - size_t response_size; + struct hpi_control_cache_pad *p_pad; + if (!find_control(phm->obj_index, p_cache, &pI)) { HPI_DEBUG_LOG(VERBOSE, "HPICMN find_control() failed for adap %d\n", @@ -325,15 +326,11 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache, phr->error = 0; - /* set the default response size */ - response_size = - sizeof(struct hpi_response_header) + - sizeof(struct hpi_control_res); - /* pC is the default cached control strucure. May be cast to something else in the following switch statement. */ pC = (struct hpi_control_cache_single *)pI; + p_pad = (struct hpi_control_cache_pad *)pI; switch (pI->control_type) { @@ -532,7 +529,9 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache, pI->control_index, pI->control_type, phm->u.c.attribute); if (found) - phr->size = (u16)response_size; + phr->size = + sizeof(struct hpi_response_header) + + sizeof(struct hpi_control_res); return found; } @@ -683,7 +682,7 @@ static void subsys_message(struct hpi_message *phm, struct hpi_response *phr) void HPI_COMMON(struct hpi_message *phm, struct hpi_response *phr) { switch (phm->type) { - case HPI_TYPE_REQUEST: + case HPI_TYPE_MESSAGE: switch (phm->object) { case HPI_OBJ_SUBSYSTEM: subsys_message(phm, phr); diff --git a/trunk/sound/pci/asihpi/hpidspcd.c b/trunk/sound/pci/asihpi/hpidspcd.c index 3a7afa31c1d8..5c6ea113d219 100644 --- a/trunk/sound/pci/asihpi/hpidspcd.c +++ b/trunk/sound/pci/asihpi/hpidspcd.c @@ -1,8 +1,8 @@ /***********************************************************************/ -/** +/*! AudioScience HPI driver - Copyright (C) 1997-2011 AudioScience Inc. + Copyright (C) 1997-2010 AudioScience Inc. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as @@ -18,59 +18,90 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \file -Functions for reading DSP code using +Functions for reading DSP code to load into DSP + +(Linux only:) If DSPCODE_FIRMWARE_LOADER is defined, code is read using hotplug firmware loader from individual dsp code files -*/ + +If neither of the above is defined, code is read from linked arrays. +DSPCODE_ARRAY is defined. + +HPI_INCLUDE_**** must be defined +and the appropriate hzz?????.c or hex?????.c linked in + + */ /***********************************************************************/ #define SOURCEFILE_NAME "hpidspcd.c" #include "hpidspcd.h" #include "hpidebug.h" -struct dsp_code_private { - /** Firmware descriptor */ - const struct firmware *firmware; - struct pci_dev *dev; +/** + Header structure for binary dsp code file (see asidsp.doc) + This structure must match that used in s2bin.c for generation of asidsp.bin + */ + +#ifndef DISABLE_PRAGMA_PACK1 +#pragma pack(push, 1) +#endif + +struct code_header { + u32 size; + char type[4]; + u32 adapter; + u32 version; + u32 crc; }; +#ifndef DISABLE_PRAGMA_PACK1 +#pragma pack(pop) +#endif + #define HPI_VER_DECIMAL ((int)(HPI_VER_MAJOR(HPI_VER) * 10000 + \ HPI_VER_MINOR(HPI_VER) * 100 + HPI_VER_RELEASE(HPI_VER))) +/***********************************************************************/ +#include /*-------------------------------------------------------------------*/ -short hpi_dsp_code_open(u32 adapter, void *os_data, struct dsp_code *dsp_code, - u32 *os_error_code) +short hpi_dsp_code_open(u32 adapter, struct dsp_code *ps_dsp_code, + u32 *pos_error_code) { - const struct firmware *firmware; - struct pci_dev *dev = os_data; + const struct firmware *ps_firmware = ps_dsp_code->ps_firmware; struct code_header header; char fw_name[20]; int err; sprintf(fw_name, "asihpi/dsp%04x.bin", adapter); - err = request_firmware(&firmware, fw_name, &dev->dev); + err = request_firmware(&ps_firmware, fw_name, + &ps_dsp_code->ps_dev->dev); - if (err || !firmware) { - dev_printk(KERN_ERR, &dev->dev, + if (err != 0) { + dev_printk(KERN_ERR, &ps_dsp_code->ps_dev->dev, "%d, request_firmware failed for %s\n", err, fw_name); goto error1; } - if (firmware->size < sizeof(header)) { - dev_printk(KERN_ERR, &dev->dev, "Header size too small %s\n", - fw_name); + if (ps_firmware->size < sizeof(header)) { + dev_printk(KERN_ERR, &ps_dsp_code->ps_dev->dev, + "Header size too small %s\n", fw_name); goto error2; } - memcpy(&header, firmware->data, sizeof(header)); - - if ((header.type != 0x45444F43) || /* "CODE" */ - (header.adapter != adapter) - || (header.size != firmware->size)) { - dev_printk(KERN_ERR, &dev->dev, "Invalid firmware file\n"); + memcpy(&header, ps_firmware->data, sizeof(header)); + if (header.adapter != adapter) { + dev_printk(KERN_ERR, &ps_dsp_code->ps_dev->dev, + "Adapter type incorrect %4x != %4x\n", header.adapter, + adapter); + goto error2; + } + if (header.size != ps_firmware->size) { + dev_printk(KERN_ERR, &ps_dsp_code->ps_dev->dev, + "Code size wrong %d != %ld\n", header.size, + (unsigned long)ps_firmware->size); goto error2; } - if ((header.version / 100 & ~1) != (HPI_VER_DECIMAL / 100 & ~1)) { - dev_printk(KERN_ERR, &dev->dev, + if (header.version / 100 != HPI_VER_DECIMAL / 100) { + dev_printk(KERN_ERR, &ps_dsp_code->ps_dev->dev, "Incompatible firmware version " "DSP image %d != Driver %d\n", header.version, HPI_VER_DECIMAL); @@ -78,70 +109,67 @@ short hpi_dsp_code_open(u32 adapter, void *os_data, struct dsp_code *dsp_code, } if (header.version != HPI_VER_DECIMAL) { - dev_printk(KERN_WARNING, &dev->dev, + dev_printk(KERN_WARNING, &ps_dsp_code->ps_dev->dev, "Firmware: release version mismatch DSP image %d != Driver %d\n", header.version, HPI_VER_DECIMAL); } HPI_DEBUG_LOG(DEBUG, "dsp code %s opened\n", fw_name); - dsp_code->pvt = kmalloc(sizeof(*dsp_code->pvt), GFP_KERNEL); - if (!dsp_code->pvt) - return HPI_ERROR_MEMORY_ALLOC; - - dsp_code->pvt->dev = dev; - dsp_code->pvt->firmware = firmware; - dsp_code->header = header; - dsp_code->block_length = header.size / sizeof(u32); - dsp_code->word_count = sizeof(header) / sizeof(u32); + ps_dsp_code->ps_firmware = ps_firmware; + ps_dsp_code->block_length = header.size / sizeof(u32); + ps_dsp_code->word_count = sizeof(header) / sizeof(u32); + ps_dsp_code->version = header.version; + ps_dsp_code->crc = header.crc; return 0; error2: - release_firmware(firmware); + release_firmware(ps_firmware); error1: - dsp_code->block_length = 0; + ps_dsp_code->ps_firmware = NULL; + ps_dsp_code->block_length = 0; return HPI_ERROR_DSP_FILE_NOT_FOUND; } /*-------------------------------------------------------------------*/ -void hpi_dsp_code_close(struct dsp_code *dsp_code) +void hpi_dsp_code_close(struct dsp_code *ps_dsp_code) { - if (dsp_code->pvt->firmware) { + if (ps_dsp_code->ps_firmware != NULL) { HPI_DEBUG_LOG(DEBUG, "dsp code closed\n"); - release_firmware(dsp_code->pvt->firmware); - dsp_code->pvt->firmware = NULL; + release_firmware(ps_dsp_code->ps_firmware); + ps_dsp_code->ps_firmware = NULL; } - kfree(dsp_code->pvt); } /*-------------------------------------------------------------------*/ -void hpi_dsp_code_rewind(struct dsp_code *dsp_code) +void hpi_dsp_code_rewind(struct dsp_code *ps_dsp_code) { /* Go back to start of data, after header */ - dsp_code->word_count = sizeof(struct code_header) / sizeof(u32); + ps_dsp_code->word_count = sizeof(struct code_header) / sizeof(u32); } /*-------------------------------------------------------------------*/ -short hpi_dsp_code_read_word(struct dsp_code *dsp_code, u32 *pword) +short hpi_dsp_code_read_word(struct dsp_code *ps_dsp_code, u32 *pword) { - if (dsp_code->word_count + 1 > dsp_code->block_length) + if (ps_dsp_code->word_count + 1 > ps_dsp_code->block_length) return HPI_ERROR_DSP_FILE_FORMAT; - *pword = ((u32 *)(dsp_code->pvt->firmware->data))[dsp_code-> + *pword = ((u32 *)(ps_dsp_code->ps_firmware->data))[ps_dsp_code-> word_count]; - dsp_code->word_count++; + ps_dsp_code->word_count++; return 0; } /*-------------------------------------------------------------------*/ short hpi_dsp_code_read_block(size_t words_requested, - struct dsp_code *dsp_code, u32 **ppblock) + struct dsp_code *ps_dsp_code, u32 **ppblock) { - if (dsp_code->word_count + words_requested > dsp_code->block_length) + if (ps_dsp_code->word_count + words_requested > + ps_dsp_code->block_length) return HPI_ERROR_DSP_FILE_FORMAT; *ppblock = - ((u32 *)(dsp_code->pvt->firmware->data)) + - dsp_code->word_count; - dsp_code->word_count += words_requested; + ((u32 *)(ps_dsp_code->ps_firmware->data)) + + ps_dsp_code->word_count; + ps_dsp_code->word_count += words_requested; return 0; } diff --git a/trunk/sound/pci/asihpi/hpidspcd.h b/trunk/sound/pci/asihpi/hpidspcd.h index b22881122f19..65f0ca732704 100644 --- a/trunk/sound/pci/asihpi/hpidspcd.h +++ b/trunk/sound/pci/asihpi/hpidspcd.h @@ -2,7 +2,7 @@ /** AudioScience HPI driver - Copyright (C) 1997-2011 AudioScience Inc. + Copyright (C) 1997-2010 AudioScience Inc. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as @@ -20,6 +20,19 @@ \file Functions for reading DSP code to load into DSP + hpi_dspcode_defines HPI DSP code loading method +Define exactly one of these to select how the DSP code is supplied to +the adapter. + +End users writing applications that use the HPI interface do not have to +use any of the below defines; they are only necessary for building drivers + +HPI_DSPCODE_FILE: +DSP code is supplied as a file that is opened and read from by the driver. + +HPI_DSPCODE_FIRMWARE: +DSP code is read using the hotplug firmware loader module. + Only valid when compiling the HPI kernel driver under Linux. */ /***********************************************************************/ #ifndef _HPIDSPCD_H_ @@ -27,56 +40,37 @@ Functions for reading DSP code to load into DSP #include "hpi_internal.h" -/** Code header version is decimal encoded e.g. 4.06.10 is 40601 */ -#define HPI_VER_DECIMAL ((int)(HPI_VER_MAJOR(HPI_VER) * 10000 + \ -HPI_VER_MINOR(HPI_VER) * 100 + HPI_VER_RELEASE(HPI_VER))) - -/** Header structure for dsp firmware file - This structure must match that used in s2bin.c for generation of asidsp.bin - */ -/*#ifndef DISABLE_PRAGMA_PACK1 */ -/*#pragma pack(push, 1) */ -/*#endif */ -struct code_header { - /** Size in bytes including header */ - u32 size; - /** File type tag "CODE" == 0x45444F43 */ - u32 type; - /** Adapter model number */ - u32 adapter; - /** Firmware version*/ - u32 version; - /** Data checksum */ - u32 checksum; -}; -/*#ifndef DISABLE_PRAGMA_PACK1 */ -/*#pragma pack(pop) */ -/*#endif */ - -/*? Don't need the pragmas? */ -compile_time_assert((sizeof(struct code_header) == 20), code_header_size); +#ifndef DISABLE_PRAGMA_PACK1 +#pragma pack(push, 1) +#endif /** Descriptor for dspcode from firmware loader */ struct dsp_code { - /** copy of file header */ - struct code_header header; + /** Firmware descriptor */ + const struct firmware *ps_firmware; + struct pci_dev *ps_dev; /** Expected number of words in the whole dsp code,INCL header */ - u32 block_length; + long int block_length; /** Number of words read so far */ - u32 word_count; - - /** internal state of DSP code reader */ - struct dsp_code_private *pvt; + long int word_count; + /** Version read from dsp code file */ + u32 version; + /** CRC read from dsp code file */ + u32 crc; }; -/** Prepare *psDspCode to refer to the requested adapter's firmware. -Code file name is obtained from HpiOs_GetDspCodePath +#ifndef DISABLE_PRAGMA_PACK1 +#pragma pack(pop) +#endif + +/** Prepare *psDspCode to refer to the requuested adapter. + Searches the file, or selects the appropriate linked array \return 0 for success, or error code if requested code is not available */ short hpi_dsp_code_open( /** Code identifier, usually adapter family */ - u32 adapter, void *pci_dev, + u32 adapter, /** Pointer to DSP code control structure */ struct dsp_code *ps_dsp_code, /** Pointer to dword to receive OS specific error code */ diff --git a/trunk/sound/pci/asihpi/hpifunc.c b/trunk/sound/pci/asihpi/hpifunc.c index ebb568d695f1..7397b169b89f 100644 --- a/trunk/sound/pci/asihpi/hpifunc.c +++ b/trunk/sound/pci/asihpi/hpifunc.c @@ -1663,64 +1663,68 @@ u16 hpi_channel_mode_get(u32 h_control, u16 *mode) u16 hpi_cobranet_hmi_write(u32 h_control, u32 hmi_address, u32 byte_count, u8 *pb_data) { - struct hpi_msg_cobranet_hmiwrite hm; - struct hpi_response_header hr; - - hpi_init_message_responseV1(&hm.h, sizeof(hm), &hr, sizeof(hr), - HPI_OBJ_CONTROL, HPI_CONTROL_SET_STATE); + struct hpi_message hm; + struct hpi_response hr; - if (hpi_handle_indexes(h_control, &hm.h.adapter_index, - &hm.h.obj_index)) + hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX, + HPI_CONTROL_SET_STATE); + if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index)) return HPI_ERROR_INVALID_HANDLE; - if (byte_count > sizeof(hm.bytes)) - return HPI_ERROR_MESSAGE_BUFFER_TOO_SMALL; + hm.u.cx.u.cobranet_data.byte_count = byte_count; + hm.u.cx.u.cobranet_data.hmi_address = hmi_address; + + if (byte_count <= 8) { + memcpy(hm.u.cx.u.cobranet_data.data, pb_data, byte_count); + hm.u.cx.attribute = HPI_COBRANET_SET; + } else { + hm.u.cx.u.cobranet_bigdata.pb_data = pb_data; + hm.u.cx.attribute = HPI_COBRANET_SET_DATA; + } - hm.p.attribute = HPI_COBRANET_SET; - hm.p.byte_count = byte_count; - hm.p.hmi_address = hmi_address; - memcpy(hm.bytes, pb_data, byte_count); - hm.h.size = (u16)(sizeof(hm.h) + sizeof(hm.p) + byte_count); + hpi_send_recv(&hm, &hr); - hpi_send_recvV1(&hm.h, &hr); return hr.error; } u16 hpi_cobranet_hmi_read(u32 h_control, u32 hmi_address, u32 max_byte_count, u32 *pbyte_count, u8 *pb_data) { - struct hpi_msg_cobranet_hmiread hm; - struct hpi_res_cobranet_hmiread hr; - - hpi_init_message_responseV1(&hm.h, sizeof(hm), &hr.h, sizeof(hr), - HPI_OBJ_CONTROL, HPI_CONTROL_GET_STATE); + struct hpi_message hm; + struct hpi_response hr; - if (hpi_handle_indexes(h_control, &hm.h.adapter_index, - &hm.h.obj_index)) + hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX, + HPI_CONTROL_GET_STATE); + if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index)) return HPI_ERROR_INVALID_HANDLE; - if (max_byte_count > sizeof(hr.bytes)) - return HPI_ERROR_RESPONSE_BUFFER_TOO_SMALL; + hm.u.cx.u.cobranet_data.byte_count = max_byte_count; + hm.u.cx.u.cobranet_data.hmi_address = hmi_address; - hm.p.attribute = HPI_COBRANET_GET; - hm.p.byte_count = max_byte_count; - hm.p.hmi_address = hmi_address; + if (max_byte_count <= 8) { + hm.u.cx.attribute = HPI_COBRANET_GET; + } else { + hm.u.cx.u.cobranet_bigdata.pb_data = pb_data; + hm.u.cx.attribute = HPI_COBRANET_GET_DATA; + } - hpi_send_recvV1(&hm.h, &hr.h); + hpi_send_recv(&hm, &hr); + if (!hr.error && pb_data) { - if (!hr.h.error && pb_data) { - if (hr.byte_count > sizeof(hr.bytes)) + *pbyte_count = hr.u.cx.u.cobranet_data.byte_count; - return HPI_ERROR_RESPONSE_BUFFER_TOO_SMALL; + if (*pbyte_count < max_byte_count) + max_byte_count = *pbyte_count; - *pbyte_count = hr.byte_count; + if (hm.u.cx.attribute == HPI_COBRANET_GET) { + memcpy(pb_data, hr.u.cx.u.cobranet_data.data, + max_byte_count); + } else { - if (hr.byte_count < max_byte_count) - max_byte_count = *pbyte_count; + } - memcpy(pb_data, hr.bytes, max_byte_count); } - return hr.h.error; + return hr.error; } u16 hpi_cobranet_hmi_get_status(u32 h_control, u32 *pstatus, @@ -1729,23 +1733,23 @@ u16 hpi_cobranet_hmi_get_status(u32 h_control, u32 *pstatus, struct hpi_message hm; struct hpi_response hr; - hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, + hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX, HPI_CONTROL_GET_STATE); if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index)) return HPI_ERROR_INVALID_HANDLE; - hm.u.c.attribute = HPI_COBRANET_GET_STATUS; + hm.u.cx.attribute = HPI_COBRANET_GET_STATUS; hpi_send_recv(&hm, &hr); if (!hr.error) { if (pstatus) - *pstatus = hr.u.cu.cobranet.status.status; + *pstatus = hr.u.cx.u.cobranet_status.status; if (preadable_size) *preadable_size = - hr.u.cu.cobranet.status.readable_size; + hr.u.cx.u.cobranet_status.readable_size; if (pwriteable_size) *pwriteable_size = - hr.u.cu.cobranet.status.writeable_size; + hr.u.cx.u.cobranet_status.writeable_size; } return hr.error; } diff --git a/trunk/sound/pci/asihpi/hpimsginit.c b/trunk/sound/pci/asihpi/hpimsginit.c index 52400a6b5f15..628376ce4a49 100644 --- a/trunk/sound/pci/asihpi/hpimsginit.c +++ b/trunk/sound/pci/asihpi/hpimsginit.c @@ -46,7 +46,7 @@ static void hpi_init_message(struct hpi_message *phm, u16 object, if (gwSSX2_bypass) phm->type = HPI_TYPE_SSX2BYPASS_MESSAGE; else - phm->type = HPI_TYPE_REQUEST; + phm->type = HPI_TYPE_MESSAGE; phm->object = object; phm->function = function; phm->version = 0; @@ -89,7 +89,7 @@ static void hpi_init_messageV1(struct hpi_message_header *phm, u16 size, memset(phm, 0, sizeof(*phm)); if ((object > 0) && (object <= HPI_OBJ_MAXINDEX)) { phm->size = size; - phm->type = HPI_TYPE_REQUEST; + phm->type = HPI_TYPE_MESSAGE; phm->object = object; phm->function = function; phm->version = 1; diff --git a/trunk/sound/pci/asihpi/hpimsgx.c b/trunk/sound/pci/asihpi/hpimsgx.c index 2e779421a618..7352a5f7b4f7 100644 --- a/trunk/sound/pci/asihpi/hpimsgx.c +++ b/trunk/sound/pci/asihpi/hpimsgx.c @@ -16,7 +16,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -Extended Message Function With Response Caching +Extended Message Function With Response Cacheing (C) Copyright AudioScience Inc. 2002 *****************************************************************************/ @@ -186,6 +186,7 @@ static void subsys_message(struct hpi_message *phm, struct hpi_response *phr, /* Initialize this module's internal state */ hpios_msgxlock_init(&msgx_lock); memset(&hpi_entry_points, 0, sizeof(hpi_entry_points)); + hpios_locked_mem_init(); /* Init subsys_findadapters response to no-adapters */ HPIMSGX__reset(HPIMSGX_ALLADAPTERS); hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, @@ -196,6 +197,7 @@ static void subsys_message(struct hpi_message *phm, struct hpi_response *phr, case HPI_SUBSYS_DRIVER_UNLOAD: HPI_COMMON(phm, phr); HPIMSGX__cleanup(HPIMSGX_ALLADAPTERS, h_owner); + hpios_locked_mem_free_all(); hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, HPI_SUBSYS_DRIVER_UNLOAD, 0); return; @@ -313,7 +315,7 @@ void hpi_send_recv_ex(struct hpi_message *phm, struct hpi_response *phr, { HPI_DEBUG_MESSAGE(DEBUG, phm); - if (phm->type != HPI_TYPE_REQUEST) { + if (phm->type != HPI_TYPE_MESSAGE) { hpi_init_response(phr, phm->object, phm->function, HPI_ERROR_INVALID_TYPE); return; diff --git a/trunk/sound/pci/asihpi/hpioctl.c b/trunk/sound/pci/asihpi/hpioctl.c index 65fcf4770731..d8e7047512f8 100644 --- a/trunk/sound/pci/asihpi/hpioctl.c +++ b/trunk/sound/pci/asihpi/hpioctl.c @@ -1,7 +1,7 @@ /******************************************************************************* AudioScience HPI driver - Copyright (C) 1997-2011 AudioScience Inc. + Copyright (C) 1997-2010 AudioScience Inc. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as @@ -157,6 +157,11 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg) goto out; } + if (hm->h.adapter_index >= HPI_MAX_ADAPTERS) { + err = -EINVAL; + goto out; + } + switch (hm->h.function) { case HPI_SUBSYS_CREATE_ADAPTER: case HPI_ADAPTER_DELETE: @@ -182,6 +187,7 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg) /* -1=no data 0=read from user mem, 1=write to user mem */ int wrflag = -1; u32 adapter = hm->h.adapter_index; + pa = &adapters[adapter]; if ((adapter > HPI_MAX_ADAPTERS) || (!pa->type)) { hpi_init_response(&hr->r0, HPI_OBJ_ADAPTER, @@ -197,8 +203,6 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg) goto out; } - pa = &adapters[adapter]; - if (mutex_lock_interruptible(&adapters[adapter].mutex)) { err = -EINTR; goto out; diff --git a/trunk/sound/pci/asihpi/hpios.c b/trunk/sound/pci/asihpi/hpios.c index ff2a19b544fa..742ee12a9e17 100644 --- a/trunk/sound/pci/asihpi/hpios.c +++ b/trunk/sound/pci/asihpi/hpios.c @@ -39,6 +39,10 @@ void hpios_delay_micro_seconds(u32 num_micro_sec) } +void hpios_locked_mem_init(void) +{ +} + /** Allocated an area of locked memory for bus master DMA operations. On error, return -ENOMEM, and *pMemArea.size = 0 @@ -81,3 +85,7 @@ u16 hpios_locked_mem_free(struct consistent_dma_area *p_mem_area) return 1; } } + +void hpios_locked_mem_free_all(void) +{ +} diff --git a/trunk/sound/pci/asihpi/hpios.h b/trunk/sound/pci/asihpi/hpios.h index 2f605e34bad0..03273e729f99 100644 --- a/trunk/sound/pci/asihpi/hpios.h +++ b/trunk/sound/pci/asihpi/hpios.h @@ -38,7 +38,6 @@ HPI Operating System Specific macros for Linux Kernel driver #include #include #include -#include #define HPI_NO_OS_FILE_OPS diff --git a/trunk/sound/pci/atiixp.c b/trunk/sound/pci/atiixp.c index 537e0a2cc68a..3119cd97a217 100644 --- a/trunk/sound/pci/atiixp.c +++ b/trunk/sound/pci/atiixp.c @@ -1624,7 +1624,7 @@ static int __devinit snd_atiixp_create(struct snd_card *card, } if (request_irq(pci->irq, snd_atiixp_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + card->shortname, chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_atiixp_free(chip); return -EBUSY; @@ -1701,7 +1701,7 @@ static void __devexit snd_atiixp_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "ATI IXP AC97 controller", .id_table = snd_atiixp_ids, .probe = snd_atiixp_probe, .remove = __devexit_p(snd_atiixp_remove), diff --git a/trunk/sound/pci/atiixp_modem.c b/trunk/sound/pci/atiixp_modem.c index 45df275c8248..2f74c2fdf1ea 100644 --- a/trunk/sound/pci/atiixp_modem.c +++ b/trunk/sound/pci/atiixp_modem.c @@ -1260,7 +1260,7 @@ static int __devinit snd_atiixp_create(struct snd_card *card, } if (request_irq(pci->irq, snd_atiixp_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + card->shortname, chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_atiixp_free(chip); return -EBUSY; @@ -1332,7 +1332,7 @@ static void __devexit snd_atiixp_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "ATI IXP MC97 controller", .id_table = snd_atiixp_ids, .probe = snd_atiixp_probe, .remove = __devexit_p(snd_atiixp_remove), diff --git a/trunk/sound/pci/au88x0/au88x0.c b/trunk/sound/pci/au88x0/au88x0.c index a38469986885..7b72c88e449d 100644 --- a/trunk/sound/pci/au88x0/au88x0.c +++ b/trunk/sound/pci/au88x0/au88x0.c @@ -196,7 +196,7 @@ snd_vortex_create(struct snd_card *card, struct pci_dev *pci, vortex_t ** rchip) } if ((err = request_irq(pci->irq, vortex_interrupt, - IRQF_SHARED, KBUILD_MODNAME, + IRQF_SHARED, CARD_NAME_SHORT, chip)) != 0) { printk(KERN_ERR "cannot grab irq\n"); goto irq_out; @@ -375,7 +375,7 @@ static void __devexit snd_vortex_remove(struct pci_dev *pci) // pci_driver definition static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = CARD_NAME_SHORT, .id_table = snd_vortex_ids, .probe = snd_vortex_probe, .remove = __devexit_p(snd_vortex_remove), diff --git a/trunk/sound/pci/aw2/aw2-alsa.c b/trunk/sound/pci/aw2/aw2-alsa.c index f8569b11331b..c15002242d98 100644 --- a/trunk/sound/pci/aw2/aw2-alsa.c +++ b/trunk/sound/pci/aw2/aw2-alsa.c @@ -171,7 +171,7 @@ MODULE_DEVICE_TABLE(pci, snd_aw2_ids); /* pci_driver definition */ static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "Emagic Audiowerk 2", .id_table = snd_aw2_ids, .probe = snd_aw2_probe, .remove = __devexit_p(snd_aw2_remove), @@ -317,7 +317,7 @@ static int __devinit snd_aw2_create(struct snd_card *card, snd_aw2_saa7146_setup(&chip->saa7146, chip->iobase_virt); if (request_irq(pci->irq, snd_aw2_saa7146_interrupt, - IRQF_SHARED, KBUILD_MODNAME, chip)) { + IRQF_SHARED, "Audiowerk2", chip)) { printk(KERN_ERR "aw2: Cannot grab irq %d\n", pci->irq); iounmap(chip->iobase_virt); diff --git a/trunk/sound/pci/azt3328.c b/trunk/sound/pci/azt3328.c index e4d76a270c9f..9b7a6346037a 100644 --- a/trunk/sound/pci/azt3328.c +++ b/trunk/sound/pci/azt3328.c @@ -2559,7 +2559,7 @@ snd_azf3328_create(struct snd_card *card, codec_setup->name = "I2S_OUT"; if (request_irq(pci->irq, snd_azf3328_interrupt, - IRQF_SHARED, KBUILD_MODNAME, chip)) { + IRQF_SHARED, card->shortname, chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); err = -EBUSY; goto out_err; @@ -2860,7 +2860,7 @@ snd_azf3328_resume(struct pci_dev *pci) static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "AZF3328", .id_table = snd_azf3328_ids, .probe = snd_azf3328_probe, .remove = __devexit_p(snd_azf3328_remove), diff --git a/trunk/sound/pci/bt87x.c b/trunk/sound/pci/bt87x.c index 39180335c237..2958a05b5293 100644 --- a/trunk/sound/pci/bt87x.c +++ b/trunk/sound/pci/bt87x.c @@ -760,7 +760,7 @@ static int __devinit snd_bt87x_create(struct snd_card *card, snd_bt87x_writel(chip, REG_INT_STAT, MY_INTERRUPTS); err = request_irq(pci->irq, snd_bt87x_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip); + "Bt87x audio", chip); if (err < 0) { snd_printk(KERN_ERR "cannot grab irq %d\n", pci->irq); goto fail; @@ -965,7 +965,7 @@ static DEFINE_PCI_DEVICE_TABLE(snd_bt87x_default_ids) = { }; static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "Bt87x", .id_table = snd_bt87x_ids, .probe = snd_bt87x_probe, .remove = __devexit_p(snd_bt87x_remove), diff --git a/trunk/sound/pci/ca0106/ca0106_main.c b/trunk/sound/pci/ca0106/ca0106_main.c index 061b7e654586..437759239694 100644 --- a/trunk/sound/pci/ca0106/ca0106_main.c +++ b/trunk/sound/pci/ca0106/ca0106_main.c @@ -1666,7 +1666,7 @@ static int __devinit snd_ca0106_create(int dev, struct snd_card *card, } if (request_irq(pci->irq, snd_ca0106_interrupt, - IRQF_SHARED, KBUILD_MODNAME, chip)) { + IRQF_SHARED, "snd_ca0106", chip)) { snd_ca0106_free(chip); printk(KERN_ERR "cannot grab irq\n"); return -EBUSY; @@ -1933,7 +1933,7 @@ MODULE_DEVICE_TABLE(pci, snd_ca0106_ids); // pci_driver definition static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "CA0106", .id_table = snd_ca0106_ids, .probe = snd_ca0106_probe, .remove = __devexit_p(snd_ca0106_remove), diff --git a/trunk/sound/pci/cmipci.c b/trunk/sound/pci/cmipci.c index 9cf99fb7eb9c..f4e573555da3 100644 --- a/trunk/sound/pci/cmipci.c +++ b/trunk/sound/pci/cmipci.c @@ -3053,7 +3053,7 @@ static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pc cm->iobase = pci_resource_start(pci, 0); if (request_irq(pci->irq, snd_cmipci_interrupt, - IRQF_SHARED, KBUILD_MODNAME, cm)) { + IRQF_SHARED, card->driver, cm)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_cmipci_free(cm); return -EBUSY; @@ -3398,7 +3398,7 @@ static int snd_cmipci_resume(struct pci_dev *pci) #endif /* CONFIG_PM */ static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "C-Media PCI", .id_table = snd_cmipci_ids, .probe = snd_cmipci_probe, .remove = __devexit_p(snd_cmipci_remove), diff --git a/trunk/sound/pci/cs4281.c b/trunk/sound/pci/cs4281.c index 07f04e390aa1..6772070ed492 100644 --- a/trunk/sound/pci/cs4281.c +++ b/trunk/sound/pci/cs4281.c @@ -1382,7 +1382,7 @@ static int __devinit snd_cs4281_create(struct snd_card *card, } if (request_irq(pci->irq, snd_cs4281_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + "CS4281", chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_cs4281_free(chip); return -ENOMEM; @@ -2085,7 +2085,7 @@ static int cs4281_resume(struct pci_dev *pci) #endif /* CONFIG_PM */ static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "CS4281", .id_table = snd_cs4281_ids, .probe = snd_cs4281_probe, .remove = __devexit_p(snd_cs4281_remove), diff --git a/trunk/sound/pci/cs46xx/cs46xx.c b/trunk/sound/pci/cs46xx/cs46xx.c index 1af95559aaaa..767fa7f06cd0 100644 --- a/trunk/sound/pci/cs46xx/cs46xx.c +++ b/trunk/sound/pci/cs46xx/cs46xx.c @@ -162,7 +162,7 @@ static void __devexit snd_card_cs46xx_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "Sound Fusion CS46xx", .id_table = snd_cs46xx_ids, .probe = snd_card_cs46xx_probe, .remove = __devexit_p(snd_card_cs46xx_remove), diff --git a/trunk/sound/pci/cs46xx/cs46xx_lib.c b/trunk/sound/pci/cs46xx/cs46xx_lib.c index 9546bf07f0d1..aad37082cb6e 100644 --- a/trunk/sound/pci/cs46xx/cs46xx_lib.c +++ b/trunk/sound/pci/cs46xx/cs46xx_lib.c @@ -3835,7 +3835,7 @@ int __devinit snd_cs46xx_create(struct snd_card *card, } if (request_irq(pci->irq, snd_cs46xx_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + "CS46XX", chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_cs46xx_free(chip); return -EBUSY; diff --git a/trunk/sound/pci/cs5530.c b/trunk/sound/pci/cs5530.c index a4669346d146..bc07e275d4d4 100644 --- a/trunk/sound/pci/cs5530.c +++ b/trunk/sound/pci/cs5530.c @@ -285,7 +285,7 @@ static int __devinit snd_cs5530_probe(struct pci_dev *pci, } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "CS5530_Audio", .id_table = snd_cs5530_ids, .probe = snd_cs5530_probe, .remove = __devexit_p(snd_cs5530_remove), diff --git a/trunk/sound/pci/cs5535audio/cs5535audio.c b/trunk/sound/pci/cs5535audio/cs5535audio.c index 10d22ed5fece..afb803708416 100644 --- a/trunk/sound/pci/cs5535audio/cs5535audio.c +++ b/trunk/sound/pci/cs5535audio/cs5535audio.c @@ -311,7 +311,7 @@ static int __devinit snd_cs5535audio_create(struct snd_card *card, cs5535au->port = pci_resource_start(pci, 0); if (request_irq(pci->irq, snd_cs5535audio_interrupt, - IRQF_SHARED, KBUILD_MODNAME, cs5535au)) { + IRQF_SHARED, "CS5535 Audio", cs5535au)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); err = -EBUSY; goto sndfail; @@ -395,7 +395,7 @@ static void __devexit snd_cs5535audio_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = DRIVER_NAME, .id_table = snd_cs5535audio_ids, .probe = snd_cs5535audio_probe, .remove = __devexit_p(snd_cs5535audio_remove), diff --git a/trunk/sound/pci/ctxfi/ct20k2reg.h b/trunk/sound/pci/ctxfi/ct20k2reg.h index ca501ba03d64..e0394e3996e8 100644 --- a/trunk/sound/pci/ctxfi/ct20k2reg.h +++ b/trunk/sound/pci/ctxfi/ct20k2reg.h @@ -55,7 +55,6 @@ /* GPIO Registers */ #define GPIO_DATA 0x1B7020 #define GPIO_CTRL 0x1B7024 -#define GPIO_EXT_DATA 0x1B70A0 /* Virtual memory registers */ #define VMEM_PTPAL 0x1C6300 /* 0x1C6300 + (16 * Chn) */ diff --git a/trunk/sound/pci/ctxfi/ctatc.c b/trunk/sound/pci/ctxfi/ctatc.c index d8a4423539ce..13f33c0719d3 100644 --- a/trunk/sound/pci/ctxfi/ctatc.c +++ b/trunk/sound/pci/ctxfi/ctatc.c @@ -18,6 +18,7 @@ #include "ctatc.h" #include "ctpcm.h" #include "ctmixer.h" +#include "cthardware.h" #include "ctsrc.h" #include "ctamixer.h" #include "ctdaio.h" @@ -29,6 +30,7 @@ #include #define MONO_SUM_SCALE 0x19a8 /* 2^(-0.5) in 14-bit floating format */ +#define DAIONUM 7 #define MAX_MULTI_CHN 8 #define IEC958_DEFAULT_CON ((IEC958_AES0_NONAUDIO \ @@ -51,8 +53,6 @@ static struct snd_pci_quirk __devinitdata subsys_20k1_list[] = { static struct snd_pci_quirk __devinitdata subsys_20k2_list[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB0760, "SB0760", CTSB0760), - SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB1270, - "SB1270", CTSB1270), SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08801, "SB0880", CTSB0880), SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08802, @@ -75,7 +75,6 @@ static const char *ct_subsys_name[NUM_CTCARDS] = { [CTSB0760] = "SB076x", [CTHENDRIX] = "Hendrix", [CTSB0880] = "SB0880", - [CTSB1270] = "SB1270", [CT20K2_UNKNOWN] = "Unknown", }; @@ -460,12 +459,12 @@ static void setup_src_node_conf(struct ct_atc *atc, struct ct_atc_pcm *apcm, apcm->substream->runtime->rate); *n_srcc = 0; - if (1 == atc->msr) { /* FIXME: do we really need SRC here if pitch==1 */ + if (1 == atc->msr) { *n_srcc = apcm->substream->runtime->channels; conf[0].pitch = pitch; conf[0].mix_msr = conf[0].imp_msr = conf[0].msr = 1; conf[0].vo = 1; - } else if (2 <= atc->msr) { + } else if (2 == atc->msr) { if (0x8000000 < pitch) { /* Need two-stage SRCs, SRCIMPs and * AMIXERs for converting format */ @@ -971,39 +970,11 @@ static int atc_select_mic_in(struct ct_atc *atc) return 0; } -static struct capabilities atc_capabilities(struct ct_atc *atc) +static int atc_have_digit_io_switch(struct ct_atc *atc) { struct hw *hw = atc->hw; - return hw->capabilities(hw); -} - -static int atc_output_switch_get(struct ct_atc *atc) -{ - struct hw *hw = atc->hw; - - return hw->output_switch_get(hw); -} - -static int atc_output_switch_put(struct ct_atc *atc, int position) -{ - struct hw *hw = atc->hw; - - return hw->output_switch_put(hw, position); -} - -static int atc_mic_source_switch_get(struct ct_atc *atc) -{ - struct hw *hw = atc->hw; - - return hw->mic_source_switch_get(hw); -} - -static int atc_mic_source_switch_put(struct ct_atc *atc, int position) -{ - struct hw *hw = atc->hw; - - return hw->mic_source_switch_put(hw, position); + return hw->have_digit_io_switch(hw); } static int atc_select_digit_io(struct ct_atc *atc) @@ -1074,11 +1045,6 @@ static int atc_line_in_unmute(struct ct_atc *atc, unsigned char state) return atc_daio_unmute(atc, state, LINEIM); } -static int atc_mic_unmute(struct ct_atc *atc, unsigned char state) -{ - return atc_daio_unmute(atc, state, MIC); -} - static int atc_spdif_out_unmute(struct ct_atc *atc, unsigned char state) { return atc_daio_unmute(atc, state, SPDIFOO); @@ -1365,20 +1331,17 @@ static int atc_get_resources(struct ct_atc *atc) struct srcimp_mgr *srcimp_mgr; struct sum_desc sum_dsc = {0}; struct sum_mgr *sum_mgr; - int err, i, num_srcs, num_daios; + int err, i; - num_daios = ((atc->model == CTSB1270) ? 8 : 7); - num_srcs = ((atc->model == CTSB1270) ? 6 : 4); - - atc->daios = kzalloc(sizeof(void *)*num_daios, GFP_KERNEL); + atc->daios = kzalloc(sizeof(void *)*(DAIONUM), GFP_KERNEL); if (!atc->daios) return -ENOMEM; - atc->srcs = kzalloc(sizeof(void *)*num_srcs, GFP_KERNEL); + atc->srcs = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL); if (!atc->srcs) return -ENOMEM; - atc->srcimps = kzalloc(sizeof(void *)*num_srcs, GFP_KERNEL); + atc->srcimps = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL); if (!atc->srcimps) return -ENOMEM; @@ -1388,9 +1351,8 @@ static int atc_get_resources(struct ct_atc *atc) daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO]; da_desc.msr = atc->msr; - for (i = 0, atc->n_daio = 0; i < num_daios; i++) { - da_desc.type = (atc->model != CTSB073X) ? i : - ((i == SPDIFIO) ? SPDIFI1 : i); + for (i = 0, atc->n_daio = 0; i < DAIONUM-1; i++) { + da_desc.type = i; err = daio_mgr->get_daio(daio_mgr, &da_desc, (struct daio **)&atc->daios[i]); if (err) { @@ -1400,12 +1362,23 @@ static int atc_get_resources(struct ct_atc *atc) } atc->n_daio++; } + if (atc->model == CTSB073X) + da_desc.type = SPDIFI1; + else + da_desc.type = SPDIFIO; + err = daio_mgr->get_daio(daio_mgr, &da_desc, + (struct daio **)&atc->daios[i]); + if (err) { + printk(KERN_ERR "ctxfi: Failed to get S/PDIF-in resource!!!\n"); + return err; + } + atc->n_daio++; src_mgr = atc->rsc_mgrs[SRC]; src_dsc.multi = 1; src_dsc.msr = atc->msr; src_dsc.mode = ARCRW; - for (i = 0, atc->n_src = 0; i < num_srcs; i++) { + for (i = 0, atc->n_src = 0; i < (2*2); i++) { err = src_mgr->get_src(src_mgr, &src_dsc, (struct src **)&atc->srcs[i]); if (err) @@ -1415,8 +1388,8 @@ static int atc_get_resources(struct ct_atc *atc) } srcimp_mgr = atc->rsc_mgrs[SRCIMP]; - srcimp_dsc.msr = 8; - for (i = 0, atc->n_srcimp = 0; i < num_srcs; i++) { + srcimp_dsc.msr = 8; /* SRCIMPs for S/PDIFIn SRT */ + for (i = 0, atc->n_srcimp = 0; i < (2*1); i++) { err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc, (struct srcimp **)&atc->srcimps[i]); if (err) @@ -1424,6 +1397,15 @@ static int atc_get_resources(struct ct_atc *atc) atc->n_srcimp++; } + srcimp_dsc.msr = 8; /* SRCIMPs for LINE/MICIn SRT */ + for (i = 0; i < (2*1); i++) { + err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc, + (struct srcimp **)&atc->srcimps[2*1+i]); + if (err) + return err; + + atc->n_srcimp++; + } sum_mgr = atc->rsc_mgrs[SUM]; sum_dsc.msr = atc->msr; @@ -1506,18 +1488,6 @@ static void atc_connect_resources(struct ct_atc *atc) src = atc->srcs[3]; mixer->set_input_right(mixer, MIX_LINE_IN, &src->rsc); - if (atc->model == CTSB1270) { - /* Titanium HD has a dedicated ADC for the Mic. */ - dai = container_of(atc->daios[MIC], struct dai, daio); - atc_connect_dai(atc->rsc_mgrs[SRC], dai, - (struct src **)&atc->srcs[4], - (struct srcimp **)&atc->srcimps[4]); - src = atc->srcs[4]; - mixer->set_input_left(mixer, MIX_MIC_IN, &src->rsc); - src = atc->srcs[5]; - mixer->set_input_right(mixer, MIX_MIC_IN, &src->rsc); - } - dai = container_of(atc->daios[SPDIFIO], struct dai, daio); atc_connect_dai(atc->rsc_mgrs[SRC], dai, (struct src **)&atc->srcs[0], @@ -1636,17 +1606,12 @@ static struct ct_atc atc_preset __devinitdata = { .line_clfe_unmute = atc_line_clfe_unmute, .line_rear_unmute = atc_line_rear_unmute, .line_in_unmute = atc_line_in_unmute, - .mic_unmute = atc_mic_unmute, .spdif_out_unmute = atc_spdif_out_unmute, .spdif_in_unmute = atc_spdif_in_unmute, .spdif_out_get_status = atc_spdif_out_get_status, .spdif_out_set_status = atc_spdif_out_set_status, .spdif_out_passthru = atc_spdif_out_passthru, - .capabilities = atc_capabilities, - .output_switch_get = atc_output_switch_get, - .output_switch_put = atc_output_switch_put, - .mic_source_switch_get = atc_mic_source_switch_get, - .mic_source_switch_put = atc_mic_source_switch_put, + .have_digit_io_switch = atc_have_digit_io_switch, #ifdef CONFIG_PM .suspend = atc_suspend, .resume = atc_resume, diff --git a/trunk/sound/pci/ctxfi/ctatc.h b/trunk/sound/pci/ctxfi/ctatc.h index 3a0def656af0..7167c0185d52 100644 --- a/trunk/sound/pci/ctxfi/ctatc.h +++ b/trunk/sound/pci/ctxfi/ctatc.h @@ -25,7 +25,6 @@ #include #include "ctvmem.h" -#include "cthardware.h" #include "ctresource.h" enum CTALSADEVS { /* Types of alsa devices */ @@ -116,17 +115,12 @@ struct ct_atc { int (*line_clfe_unmute)(struct ct_atc *atc, unsigned char state); int (*line_rear_unmute)(struct ct_atc *atc, unsigned char state); int (*line_in_unmute)(struct ct_atc *atc, unsigned char state); - int (*mic_unmute)(struct ct_atc *atc, unsigned char state); int (*spdif_out_unmute)(struct ct_atc *atc, unsigned char state); int (*spdif_in_unmute)(struct ct_atc *atc, unsigned char state); int (*spdif_out_get_status)(struct ct_atc *atc, unsigned int *status); int (*spdif_out_set_status)(struct ct_atc *atc, unsigned int status); int (*spdif_out_passthru)(struct ct_atc *atc, unsigned char state); - struct capabilities (*capabilities)(struct ct_atc *atc); - int (*output_switch_get)(struct ct_atc *atc); - int (*output_switch_put)(struct ct_atc *atc, int position); - int (*mic_source_switch_get)(struct ct_atc *atc); - int (*mic_source_switch_put)(struct ct_atc *atc, int position); + int (*have_digit_io_switch)(struct ct_atc *atc); /* Don't touch! Used for internal object. */ void *rsc_mgrs[NUM_RSCTYP]; /* chip resource managers */ diff --git a/trunk/sound/pci/ctxfi/ctdaio.c b/trunk/sound/pci/ctxfi/ctdaio.c index 0c00eb4088ef..47d9ea97de02 100644 --- a/trunk/sound/pci/ctxfi/ctdaio.c +++ b/trunk/sound/pci/ctxfi/ctdaio.c @@ -22,9 +22,20 @@ #include #include +#define DAIO_RESOURCE_NUM NUM_DAIOTYP #define DAIO_OUT_MAX SPDIFOO -struct daio_usage { +union daio_usage { + struct { + unsigned short lineo1:1; + unsigned short lineo2:1; + unsigned short lineo3:1; + unsigned short lineo4:1; + unsigned short spdifoo:1; + unsigned short lineim:1; + unsigned short spdifio:1; + unsigned short spdifi1:1; + } bf; unsigned short data; }; @@ -50,7 +61,6 @@ struct daio_rsc_idx idx_20k2[NUM_DAIOTYP] = { [LINEO3] = {.left = 0x50, .right = 0x51}, [LINEO4] = {.left = 0x70, .right = 0x71}, [LINEIM] = {.left = 0x45, .right = 0xc5}, - [MIC] = {.left = 0x55, .right = 0xd5}, [SPDIFOO] = {.left = 0x00, .right = 0x01}, [SPDIFIO] = {.left = 0x05, .right = 0x85}, }; @@ -128,7 +138,6 @@ static unsigned int daio_device_index(enum DAIOTYP type, struct hw *hw) case LINEO3: return 5; case LINEO4: return 6; case LINEIM: return 4; - case MIC: return 5; default: return -EINVAL; } default: @@ -510,17 +519,17 @@ static int dai_rsc_uninit(struct dai *dai) static int daio_mgr_get_rsc(struct rsc_mgr *mgr, enum DAIOTYP type) { - if (((struct daio_usage *)mgr->rscs)->data & (0x1 << type)) + if (((union daio_usage *)mgr->rscs)->data & (0x1 << type)) return -ENOENT; - ((struct daio_usage *)mgr->rscs)->data |= (0x1 << type); + ((union daio_usage *)mgr->rscs)->data |= (0x1 << type); return 0; } static int daio_mgr_put_rsc(struct rsc_mgr *mgr, enum DAIOTYP type) { - ((struct daio_usage *)mgr->rscs)->data &= ~(0x1 << type); + ((union daio_usage *)mgr->rscs)->data &= ~(0x1 << type); return 0; } @@ -703,7 +712,7 @@ int daio_mgr_create(void *hw, struct daio_mgr **rdaio_mgr) if (!daio_mgr) return -ENOMEM; - err = rsc_mgr_init(&daio_mgr->mgr, DAIO, NUM_DAIOTYP, hw); + err = rsc_mgr_init(&daio_mgr->mgr, DAIO, DAIO_RESOURCE_NUM, hw); if (err) goto error1; diff --git a/trunk/sound/pci/ctxfi/ctdaio.h b/trunk/sound/pci/ctxfi/ctdaio.h index 85ccb6ee1ab4..0f52ce571ee8 100644 --- a/trunk/sound/pci/ctxfi/ctdaio.h +++ b/trunk/sound/pci/ctxfi/ctdaio.h @@ -33,7 +33,6 @@ enum DAIOTYP { SPDIFOO, /* S/PDIF Out (Flexijack/Optical) */ LINEIM, SPDIFIO, /* S/PDIF In (Flexijack/Optical) on the card */ - MIC, /* Dedicated mic on Titanium HD */ SPDIFI1, /* S/PDIF In on internal Drive Bay */ NUM_DAIOTYP }; diff --git a/trunk/sound/pci/ctxfi/cthardware.h b/trunk/sound/pci/ctxfi/cthardware.h index 908315bec3b4..af55405f5dec 100644 --- a/trunk/sound/pci/ctxfi/cthardware.h +++ b/trunk/sound/pci/ctxfi/cthardware.h @@ -39,7 +39,6 @@ enum CTCARDS { CT20K2_MODEL_FIRST = CTSB0760, CTHENDRIX, CTSB0880, - CTSB1270, CT20K2_UNKNOWN, NUM_CTCARDS /* This should always be the last */ }; @@ -61,13 +60,6 @@ struct card_conf { unsigned int msr; /* master sample rate in rsrs */ }; -struct capabilities { - unsigned int digit_io_switch:1; - unsigned int dedicated_mic:1; - unsigned int output_switch:1; - unsigned int mic_source_switch:1; -}; - struct hw { int (*card_init)(struct hw *hw, struct card_conf *info); int (*card_stop)(struct hw *hw); @@ -78,11 +70,7 @@ struct hw { #endif int (*is_adc_source_selected)(struct hw *hw, enum ADCSRC source); int (*select_adc_source)(struct hw *hw, enum ADCSRC source); - struct capabilities (*capabilities)(struct hw *hw); - int (*output_switch_get)(struct hw *hw); - int (*output_switch_put)(struct hw *hw, int position); - int (*mic_source_switch_get)(struct hw *hw); - int (*mic_source_switch_put)(struct hw *hw, int position); + int (*have_digit_io_switch)(struct hw *hw); /* SRC operations */ int (*src_rsc_get_ctrl_blk)(void **rblk); diff --git a/trunk/sound/pci/ctxfi/cthw20k1.c b/trunk/sound/pci/ctxfi/cthw20k1.c index a7df19791f5a..a5c957db5cea 100644 --- a/trunk/sound/pci/ctxfi/cthw20k1.c +++ b/trunk/sound/pci/ctxfi/cthw20k1.c @@ -1777,17 +1777,10 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info) return adc_init_SBx(hw, info->input, info->mic20db); } -static struct capabilities hw_capabilities(struct hw *hw) +static int hw_have_digit_io_switch(struct hw *hw) { - struct capabilities cap; - /* SB073x and Vista compatible cards have no digit IO switch */ - cap.digit_io_switch = !(hw->model == CTSB073X || hw->model == CTUAA); - cap.dedicated_mic = 0; - cap.output_switch = 0; - cap.mic_source_switch = 0; - - return cap; + return !(hw->model == CTSB073X || hw->model == CTUAA); } #define CTLBITS(a, b, c, d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) @@ -1940,7 +1933,7 @@ static int hw_card_start(struct hw *hw) if (hw->irq < 0) { err = request_irq(pci->irq, ct_20k1_interrupt, IRQF_SHARED, - KBUILD_MODNAME, hw); + "ctxfi", hw); if (err < 0) { printk(KERN_ERR "XFi: Cannot get irq %d\n", pci->irq); goto error2; @@ -2179,7 +2172,7 @@ static struct hw ct20k1_preset __devinitdata = { .pll_init = hw_pll_init, .is_adc_source_selected = hw_is_adc_input_selected, .select_adc_source = hw_adc_input_select, - .capabilities = hw_capabilities, + .have_digit_io_switch = hw_have_digit_io_switch, #ifdef CONFIG_PM .suspend = hw_suspend, .resume = hw_resume, diff --git a/trunk/sound/pci/ctxfi/cthw20k2.c b/trunk/sound/pci/ctxfi/cthw20k2.c index d6c54b524bfa..5364164674e4 100644 --- a/trunk/sound/pci/ctxfi/cthw20k2.c +++ b/trunk/sound/pci/ctxfi/cthw20k2.c @@ -8,7 +8,7 @@ * @File cthw20k2.c * * @Brief - * This file contains the implementation of hardware access method for 20k2. + * This file contains the implementation of hardware access methord for 20k2. * * @Author Liu Chun * @Date May 14 2008 @@ -38,8 +38,6 @@ struct hw20k2 { unsigned char dev_id; unsigned char addr_size; unsigned char data_size; - - int mic_source; }; static u32 hw_read_20kx(struct hw *hw, u32 reg); @@ -1165,12 +1163,7 @@ static int hw_daio_init(struct hw *hw, const struct daio_conf *info) hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x01010101); hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0); } else if (2 == info->msr) { - if (hw->model != CTSB1270) { - hw_write_20kx(hw, AUDIO_IO_MCLK, 0x11111111); - } else { - /* PCM4220 on Titanium HD is different. */ - hw_write_20kx(hw, AUDIO_IO_MCLK, 0x11011111); - } + hw_write_20kx(hw, AUDIO_IO_MCLK, 0x11111111); /* Specify all playing 96khz * EA [0] - Enabled * RTA [4:5] - 96kHz @@ -1182,10 +1175,6 @@ static int hw_daio_init(struct hw *hw, const struct daio_conf *info) * RTD [28:29] - 96kHz */ hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x11111111); hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0); - } else if ((4 == info->msr) && (hw->model == CTSB1270)) { - hw_write_20kx(hw, AUDIO_IO_MCLK, 0x21011111); - hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x21212121); - hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0); } else { printk(KERN_ALERT "ctxfi: ERROR!!! Invalid sampling rate!!!\n"); return -EINVAL; @@ -1193,8 +1182,6 @@ static int hw_daio_init(struct hw *hw, const struct daio_conf *info) for (i = 0; i < 8; i++) { if (i <= 3) { - /* This comment looks wrong since loop is over 4 */ - /* channels and emu20k2 supports 4 spdif IOs. */ /* 1st 3 channels are SPDIFs (SB0960) */ if (i == 3) data = 0x1001001; @@ -1219,16 +1206,12 @@ static int hw_daio_init(struct hw *hw, const struct daio_conf *info) hw_write_20kx(hw, AUDIO_IO_TX_CSTAT_H+(0x40*i), 0x0B); } else { - /* Again, loop is over 4 channels not 5. */ /* Next 5 channels are I2S (SB0960) */ data = 0x11; hw_write_20kx(hw, AUDIO_IO_RX_CTL+(0x40*i), data); if (2 == info->msr) { /* Four channels per sample period */ data |= 0x1000; - } else if (4 == info->msr) { - /* FIXME: check this against the chip spec */ - data |= 0x2000; } hw_write_20kx(hw, AUDIO_IO_TX_CTL+(0x40*i), data); } @@ -1316,18 +1299,21 @@ static int hw_pll_init(struct hw *hw, unsigned int rsr) pllenb = 0xB; hw_write_20kx(hw, PLL_ENB, pllenb); - pllctl = 0x20C00000; - set_field(&pllctl, PLLCTL_B, 0); - set_field(&pllctl, PLLCTL_FD, 48000 == rsr ? 16 - 4 : 147 - 4); - set_field(&pllctl, PLLCTL_RD, 48000 == rsr ? 1 - 1 : 10 - 1); + pllctl = 0x20D00000; + set_field(&pllctl, PLLCTL_FD, 16 - 4); hw_write_20kx(hw, PLL_CTL, pllctl); mdelay(40); - pllctl = hw_read_20kx(hw, PLL_CTL); - set_field(&pllctl, PLLCTL_FD, 48000 == rsr ? 16 - 2 : 147 - 2); + set_field(&pllctl, PLLCTL_B, 0); + if (48000 == rsr) { + set_field(&pllctl, PLLCTL_FD, 16 - 2); + set_field(&pllctl, PLLCTL_RD, 1 - 1); /* 3000*16/1 = 48000 */ + } else { /* 44100 */ + set_field(&pllctl, PLLCTL_FD, 147 - 2); + set_field(&pllctl, PLLCTL_RD, 10 - 1); /* 3000*147/10 = 44100 */ + } hw_write_20kx(hw, PLL_CTL, pllctl); mdelay(40); - for (i = 0; i < 1000; i++) { pllstat = hw_read_20kx(hw, PLL_STAT); if (get_field(pllstat, PLLSTAT_PD)) @@ -1571,7 +1557,7 @@ static int hw20k2_i2c_write(struct hw *hw, u16 addr, u32 data) hw_write_20kx(hw, I2C_IF_STATUS, i2c_status); hw20k2_i2c_wait_data_ready(hw); - /* Dummy write to trigger the write operation */ + /* Dummy write to trigger the write oprtation */ hw_write_20kx(hw, I2C_IF_WDATA, 0); hw20k2_i2c_wait_data_ready(hw); @@ -1582,30 +1568,6 @@ static int hw20k2_i2c_write(struct hw *hw, u16 addr, u32 data) return 0; } -static void hw_dac_stop(struct hw *hw) -{ - u32 data; - data = hw_read_20kx(hw, GPIO_DATA); - data &= 0xFFFFFFFD; - hw_write_20kx(hw, GPIO_DATA, data); - mdelay(10); -} - -static void hw_dac_start(struct hw *hw) -{ - u32 data; - data = hw_read_20kx(hw, GPIO_DATA); - data |= 0x2; - hw_write_20kx(hw, GPIO_DATA, data); - mdelay(50); -} - -static void hw_dac_reset(struct hw *hw) -{ - hw_dac_stop(hw); - hw_dac_start(hw); -} - static int hw_dac_init(struct hw *hw, const struct dac_conf *info) { int err; @@ -1632,21 +1594,6 @@ static int hw_dac_init(struct hw *hw, const struct dac_conf *info) 0x00000000 /* Vol Control B4 */ }; - if (hw->model == CTSB1270) { - hw_dac_stop(hw); - data = hw_read_20kx(hw, GPIO_DATA); - data &= ~0x0600; - if (1 == info->msr) - data |= 0x0000; /* Single Speed Mode 0-50kHz */ - else if (2 == info->msr) - data |= 0x0200; /* Double Speed Mode 50-100kHz */ - else - data |= 0x0600; /* Quad Speed Mode 100-200kHz */ - hw_write_20kx(hw, GPIO_DATA, data); - hw_dac_start(hw); - return 0; - } - /* Set DAC reset bit as output */ data = hw_read_20kx(hw, GPIO_CTRL); data |= 0x02; @@ -1659,8 +1606,22 @@ static int hw_dac_init(struct hw *hw, const struct dac_conf *info) for (i = 0; i < 2; i++) { /* Reset DAC twice just in-case the chip * didn't initialized properly */ - hw_dac_reset(hw); - hw_dac_reset(hw); + data = hw_read_20kx(hw, GPIO_DATA); + /* GPIO data bit 1 */ + data &= 0xFFFFFFFD; + hw_write_20kx(hw, GPIO_DATA, data); + mdelay(10); + data |= 0x2; + hw_write_20kx(hw, GPIO_DATA, data); + mdelay(50); + + /* Reset the 2nd time */ + data &= 0xFFFFFFFD; + hw_write_20kx(hw, GPIO_DATA, data); + mdelay(10); + data |= 0x2; + hw_write_20kx(hw, GPIO_DATA, data); + mdelay(50); if (hw20k2_i2c_read(hw, CS4382_MC1, &cs_read.mode_control_1)) continue; @@ -1764,11 +1725,7 @@ static int hw_dac_init(struct hw *hw, const struct dac_conf *info) static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type) { u32 data; - if (hw->model == CTSB1270) { - /* Titanium HD has two ADC chips, one for line in and one */ - /* for MIC. We don't need to switch the ADC input. */ - return 1; - } + data = hw_read_20kx(hw, GPIO_DATA); switch (type) { case ADC_MICIN: @@ -1785,47 +1742,35 @@ static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type) #define MIC_BOOST_0DB 0xCF #define MIC_BOOST_STEPS_PER_DB 2 - -static void hw_wm8775_input_select(struct hw *hw, u8 input, s8 gain_in_db) -{ - u32 adcmc, gain; - - if (input > 3) - input = 3; - - adcmc = ((u32)1 << input) | 0x100; /* Link L+R gain... */ - - hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, adcmc), - MAKE_WM8775_DATA(adcmc)); - - if (gain_in_db < -103) - gain_in_db = -103; - if (gain_in_db > 24) - gain_in_db = 24; - - gain = gain_in_db * MIC_BOOST_STEPS_PER_DB + MIC_BOOST_0DB; - - hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, gain), - MAKE_WM8775_DATA(gain)); - /* ...so there should be no need for the following. */ - hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, gain), - MAKE_WM8775_DATA(gain)); -} +#define MIC_BOOST_20DB (MIC_BOOST_0DB + 20 * MIC_BOOST_STEPS_PER_DB) static int hw_adc_input_select(struct hw *hw, enum ADCSRC type) { u32 data; + data = hw_read_20kx(hw, GPIO_DATA); switch (type) { case ADC_MICIN: data |= (0x1 << 14); hw_write_20kx(hw, GPIO_DATA, data); - hw_wm8775_input_select(hw, 0, 20); /* Mic, 20dB */ + hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x101), + MAKE_WM8775_DATA(0x101)); /* Mic-in */ + hw20k2_i2c_write(hw, + MAKE_WM8775_ADDR(WM8775_AADCL, MIC_BOOST_20DB), + MAKE_WM8775_DATA(MIC_BOOST_20DB)); /* +20dB */ + hw20k2_i2c_write(hw, + MAKE_WM8775_ADDR(WM8775_AADCR, MIC_BOOST_20DB), + MAKE_WM8775_DATA(MIC_BOOST_20DB)); /* +20dB */ break; case ADC_LINEIN: data &= ~(0x1 << 14); hw_write_20kx(hw, GPIO_DATA, data); - hw_wm8775_input_select(hw, 1, 0); /* Line-in, 0dB */ + hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x102), + MAKE_WM8775_DATA(0x102)); /* Line-in */ + hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xCF), + MAKE_WM8775_DATA(0xCF)); /* No boost */ + hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xCF), + MAKE_WM8775_DATA(0xCF)); /* No boost */ break; default: break; @@ -1837,7 +1782,7 @@ static int hw_adc_input_select(struct hw *hw, enum ADCSRC type) static int hw_adc_init(struct hw *hw, const struct adc_conf *info) { int err; - u32 data, ctl; + u32 mux = 2, data, ctl; /* Set ADC reset bit as output */ data = hw_read_20kx(hw, GPIO_CTRL); @@ -1851,42 +1796,19 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info) goto error; } - /* Reset the ADC (reset is active low). */ + /* Make ADC in normal operation */ data = hw_read_20kx(hw, GPIO_DATA); data &= ~(0x1 << 15); - hw_write_20kx(hw, GPIO_DATA, data); - - if (hw->model == CTSB1270) { - /* Set up the PCM4220 ADC on Titanium HD */ - data &= ~0x0C; - if (1 == info->msr) - data |= 0x00; /* Single Speed Mode 32-50kHz */ - else if (2 == info->msr) - data |= 0x08; /* Double Speed Mode 50-108kHz */ - else - data |= 0x04; /* Quad Speed Mode 108kHz-216kHz */ - hw_write_20kx(hw, GPIO_DATA, data); - } - mdelay(10); - /* Return the ADC to normal operation. */ data |= (0x1 << 15); hw_write_20kx(hw, GPIO_DATA, data); mdelay(50); - /* I2C write to register offset 0x0B to set ADC LRCLK polarity */ - /* invert bit, interface format to I2S, word length to 24-bit, */ - /* enable ADC high pass filter. Fixes bug 5323? */ - hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_IC, 0x26), - MAKE_WM8775_DATA(0x26)); - /* Set the master mode (256fs) */ if (1 == info->msr) { - /* slave mode, 128x oversampling 256fs */ hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x02), MAKE_WM8775_DATA(0x02)); - } else if ((2 == info->msr) || (4 == info->msr)) { - /* slave mode, 64x oversampling, 256fs */ + } else if (2 == info->msr) { hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x0A), MAKE_WM8775_DATA(0x0A)); } else { @@ -1896,113 +1818,55 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info) goto error; } - if (hw->model != CTSB1270) { - /* Configure GPIO bit 14 change to line-in/mic-in */ - ctl = hw_read_20kx(hw, GPIO_CTRL); - ctl |= 0x1 << 14; - hw_write_20kx(hw, GPIO_CTRL, ctl); - hw_adc_input_select(hw, ADC_LINEIN); - } else { - hw_wm8775_input_select(hw, 0, 0); - } + /* Configure GPIO bit 14 change to line-in/mic-in */ + ctl = hw_read_20kx(hw, GPIO_CTRL); + ctl |= 0x1 << 14; + hw_write_20kx(hw, GPIO_CTRL, ctl); - return 0; -error: - hw20k2_i2c_uninit(hw); - return err; -} - -static struct capabilities hw_capabilities(struct hw *hw) -{ - struct capabilities cap; - - cap.digit_io_switch = 0; - cap.dedicated_mic = hw->model == CTSB1270; - cap.output_switch = hw->model == CTSB1270; - cap.mic_source_switch = hw->model == CTSB1270; - - return cap; -} - -static int hw_output_switch_get(struct hw *hw) -{ - u32 data = hw_read_20kx(hw, GPIO_EXT_DATA); - - switch (data & 0x30) { - case 0x00: - return 0; - case 0x10: - return 1; - case 0x20: - return 2; - default: - return 3; - } -} - -static int hw_output_switch_put(struct hw *hw, int position) -{ - u32 data; - - if (position == hw_output_switch_get(hw)) - return 0; - - /* Mute line and headphones (intended for anti-pop). */ + /* Check using Mic-in or Line-in */ data = hw_read_20kx(hw, GPIO_DATA); - data |= (0x03 << 11); - hw_write_20kx(hw, GPIO_DATA, data); - data = hw_read_20kx(hw, GPIO_EXT_DATA) & ~0x30; - switch (position) { - case 0: - break; - case 1: - data |= 0x10; - break; - default: - data |= 0x20; - } - hw_write_20kx(hw, GPIO_EXT_DATA, data); + if (mux == 1) { + /* Configures GPIO data to select Mic-in */ + data |= 0x1 << 14; + hw_write_20kx(hw, GPIO_DATA, data); - /* Unmute line and headphones. */ - data = hw_read_20kx(hw, GPIO_DATA); - data &= ~(0x03 << 11); - hw_write_20kx(hw, GPIO_DATA, data); + hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x101), + MAKE_WM8775_DATA(0x101)); /* Mic-in */ + hw20k2_i2c_write(hw, + MAKE_WM8775_ADDR(WM8775_AADCL, MIC_BOOST_20DB), + MAKE_WM8775_DATA(MIC_BOOST_20DB)); /* +20dB */ + hw20k2_i2c_write(hw, + MAKE_WM8775_ADDR(WM8775_AADCR, MIC_BOOST_20DB), + MAKE_WM8775_DATA(MIC_BOOST_20DB)); /* +20dB */ + } else if (mux == 2) { + /* Configures GPIO data to select Line-in */ + data &= ~(0x1 << 14); + hw_write_20kx(hw, GPIO_DATA, data); - return 1; -} + /* Setup ADC */ + hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x102), + MAKE_WM8775_DATA(0x102)); /* Line-in */ + hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xCF), + MAKE_WM8775_DATA(0xCF)); /* No boost */ + hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xCF), + MAKE_WM8775_DATA(0xCF)); /* No boost */ + } else { + printk(KERN_ALERT "ctxfi: ERROR!!! Invalid input mux!!!\n"); + err = -EINVAL; + goto error; + } -static int hw_mic_source_switch_get(struct hw *hw) -{ - struct hw20k2 *hw20k2 = (struct hw20k2 *)hw; + return 0; - return hw20k2->mic_source; +error: + hw20k2_i2c_uninit(hw); + return err; } -static int hw_mic_source_switch_put(struct hw *hw, int position) +static int hw_have_digit_io_switch(struct hw *hw) { - struct hw20k2 *hw20k2 = (struct hw20k2 *)hw; - - if (position == hw20k2->mic_source) - return 0; - - switch (position) { - case 0: - hw_wm8775_input_select(hw, 0, 0); /* Mic, 0dB */ - break; - case 1: - hw_wm8775_input_select(hw, 1, 0); /* FP Mic, 0dB */ - break; - case 2: - hw_wm8775_input_select(hw, 3, 0); /* Aux Ext, 0dB */ - break; - default: - return 0; - } - - hw20k2->mic_source = position; - - return 1; + return 0; } static irqreturn_t ct_20k2_interrupt(int irq, void *dev_id) @@ -2061,7 +1925,7 @@ static int hw_card_start(struct hw *hw) if (hw->irq < 0) { err = request_irq(pci->irq, ct_20k2_interrupt, IRQF_SHARED, - KBUILD_MODNAME, hw); + "ctxfi", hw); if (err < 0) { printk(KERN_ERR "XFi: Cannot get irq %d\n", pci->irq); goto error2; @@ -2159,16 +2023,13 @@ static int hw_card_init(struct hw *hw, struct card_conf *info) /* Reset all SRC pending interrupts */ hw_write_20kx(hw, SRC_IP, 0); - if (hw->model != CTSB1270) { - /* TODO: detect the card ID and configure GPIO accordingly. */ - /* Configures GPIO (0xD802 0x98028) */ - /*hw_write_20kx(hw, GPIO_CTRL, 0x7F07);*/ - /* Configures GPIO (SB0880) */ - /*hw_write_20kx(hw, GPIO_CTRL, 0xFF07);*/ - hw_write_20kx(hw, GPIO_CTRL, 0xD802); - } else { - hw_write_20kx(hw, GPIO_CTRL, 0x9E5F); - } + /* TODO: detect the card ID and configure GPIO accordingly. */ + /* Configures GPIO (0xD802 0x98028) */ + /*hw_write_20kx(hw, GPIO_CTRL, 0x7F07);*/ + /* Configures GPIO (SB0880) */ + /*hw_write_20kx(hw, GPIO_CTRL, 0xFF07);*/ + hw_write_20kx(hw, GPIO_CTRL, 0xD802); + /* Enable audio ring */ hw_write_20kx(hw, MIXER_AR_ENABLE, 0x01); @@ -2245,11 +2106,7 @@ static struct hw ct20k2_preset __devinitdata = { .pll_init = hw_pll_init, .is_adc_source_selected = hw_is_adc_input_selected, .select_adc_source = hw_adc_input_select, - .capabilities = hw_capabilities, - .output_switch_get = hw_output_switch_get, - .output_switch_put = hw_output_switch_put, - .mic_source_switch_get = hw_mic_source_switch_get, - .mic_source_switch_put = hw_mic_source_switch_put, + .have_digit_io_switch = hw_have_digit_io_switch, #ifdef CONFIG_PM .suspend = hw_suspend, .resume = hw_resume, diff --git a/trunk/sound/pci/ctxfi/ctmixer.c b/trunk/sound/pci/ctxfi/ctmixer.c index 0cc13eeef8da..c3519ff42fbb 100644 --- a/trunk/sound/pci/ctxfi/ctmixer.c +++ b/trunk/sound/pci/ctxfi/ctmixer.c @@ -86,7 +86,9 @@ enum CTALSA_MIXER_CTL { MIXER_LINEIN_C_S, MIXER_MIC_C_S, MIXER_SPDIFI_C_S, + MIXER_LINEIN_P_S, MIXER_SPDIFO_P_S, + MIXER_SPDIFI_P_S, MIXER_WAVEF_P_S, MIXER_WAVER_P_S, MIXER_WAVEC_P_S, @@ -135,11 +137,11 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = { }, [MIXER_LINEIN_P] = { .ctl = 1, - .name = "Line Playback Volume", + .name = "Line-in Playback Volume", }, [MIXER_LINEIN_C] = { .ctl = 1, - .name = "Line Capture Volume", + .name = "Line-in Capture Volume", }, [MIXER_MIC_P] = { .ctl = 1, @@ -151,15 +153,15 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = { }, [MIXER_SPDIFI_P] = { .ctl = 1, - .name = "IEC958 Playback Volume", + .name = "S/PDIF-in Playback Volume", }, [MIXER_SPDIFI_C] = { .ctl = 1, - .name = "IEC958 Capture Volume", + .name = "S/PDIF-in Capture Volume", }, [MIXER_SPDIFO_P] = { .ctl = 1, - .name = "Digital Playback Volume", + .name = "S/PDIF-out Playback Volume", }, [MIXER_WAVEF_P] = { .ctl = 1, @@ -177,13 +179,14 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = { .ctl = 1, .name = "Surround Playback Volume", }, + [MIXER_PCM_C_S] = { .ctl = 1, .name = "PCM Capture Switch", }, [MIXER_LINEIN_C_S] = { .ctl = 1, - .name = "Line Capture Switch", + .name = "Line-in Capture Switch", }, [MIXER_MIC_C_S] = { .ctl = 1, @@ -191,11 +194,19 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = { }, [MIXER_SPDIFI_C_S] = { .ctl = 1, - .name = "IEC958 Capture Switch", + .name = "S/PDIF-in Capture Switch", + }, + [MIXER_LINEIN_P_S] = { + .ctl = 1, + .name = "Line-in Playback Switch", }, [MIXER_SPDIFO_P_S] = { .ctl = 1, - .name = "Digital Playback Switch", + .name = "S/PDIF-out Playback Switch", + }, + [MIXER_SPDIFI_P_S] = { + .ctl = 1, + .name = "S/PDIF-in Playback Switch", }, [MIXER_WAVEF_P_S] = { .ctl = 1, @@ -225,8 +236,6 @@ ct_mixer_recording_select(struct ct_mixer *mixer, enum CT_AMIXER_CTL type); static void ct_mixer_recording_unselect(struct ct_mixer *mixer, enum CT_AMIXER_CTL type); -/* FIXME: this static looks like it would fail if more than one card was */ -/* installed. */ static struct snd_kcontrol *kctls[2] = {NULL}; static enum CT_AMIXER_CTL get_amixer_index(enum CTALSA_MIXER_CTL alsa_index) @@ -411,77 +420,6 @@ static struct snd_kcontrol_new vol_ctl = { .tlv = { .p = ct_vol_db_scale }, }; -static int output_switch_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *info) -{ - static const char *const names[3] = { - "FP Headphones", "Headphones", "Speakers" - }; - - return snd_ctl_enum_info(info, 1, 3, names); -} - -static int output_switch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct ct_atc *atc = snd_kcontrol_chip(kcontrol); - ucontrol->value.enumerated.item[0] = atc->output_switch_get(atc); - return 0; -} - -static int output_switch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct ct_atc *atc = snd_kcontrol_chip(kcontrol); - if (ucontrol->value.enumerated.item[0] > 2) - return -EINVAL; - return atc->output_switch_put(atc, ucontrol->value.enumerated.item[0]); -} - -static struct snd_kcontrol_new output_ctl = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog Output Playback Enum", - .info = output_switch_info, - .get = output_switch_get, - .put = output_switch_put, -}; - -static int mic_source_switch_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *info) -{ - static const char *const names[3] = { - "Mic", "FP Mic", "Aux" - }; - - return snd_ctl_enum_info(info, 1, 3, names); -} - -static int mic_source_switch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct ct_atc *atc = snd_kcontrol_chip(kcontrol); - ucontrol->value.enumerated.item[0] = atc->mic_source_switch_get(atc); - return 0; -} - -static int mic_source_switch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct ct_atc *atc = snd_kcontrol_chip(kcontrol); - if (ucontrol->value.enumerated.item[0] > 2) - return -EINVAL; - return atc->mic_source_switch_put(atc, - ucontrol->value.enumerated.item[0]); -} - -static struct snd_kcontrol_new mic_source_ctl = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Mic Source Capture Enum", - .info = mic_source_switch_info, - .get = mic_source_switch_get, - .put = mic_source_switch_put, -}; - static void do_line_mic_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type) { @@ -527,7 +465,6 @@ do_digit_io_switch(struct ct_atc *atc, int state) static void do_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type, int state) { struct ct_mixer *mixer = atc->mixer; - struct capabilities cap = atc->capabilities(atc); /* Do changes in mixer. */ if ((SWH_CAPTURE_START <= type) && (SWH_CAPTURE_END >= type)) { @@ -540,17 +477,8 @@ static void do_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type, int state) } } /* Do changes out of mixer. */ - if (!cap.dedicated_mic && - (MIXER_LINEIN_C_S == type || MIXER_MIC_C_S == type)) { - if (state) - do_line_mic_switch(atc, type); - atc->line_in_unmute(atc, state); - } else if (cap.dedicated_mic && (MIXER_LINEIN_C_S == type)) - atc->line_in_unmute(atc, state); - else if (cap.dedicated_mic && (MIXER_MIC_C_S == type)) - atc->mic_unmute(atc, state); - else if (MIXER_SPDIFI_C_S == type) - atc->spdif_in_unmute(atc, state); + if (state && (MIXER_LINEIN_C_S == type || MIXER_MIC_C_S == type)) + do_line_mic_switch(atc, type); else if (MIXER_WAVEF_P_S == type) atc->line_front_unmute(atc, state); else if (MIXER_WAVES_P_S == type) @@ -559,8 +487,12 @@ static void do_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type, int state) atc->line_clfe_unmute(atc, state); else if (MIXER_WAVER_P_S == type) atc->line_rear_unmute(atc, state); + else if (MIXER_LINEIN_P_S == type) + atc->line_in_unmute(atc, state); else if (MIXER_SPDIFO_P_S == type) atc->spdif_out_unmute(atc, state); + else if (MIXER_SPDIFI_P_S == type) + atc->spdif_in_unmute(atc, state); else if (MIXER_DIGITAL_IO_S == type) do_digit_io_switch(atc, state); @@ -739,7 +671,6 @@ static int ct_mixer_kcontrols_create(struct ct_mixer *mixer) { enum CTALSA_MIXER_CTL type; struct ct_atc *atc = mixer->atc; - struct capabilities cap = atc->capabilities(atc); int err; /* Create snd kcontrol instances on demand */ @@ -753,8 +684,8 @@ static int ct_mixer_kcontrols_create(struct ct_mixer *mixer) } } - ct_kcontrol_init_table[MIXER_DIGITAL_IO_S].ctl = cap.digit_io_switch; - + ct_kcontrol_init_table[MIXER_DIGITAL_IO_S].ctl = + atc->have_digit_io_switch(atc); for (type = SWH_MIXER_START; type <= SWH_MIXER_END; type++) { if (ct_kcontrol_init_table[type].ctl) { swh_ctl.name = ct_kcontrol_init_table[type].name; @@ -777,17 +708,6 @@ static int ct_mixer_kcontrols_create(struct ct_mixer *mixer) if (err) return err; - if (cap.output_switch) { - err = ct_mixer_kcontrol_new(mixer, &output_ctl); - if (err) - return err; - } - - if (cap.mic_source_switch) { - err = ct_mixer_kcontrol_new(mixer, &mic_source_ctl); - if (err) - return err; - } atc->line_front_unmute(atc, 1); set_switch_state(mixer, MIXER_WAVEF_P_S, 1); atc->line_surround_unmute(atc, 0); @@ -799,12 +719,13 @@ static int ct_mixer_kcontrols_create(struct ct_mixer *mixer) atc->spdif_out_unmute(atc, 0); set_switch_state(mixer, MIXER_SPDIFO_P_S, 0); atc->line_in_unmute(atc, 0); - if (cap.dedicated_mic) - atc->mic_unmute(atc, 0); + set_switch_state(mixer, MIXER_LINEIN_P_S, 0); atc->spdif_in_unmute(atc, 0); - set_switch_state(mixer, MIXER_PCM_C_S, 0); - set_switch_state(mixer, MIXER_LINEIN_C_S, 0); - set_switch_state(mixer, MIXER_SPDIFI_C_S, 0); + set_switch_state(mixer, MIXER_SPDIFI_P_S, 0); + + set_switch_state(mixer, MIXER_PCM_C_S, 1); + set_switch_state(mixer, MIXER_LINEIN_C_S, 1); + set_switch_state(mixer, MIXER_SPDIFI_C_S, 1); return 0; } diff --git a/trunk/sound/pci/ctxfi/xfi.c b/trunk/sound/pci/ctxfi/xfi.c index b259aa03a3a9..f42e7e1a1074 100644 --- a/trunk/sound/pci/ctxfi/xfi.c +++ b/trunk/sound/pci/ctxfi/xfi.c @@ -80,11 +80,11 @@ ct_card_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) "are 48000 and 44100, Value 48000 is assumed.\n"); reference_rate = 48000; } - if ((multiple != 1) && (multiple != 2) && (multiple != 4)) { + if ((multiple != 1) && (multiple != 2)) { printk(KERN_ERR "ctxfi: Invalid multiple value %u!!!\n", multiple); printk(KERN_ERR "ctxfi: The valid values for multiple are " - "1, 2 and 4, Value 2 is assumed.\n"); + "1 and 2, Value 2 is assumed.\n"); multiple = 2; } err = ct_atc_create(card, pci, reference_rate, multiple, @@ -143,7 +143,7 @@ static int ct_card_resume(struct pci_dev *pci) #endif static struct pci_driver ct_driver = { - .name = KBUILD_MODNAME, + .name = "SB-XFi", .id_table = ct_pci_dev_ids, .probe = ct_card_probe, .remove = __devexit_p(ct_card_remove), diff --git a/trunk/sound/pci/echoaudio/echoaudio.c b/trunk/sound/pci/echoaudio/echoaudio.c index d7306980d0f1..20763dd03fa0 100644 --- a/trunk/sound/pci/echoaudio/echoaudio.c +++ b/trunk/sound/pci/echoaudio/echoaudio.c @@ -1995,7 +1995,7 @@ static __devinit int snd_echo_create(struct snd_card *card, ioremap_nocache(chip->dsp_registers_phys, sz); if (request_irq(pci->irq, snd_echo_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + ECHOCARD_NAME, chip)) { snd_echo_free(chip); snd_printk(KERN_ERR "cannot grab irq\n"); return -EBUSY; @@ -2286,7 +2286,7 @@ static int snd_echo_resume(struct pci_dev *pci) kfree(commpage_bak); if (request_irq(pci->irq, snd_echo_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + ECHOCARD_NAME, chip)) { snd_echo_free(chip); snd_printk(KERN_ERR "cannot grab irq\n"); return -EBUSY; @@ -2327,7 +2327,7 @@ static void __devexit snd_echo_remove(struct pci_dev *pci) /* pci_driver definition */ static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "Echoaudio " ECHOCARD_NAME, .id_table = snd_echo_ids, .probe = snd_echo_probe, .remove = __devexit_p(snd_echo_remove), diff --git a/trunk/sound/pci/emu10k1/emu10k1.c b/trunk/sound/pci/emu10k1/emu10k1.c index a9c45d2cdb13..aff8387c45cf 100644 --- a/trunk/sound/pci/emu10k1/emu10k1.c +++ b/trunk/sound/pci/emu10k1/emu10k1.c @@ -264,7 +264,7 @@ static int snd_emu10k1_resume(struct pci_dev *pci) #endif static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "EMU10K1_Audigy", .id_table = snd_emu10k1_ids, .probe = snd_card_emu10k1_probe, .remove = __devexit_p(snd_card_emu10k1_remove), diff --git a/trunk/sound/pci/emu10k1/emu10k1_main.c b/trunk/sound/pci/emu10k1/emu10k1_main.c index fcd4935766b2..15f0161ce4a2 100644 --- a/trunk/sound/pci/emu10k1/emu10k1_main.c +++ b/trunk/sound/pci/emu10k1/emu10k1_main.c @@ -1912,7 +1912,7 @@ int __devinit snd_emu10k1_create(struct snd_card *card, /* irq handler must be registered after I/O ports are activated */ if (request_irq(pci->irq, snd_emu10k1_interrupt, IRQF_SHARED, - KBUILD_MODNAME, emu)) { + "EMU10K1", emu)) { err = -EBUSY; goto error; } diff --git a/trunk/sound/pci/emu10k1/emu10k1x.c b/trunk/sound/pci/emu10k1/emu10k1x.c index d4fde1b4b093..0c701e4ec8a5 100644 --- a/trunk/sound/pci/emu10k1/emu10k1x.c +++ b/trunk/sound/pci/emu10k1/emu10k1x.c @@ -925,7 +925,7 @@ static int __devinit snd_emu10k1x_create(struct snd_card *card, } if (request_irq(pci->irq, snd_emu10k1x_interrupt, - IRQF_SHARED, KBUILD_MODNAME, chip)) { + IRQF_SHARED, "EMU10K1X", chip)) { snd_printk(KERN_ERR "emu10k1x: cannot grab irq %d\n", pci->irq); snd_emu10k1x_free(chip); return -EBUSY; @@ -1613,7 +1613,7 @@ MODULE_DEVICE_TABLE(pci, snd_emu10k1x_ids); // pci_driver definition static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "EMU10K1X", .id_table = snd_emu10k1x_ids, .probe = snd_emu10k1x_probe, .remove = __devexit_p(snd_emu10k1x_remove), diff --git a/trunk/sound/pci/ens1370.c b/trunk/sound/pci/ens1370.c index f02e2f8d7122..863eafea691f 100644 --- a/trunk/sound/pci/ens1370.c +++ b/trunk/sound/pci/ens1370.c @@ -2120,7 +2120,7 @@ static int __devinit snd_ensoniq_create(struct snd_card *card, } ensoniq->port = pci_resource_start(pci, 0); if (request_irq(pci->irq, snd_audiopci_interrupt, IRQF_SHARED, - KBUILD_MODNAME, ensoniq)) { + "Ensoniq AudioPCI", ensoniq)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_ensoniq_free(ensoniq); return -EBUSY; @@ -2489,7 +2489,7 @@ static void __devexit snd_audiopci_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = DRIVER_NAME, .id_table = snd_audiopci_ids, .probe = snd_audiopci_probe, .remove = __devexit_p(snd_audiopci_remove), diff --git a/trunk/sound/pci/es1938.c b/trunk/sound/pci/es1938.c index 26a5a2f25d4b..553b75217259 100644 --- a/trunk/sound/pci/es1938.c +++ b/trunk/sound/pci/es1938.c @@ -1514,7 +1514,7 @@ static int es1938_resume(struct pci_dev *pci) } if (request_irq(pci->irq, snd_es1938_interrupt, - IRQF_SHARED, KBUILD_MODNAME, chip)) { + IRQF_SHARED, "ES1938", chip)) { printk(KERN_ERR "es1938: unable to grab IRQ %d, " "disabling device\n", pci->irq); snd_card_disconnect(card); @@ -1636,7 +1636,7 @@ static int __devinit snd_es1938_create(struct snd_card *card, chip->mpu_port = pci_resource_start(pci, 3); chip->game_port = pci_resource_start(pci, 4); if (request_irq(pci->irq, snd_es1938_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + "ES1938", chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_es1938_free(chip); return -EBUSY; @@ -1882,7 +1882,7 @@ static void __devexit snd_es1938_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "ESS ES1938 (Solo-1)", .id_table = snd_es1938_ids, .probe = snd_es1938_probe, .remove = __devexit_p(snd_es1938_remove), diff --git a/trunk/sound/pci/es1968.c b/trunk/sound/pci/es1968.c index 99ea9320c6b5..ab0a6156a704 100644 --- a/trunk/sound/pci/es1968.c +++ b/trunk/sound/pci/es1968.c @@ -554,8 +554,9 @@ struct es1968 { #else struct snd_kcontrol *master_switch; /* for h/w volume control */ struct snd_kcontrol *master_volume; + spinlock_t ac97_lock; + struct tasklet_struct hwvol_tq; #endif - struct work_struct hwvol_work; #ifdef CONFIG_SND_ES1968_RADIO struct snd_tea575x tea; @@ -645,23 +646,38 @@ static int snd_es1968_ac97_wait_poll(struct es1968 *chip) static void snd_es1968_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val) { struct es1968 *chip = ac97->private_data; +#ifndef CONFIG_SND_ES1968_INPUT + unsigned long flags; +#endif snd_es1968_ac97_wait(chip); /* Write the bus */ +#ifndef CONFIG_SND_ES1968_INPUT + spin_lock_irqsave(&chip->ac97_lock, flags); +#endif outw(val, chip->io_port + ESM_AC97_DATA); /*msleep(1);*/ outb(reg, chip->io_port + ESM_AC97_INDEX); /*msleep(1);*/ +#ifndef CONFIG_SND_ES1968_INPUT + spin_unlock_irqrestore(&chip->ac97_lock, flags); +#endif } static unsigned short snd_es1968_ac97_read(struct snd_ac97 *ac97, unsigned short reg) { u16 data = 0; struct es1968 *chip = ac97->private_data; +#ifndef CONFIG_SND_ES1968_INPUT + unsigned long flags; +#endif snd_es1968_ac97_wait(chip); +#ifndef CONFIG_SND_ES1968_INPUT + spin_lock_irqsave(&chip->ac97_lock, flags); +#endif outb(reg | 0x80, chip->io_port + ESM_AC97_INDEX); /*msleep(1);*/ @@ -669,6 +685,9 @@ static unsigned short snd_es1968_ac97_read(struct snd_ac97 *ac97, unsigned short data = inw(chip->io_port + ESM_AC97_DATA); /*msleep(1);*/ } +#ifndef CONFIG_SND_ES1968_INPUT + spin_unlock_irqrestore(&chip->ac97_lock, flags); +#endif return data; } @@ -1885,10 +1904,13 @@ static void snd_es1968_update_pcm(struct es1968 *chip, struct esschan *es) (without wrap around) in response to volume button presses and then generating an interrupt. The pair of counters is stored in bits 1-3 and 5-7 of a byte wide register. The meaning of bits 0 and 4 is unknown. */ -static void es1968_update_hw_volume(struct work_struct *work) +static void es1968_update_hw_volume(unsigned long private_data) { - struct es1968 *chip = container_of(work, struct es1968, hwvol_work); + struct es1968 *chip = (struct es1968 *) private_data; int x, val; +#ifndef CONFIG_SND_ES1968_INPUT + unsigned long flags; +#endif /* Figure out which volume control button was pushed, based on differences from the default register @@ -1907,11 +1929,18 @@ static void es1968_update_hw_volume(struct work_struct *work) if (! chip->master_switch || ! chip->master_volume) return; - val = snd_ac97_read(chip->ac97, AC97_MASTER); + /* FIXME: we can't call snd_ac97_* functions since here is in tasklet. */ + spin_lock_irqsave(&chip->ac97_lock, flags); + val = chip->ac97->regs[AC97_MASTER]; switch (x) { case 0x88: /* mute */ val ^= 0x8000; + chip->ac97->regs[AC97_MASTER] = val; + outw(val, chip->io_port + ESM_AC97_DATA); + outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX); + snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, + &chip->master_switch->id); break; case 0xaa: /* volume up */ @@ -1919,6 +1948,11 @@ static void es1968_update_hw_volume(struct work_struct *work) val--; if ((val & 0x7f00) > 0) val -= 0x0100; + chip->ac97->regs[AC97_MASTER] = val; + outw(val, chip->io_port + ESM_AC97_DATA); + outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX); + snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, + &chip->master_volume->id); break; case 0x66: /* volume down */ @@ -1926,11 +1960,14 @@ static void es1968_update_hw_volume(struct work_struct *work) val++; if ((val & 0x7f00) < 0x1f00) val += 0x0100; - break; - } - if (snd_ac97_update(chip->ac97, AC97_MASTER, val)) + chip->ac97->regs[AC97_MASTER] = val; + outw(val, chip->io_port + ESM_AC97_DATA); + outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX); snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_volume->id); + break; + } + spin_unlock_irqrestore(&chip->ac97_lock, flags); #else if (!chip->input_dev) return; @@ -1976,7 +2013,11 @@ static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id) outw(inw(chip->io_port + 4) & 1, chip->io_port + 4); if (event & ESM_HWVOL_IRQ) - schedule_work(&chip->hwvol_work); +#ifdef CONFIG_SND_ES1968_INPUT + es1968_update_hw_volume((unsigned long)chip); +#else + tasklet_schedule(&chip->hwvol_tq); /* we'll do this later */ +#endif /* else ack 'em all, i imagine */ outb(0xFF, chip->io_port + 0x1A); @@ -2385,7 +2426,6 @@ static int es1968_suspend(struct pci_dev *pci, pm_message_t state) return 0; chip->in_suspend = 1; - cancel_work_sync(&chip->hwvol_work); snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); snd_pcm_suspend_all(chip->pcm); snd_ac97_suspend(chip->ac97); @@ -2598,7 +2638,6 @@ static struct snd_tea575x_ops snd_es1968_tea_ops = { static int snd_es1968_free(struct es1968 *chip) { - cancel_work_sync(&chip->hwvol_work); #ifdef CONFIG_SND_ES1968_INPUT if (chip->input_dev) input_unregister_device(chip->input_dev); @@ -2689,7 +2728,10 @@ static int __devinit snd_es1968_create(struct snd_card *card, INIT_LIST_HEAD(&chip->buf_list); INIT_LIST_HEAD(&chip->substream_list); mutex_init(&chip->memory_mutex); - INIT_WORK(&chip->hwvol_work, es1968_update_hw_volume); +#ifndef CONFIG_SND_ES1968_INPUT + spin_lock_init(&chip->ac97_lock); + tasklet_init(&chip->hwvol_tq, es1968_update_hw_volume, (unsigned long)chip); +#endif chip->card = card; chip->pci = pci; chip->irq = -1; @@ -2704,7 +2746,7 @@ static int __devinit snd_es1968_create(struct snd_card *card, } chip->io_port = pci_resource_start(pci, 0); if (request_irq(pci->irq, snd_es1968_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + "ESS Maestro", chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_es1968_free(chip); return -EBUSY; @@ -2883,7 +2925,7 @@ static void __devexit snd_es1968_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "ES1968 (ESS Maestro)", .id_table = snd_es1968_ids, .probe = snd_es1968_probe, .remove = __devexit_p(snd_es1968_remove), diff --git a/trunk/sound/pci/fm801.c b/trunk/sound/pci/fm801.c index f9123f09e83e..a7ec7030cf87 100644 --- a/trunk/sound/pci/fm801.c +++ b/trunk/sound/pci/fm801.c @@ -1199,7 +1199,7 @@ static int __devinit snd_fm801_create(struct snd_card *card, chip->port = pci_resource_start(pci, 0); if ((tea575x_tuner & TUNER_ONLY) == 0) { if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + "FM801", chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->irq); snd_fm801_free(chip); return -EBUSY; @@ -1394,7 +1394,7 @@ static int snd_fm801_resume(struct pci_dev *pci) #endif static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "FM801", .id_table = snd_fm801_ids, .probe = snd_card_fm801_probe, .remove = __devexit_p(snd_card_fm801_remove), diff --git a/trunk/sound/pci/hda/Kconfig b/trunk/sound/pci/hda/Kconfig index 7489b4608551..0ea5cc60ac78 100644 --- a/trunk/sound/pci/hda/Kconfig +++ b/trunk/sound/pci/hda/Kconfig @@ -14,19 +14,6 @@ menuconfig SND_HDA_INTEL if SND_HDA_INTEL -config SND_HDA_PREALLOC_SIZE - int "Pre-allocated buffer size for HD-audio driver" - range 0 32768 - default 64 - help - Specifies the default pre-allocated buffer-size in kB for the - HD-audio driver. A larger buffer (e.g. 2048) is preferred - for systems using PulseAudio. The default 64 is chosen just - for compatibility reasons. - - Note that the pre-allocation size can be changed dynamically - via a proc file (/proc/asound/card*/pcm*/sub*/prealloc), too. - config SND_HDA_HWDEP bool "Build hwdep interface for HD-audio driver" select SND_HWDEP @@ -96,19 +83,6 @@ config SND_HDA_CODEC_REALTEK snd-hda-codec-realtek. This module is automatically loaded at probing. -config SND_HDA_ENABLE_REALTEK_QUIRKS - bool "Build static quirks for Realtek codecs" - depends on SND_HDA_CODEC_REALTEK - default y - help - Say Y here to build the static quirks codes for Realtek codecs. - If you need the "model" preset that the default BIOS auto-parser - can't handle, turn this option on. - - If your device works with model=auto option, basically you don't - need the quirk code. By turning this off, you can reduce the - module size quite a lot. - config SND_HDA_CODEC_ANALOG bool "Build Analog Device HD-audio codec support" default y @@ -197,19 +171,6 @@ config SND_HDA_CODEC_CA0110 snd-hda-codec-ca0110. This module is automatically loaded at probing. -config SND_HDA_CODEC_CA0132 - bool "Build Creative CA0132 codec support" - depends on SND_HDA_INTEL - default y - help - Say Y here to include Creative CA0132 codec support in - snd-hda-intel driver. - - When the HD-audio driver is built as a module, the codec - support code is also built as another module, - snd-hda-codec-ca0132. - This module is automatically loaded at probing. - config SND_HDA_CODEC_CMEDIA bool "Build C-Media HD-audio codec support" default y diff --git a/trunk/sound/pci/hda/Makefile b/trunk/sound/pci/hda/Makefile index 87365d5ea2a9..17ef3658f34b 100644 --- a/trunk/sound/pci/hda/Makefile +++ b/trunk/sound/pci/hda/Makefile @@ -13,7 +13,6 @@ snd-hda-codec-idt-objs := patch_sigmatel.o snd-hda-codec-si3054-objs := patch_si3054.o snd-hda-codec-cirrus-objs := patch_cirrus.o snd-hda-codec-ca0110-objs := patch_ca0110.o -snd-hda-codec-ca0132-objs := patch_ca0132.o snd-hda-codec-conexant-objs := patch_conexant.o snd-hda-codec-via-objs := patch_via.o snd-hda-codec-hdmi-objs := patch_hdmi.o hda_eld.o @@ -43,9 +42,6 @@ endif ifdef CONFIG_SND_HDA_CODEC_CA0110 obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-ca0110.o endif -ifdef CONFIG_SND_HDA_CODEC_CA0132 -obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-ca0132.o -endif ifdef CONFIG_SND_HDA_CODEC_CONEXANT obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-conexant.o endif diff --git a/trunk/sound/pci/hda/alc260_quirks.c b/trunk/sound/pci/hda/alc260_quirks.c deleted file mode 100644 index 21ec2cb100b0..000000000000 --- a/trunk/sound/pci/hda/alc260_quirks.c +++ /dev/null @@ -1,1272 +0,0 @@ -/* - * ALC260 quirk models - * included by patch_realtek.c - */ - -/* ALC260 models */ -enum { - ALC260_AUTO, - ALC260_BASIC, - ALC260_HP, - ALC260_HP_DC7600, - ALC260_HP_3013, - ALC260_FUJITSU_S702X, - ALC260_ACER, - ALC260_WILL, - ALC260_REPLACER_672V, - ALC260_FAVORIT100, -#ifdef CONFIG_SND_DEBUG - ALC260_TEST, -#endif - ALC260_MODEL_LAST /* last tag */ -}; - -static const hda_nid_t alc260_dac_nids[1] = { - /* front */ - 0x02, -}; - -static const hda_nid_t alc260_adc_nids[1] = { - /* ADC0 */ - 0x04, -}; - -static const hda_nid_t alc260_adc_nids_alt[1] = { - /* ADC1 */ - 0x05, -}; - -/* NIDs used when simultaneous access to both ADCs makes sense. Note that - * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC. - */ -static const hda_nid_t alc260_dual_adc_nids[2] = { - /* ADC0, ADC1 */ - 0x04, 0x05 -}; - -#define ALC260_DIGOUT_NID 0x03 -#define ALC260_DIGIN_NID 0x06 - -static const struct hda_input_mux alc260_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - -/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack, - * headphone jack and the internal CD lines since these are the only pins at - * which audio can appear. For flexibility, also allow the option of - * recording the mixer output on the second ADC (ADC0 doesn't have a - * connection to the mixer output). - */ -static const struct hda_input_mux alc260_fujitsu_capture_sources[2] = { - { - .num_items = 3, - .items = { - { "Mic/Line", 0x0 }, - { "CD", 0x4 }, - { "Headphone", 0x2 }, - }, - }, - { - .num_items = 4, - .items = { - { "Mic/Line", 0x0 }, - { "CD", 0x4 }, - { "Headphone", 0x2 }, - { "Mixer", 0x5 }, - }, - }, - -}; - -/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to - * the Fujitsu S702x, but jacks are marked differently. - */ -static const struct hda_input_mux alc260_acer_capture_sources[2] = { - { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - { "Headphone", 0x5 }, - }, - }, - { - .num_items = 5, - .items = { - { "Mic", 0x0 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - { "Headphone", 0x6 }, - { "Mixer", 0x5 }, - }, - }, -}; - -/* Maxdata Favorit 100XS */ -static const struct hda_input_mux alc260_favorit100_capture_sources[2] = { - { - .num_items = 2, - .items = { - { "Line/Mic", 0x0 }, - { "CD", 0x4 }, - }, - }, - { - .num_items = 3, - .items = { - { "Line/Mic", 0x0 }, - { "CD", 0x4 }, - { "Mixer", 0x5 }, - }, - }, -}; - -/* - * This is just place-holder, so there's something for alc_build_pcms to look - * at when it calculates the maximum number of channels. ALC260 has no mixer - * element which allows changing the channel mode, so the verb list is - * never used. - */ -static const struct hda_channel_mode alc260_modes[1] = { - { 2, NULL }, -}; - - -/* Mixer combinations - * - * basic: base_output + input + pc_beep + capture - * HP: base_output + input + capture_alt - * HP_3013: hp_3013 + input + capture - * fujitsu: fujitsu + capture - * acer: acer + capture - */ - -static const struct snd_kcontrol_new alc260_base_output_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc260_input_mixer[] = { - HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT), - { } /* end */ -}; - -/* update HP, line and mono out pins according to the master switch */ -static void alc260_hp_master_update(struct hda_codec *codec) -{ - update_speakers(codec); -} - -static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - *ucontrol->value.integer.value = !spec->master_mute; - return 0; -} - -static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - int val = !*ucontrol->value.integer.value; - - if (val == spec->master_mute) - return 0; - spec->master_mute = val; - alc260_hp_master_update(codec); - return 1; -} - -static const struct snd_kcontrol_new alc260_hp_output_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | 0x11, - .info = snd_ctl_boolean_mono_info, - .get = alc260_hp_master_sw_get, - .put = alc260_hp_master_sw_put, - }, - HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, - HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT), - { } /* end */ -}; - -static const struct hda_verb alc260_hp_unsol_verbs[] = { - {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {}, -}; - -static void alc260_hp_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x0f; - spec->autocfg.speaker_pins[0] = 0x10; - spec->autocfg.speaker_pins[1] = 0x11; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_PIN; -} - -static const struct snd_kcontrol_new alc260_hp_3013_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | 0x11, - .info = snd_ctl_boolean_mono_info, - .get = alc260_hp_master_sw_get, - .put = alc260_hp_master_sw_put, - }, - HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT), - HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static void alc260_hp_3013_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x10; - spec->autocfg.speaker_pins[1] = 0x11; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_PIN; -} - -static const struct hda_bind_ctls alc260_dc7600_bind_master_vol = { - .ops = &snd_hda_bind_vol, - .values = { - HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -static const struct hda_bind_ctls alc260_dc7600_bind_switch = { - .ops = &snd_hda_bind_sw, - .values = { - HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -static const struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = { - HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol), - HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static const struct hda_verb alc260_hp_3013_unsol_verbs[] = { - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {}, -}; - -static void alc260_hp_3012_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x10; - spec->autocfg.speaker_pins[0] = 0x0f; - spec->autocfg.speaker_pins[1] = 0x11; - spec->autocfg.speaker_pins[2] = 0x15; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_PIN; -} - -/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12, - * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10. - */ -static const struct snd_kcontrol_new alc260_fujitsu_mixer[] = { - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT), - ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT), - ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT), - { } /* end */ -}; - -/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current - * versions of the ALC260 don't act on requests to enable mic bias from NID - * 0x0f (used to drive the headphone jack in these laptops). The ALC260 - * datasheet doesn't mention this restriction. At this stage it's not clear - * whether this behaviour is intentional or is a hardware bug in chip - * revisions available in early 2006. Therefore for now allow the - * "Headphone Jack Mode" control to span all choices, but if it turns out - * that the lack of mic bias for this NID is intentional we could change the - * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS. - * - * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006 - * don't appear to make the mic bias available from the "line" jack, even - * though the NID used for this jack (0x14) can supply it. The theory is - * that perhaps Acer have included blocking capacitors between the ALC260 - * and the output jack. If this turns out to be the case for all such - * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT - * to ALC_PIN_DIR_INOUT_NOMICBIAS. - * - * The C20x Tablet series have a mono internal speaker which is controlled - * via the chip's Mono sum widget and pin complex, so include the necessary - * controls for such models. On models without a "mono speaker" the control - * won't do anything. - */ -static const struct snd_kcontrol_new alc260_acer_mixer[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT), - ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT), - HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, - HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, - HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), - ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN), - HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), - ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT), - { } /* end */ -}; - -/* Maxdata Favorit 100XS: one output and one input (0x12) jack - */ -static const struct snd_kcontrol_new alc260_favorit100_mixer[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT), - ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT), - HDA_CODEC_VOLUME("Line/Mic Playback Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Line/Mic Playback Switch", 0x07, 0x0, HDA_INPUT), - ALC_PIN_MODE("Line/Mic Jack Mode", 0x12, ALC_PIN_DIR_IN), - { } /* end */ -}; - -/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12, - * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17. - */ -static const struct snd_kcontrol_new alc260_will_mixer[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), - ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN), - HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), - ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), - { } /* end */ -}; - -/* Replacer 672V ALC260 pin usage: Mic jack = 0x12, - * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f. - */ -static const struct snd_kcontrol_new alc260_replacer_672v_mixer[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), - ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN), - HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), - ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT), - { } /* end */ -}; - -/* - * initialization verbs - */ -static const struct hda_verb alc260_init_verbs[] = { - /* Line In pin widget for input */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* CD pin widget for input */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - /* Mic2 (front panel) pin widget for input and vref at 80% */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - /* LINE-2 is used for line-out in rear */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* select line-out */ - {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* LINE-OUT pin */ - {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* enable HP */ - {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* enable Mono */ - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* mute capture amp left and right */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* set connection select to line in (default select for this ADC) */ - {0x04, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* mute capture amp left and right */ - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* set connection select to line in (default select for this ADC) */ - {0x05, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* set vol=0 Line-Out mixer amp left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* unmute pin widget amp left and right (no gain on this amp) */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* set vol=0 HP mixer amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* unmute pin widget amp left and right (no gain on this amp) */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* set vol=0 Mono mixer amp left and right */ - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* unmute pin widget amp left and right (no gain on this amp) */ - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* unmute LINE-2 out pin */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & - * Line In 2 = 0x03 - */ - /* mute analog inputs */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ - /* mute Front out path */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* mute Headphone out path */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* mute Mono out path */ - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - { } -}; - -#if 0 /* should be identical with alc260_init_verbs? */ -static const struct hda_verb alc260_hp_init_verbs[] = { - /* Headphone and output */ - {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, - /* mono output */ - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - /* Mic2 (front panel) pin widget for input and vref at 80% */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - /* Line In pin widget for input */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - /* Line-2 pin widget for output */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - /* CD pin widget for input */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - /* unmute amp left and right */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, - /* set connection select to line in (default select for this ADC) */ - {0x04, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* unmute Line-Out mixer amp left and right (volume = 0) */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* mute pin widget amp left and right (no gain on this amp) */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, - /* unmute HP mixer amp left and right (volume = 0) */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* mute pin widget amp left and right (no gain on this amp) */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, - /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & - * Line In 2 = 0x03 - */ - /* mute analog inputs */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ - /* Unmute Front out path */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - /* Unmute Headphone out path */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - /* Unmute Mono out path */ - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - { } -}; -#endif - -static const struct hda_verb alc260_hp_3013_init_verbs[] = { - /* Line out and output */ - {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - /* mono output */ - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - /* Mic2 (front panel) pin widget for input and vref at 80% */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - /* Line In pin widget for input */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - /* Headphone pin widget for output */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, - /* CD pin widget for input */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - /* unmute amp left and right */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, - /* set connection select to line in (default select for this ADC) */ - {0x04, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* unmute Line-Out mixer amp left and right (volume = 0) */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* mute pin widget amp left and right (no gain on this amp) */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, - /* unmute HP mixer amp left and right (volume = 0) */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* mute pin widget amp left and right (no gain on this amp) */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, - /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & - * Line In 2 = 0x03 - */ - /* mute analog inputs */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ - /* Unmute Front out path */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - /* Unmute Headphone out path */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - /* Unmute Mono out path */ - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - { } -}; - -/* Initialisation sequence for ALC260 as configured in Fujitsu S702x - * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD - * audio = 0x16, internal speaker = 0x10. - */ -static const struct hda_verb alc260_fujitsu_init_verbs[] = { - /* Disable all GPIOs */ - {0x01, AC_VERB_SET_GPIO_MASK, 0}, - /* Internal speaker is connected to headphone pin */ - {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* Headphone/Line-out jack connects to Line1 pin; make it an output */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Mic/Line-in jack is connected to mic1 pin, so make it an input */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* Ensure all other unused pins are disabled and muted. */ - {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - - /* Disable digital (SPDIF) pins */ - {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, - {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, - - /* Ensure Line1 pin widget takes its input from the OUT1 sum bus - * when acting as an output. - */ - {0x0d, AC_VERB_SET_CONNECT_SEL, 0}, - - /* Start with output sum widgets muted and their output gains at min */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Unmute Line1 pin widget output buffer since it starts as an output. - * If the pin mode is changed by the user the pin mode control will - * take care of enabling the pin's input/output buffers as needed. - * Therefore there's no need to enable the input buffer at this - * stage. - */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Unmute input buffer of pin widget used for Line-in (no equiv - * mixer ctrl) - */ - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Mute capture amp left and right */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - /* Set ADC connection select to match default mixer setting - line - * in (on mic1 pin) - */ - {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Do the same for the second ADC: mute capture input amp and - * set ADC connection to line in (on mic1 pin) - */ - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x05, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Mute all inputs to mixer widget (even unconnected ones) */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ - - { } -}; - -/* Initialisation sequence for ALC260 as configured in Acer TravelMate and - * similar laptops (adapted from Fujitsu init verbs). - */ -static const struct hda_verb alc260_acer_init_verbs[] = { - /* On TravelMate laptops, GPIO 0 enables the internal speaker and - * the headphone jack. Turn this on and rely on the standard mute - * methods whenever the user wants to turn these outputs off. - */ - {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, - {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, - {0x01, AC_VERB_SET_GPIO_DATA, 0x01}, - /* Internal speaker/Headphone jack is connected to Line-out pin */ - {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* Internal microphone/Mic jack is connected to Mic1 pin */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, - /* Line In jack is connected to Line1 pin */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */ - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* Ensure all other unused pins are disabled and muted. */ - {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - /* Disable digital (SPDIF) pins */ - {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, - {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, - - /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum - * bus when acting as outputs. - */ - {0x0b, AC_VERB_SET_CONNECT_SEL, 0}, - {0x0d, AC_VERB_SET_CONNECT_SEL, 0}, - - /* Start with output sum widgets muted and their output gains at min */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* Unmute Line-out pin widget amp left and right - * (no equiv mixer ctrl) - */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Unmute mono pin widget amp output (no equiv mixer ctrl) */ - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Unmute Mic1 and Line1 pin widget input buffers since they start as - * inputs. If the pin mode is changed by the user the pin mode control - * will take care of enabling the pin's input/output buffers as needed. - * Therefore there's no need to enable the input buffer at this - * stage. - */ - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Mute capture amp left and right */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - /* Set ADC connection select to match default mixer setting - mic - * (on mic1 pin) - */ - {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Do similar with the second ADC: mute capture input amp and - * set ADC connection to mic to match ALSA's default state. - */ - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x05, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Mute all inputs to mixer widget (even unconnected ones) */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ - - { } -}; - -/* Initialisation sequence for Maxdata Favorit 100XS - * (adapted from Acer init verbs). - */ -static const struct hda_verb alc260_favorit100_init_verbs[] = { - /* GPIO 0 enables the output jack. - * Turn this on and rely on the standard mute - * methods whenever the user wants to turn these outputs off. - */ - {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, - {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, - {0x01, AC_VERB_SET_GPIO_DATA, 0x01}, - /* Line/Mic input jack is connected to Mic1 pin */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, - /* Ensure all other unused pins are disabled and muted. */ - {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - /* Disable digital (SPDIF) pins */ - {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, - {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, - - /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum - * bus when acting as outputs. - */ - {0x0b, AC_VERB_SET_CONNECT_SEL, 0}, - {0x0d, AC_VERB_SET_CONNECT_SEL, 0}, - - /* Start with output sum widgets muted and their output gains at min */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* Unmute Line-out pin widget amp left and right - * (no equiv mixer ctrl) - */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Unmute Mic1 and Line1 pin widget input buffers since they start as - * inputs. If the pin mode is changed by the user the pin mode control - * will take care of enabling the pin's input/output buffers as needed. - * Therefore there's no need to enable the input buffer at this - * stage. - */ - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Mute capture amp left and right */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - /* Set ADC connection select to match default mixer setting - mic - * (on mic1 pin) - */ - {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Do similar with the second ADC: mute capture input amp and - * set ADC connection to mic to match ALSA's default state. - */ - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x05, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Mute all inputs to mixer widget (even unconnected ones) */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ - - { } -}; - -static const struct hda_verb alc260_will_verbs[] = { - {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, - {0x1a, AC_VERB_SET_COEF_INDEX, 0x07}, - {0x1a, AC_VERB_SET_PROC_COEF, 0x3040}, - {} -}; - -static const struct hda_verb alc260_replacer_672v_verbs[] = { - {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, - {0x1a, AC_VERB_SET_COEF_INDEX, 0x07}, - {0x1a, AC_VERB_SET_PROC_COEF, 0x3050}, - - {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, - {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, - {0x01, AC_VERB_SET_GPIO_DATA, 0x00}, - - {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -/* toggle speaker-output according to the hp-jack state */ -static void alc260_replacer_672v_automute(struct hda_codec *codec) -{ - unsigned int present; - - /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */ - present = snd_hda_jack_detect(codec, 0x0f); - if (present) { - snd_hda_codec_write_cache(codec, 0x01, 0, - AC_VERB_SET_GPIO_DATA, 1); - snd_hda_codec_write_cache(codec, 0x0f, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - PIN_HP); - } else { - snd_hda_codec_write_cache(codec, 0x01, 0, - AC_VERB_SET_GPIO_DATA, 0); - snd_hda_codec_write_cache(codec, 0x0f, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - PIN_OUT); - } -} - -static void alc260_replacer_672v_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) == ALC_HP_EVENT) - alc260_replacer_672v_automute(codec); -} - -static const struct hda_verb alc260_hp_dc7600_verbs[] = { - {0x05, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -/* Test configuration for debugging, modelled after the ALC880 test - * configuration. - */ -#ifdef CONFIG_SND_DEBUG -static const hda_nid_t alc260_test_dac_nids[1] = { - 0x02, -}; -static const hda_nid_t alc260_test_adc_nids[2] = { - 0x04, 0x05, -}; -/* For testing the ALC260, each input MUX needs its own definition since - * the signal assignments are different. This assumes that the first ADC - * is NID 0x04. - */ -static const struct hda_input_mux alc260_test_capture_sources[2] = { - { - .num_items = 7, - .items = { - { "MIC1 pin", 0x0 }, - { "MIC2 pin", 0x1 }, - { "LINE1 pin", 0x2 }, - { "LINE2 pin", 0x3 }, - { "CD pin", 0x4 }, - { "LINE-OUT pin", 0x5 }, - { "HP-OUT pin", 0x6 }, - }, - }, - { - .num_items = 8, - .items = { - { "MIC1 pin", 0x0 }, - { "MIC2 pin", 0x1 }, - { "LINE1 pin", 0x2 }, - { "LINE2 pin", 0x3 }, - { "CD pin", 0x4 }, - { "Mixer", 0x5 }, - { "LINE-OUT pin", 0x6 }, - { "HP-OUT pin", 0x7 }, - }, - }, -}; -static const struct snd_kcontrol_new alc260_test_mixer[] = { - /* Output driver widgets */ - HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT), - HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT), - HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT), - - /* Modes for retasking pin widgets - * Note: the ALC260 doesn't seem to act on requests to enable mic - * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't - * mention this restriction. At this stage it's not clear whether - * this behaviour is intentional or is a hardware bug in chip - * revisions available at least up until early 2006. Therefore for - * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all - * choices, but if it turns out that the lack of mic bias for these - * NIDs is intentional we could change their modes from - * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS. - */ - ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT), - ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT), - ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT), - ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT), - ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT), - ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT), - - /* Loopback mixer controls */ - HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT), - HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT), - HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT), - HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT), - HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT), - - /* Controls for GPIO pins, assuming they are configured as outputs */ - ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01), - ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02), - ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04), - ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08), - - /* Switches to allow the digital IO pins to be enabled. The datasheet - * is ambigious as to which NID is which; testing on laptops which - * make this output available should provide clarification. - */ - ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01), - ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01), - - /* A switch allowing EAPD to be enabled. Some laptops seem to use - * this output to turn on an external amplifier. - */ - ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02), - ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02), - - { } /* end */ -}; -static const struct hda_verb alc260_test_init_verbs[] = { - /* Enable all GPIOs as outputs with an initial value of 0 */ - {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f}, - {0x01, AC_VERB_SET_GPIO_DATA, 0x00}, - {0x01, AC_VERB_SET_GPIO_MASK, 0x0f}, - - /* Enable retasking pins as output, initially without power amp */ - {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - /* Disable digital (SPDIF) pins initially, but users can enable - * them via a mixer switch. In the case of SPDIF-out, this initverb - * payload also sets the generation to 0, output to be in "consumer" - * PCM format, copyright asserted, no pre-emphasis and no validity - * control. - */ - {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, - {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, - - /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the - * OUT1 sum bus when acting as an output. - */ - {0x0b, AC_VERB_SET_CONNECT_SEL, 0}, - {0x0c, AC_VERB_SET_CONNECT_SEL, 0}, - {0x0d, AC_VERB_SET_CONNECT_SEL, 0}, - {0x0e, AC_VERB_SET_CONNECT_SEL, 0}, - - /* Start with output sum widgets muted and their output gains at min */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* Unmute retasking pin widget output buffers since the default - * state appears to be output. As the pin mode is changed by the - * user the pin mode control will take care of enabling the pin's - * input/output buffers as needed. - */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Also unmute the mono-out pin widget */ - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Mute capture amp left and right */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - /* Set ADC connection select to match default mixer setting (mic1 - * pin) - */ - {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Do the same for the second ADC: mute capture input amp and - * set ADC connection to mic1 pin - */ - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x05, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Mute all inputs to mixer widget (even unconnected ones) */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ - - { } -}; -#endif - -/* - * ALC260 configurations - */ -static const char * const alc260_models[ALC260_MODEL_LAST] = { - [ALC260_BASIC] = "basic", - [ALC260_HP] = "hp", - [ALC260_HP_3013] = "hp-3013", - [ALC260_HP_DC7600] = "hp-dc7600", - [ALC260_FUJITSU_S702X] = "fujitsu", - [ALC260_ACER] = "acer", - [ALC260_WILL] = "will", - [ALC260_REPLACER_672V] = "replacer", - [ALC260_FAVORIT100] = "favorit100", -#ifdef CONFIG_SND_DEBUG - [ALC260_TEST] = "test", -#endif - [ALC260_AUTO] = "auto", -}; - -static const struct snd_pci_quirk alc260_cfg_tbl[] = { - SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER), - SND_PCI_QUIRK(0x1025, 0x007f, "Acer", ALC260_WILL), - SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER), - SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100), - SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013), - SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_AUTO), /* no quirk */ - SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013), - SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013), - SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600), - SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013), - SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP), - SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP), - SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP), - SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC), - SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC), - SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC), - SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X), - SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC), - SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V), - SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL), - {} -}; - -static const struct alc_config_preset alc260_presets[] = { - [ALC260_BASIC] = { - .mixers = { alc260_base_output_mixer, - alc260_input_mixer }, - .init_verbs = { alc260_init_verbs }, - .num_dacs = ARRAY_SIZE(alc260_dac_nids), - .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), - .adc_nids = alc260_dual_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc260_modes), - .channel_mode = alc260_modes, - .input_mux = &alc260_capture_source, - }, - [ALC260_HP] = { - .mixers = { alc260_hp_output_mixer, - alc260_input_mixer }, - .init_verbs = { alc260_init_verbs, - alc260_hp_unsol_verbs }, - .num_dacs = ARRAY_SIZE(alc260_dac_nids), - .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt), - .adc_nids = alc260_adc_nids_alt, - .num_channel_mode = ARRAY_SIZE(alc260_modes), - .channel_mode = alc260_modes, - .input_mux = &alc260_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc260_hp_setup, - .init_hook = alc_inithook, - }, - [ALC260_HP_DC7600] = { - .mixers = { alc260_hp_dc7600_mixer, - alc260_input_mixer }, - .init_verbs = { alc260_init_verbs, - alc260_hp_dc7600_verbs }, - .num_dacs = ARRAY_SIZE(alc260_dac_nids), - .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt), - .adc_nids = alc260_adc_nids_alt, - .num_channel_mode = ARRAY_SIZE(alc260_modes), - .channel_mode = alc260_modes, - .input_mux = &alc260_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc260_hp_3012_setup, - .init_hook = alc_inithook, - }, - [ALC260_HP_3013] = { - .mixers = { alc260_hp_3013_mixer, - alc260_input_mixer }, - .init_verbs = { alc260_hp_3013_init_verbs, - alc260_hp_3013_unsol_verbs }, - .num_dacs = ARRAY_SIZE(alc260_dac_nids), - .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt), - .adc_nids = alc260_adc_nids_alt, - .num_channel_mode = ARRAY_SIZE(alc260_modes), - .channel_mode = alc260_modes, - .input_mux = &alc260_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc260_hp_3013_setup, - .init_hook = alc_inithook, - }, - [ALC260_FUJITSU_S702X] = { - .mixers = { alc260_fujitsu_mixer }, - .init_verbs = { alc260_fujitsu_init_verbs }, - .num_dacs = ARRAY_SIZE(alc260_dac_nids), - .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), - .adc_nids = alc260_dual_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc260_modes), - .channel_mode = alc260_modes, - .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources), - .input_mux = alc260_fujitsu_capture_sources, - }, - [ALC260_ACER] = { - .mixers = { alc260_acer_mixer }, - .init_verbs = { alc260_acer_init_verbs }, - .num_dacs = ARRAY_SIZE(alc260_dac_nids), - .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), - .adc_nids = alc260_dual_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc260_modes), - .channel_mode = alc260_modes, - .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources), - .input_mux = alc260_acer_capture_sources, - }, - [ALC260_FAVORIT100] = { - .mixers = { alc260_favorit100_mixer }, - .init_verbs = { alc260_favorit100_init_verbs }, - .num_dacs = ARRAY_SIZE(alc260_dac_nids), - .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), - .adc_nids = alc260_dual_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc260_modes), - .channel_mode = alc260_modes, - .num_mux_defs = ARRAY_SIZE(alc260_favorit100_capture_sources), - .input_mux = alc260_favorit100_capture_sources, - }, - [ALC260_WILL] = { - .mixers = { alc260_will_mixer }, - .init_verbs = { alc260_init_verbs, alc260_will_verbs }, - .num_dacs = ARRAY_SIZE(alc260_dac_nids), - .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_adc_nids), - .adc_nids = alc260_adc_nids, - .dig_out_nid = ALC260_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc260_modes), - .channel_mode = alc260_modes, - .input_mux = &alc260_capture_source, - }, - [ALC260_REPLACER_672V] = { - .mixers = { alc260_replacer_672v_mixer }, - .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs }, - .num_dacs = ARRAY_SIZE(alc260_dac_nids), - .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_adc_nids), - .adc_nids = alc260_adc_nids, - .dig_out_nid = ALC260_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc260_modes), - .channel_mode = alc260_modes, - .input_mux = &alc260_capture_source, - .unsol_event = alc260_replacer_672v_unsol_event, - .init_hook = alc260_replacer_672v_automute, - }, -#ifdef CONFIG_SND_DEBUG - [ALC260_TEST] = { - .mixers = { alc260_test_mixer }, - .init_verbs = { alc260_test_init_verbs }, - .num_dacs = ARRAY_SIZE(alc260_test_dac_nids), - .dac_nids = alc260_test_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids), - .adc_nids = alc260_test_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc260_modes), - .channel_mode = alc260_modes, - .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources), - .input_mux = alc260_test_capture_sources, - }, -#endif -}; - diff --git a/trunk/sound/pci/hda/alc262_quirks.c b/trunk/sound/pci/hda/alc262_quirks.c deleted file mode 100644 index 8d2097d77642..000000000000 --- a/trunk/sound/pci/hda/alc262_quirks.c +++ /dev/null @@ -1,1353 +0,0 @@ -/* - * ALC262 quirk models - * included by patch_realtek.c - */ - -/* ALC262 models */ -enum { - ALC262_AUTO, - ALC262_BASIC, - ALC262_HIPPO, - ALC262_HIPPO_1, - ALC262_FUJITSU, - ALC262_HP_BPC, - ALC262_HP_BPC_D7000_WL, - ALC262_HP_BPC_D7000_WF, - ALC262_HP_TC_T5735, - ALC262_HP_RP5700, - ALC262_BENQ_ED8, - ALC262_SONY_ASSAMD, - ALC262_BENQ_T31, - ALC262_ULTRA, - ALC262_LENOVO_3000, - ALC262_NEC, - ALC262_TOSHIBA_S06, - ALC262_TOSHIBA_RX1, - ALC262_TYAN, - ALC262_MODEL_LAST /* last tag */ -}; - -#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID -#define ALC262_DIGIN_NID ALC880_DIGIN_NID - -#define alc262_dac_nids alc260_dac_nids -#define alc262_adc_nids alc882_adc_nids -#define alc262_adc_nids_alt alc882_adc_nids_alt -#define alc262_capsrc_nids alc882_capsrc_nids -#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt - -#define alc262_modes alc260_modes -#define alc262_capture_source alc882_capture_source - -static const hda_nid_t alc262_dmic_adc_nids[1] = { - /* ADC0 */ - 0x09 -}; - -static const hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 }; - -static const struct snd_kcontrol_new alc262_base_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -/* update HP, line and mono-out pins according to the master switch */ -#define alc262_hp_master_update alc260_hp_master_update - -static void alc262_hp_bpc_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x16; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_PIN; -} - -static void alc262_hp_wildwest_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x16; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_PIN; -} - -#define alc262_hp_master_sw_get alc260_hp_master_sw_get -#define alc262_hp_master_sw_put alc260_hp_master_sw_put - -#define ALC262_HP_MASTER_SWITCH \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = "Master Playback Switch", \ - .info = snd_ctl_boolean_mono_info, \ - .get = alc262_hp_master_sw_get, \ - .put = alc262_hp_master_sw_put, \ - }, \ - { \ - .iface = NID_MAPPING, \ - .name = "Master Playback Switch", \ - .private_value = 0x15 | (0x16 << 8) | (0x1b << 16), \ - } - - -static const struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { - ALC262_HP_MASTER_SWITCH, - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0, - HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0, - HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT), - HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = { - ALC262_HP_MASTER_SWITCH, - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0, - HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0, - HDA_OUTPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x1a, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = { - HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Rear Mic Boost Volume", 0x18, 0, HDA_INPUT), - { } /* end */ -}; - -/* mute/unmute internal speaker according to the hp jack and mute state */ -static void alc262_hp_t5735_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_PIN; -} - -static const struct snd_kcontrol_new alc262_hp_t5735_mixer[] = { - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - { } /* end */ -}; - -static const struct hda_verb alc262_hp_t5735_verbs[] = { - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - { } -}; - -static const struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = { - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT), - { } /* end */ -}; - -static const struct hda_verb alc262_hp_rp5700_verbs[] = { - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))}, - {} -}; - -static const struct hda_input_mux alc262_hp_rp5700_capture_source = { - .num_items = 1, - .items = { - { "Line", 0x1 }, - }, -}; - -/* bind hp and internal speaker mute (with plug check) as master switch */ -#define alc262_hippo_master_update alc262_hp_master_update -#define alc262_hippo_master_sw_get alc262_hp_master_sw_get -#define alc262_hippo_master_sw_put alc262_hp_master_sw_put - -#define ALC262_HIPPO_MASTER_SWITCH \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = "Master Playback Switch", \ - .info = snd_ctl_boolean_mono_info, \ - .get = alc262_hippo_master_sw_get, \ - .put = alc262_hippo_master_sw_put, \ - }, \ - { \ - .iface = NID_MAPPING, \ - .name = "Master Playback Switch", \ - .subdevice = SUBDEV_HP(0) | (SUBDEV_LINE(0) << 8) | \ - (SUBDEV_SPEAKER(0) << 16), \ - } - -static const struct snd_kcontrol_new alc262_hippo_mixer[] = { - ALC262_HIPPO_MASTER_SWITCH, - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc262_hippo1_mixer[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - ALC262_HIPPO_MASTER_SWITCH, - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - { } /* end */ -}; - -/* mute/unmute internal speaker according to the hp jack and mute state */ -static void alc262_hippo_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc262_hippo1_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - - -static const struct snd_kcontrol_new alc262_sony_mixer[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - ALC262_HIPPO_MASTER_SWITCH, - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc262_benq_t31_mixer[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - ALC262_HIPPO_MASTER_SWITCH, - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc262_tyan_mixer[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT), - HDA_CODEC_MUTE("Aux Playback Switch", 0x0b, 0x06, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - { } /* end */ -}; - -static const struct hda_verb alc262_tyan_verbs[] = { - /* Headphone automute */ - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* P11 AUX_IN, white 4-pin connector */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0xe1}, - {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x93}, - {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x19}, - - {} -}; - -/* unsolicited event for HP jack sensing */ -static void alc262_tyan_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x15; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - - -#define alc262_capture_mixer alc882_capture_mixer -#define alc262_capture_alt_mixer alc882_capture_alt_mixer - -/* - * generic initialization of ADC, input mixers and output mixers - */ -static const struct hda_verb alc262_init_verbs[] = { - /* - * Unmute ADC0-2 and set the default input to mic-in - */ - {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback - * mixer widget - * Note: PASD motherboards uses the Line In 2 as the input for - * front panel mic (mic 2) - */ - /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - - /* - * Set up output mixers (0x0c - 0x0e) - */ - /* set vol=0 to output mixers */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* set up input amps for analog loopback */ - /* Amp Indices: DAC = 0, mixer = 1 */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, - - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, - - /* FIXME: use matrix-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ - /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, - /* Input mixer2 */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, - /* Input mixer3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, - - { } -}; - -static const struct hda_verb alc262_eapd_verbs[] = { - {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, - {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, - { } -}; - -static const struct hda_verb alc262_hippo1_unsol_verbs[] = { - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, - - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {} -}; - -static const struct hda_verb alc262_sony_unsol_verbs[] = { - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic - - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {} -}; - -static const struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = { - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct hda_verb alc262_toshiba_s06_verbs[] = { - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x22, AC_VERB_SET_CONNECT_SEL, 0x09}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static void alc262_toshiba_s06_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x12; - spec->auto_mic = 1; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_PIN; -} - -/* - * nec model - * 0x15 = headphone - * 0x16 = internal speaker - * 0x18 = external mic - */ - -static const struct snd_kcontrol_new alc262_nec_mixer[] = { - HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static const struct hda_verb alc262_nec_verbs[] = { - /* Unmute Speaker */ - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Headphone */ - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - /* External mic to headphone */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* External mic to speaker */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {} -}; - -/* - * fujitsu model - * 0x14 = headphone/spdif-out, 0x15 = internal speaker, - * 0x1b = port replicator headphone out - */ - -static const struct hda_verb alc262_fujitsu_unsol_verbs[] = { - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {} -}; - -static const struct hda_verb alc262_lenovo_3000_unsol_verbs[] = { - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {} -}; - -static const struct hda_verb alc262_lenovo_3000_init_verbs[] = { - /* Front Mic pin: input vref at 50% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {} -}; - -static const struct hda_input_mux alc262_fujitsu_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x0 }, - { "Internal Mic", 0x1 }, - { "CD", 0x4 }, - }, -}; - -static const struct hda_input_mux alc262_HP_capture_source = { - .num_items = 5, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - { "AUX IN", 0x6 }, - }, -}; - -static const struct hda_input_mux alc262_HP_D7000_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x2 }, - { "Line", 0x1 }, - { "CD", 0x4 }, - }, -}; - -static void alc262_fujitsu_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.hp_pins[1] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x15; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -/* bind volumes of both NID 0x0c and 0x0d */ -static const struct hda_bind_ctls alc262_fujitsu_bind_master_vol = { - .ops = &snd_hda_bind_vol, - .values = { - HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -static const struct snd_kcontrol_new alc262_fujitsu_mixer[] = { - HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | 0x14, - .info = snd_ctl_boolean_mono_info, - .get = alc262_hp_master_sw_get, - .put = alc262_hp_master_sw_put, - }, - { - .iface = NID_MAPPING, - .name = "Master Playback Switch", - .private_value = 0x1b, - }, - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static void alc262_lenovo_3000_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x16; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static const struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = { - HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b, - .info = snd_ctl_boolean_mono_info, - .get = alc262_hp_master_sw_get, - .put = alc262_hp_master_sw_put, - }, - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = { - HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol), - ALC262_HIPPO_MASTER_SWITCH, - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - { } /* end */ -}; - -/* additional init verbs for Benq laptops */ -static const struct hda_verb alc262_EAPD_verbs[] = { - {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, - {0x20, AC_VERB_SET_PROC_COEF, 0x3070}, - {} -}; - -static const struct hda_verb alc262_benq_t31_EAPD_verbs[] = { - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - - {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, - {0x20, AC_VERB_SET_PROC_COEF, 0x3050}, - {} -}; - -/* Samsung Q1 Ultra Vista model setup */ -static const struct snd_kcontrol_new alc262_ultra_mixer[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Mic Boost Volume", 0x15, 0, HDA_INPUT), - { } /* end */ -}; - -static const struct hda_verb alc262_ultra_verbs[] = { - /* output mixer */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* speaker */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* HP */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - /* internal mic */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* ADC, choose mic */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)}, - {} -}; - -/* mute/unmute internal speaker according to the hp jack and mute state */ -static void alc262_ultra_automute(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - unsigned int mute; - - mute = 0; - /* auto-mute only when HP is used as HP */ - if (!spec->cur_mux[0]) { - spec->jack_present = snd_hda_jack_detect(codec, 0x15); - if (spec->jack_present) - mute = HDA_AMP_MUTE; - } - /* mute/unmute internal speaker */ - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); - /* mute/unmute HP */ - snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE); -} - -/* unsolicited event for HP jack sensing */ -static void alc262_ultra_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) != ALC_HP_EVENT) - return; - alc262_ultra_automute(codec); -} - -static const struct hda_input_mux alc262_ultra_capture_source = { - .num_items = 2, - .items = { - { "Mic", 0x1 }, - { "Headphone", 0x7 }, - }, -}; - -static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - int ret; - - ret = alc_mux_enum_put(kcontrol, ucontrol); - if (!ret) - return 0; - /* reprogram the HP pin as mic or HP according to the input source */ - snd_hda_codec_write_cache(codec, 0x15, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - spec->cur_mux[0] ? PIN_VREF80 : PIN_HP); - alc262_ultra_automute(codec); /* mute/unmute HP */ - return ret; -} - -static const struct snd_kcontrol_new alc262_ultra_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc262_ultra_mux_enum_put, - }, - { - .iface = NID_MAPPING, - .name = "Capture Source", - .private_value = 0x15, - }, - { } /* end */ -}; - -static const struct hda_verb alc262_HP_BPC_init_verbs[] = { - /* - * Unmute ADC0-2 and set the default input to mic-in - */ - {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback - * mixer widget - * Note: PASD motherboards uses the Line In 2 as the input for - * front panel mic (mic 2) - */ - /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, - - /* - * Set up output mixers (0x0c - 0x0e) - */ - /* set vol=0 to output mixers */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* set up input amps for analog loopback */ - /* Amp Indices: DAC = 0, mixer = 1 */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, - {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, - {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, - - - /* FIXME: use matrix-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 0b, 12 */ - /* Input mixer1: only unmute Mic */ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))}, - /* Input mixer2 */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))}, - /* Input mixer3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))}, - - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - - { } -}; - -static const struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = { - /* - * Unmute ADC0-2 and set the default input to mic-in - */ - {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback - * mixer widget - * Note: PASD motherboards uses the Line In 2 as the input for front - * panel mic (mic 2) - */ - /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, - /* - * Set up output mixers (0x0c - 0x0e) - */ - /* set vol=0 to output mixers */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* set up input amps for analog loopback */ - /* Amp Indices: DAC = 0, mixer = 1 */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */ - - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, - - /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */ - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, - {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, - {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, - - /* FIXME: use matrix-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ - /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/ - /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/ - /* Input mixer2 */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, - /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, - /* Input mixer3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, - /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, - - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - - { } -}; - -static const struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = { - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Front Speaker */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x01}, - - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* MIC jack */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */ - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) }, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) }, - - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP jack */ - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -/* - * configuration and preset - */ -static const char * const alc262_models[ALC262_MODEL_LAST] = { - [ALC262_BASIC] = "basic", - [ALC262_HIPPO] = "hippo", - [ALC262_HIPPO_1] = "hippo_1", - [ALC262_FUJITSU] = "fujitsu", - [ALC262_HP_BPC] = "hp-bpc", - [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000", - [ALC262_HP_TC_T5735] = "hp-tc-t5735", - [ALC262_HP_RP5700] = "hp-rp5700", - [ALC262_BENQ_ED8] = "benq", - [ALC262_BENQ_T31] = "benq-t31", - [ALC262_SONY_ASSAMD] = "sony-assamd", - [ALC262_TOSHIBA_S06] = "toshiba-s06", - [ALC262_TOSHIBA_RX1] = "toshiba-rx1", - [ALC262_ULTRA] = "ultra", - [ALC262_LENOVO_3000] = "lenovo-3000", - [ALC262_NEC] = "nec", - [ALC262_TYAN] = "tyan", - [ALC262_AUTO] = "auto", -}; - -static const struct snd_pci_quirk alc262_cfg_tbl[] = { - SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO), - SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC), - SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1200, "HP xw series", - ALC262_HP_BPC), - SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1300, "HP xw series", - ALC262_HP_BPC), - SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1500, "HP z series", - ALC262_HP_BPC), - SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", - ALC262_AUTO), - SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1700, "HP xw series", - ALC262_HP_BPC), - SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL), - SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF), - SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL), - SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF), - SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL), - SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF), - SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL), - SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF), - SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC), - SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC), - SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC), - SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735", - ALC262_HP_TC_T5735), - SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700), - SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD), - SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO), - SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD), - SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */ - SND_PCI_QUIRK(0x104d, 0x9025, "Sony VAIO Z21MN", ALC262_TOSHIBA_S06), - SND_PCI_QUIRK(0x104d, 0x9035, "Sony VAIO VGN-FW170J", ALC262_AUTO), - SND_PCI_QUIRK(0x104d, 0x9047, "Sony VAIO Type G", ALC262_AUTO), -#if 0 /* disable the quirk since model=auto works better in recent versions */ - SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO", - ALC262_SONY_ASSAMD), -#endif - SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1", - ALC262_TOSHIBA_RX1), - SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06), - SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU), - SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU), - SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_TYAN), - SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc032, "Samsung Q1", - ALC262_ULTRA), - SND_PCI_QUIRK(0x144d, 0xc510, "Samsung Q45", ALC262_HIPPO), - SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000), - SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8), - SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31), - SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1), - {} -}; - -static const struct alc_config_preset alc262_presets[] = { - [ALC262_BASIC] = { - .mixers = { alc262_base_mixer }, - .init_verbs = { alc262_init_verbs }, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_capture_source, - }, - [ALC262_HIPPO] = { - .mixers = { alc262_hippo_mixer }, - .init_verbs = { alc262_init_verbs, alc_hp15_unsol_verbs}, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .hp_nid = 0x03, - .dig_out_nid = ALC262_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc262_hippo_setup, - .init_hook = alc_inithook, - }, - [ALC262_HIPPO_1] = { - .mixers = { alc262_hippo1_mixer }, - .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs}, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .hp_nid = 0x02, - .dig_out_nid = ALC262_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc262_hippo1_setup, - .init_hook = alc_inithook, - }, - [ALC262_FUJITSU] = { - .mixers = { alc262_fujitsu_mixer }, - .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs, - alc262_fujitsu_unsol_verbs }, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .hp_nid = 0x03, - .dig_out_nid = ALC262_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_fujitsu_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc262_fujitsu_setup, - .init_hook = alc_inithook, - }, - [ALC262_HP_BPC] = { - .mixers = { alc262_HP_BPC_mixer }, - .init_verbs = { alc262_HP_BPC_init_verbs }, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_HP_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc262_hp_bpc_setup, - .init_hook = alc_inithook, - }, - [ALC262_HP_BPC_D7000_WF] = { - .mixers = { alc262_HP_BPC_WildWest_mixer }, - .init_verbs = { alc262_HP_BPC_WildWest_init_verbs }, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_HP_D7000_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc262_hp_wildwest_setup, - .init_hook = alc_inithook, - }, - [ALC262_HP_BPC_D7000_WL] = { - .mixers = { alc262_HP_BPC_WildWest_mixer, - alc262_HP_BPC_WildWest_option_mixer }, - .init_verbs = { alc262_HP_BPC_WildWest_init_verbs }, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_HP_D7000_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc262_hp_wildwest_setup, - .init_hook = alc_inithook, - }, - [ALC262_HP_TC_T5735] = { - .mixers = { alc262_hp_t5735_mixer }, - .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs }, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc262_hp_t5735_setup, - .init_hook = alc_inithook, - }, - [ALC262_HP_RP5700] = { - .mixers = { alc262_hp_rp5700_mixer }, - .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs }, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_hp_rp5700_capture_source, - }, - [ALC262_BENQ_ED8] = { - .mixers = { alc262_base_mixer }, - .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs }, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_capture_source, - }, - [ALC262_SONY_ASSAMD] = { - .mixers = { alc262_sony_mixer }, - .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs}, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .hp_nid = 0x02, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc262_hippo_setup, - .init_hook = alc_inithook, - }, - [ALC262_BENQ_T31] = { - .mixers = { alc262_benq_t31_mixer }, - .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs, - alc_hp15_unsol_verbs }, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc262_hippo_setup, - .init_hook = alc_inithook, - }, - [ALC262_ULTRA] = { - .mixers = { alc262_ultra_mixer }, - .cap_mixer = alc262_ultra_capture_mixer, - .init_verbs = { alc262_ultra_verbs }, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_ultra_capture_source, - .adc_nids = alc262_adc_nids, /* ADC0 */ - .capsrc_nids = alc262_capsrc_nids, - .num_adc_nids = 1, /* single ADC */ - .unsol_event = alc262_ultra_unsol_event, - .init_hook = alc262_ultra_automute, - }, - [ALC262_LENOVO_3000] = { - .mixers = { alc262_lenovo_3000_mixer }, - .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs, - alc262_lenovo_3000_unsol_verbs, - alc262_lenovo_3000_init_verbs }, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .hp_nid = 0x03, - .dig_out_nid = ALC262_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_fujitsu_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc262_lenovo_3000_setup, - .init_hook = alc_inithook, - }, - [ALC262_NEC] = { - .mixers = { alc262_nec_mixer }, - .init_verbs = { alc262_nec_verbs }, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_capture_source, - }, - [ALC262_TOSHIBA_S06] = { - .mixers = { alc262_toshiba_s06_mixer }, - .init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs, - alc262_eapd_verbs }, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .capsrc_nids = alc262_dmic_capsrc_nids, - .dac_nids = alc262_dac_nids, - .adc_nids = alc262_dmic_adc_nids, /* ADC0 */ - .num_adc_nids = 1, /* single ADC */ - .dig_out_nid = ALC262_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc262_toshiba_s06_setup, - .init_hook = alc_inithook, - }, - [ALC262_TOSHIBA_RX1] = { - .mixers = { alc262_toshiba_rx1_mixer }, - .init_verbs = { alc262_init_verbs, alc262_toshiba_rx1_unsol_verbs }, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc262_hippo_setup, - .init_hook = alc_inithook, - }, - [ALC262_TYAN] = { - .mixers = { alc262_tyan_mixer }, - .init_verbs = { alc262_init_verbs, alc262_tyan_verbs}, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .hp_nid = 0x02, - .dig_out_nid = ALC262_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc262_tyan_setup, - .init_hook = alc_hp_automute, - }, -}; - diff --git a/trunk/sound/pci/hda/alc268_quirks.c b/trunk/sound/pci/hda/alc268_quirks.c deleted file mode 100644 index be58bf2f3aec..000000000000 --- a/trunk/sound/pci/hda/alc268_quirks.c +++ /dev/null @@ -1,636 +0,0 @@ -/* - * ALC267/ALC268 quirk models - * included by patch_realtek.c - */ - -/* ALC268 models */ -enum { - ALC268_AUTO, - ALC267_QUANTA_IL1, - ALC268_3ST, - ALC268_TOSHIBA, - ALC268_ACER, - ALC268_ACER_DMIC, - ALC268_ACER_ASPIRE_ONE, - ALC268_DELL, - ALC268_ZEPTO, -#ifdef CONFIG_SND_DEBUG - ALC268_TEST, -#endif - ALC268_MODEL_LAST /* last tag */ -}; - -/* - * ALC268 channel source setting (2 channel) - */ -#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID -#define alc268_modes alc260_modes - -static const hda_nid_t alc268_dac_nids[2] = { - /* front, hp */ - 0x02, 0x03 -}; - -static const hda_nid_t alc268_adc_nids[2] = { - /* ADC0-1 */ - 0x08, 0x07 -}; - -static const hda_nid_t alc268_adc_nids_alt[1] = { - /* ADC0 */ - 0x08 -}; - -static const hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 }; - -static const struct snd_kcontrol_new alc268_base_mixer[] = { - /* output mixer control */ - HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT), - { } -}; - -static const struct snd_kcontrol_new alc268_toshiba_mixer[] = { - /* output mixer control */ - HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT), - ALC262_HIPPO_MASTER_SWITCH, - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT), - { } -}; - -static const struct hda_verb alc268_eapd_verbs[] = { - {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, - {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, - { } -}; - -/* Toshiba specific */ -static const struct hda_verb alc268_toshiba_verbs[] = { - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - { } /* end */ -}; - -/* Acer specific */ -/* bind volumes of both NID 0x02 and 0x03 */ -static const struct hda_bind_ctls alc268_acer_bind_master_vol = { - .ops = &snd_hda_bind_vol, - .values = { - HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -static void alc268_acer_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x15; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -#define alc268_acer_master_sw_get alc262_hp_master_sw_get -#define alc268_acer_master_sw_put alc262_hp_master_sw_put - -static const struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = { - /* output mixer control */ - HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | 0x15, - .info = snd_ctl_boolean_mono_info, - .get = alc268_acer_master_sw_get, - .put = alc268_acer_master_sw_put, - }, - HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT), - { } -}; - -static const struct snd_kcontrol_new alc268_acer_mixer[] = { - /* output mixer control */ - HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | 0x14, - .info = snd_ctl_boolean_mono_info, - .get = alc268_acer_master_sw_get, - .put = alc268_acer_master_sw_put, - }, - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT), - { } -}; - -static const struct snd_kcontrol_new alc268_acer_dmic_mixer[] = { - /* output mixer control */ - HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | 0x14, - .info = snd_ctl_boolean_mono_info, - .get = alc268_acer_master_sw_get, - .put = alc268_acer_master_sw_put, - }, - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT), - { } -}; - -static const struct hda_verb alc268_acer_aspire_one_verbs[] = { - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x23, AC_VERB_SET_CONNECT_SEL, 0x06}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017}, - { } -}; - -static const struct hda_verb alc268_acer_verbs[] = { - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - { } -}; - -/* unsolicited event for HP jack sensing */ -#define alc268_toshiba_setup alc262_hippo_setup - -static void alc268_acer_lc_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x12; - spec->auto_mic = 1; -} - -static const struct snd_kcontrol_new alc268_dell_mixer[] = { - /* output mixer control */ - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - { } -}; - -static const struct hda_verb alc268_dell_verbs[] = { - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN}, - { } -}; - -/* mute/unmute internal speaker according to the hp jack and mute state */ -static void alc268_dell_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_PIN; -} - -static const struct snd_kcontrol_new alc267_quanta_il1_mixer[] = { - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - { } -}; - -static const struct hda_verb alc267_quanta_il1_verbs[] = { - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN}, - { } -}; - -static void alc267_quanta_il1_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_PIN; -} - -/* - * generic initialization of ADC, input mixers and output mixers - */ -static const struct hda_verb alc268_base_init_verbs[] = { - /* Unmute DAC0-1 and set vol = 0 */ - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* - * Set up output mixers (0x0c - 0x0e) - */ - /* set vol=0 to output mixers */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00}, - - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - /* set PCBEEP vol = 0, mute connections */ - {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - - /* Unmute Selector 23h,24h and set the default input to mic-in */ - - {0x23, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x24, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - { } -}; - -/* only for model=test */ -#ifdef CONFIG_SND_DEBUG -/* - * generic initialization of ADC, input mixers and output mixers - */ -static const struct hda_verb alc268_volume_init_verbs[] = { - /* set output DAC */ - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - { } -}; -#endif /* CONFIG_SND_DEBUG */ - -static const struct snd_kcontrol_new alc268_capture_nosrc_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc268_capture_alt_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT), - _DEFINE_CAPSRC(1), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc268_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT), - _DEFINE_CAPSRC(2), - { } /* end */ -}; - -static const struct hda_input_mux alc268_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x2 }, - { "CD", 0x3 }, - }, -}; - -static const struct hda_input_mux alc268_acer_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x0 }, - { "Internal Mic", 0x1 }, - { "Line", 0x2 }, - }, -}; - -static const struct hda_input_mux alc268_acer_dmic_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x0 }, - { "Internal Mic", 0x6 }, - { "Line", 0x2 }, - }, -}; - -#ifdef CONFIG_SND_DEBUG -static const struct snd_kcontrol_new alc268_test_mixer[] = { - /* Volume widgets */ - HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT), - HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT), - HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT), - HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT), - HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT), - HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT), - HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT), - HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT), - HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT), - /* The below appears problematic on some hardwares */ - /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/ - HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT), - HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT), - - /* Modes for retasking pin widgets */ - ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT), - ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT), - ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT), - ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT), - - /* Controls for GPIO pins, assuming they are configured as outputs */ - ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01), - ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02), - ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04), - ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08), - - /* Switches to allow the digital SPDIF output pin to be enabled. - * The ALC268 does not have an SPDIF input. - */ - ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01), - - /* A switch allowing EAPD to be enabled. Some laptops seem to use - * this output to turn on an external amplifier. - */ - ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02), - ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02), - - { } /* end */ -}; -#endif - -/* - * configuration and preset - */ -static const char * const alc268_models[ALC268_MODEL_LAST] = { - [ALC267_QUANTA_IL1] = "quanta-il1", - [ALC268_3ST] = "3stack", - [ALC268_TOSHIBA] = "toshiba", - [ALC268_ACER] = "acer", - [ALC268_ACER_DMIC] = "acer-dmic", - [ALC268_ACER_ASPIRE_ONE] = "acer-aspire", - [ALC268_DELL] = "dell", - [ALC268_ZEPTO] = "zepto", -#ifdef CONFIG_SND_DEBUG - [ALC268_TEST] = "test", -#endif - [ALC268_AUTO] = "auto", -}; - -static const struct snd_pci_quirk alc268_cfg_tbl[] = { - SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER), - SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER), - SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER), - SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER), - SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER), - SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One", - ALC268_ACER_ASPIRE_ONE), - SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL), - SND_PCI_QUIRK(0x1028, 0x02b0, "Dell Inspiron 910", ALC268_AUTO), - SND_PCI_QUIRK_MASK(0x1028, 0xfff0, 0x02b0, - "Dell Inspiron Mini9/Vostro A90", ALC268_DELL), - /* almost compatible with toshiba but with optional digital outs; - * auto-probing seems working fine - */ - SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP TX25xx series", - ALC268_AUTO), - SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST), - SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO), - SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA), - SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1), - {} -}; - -/* Toshiba laptops have no unique PCI SSID but only codec SSID */ -static const struct snd_pci_quirk alc268_ssid_cfg_tbl[] = { - SND_PCI_QUIRK(0x1179, 0xff0a, "TOSHIBA X-200", ALC268_AUTO), - SND_PCI_QUIRK(0x1179, 0xff0e, "TOSHIBA X-200 HDMI", ALC268_AUTO), - SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05", - ALC268_TOSHIBA), - {} -}; - -static const struct alc_config_preset alc268_presets[] = { - [ALC267_QUANTA_IL1] = { - .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer, - alc268_capture_nosrc_mixer }, - .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, - alc267_quanta_il1_verbs }, - .num_dacs = ARRAY_SIZE(alc268_dac_nids), - .dac_nids = alc268_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), - .adc_nids = alc268_adc_nids_alt, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc268_modes), - .channel_mode = alc268_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc267_quanta_il1_setup, - .init_hook = alc_inithook, - }, - [ALC268_3ST] = { - .mixers = { alc268_base_mixer, alc268_capture_alt_mixer, - alc268_beep_mixer }, - .init_verbs = { alc268_base_init_verbs }, - .num_dacs = ARRAY_SIZE(alc268_dac_nids), - .dac_nids = alc268_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), - .adc_nids = alc268_adc_nids_alt, - .capsrc_nids = alc268_capsrc_nids, - .hp_nid = 0x03, - .dig_out_nid = ALC268_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc268_modes), - .channel_mode = alc268_modes, - .input_mux = &alc268_capture_source, - }, - [ALC268_TOSHIBA] = { - .mixers = { alc268_toshiba_mixer, alc268_capture_alt_mixer, - alc268_beep_mixer }, - .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, - alc268_toshiba_verbs }, - .num_dacs = ARRAY_SIZE(alc268_dac_nids), - .dac_nids = alc268_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), - .adc_nids = alc268_adc_nids_alt, - .capsrc_nids = alc268_capsrc_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc268_modes), - .channel_mode = alc268_modes, - .input_mux = &alc268_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc268_toshiba_setup, - .init_hook = alc_inithook, - }, - [ALC268_ACER] = { - .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer, - alc268_beep_mixer }, - .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, - alc268_acer_verbs }, - .num_dacs = ARRAY_SIZE(alc268_dac_nids), - .dac_nids = alc268_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), - .adc_nids = alc268_adc_nids_alt, - .capsrc_nids = alc268_capsrc_nids, - .hp_nid = 0x02, - .num_channel_mode = ARRAY_SIZE(alc268_modes), - .channel_mode = alc268_modes, - .input_mux = &alc268_acer_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc268_acer_setup, - .init_hook = alc_inithook, - }, - [ALC268_ACER_DMIC] = { - .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer, - alc268_beep_mixer }, - .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, - alc268_acer_verbs }, - .num_dacs = ARRAY_SIZE(alc268_dac_nids), - .dac_nids = alc268_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), - .adc_nids = alc268_adc_nids_alt, - .capsrc_nids = alc268_capsrc_nids, - .hp_nid = 0x02, - .num_channel_mode = ARRAY_SIZE(alc268_modes), - .channel_mode = alc268_modes, - .input_mux = &alc268_acer_dmic_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc268_acer_setup, - .init_hook = alc_inithook, - }, - [ALC268_ACER_ASPIRE_ONE] = { - .mixers = { alc268_acer_aspire_one_mixer, - alc268_beep_mixer, - alc268_capture_nosrc_mixer }, - .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, - alc268_acer_aspire_one_verbs }, - .num_dacs = ARRAY_SIZE(alc268_dac_nids), - .dac_nids = alc268_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), - .adc_nids = alc268_adc_nids_alt, - .capsrc_nids = alc268_capsrc_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc268_modes), - .channel_mode = alc268_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc268_acer_lc_setup, - .init_hook = alc_inithook, - }, - [ALC268_DELL] = { - .mixers = { alc268_dell_mixer, alc268_beep_mixer, - alc268_capture_nosrc_mixer }, - .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, - alc268_dell_verbs }, - .num_dacs = ARRAY_SIZE(alc268_dac_nids), - .dac_nids = alc268_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), - .adc_nids = alc268_adc_nids_alt, - .capsrc_nids = alc268_capsrc_nids, - .hp_nid = 0x02, - .num_channel_mode = ARRAY_SIZE(alc268_modes), - .channel_mode = alc268_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc268_dell_setup, - .init_hook = alc_inithook, - }, - [ALC268_ZEPTO] = { - .mixers = { alc268_base_mixer, alc268_capture_alt_mixer, - alc268_beep_mixer }, - .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, - alc268_toshiba_verbs }, - .num_dacs = ARRAY_SIZE(alc268_dac_nids), - .dac_nids = alc268_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), - .adc_nids = alc268_adc_nids_alt, - .capsrc_nids = alc268_capsrc_nids, - .hp_nid = 0x03, - .dig_out_nid = ALC268_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc268_modes), - .channel_mode = alc268_modes, - .input_mux = &alc268_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc268_toshiba_setup, - .init_hook = alc_inithook, - }, -#ifdef CONFIG_SND_DEBUG - [ALC268_TEST] = { - .mixers = { alc268_test_mixer, alc268_capture_mixer }, - .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, - alc268_volume_init_verbs, - alc268_beep_init_verbs }, - .num_dacs = ARRAY_SIZE(alc268_dac_nids), - .dac_nids = alc268_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), - .adc_nids = alc268_adc_nids_alt, - .capsrc_nids = alc268_capsrc_nids, - .hp_nid = 0x03, - .dig_out_nid = ALC268_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc268_modes), - .channel_mode = alc268_modes, - .input_mux = &alc268_capture_source, - }, -#endif -}; - diff --git a/trunk/sound/pci/hda/alc269_quirks.c b/trunk/sound/pci/hda/alc269_quirks.c deleted file mode 100644 index 14fdcf29b154..000000000000 --- a/trunk/sound/pci/hda/alc269_quirks.c +++ /dev/null @@ -1,681 +0,0 @@ -/* - * ALC269/ALC270/ALC275/ALC276 quirk models - * included by patch_realtek.c - */ - -/* ALC269 models */ -enum { - ALC269_AUTO, - ALC269_BASIC, - ALC269_QUANTA_FL1, - ALC269_AMIC, - ALC269_DMIC, - ALC269VB_AMIC, - ALC269VB_DMIC, - ALC269_FUJITSU, - ALC269_LIFEBOOK, - ALC271_ACER, - ALC269_MODEL_LAST /* last tag */ -}; - -/* - * ALC269 channel source setting (2 channel) - */ -#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID - -#define alc269_dac_nids alc260_dac_nids - -static const hda_nid_t alc269_adc_nids[1] = { - /* ADC1 */ - 0x08, -}; - -static const hda_nid_t alc269_capsrc_nids[1] = { - 0x23, -}; - -static const hda_nid_t alc269vb_adc_nids[1] = { - /* ADC1 */ - 0x09, -}; - -static const hda_nid_t alc269vb_capsrc_nids[1] = { - 0x22, -}; - -#define alc269_modes alc260_modes -#define alc269_capture_source alc880_lg_lw_capture_source - -static const struct snd_kcontrol_new alc269_base_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = { - /* output mixer control */ - HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_AMP_FLAG, - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, - .put = alc268_acer_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), - }, - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - { } -}; - -static const struct snd_kcontrol_new alc269_lifebook_mixer[] = { - /* output mixer control */ - HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_AMP_FLAG, - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, - .put = alc268_acer_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), - }, - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT), - HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT), - HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x1b, 0, HDA_INPUT), - { } -}; - -static const struct snd_kcontrol_new alc269_laptop_mixer[] = { - HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc269vb_laptop_mixer[] = { - HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc269_asus_mixer[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x0, HDA_INPUT), - { } /* end */ -}; - -/* capture mixer elements */ -static const struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - { } /* end */ -}; - -/* FSC amilo */ -#define alc269_fujitsu_mixer alc269_laptop_mixer - -static const struct hda_verb alc269_quanta_fl1_verbs[] = { - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - { } -}; - -static const struct hda_verb alc269_lifebook_verbs[] = { - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - { } -}; - -/* toggle speaker-output according to the hp-jack state */ -static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec) -{ - alc_hp_automute(codec); - - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_COEF_INDEX, 0x0c); - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_PROC_COEF, 0x680); - - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_COEF_INDEX, 0x0c); - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_PROC_COEF, 0x480); -} - -#define alc269_lifebook_speaker_automute \ - alc269_quanta_fl1_speaker_automute - -static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec) -{ - unsigned int present_laptop; - unsigned int present_dock; - - present_laptop = snd_hda_jack_detect(codec, 0x18); - present_dock = snd_hda_jack_detect(codec, 0x1b); - - /* Laptop mic port overrides dock mic port, design decision */ - if (present_dock) - snd_hda_codec_write(codec, 0x23, 0, - AC_VERB_SET_CONNECT_SEL, 0x3); - if (present_laptop) - snd_hda_codec_write(codec, 0x23, 0, - AC_VERB_SET_CONNECT_SEL, 0x0); - if (!present_dock && !present_laptop) - snd_hda_codec_write(codec, 0x23, 0, - AC_VERB_SET_CONNECT_SEL, 0x1); -} - -static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case ALC_HP_EVENT: - alc269_quanta_fl1_speaker_automute(codec); - break; - case ALC_MIC_EVENT: - alc_mic_automute(codec); - break; - } -} - -static void alc269_lifebook_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) == ALC_HP_EVENT) - alc269_lifebook_speaker_automute(codec); - if ((res >> 26) == ALC_MIC_EVENT) - alc269_lifebook_mic_autoswitch(codec); -} - -static void alc269_quanta_fl1_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute_mixer_nid[0] = 0x0c; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_MIXER; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; -} - -static void alc269_quanta_fl1_init_hook(struct hda_codec *codec) -{ - alc269_quanta_fl1_speaker_automute(codec); - alc_mic_automute(codec); -} - -static void alc269_lifebook_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.hp_pins[1] = 0x1a; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute_mixer_nid[0] = 0x0c; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_MIXER; -} - -static void alc269_lifebook_init_hook(struct hda_codec *codec) -{ - alc269_lifebook_speaker_automute(codec); - alc269_lifebook_mic_autoswitch(codec); -} - -static const struct hda_verb alc269_laptop_dmic_init_verbs[] = { - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x23, AC_VERB_SET_CONNECT_SEL, 0x05}, - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))}, - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc269_laptop_amic_init_verbs[] = { - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x23, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc269vb_laptop_dmic_init_verbs[] = { - {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x22, AC_VERB_SET_CONNECT_SEL, 0x06}, - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))}, - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc269vb_laptop_amic_init_verbs[] = { - {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x22, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))}, - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc271_acer_dmic_verbs[] = { - {0x20, AC_VERB_SET_COEF_INDEX, 0x0d}, - {0x20, AC_VERB_SET_PROC_COEF, 0x4000}, - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x22, AC_VERB_SET_CONNECT_SEL, 6}, - { } -}; - -static void alc269_laptop_amic_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute_mixer_nid[0] = 0x0c; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_MIXER; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; -} - -static void alc269_laptop_dmic_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute_mixer_nid[0] = 0x0c; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_MIXER; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x12; - spec->auto_mic = 1; -} - -static void alc269vb_laptop_amic_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x21; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute_mixer_nid[0] = 0x0c; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_MIXER; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; -} - -static void alc269vb_laptop_dmic_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x21; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute_mixer_nid[0] = 0x0c; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_MIXER; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x12; - spec->auto_mic = 1; -} - -/* - * generic initialization of ADC, input mixers and output mixers - */ -static const struct hda_verb alc269_init_verbs[] = { - /* - * Unmute ADC0 and set the default input to mic-in - */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* - * Set up output mixers (0x02 - 0x03) - */ - /* set vol=0 to output mixers */ - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* set up input amps for analog loopback */ - /* Amp Indices: DAC = 0, mixer = 1 */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* FIXME: use Mux-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */ - /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ - {0x23, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* set EAPD */ - {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, - { } -}; - -static const struct hda_verb alc269vb_init_verbs[] = { - /* - * Unmute ADC0 and set the default input to mic-in - */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* - * Set up output mixers (0x02 - 0x03) - */ - /* set vol=0 to output mixers */ - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* set up input amps for analog loopback */ - /* Amp Indices: DAC = 0, mixer = 1 */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* FIXME: use Mux-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */ - /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ - {0x22, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* set EAPD */ - {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, - { } -}; - -/* - * configuration and preset - */ -static const char * const alc269_models[ALC269_MODEL_LAST] = { - [ALC269_BASIC] = "basic", - [ALC269_QUANTA_FL1] = "quanta", - [ALC269_AMIC] = "laptop-amic", - [ALC269_DMIC] = "laptop-dmic", - [ALC269_FUJITSU] = "fujitsu", - [ALC269_LIFEBOOK] = "lifebook", - [ALC269_AUTO] = "auto", -}; - -static const struct snd_pci_quirk alc269_cfg_tbl[] = { - SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1), - SND_PCI_QUIRK(0x1025, 0x047c, "ACER ZGA", ALC271_ACER), - SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A", - ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269VB_AMIC), - SND_PCI_QUIRK(0x1043, 0x1113, "ASUS N63Jn", ALC269VB_AMIC), - SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269VB_AMIC), - SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269VB_AMIC), - SND_PCI_QUIRK(0x1043, 0x11b3, "ASUS K52DR", ALC269VB_AMIC), - SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269VB_AMIC), - SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269VB_AMIC), - SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82JV", ALC269VB_AMIC), - SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1593, "ASUS N51Vn", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_DMIC), - SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901", - ALC269_DMIC), - SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101", - ALC269_DMIC), - SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005HA", ALC269_DMIC), - SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005HA", ALC269_DMIC), - SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_AUTO), - SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK), - SND_PCI_QUIRK(0x152d, 0x1778, "Quanta ON1", ALC269_DMIC), - SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU), - SND_PCI_QUIRK(0x17aa, 0x3be9, "Quanta Wistron", ALC269_AMIC), - SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_AMIC), - SND_PCI_QUIRK(0x17ff, 0x059a, "Quanta EL3", ALC269_DMIC), - SND_PCI_QUIRK(0x17ff, 0x059b, "Quanta JR1", ALC269_DMIC), - {} -}; - -static const struct alc_config_preset alc269_presets[] = { - [ALC269_BASIC] = { - .mixers = { alc269_base_mixer }, - .init_verbs = { alc269_init_verbs }, - .num_dacs = ARRAY_SIZE(alc269_dac_nids), - .dac_nids = alc269_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc269_modes), - .channel_mode = alc269_modes, - .input_mux = &alc269_capture_source, - }, - [ALC269_QUANTA_FL1] = { - .mixers = { alc269_quanta_fl1_mixer }, - .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs }, - .num_dacs = ARRAY_SIZE(alc269_dac_nids), - .dac_nids = alc269_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc269_modes), - .channel_mode = alc269_modes, - .input_mux = &alc269_capture_source, - .unsol_event = alc269_quanta_fl1_unsol_event, - .setup = alc269_quanta_fl1_setup, - .init_hook = alc269_quanta_fl1_init_hook, - }, - [ALC269_AMIC] = { - .mixers = { alc269_laptop_mixer }, - .cap_mixer = alc269_laptop_analog_capture_mixer, - .init_verbs = { alc269_init_verbs, - alc269_laptop_amic_init_verbs }, - .num_dacs = ARRAY_SIZE(alc269_dac_nids), - .dac_nids = alc269_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc269_modes), - .channel_mode = alc269_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc269_laptop_amic_setup, - .init_hook = alc_inithook, - }, - [ALC269_DMIC] = { - .mixers = { alc269_laptop_mixer }, - .cap_mixer = alc269_laptop_digital_capture_mixer, - .init_verbs = { alc269_init_verbs, - alc269_laptop_dmic_init_verbs }, - .num_dacs = ARRAY_SIZE(alc269_dac_nids), - .dac_nids = alc269_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc269_modes), - .channel_mode = alc269_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc269_laptop_dmic_setup, - .init_hook = alc_inithook, - }, - [ALC269VB_AMIC] = { - .mixers = { alc269vb_laptop_mixer }, - .cap_mixer = alc269vb_laptop_analog_capture_mixer, - .init_verbs = { alc269vb_init_verbs, - alc269vb_laptop_amic_init_verbs }, - .num_dacs = ARRAY_SIZE(alc269_dac_nids), - .dac_nids = alc269_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc269_modes), - .channel_mode = alc269_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc269vb_laptop_amic_setup, - .init_hook = alc_inithook, - }, - [ALC269VB_DMIC] = { - .mixers = { alc269vb_laptop_mixer }, - .cap_mixer = alc269vb_laptop_digital_capture_mixer, - .init_verbs = { alc269vb_init_verbs, - alc269vb_laptop_dmic_init_verbs }, - .num_dacs = ARRAY_SIZE(alc269_dac_nids), - .dac_nids = alc269_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc269_modes), - .channel_mode = alc269_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc269vb_laptop_dmic_setup, - .init_hook = alc_inithook, - }, - [ALC269_FUJITSU] = { - .mixers = { alc269_fujitsu_mixer }, - .cap_mixer = alc269_laptop_digital_capture_mixer, - .init_verbs = { alc269_init_verbs, - alc269_laptop_dmic_init_verbs }, - .num_dacs = ARRAY_SIZE(alc269_dac_nids), - .dac_nids = alc269_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc269_modes), - .channel_mode = alc269_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc269_laptop_dmic_setup, - .init_hook = alc_inithook, - }, - [ALC269_LIFEBOOK] = { - .mixers = { alc269_lifebook_mixer }, - .init_verbs = { alc269_init_verbs, alc269_lifebook_verbs }, - .num_dacs = ARRAY_SIZE(alc269_dac_nids), - .dac_nids = alc269_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc269_modes), - .channel_mode = alc269_modes, - .input_mux = &alc269_capture_source, - .unsol_event = alc269_lifebook_unsol_event, - .setup = alc269_lifebook_setup, - .init_hook = alc269_lifebook_init_hook, - }, - [ALC271_ACER] = { - .mixers = { alc269_asus_mixer }, - .cap_mixer = alc269vb_laptop_digital_capture_mixer, - .init_verbs = { alc269_init_verbs, alc271_acer_dmic_verbs }, - .num_dacs = ARRAY_SIZE(alc269_dac_nids), - .dac_nids = alc269_dac_nids, - .adc_nids = alc262_dmic_adc_nids, - .num_adc_nids = ARRAY_SIZE(alc262_dmic_adc_nids), - .capsrc_nids = alc262_dmic_capsrc_nids, - .num_channel_mode = ARRAY_SIZE(alc269_modes), - .channel_mode = alc269_modes, - .input_mux = &alc269_capture_source, - .dig_out_nid = ALC880_DIGOUT_NID, - .unsol_event = alc_sku_unsol_event, - .setup = alc269vb_laptop_dmic_setup, - .init_hook = alc_inithook, - }, -}; - diff --git a/trunk/sound/pci/hda/alc662_quirks.c b/trunk/sound/pci/hda/alc662_quirks.c deleted file mode 100644 index e69a6ea3083a..000000000000 --- a/trunk/sound/pci/hda/alc662_quirks.c +++ /dev/null @@ -1,1408 +0,0 @@ -/* - * ALC662/ALC663/ALC665/ALC670 quirk models - * included by patch_realtek.c - */ - -/* ALC662 models */ -enum { - ALC662_AUTO, - ALC662_3ST_2ch_DIG, - ALC662_3ST_6ch_DIG, - ALC662_3ST_6ch, - ALC662_5ST_DIG, - ALC662_LENOVO_101E, - ALC662_ASUS_EEEPC_P701, - ALC662_ASUS_EEEPC_EP20, - ALC663_ASUS_M51VA, - ALC663_ASUS_G71V, - ALC663_ASUS_H13, - ALC663_ASUS_G50V, - ALC662_ECS, - ALC663_ASUS_MODE1, - ALC662_ASUS_MODE2, - ALC663_ASUS_MODE3, - ALC663_ASUS_MODE4, - ALC663_ASUS_MODE5, - ALC663_ASUS_MODE6, - ALC663_ASUS_MODE7, - ALC663_ASUS_MODE8, - ALC272_DELL, - ALC272_DELL_ZM1, - ALC272_SAMSUNG_NC10, - ALC662_MODEL_LAST, -}; - -#define ALC662_DIGOUT_NID 0x06 -#define ALC662_DIGIN_NID 0x0a - -static const hda_nid_t alc662_dac_nids[3] = { - /* front, rear, clfe */ - 0x02, 0x03, 0x04 -}; - -static const hda_nid_t alc272_dac_nids[2] = { - 0x02, 0x03 -}; - -static const hda_nid_t alc662_adc_nids[2] = { - /* ADC1-2 */ - 0x09, 0x08 -}; - -static const hda_nid_t alc272_adc_nids[1] = { - /* ADC1-2 */ - 0x08, -}; - -static const hda_nid_t alc662_capsrc_nids[2] = { 0x22, 0x23 }; -static const hda_nid_t alc272_capsrc_nids[1] = { 0x23 }; - - -/* input MUX */ -/* FIXME: should be a matrix-type input source selection */ -static const struct hda_input_mux alc662_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - -static const struct hda_input_mux alc662_lenovo_101e_capture_source = { - .num_items = 2, - .items = { - { "Mic", 0x1 }, - { "Line", 0x2 }, - }, -}; - -static const struct hda_input_mux alc663_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x2 }, - }, -}; - -#if 0 /* set to 1 for testing other input sources below */ -static const struct hda_input_mux alc272_nc10_capture_source = { - .num_items = 16, - .items = { - { "Autoselect Mic", 0x0 }, - { "Internal Mic", 0x1 }, - { "In-0x02", 0x2 }, - { "In-0x03", 0x3 }, - { "In-0x04", 0x4 }, - { "In-0x05", 0x5 }, - { "In-0x06", 0x6 }, - { "In-0x07", 0x7 }, - { "In-0x08", 0x8 }, - { "In-0x09", 0x9 }, - { "In-0x0a", 0x0a }, - { "In-0x0b", 0x0b }, - { "In-0x0c", 0x0c }, - { "In-0x0d", 0x0d }, - { "In-0x0e", 0x0e }, - { "In-0x0f", 0x0f }, - }, -}; -#endif - -/* - * 2ch mode - */ -static const struct hda_channel_mode alc662_3ST_2ch_modes[1] = { - { 2, NULL } -}; - -/* - * 2ch mode - */ -static const struct hda_verb alc662_3ST_ch2_init[] = { - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { } /* end */ -}; - -/* - * 6ch mode - */ -static const struct hda_verb alc662_3ST_ch6_init[] = { - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { } /* end */ -}; - -static const struct hda_channel_mode alc662_3ST_6ch_modes[2] = { - { 2, alc662_3ST_ch2_init }, - { 6, alc662_3ST_ch6_init }, -}; - -/* - * 2ch mode - */ -static const struct hda_verb alc662_sixstack_ch6_init[] = { - { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, - { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, - { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { } /* end */ -}; - -/* - * 6ch mode - */ -static const struct hda_verb alc662_sixstack_ch8_init[] = { - { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { } /* end */ -}; - -static const struct hda_channel_mode alc662_5stack_modes[2] = { - { 2, alc662_sixstack_ch6_init }, - { 6, alc662_sixstack_ch8_init }, -}; - -/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 - * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b - */ - -static const struct snd_kcontrol_new alc662_base_mixer[] = { - /* output mixer control */ - HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - - /*Input mixer control */ - HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT), - ALC262_HIPPO_MASTER_SWITCH, - - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = { - ALC262_HIPPO_MASTER_SWITCH, - HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct hda_bind_ctls alc663_asus_bind_master_vol = { - .ops = &snd_hda_bind_vol, - .values = { - HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -static const struct hda_bind_ctls alc663_asus_one_bind_switch = { - .ops = &snd_hda_bind_sw, - .values = { - HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -static const struct snd_kcontrol_new alc663_m51va_mixer[] = { - HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol), - HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct hda_bind_ctls alc663_asus_tree_bind_switch = { - .ops = &snd_hda_bind_sw, - .values = { - HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -static const struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = { - HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol), - HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - - { } /* end */ -}; - -static const struct hda_bind_ctls alc663_asus_four_bind_switch = { - .ops = &snd_hda_bind_sw, - .values = { - HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -static const struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = { - HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol), - HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc662_1bjd_mixer[] = { - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct hda_bind_ctls alc663_asus_two_bind_master_vol = { - .ops = &snd_hda_bind_vol, - .values = { - HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -static const struct hda_bind_ctls alc663_asus_two_bind_switch = { - .ops = &snd_hda_bind_sw, - .values = { - HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -static const struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = { - HDA_BIND_VOL("Master Playback Volume", - &alc663_asus_two_bind_master_vol), - HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = { - HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol), - HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc663_g71v_mixer[] = { - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc663_g50v_mixer[] = { - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - { } /* end */ -}; - -static const struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = { - .ops = &snd_hda_bind_sw, - .values = { - HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -static const struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = { - .ops = &snd_hda_bind_sw, - .values = { - HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -static const struct snd_kcontrol_new alc663_mode7_mixer[] = { - HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch), - HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol), - HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch), - HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("IntMic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("IntMic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc663_mode8_mixer[] = { - HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch), - HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol), - HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch), - HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - - -static const struct snd_kcontrol_new alc662_chmode_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -static const struct hda_verb alc662_init_verbs[] = { - /* ADC: mute amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - /* Front Pin: output 0 (0x0c) */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Rear Pin: output 1 (0x0d) */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* CLFE Pin: output 2 (0x0e) */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Mic (rear) pin: input vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Front Mic pin: input vref at 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line In pin: input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line-2 In: Headphone output (output 0 - 0x0c) */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - /* FIXME: use matrix-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ - /* Input mixer */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - { } -}; - -static const struct hda_verb alc662_eapd_init_verbs[] = { - /* always trun on EAPD */ - {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, - {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, - { } -}; - -static const struct hda_verb alc662_sue_init_verbs[] = { - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC_FRONT_EVENT}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc662_eeepc_sue_init_verbs[] = { - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -/* Set Unsolicited Event*/ -static const struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = { - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc663_m51va_init_verbs[] = { - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc663_21jd_amic_init_verbs[] = { - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc662_1bjd_amic_init_verbs[] = { - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc663_15jd_amic_init_verbs[] = { - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = { - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = { - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc663_g71v_init_verbs[] = { - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */ - /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */ - - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */ - - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC_FRONT_EVENT}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC_MIC_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc663_g50v_init_verbs[] = { - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */ - - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc662_ecs_init_verbs[] = { - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc272_dell_zm1_init_verbs[] = { - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc272_dell_init_verbs[] = { - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc663_mode7_init_verbs[] = { - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)}, - {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc663_mode8_init_verbs[] = { - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct snd_kcontrol_new alc662_auto_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc272_auto_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - { } /* end */ -}; - -static void alc662_lenovo_101e_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.line_out_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x15; - spec->automute = 1; - spec->detect_line = 1; - spec->automute_lines = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc662_eeepc_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - alc262_hippo1_setup(codec); - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; -} - -static void alc662_eeepc_ep20_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x1b; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc663_m51va_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x21; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute_mixer_nid[0] = 0x0c; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_MIXER; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x12; - spec->auto_mic = 1; -} - -/* ***************** Mode1 ******************************/ -static void alc663_mode1_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x21; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute_mixer_nid[0] = 0x0c; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_MIXER; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; -} - -/* ***************** Mode2 ******************************/ -static void alc662_mode2_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_PIN; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; -} - -/* ***************** Mode3 ******************************/ -static void alc663_mode3_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x21; - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_PIN; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; -} - -/* ***************** Mode4 ******************************/ -static void alc663_mode4_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x21; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x16; - spec->automute_mixer_nid[0] = 0x0c; - spec->automute_mixer_nid[1] = 0x0e; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_MIXER; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; -} - -/* ***************** Mode5 ******************************/ -static void alc663_mode5_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x16; - spec->automute_mixer_nid[0] = 0x0c; - spec->automute_mixer_nid[1] = 0x0e; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_MIXER; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; -} - -/* ***************** Mode6 ******************************/ -static void alc663_mode6_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute_mixer_nid[0] = 0x0c; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_MIXER; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; -} - -/* ***************** Mode7 ******************************/ -static void alc663_mode7_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.hp_pins[0] = 0x21; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x17; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_PIN; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; -} - -/* ***************** Mode8 ******************************/ -static void alc663_mode8_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x21; - spec->autocfg.hp_pins[1] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x17; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_PIN; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x12; - spec->auto_mic = 1; -} - -static void alc663_g71v_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x21; - spec->autocfg.line_out_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; - spec->detect_line = 1; - spec->automute_lines = 1; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x12; - spec->auto_mic = 1; -} - -#define alc663_g50v_setup alc663_m51va_setup - -static const struct snd_kcontrol_new alc662_ecs_mixer[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT), - ALC262_HIPPO_MASTER_SWITCH, - - HDA_CODEC_VOLUME("Mic/LineIn Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT), - - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc272_nc10_mixer[] = { - /* Master Playback automatically created from Speaker and Headphone */ - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - { } /* end */ -}; - - -/* - * configuration and preset - */ -static const char * const alc662_models[ALC662_MODEL_LAST] = { - [ALC662_3ST_2ch_DIG] = "3stack-dig", - [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig", - [ALC662_3ST_6ch] = "3stack-6ch", - [ALC662_5ST_DIG] = "5stack-dig", - [ALC662_LENOVO_101E] = "lenovo-101e", - [ALC662_ASUS_EEEPC_P701] = "eeepc-p701", - [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20", - [ALC662_ECS] = "ecs", - [ALC663_ASUS_M51VA] = "m51va", - [ALC663_ASUS_G71V] = "g71v", - [ALC663_ASUS_H13] = "h13", - [ALC663_ASUS_G50V] = "g50v", - [ALC663_ASUS_MODE1] = "asus-mode1", - [ALC662_ASUS_MODE2] = "asus-mode2", - [ALC663_ASUS_MODE3] = "asus-mode3", - [ALC663_ASUS_MODE4] = "asus-mode4", - [ALC663_ASUS_MODE5] = "asus-mode5", - [ALC663_ASUS_MODE6] = "asus-mode6", - [ALC663_ASUS_MODE7] = "asus-mode7", - [ALC663_ASUS_MODE8] = "asus-mode8", - [ALC272_DELL] = "dell", - [ALC272_DELL_ZM1] = "dell-zm1", - [ALC272_SAMSUNG_NC10] = "samsung-nc10", - [ALC662_AUTO] = "auto", -}; - -static const struct snd_pci_quirk alc662_cfg_tbl[] = { - SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS), - SND_PCI_QUIRK(0x1028, 0x02d6, "DELL", ALC272_DELL), - SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1), - SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3), - SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3), - SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC663_ASUS_MODE7), - SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC663_ASUS_MODE7), - SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC663_ASUS_MODE8), - SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC663_ASUS_MODE3), - SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6), - SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6), - SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC663_ASUS_MODE3), - SND_PCI_QUIRK(0x1043, 0x17c3, "ASUS UX20", ALC663_ASUS_M51VA), - SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5), - SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6), - SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA), - /*SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),*/ - SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3), - SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3), - SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3), - SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V), - /*SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),*/ - SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x19d3, "ASUS NB", ALC663_ASUS_M51VA), - SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4), - SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG), - SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701), - SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20), - SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS), - SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K", - ALC662_3ST_6ch_DIG), - SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB20x", ALC662_AUTO), - SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10), - SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L", - ALC662_3ST_6ch_DIG), - SND_PCI_QUIRK(0x152d, 0x2304, "Quanta WH1", ALC663_ASUS_H13), - SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG), - SND_PCI_QUIRK(0x1631, 0xc10c, "PB RS65", ALC663_ASUS_M51VA), - SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E), - SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0", - ALC662_3ST_6ch_DIG), - SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x", - ALC663_ASUS_H13), - SND_PCI_QUIRK(0x1991, 0x5628, "Ordissimo EVE", ALC662_LENOVO_101E), - {} -}; - -static const struct alc_config_preset alc662_presets[] = { - [ALC662_3ST_2ch_DIG] = { - .mixers = { alc662_3ST_2ch_mixer }, - .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .dig_in_nid = ALC662_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .input_mux = &alc662_capture_source, - }, - [ALC662_3ST_6ch_DIG] = { - .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer }, - .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .dig_in_nid = ALC662_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), - .channel_mode = alc662_3ST_6ch_modes, - .need_dac_fix = 1, - .input_mux = &alc662_capture_source, - }, - [ALC662_3ST_6ch] = { - .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer }, - .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), - .channel_mode = alc662_3ST_6ch_modes, - .need_dac_fix = 1, - .input_mux = &alc662_capture_source, - }, - [ALC662_5ST_DIG] = { - .mixers = { alc662_base_mixer, alc662_chmode_mixer }, - .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .dig_in_nid = ALC662_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes), - .channel_mode = alc662_5stack_modes, - .input_mux = &alc662_capture_source, - }, - [ALC662_LENOVO_101E] = { - .mixers = { alc662_lenovo_101e_mixer }, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc662_sue_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .input_mux = &alc662_lenovo_101e_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc662_lenovo_101e_setup, - .init_hook = alc_inithook, - }, - [ALC662_ASUS_EEEPC_P701] = { - .mixers = { alc662_eeepc_p701_mixer }, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc662_eeepc_sue_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc662_eeepc_setup, - .init_hook = alc_inithook, - }, - [ALC662_ASUS_EEEPC_EP20] = { - .mixers = { alc662_eeepc_ep20_mixer, - alc662_chmode_mixer }, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc662_eeepc_ep20_sue_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), - .channel_mode = alc662_3ST_6ch_modes, - .input_mux = &alc662_lenovo_101e_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc662_eeepc_ep20_setup, - .init_hook = alc_inithook, - }, - [ALC662_ECS] = { - .mixers = { alc662_ecs_mixer }, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc662_ecs_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc662_eeepc_setup, - .init_hook = alc_inithook, - }, - [ALC663_ASUS_M51VA] = { - .mixers = { alc663_m51va_mixer }, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc663_m51va_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc663_m51va_setup, - .init_hook = alc_inithook, - }, - [ALC663_ASUS_G71V] = { - .mixers = { alc663_g71v_mixer }, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc663_g71v_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc663_g71v_setup, - .init_hook = alc_inithook, - }, - [ALC663_ASUS_H13] = { - .mixers = { alc663_m51va_mixer }, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc663_m51va_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .setup = alc663_m51va_setup, - .unsol_event = alc_sku_unsol_event, - .init_hook = alc_inithook, - }, - [ALC663_ASUS_G50V] = { - .mixers = { alc663_g50v_mixer }, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc663_g50v_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), - .channel_mode = alc662_3ST_6ch_modes, - .input_mux = &alc663_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc663_g50v_setup, - .init_hook = alc_inithook, - }, - [ALC663_ASUS_MODE1] = { - .mixers = { alc663_m51va_mixer }, - .cap_mixer = alc662_auto_capture_mixer, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc663_21jd_amic_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .hp_nid = 0x03, - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc663_mode1_setup, - .init_hook = alc_inithook, - }, - [ALC662_ASUS_MODE2] = { - .mixers = { alc662_1bjd_mixer }, - .cap_mixer = alc662_auto_capture_mixer, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc662_1bjd_amic_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc662_mode2_setup, - .init_hook = alc_inithook, - }, - [ALC663_ASUS_MODE3] = { - .mixers = { alc663_two_hp_m1_mixer }, - .cap_mixer = alc662_auto_capture_mixer, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc663_two_hp_amic_m1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .hp_nid = 0x03, - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc663_mode3_setup, - .init_hook = alc_inithook, - }, - [ALC663_ASUS_MODE4] = { - .mixers = { alc663_asus_21jd_clfe_mixer }, - .cap_mixer = alc662_auto_capture_mixer, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc663_21jd_amic_init_verbs}, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .hp_nid = 0x03, - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc663_mode4_setup, - .init_hook = alc_inithook, - }, - [ALC663_ASUS_MODE5] = { - .mixers = { alc663_asus_15jd_clfe_mixer }, - .cap_mixer = alc662_auto_capture_mixer, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc663_15jd_amic_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .hp_nid = 0x03, - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc663_mode5_setup, - .init_hook = alc_inithook, - }, - [ALC663_ASUS_MODE6] = { - .mixers = { alc663_two_hp_m2_mixer }, - .cap_mixer = alc662_auto_capture_mixer, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc663_two_hp_amic_m2_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .hp_nid = 0x03, - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc663_mode6_setup, - .init_hook = alc_inithook, - }, - [ALC663_ASUS_MODE7] = { - .mixers = { alc663_mode7_mixer }, - .cap_mixer = alc662_auto_capture_mixer, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc663_mode7_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .hp_nid = 0x03, - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc663_mode7_setup, - .init_hook = alc_inithook, - }, - [ALC663_ASUS_MODE8] = { - .mixers = { alc663_mode8_mixer }, - .cap_mixer = alc662_auto_capture_mixer, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc663_mode8_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .hp_nid = 0x03, - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc663_mode8_setup, - .init_hook = alc_inithook, - }, - [ALC272_DELL] = { - .mixers = { alc663_m51va_mixer }, - .cap_mixer = alc272_auto_capture_mixer, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc272_dell_init_verbs }, - .num_dacs = ARRAY_SIZE(alc272_dac_nids), - .dac_nids = alc272_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .adc_nids = alc272_adc_nids, - .num_adc_nids = ARRAY_SIZE(alc272_adc_nids), - .capsrc_nids = alc272_capsrc_nids, - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc663_m51va_setup, - .init_hook = alc_inithook, - }, - [ALC272_DELL_ZM1] = { - .mixers = { alc663_m51va_mixer }, - .cap_mixer = alc662_auto_capture_mixer, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc272_dell_zm1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc272_dac_nids), - .dac_nids = alc272_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .adc_nids = alc662_adc_nids, - .num_adc_nids = 1, - .capsrc_nids = alc662_capsrc_nids, - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc663_m51va_setup, - .init_hook = alc_inithook, - }, - [ALC272_SAMSUNG_NC10] = { - .mixers = { alc272_nc10_mixer }, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc663_21jd_amic_init_verbs }, - .num_dacs = ARRAY_SIZE(alc272_dac_nids), - .dac_nids = alc272_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - /*.input_mux = &alc272_nc10_capture_source,*/ - .unsol_event = alc_sku_unsol_event, - .setup = alc663_mode4_setup, - .init_hook = alc_inithook, - }, -}; - - diff --git a/trunk/sound/pci/hda/alc680_quirks.c b/trunk/sound/pci/hda/alc680_quirks.c deleted file mode 100644 index 0eeb227c7bc2..000000000000 --- a/trunk/sound/pci/hda/alc680_quirks.c +++ /dev/null @@ -1,222 +0,0 @@ -/* - * ALC680 quirk models - * included by patch_realtek.c - */ - -/* ALC680 models */ -enum { - ALC680_AUTO, - ALC680_BASE, - ALC680_MODEL_LAST, -}; - -#define ALC680_DIGIN_NID ALC880_DIGIN_NID -#define ALC680_DIGOUT_NID ALC880_DIGOUT_NID -#define alc680_modes alc260_modes - -static const hda_nid_t alc680_dac_nids[3] = { - /* Lout1, Lout2, hp */ - 0x02, 0x03, 0x04 -}; - -static const hda_nid_t alc680_adc_nids[3] = { - /* ADC0-2 */ - /* DMIC, MIC, Line-in*/ - 0x07, 0x08, 0x09 -}; - -/* - * Analog capture ADC cgange - */ -static hda_nid_t alc680_get_cur_adc(struct hda_codec *codec) -{ - static hda_nid_t pins[] = {0x18, 0x19}; - static hda_nid_t adcs[] = {0x08, 0x09}; - int i; - - for (i = 0; i < ARRAY_SIZE(pins); i++) { - if (!is_jack_detectable(codec, pins[i])) - continue; - if (snd_hda_jack_detect(codec, pins[i])) - return adcs[i]; - } - return 0x07; -} - -static void alc680_rec_autoswitch(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t nid = alc680_get_cur_adc(codec); - if (spec->cur_adc && nid != spec->cur_adc) { - __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); - spec->cur_adc = nid; - snd_hda_codec_setup_stream(codec, nid, - spec->cur_adc_stream_tag, 0, - spec->cur_adc_format); - } -} - -static int alc680_capture_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t nid = alc680_get_cur_adc(codec); - - spec->cur_adc = nid; - spec->cur_adc_stream_tag = stream_tag; - spec->cur_adc_format = format; - snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format); - return 0; -} - -static int alc680_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; - snd_hda_codec_cleanup_stream(codec, spec->cur_adc); - spec->cur_adc = 0; - return 0; -} - -static const struct hda_pcm_stream alc680_pcm_analog_auto_capture = { - .substreams = 1, /* can be overridden */ - .channels_min = 2, - .channels_max = 2, - /* NID is set in alc_build_pcms */ - .ops = { - .prepare = alc680_capture_pcm_prepare, - .cleanup = alc680_capture_pcm_cleanup - }, -}; - -static const struct snd_kcontrol_new alc680_base_mixer[] = { - /* output mixer control */ - HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x4, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x16, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x12, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Line In Boost Volume", 0x19, 0, HDA_INPUT), - { } -}; - -static const struct hda_bind_ctls alc680_bind_cap_vol = { - .ops = &snd_hda_bind_vol, - .values = { - HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT), - HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT), - HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT), - 0 - }, -}; - -static const struct hda_bind_ctls alc680_bind_cap_switch = { - .ops = &snd_hda_bind_sw, - .values = { - HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT), - HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT), - HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT), - 0 - }, -}; - -static const struct snd_kcontrol_new alc680_master_capture_mixer[] = { - HDA_BIND_VOL("Capture Volume", &alc680_bind_cap_vol), - HDA_BIND_SW("Capture Switch", &alc680_bind_cap_switch), - { } /* end */ -}; - -/* - * generic initialization of ADC, input mixers and output mixers - */ -static const struct hda_verb alc680_init_verbs[] = { - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN}, - {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN}, - - { } -}; - -/* toggle speaker-output according to the hp-jack state */ -static void alc680_base_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x16; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x15; - spec->autocfg.num_inputs = 2; - spec->autocfg.inputs[0].pin = 0x18; - spec->autocfg.inputs[0].type = AUTO_PIN_MIC; - spec->autocfg.inputs[1].pin = 0x19; - spec->autocfg.inputs[1].type = AUTO_PIN_LINE_IN; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc680_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) == ALC_HP_EVENT) - alc_hp_automute(codec); - if ((res >> 26) == ALC_MIC_EVENT) - alc680_rec_autoswitch(codec); -} - -static void alc680_inithook(struct hda_codec *codec) -{ - alc_hp_automute(codec); - alc680_rec_autoswitch(codec); -} - -/* - * configuration and preset - */ -static const char * const alc680_models[ALC680_MODEL_LAST] = { - [ALC680_BASE] = "base", - [ALC680_AUTO] = "auto", -}; - -static const struct snd_pci_quirk alc680_cfg_tbl[] = { - SND_PCI_QUIRK(0x1043, 0x12f3, "ASUS NX90", ALC680_BASE), - {} -}; - -static const struct alc_config_preset alc680_presets[] = { - [ALC680_BASE] = { - .mixers = { alc680_base_mixer }, - .cap_mixer = alc680_master_capture_mixer, - .init_verbs = { alc680_init_verbs }, - .num_dacs = ARRAY_SIZE(alc680_dac_nids), - .dac_nids = alc680_dac_nids, - .dig_out_nid = ALC680_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc680_modes), - .channel_mode = alc680_modes, - .unsol_event = alc680_unsol_event, - .setup = alc680_base_setup, - .init_hook = alc680_inithook, - - }, -}; diff --git a/trunk/sound/pci/hda/alc861_quirks.c b/trunk/sound/pci/hda/alc861_quirks.c deleted file mode 100644 index d719ec6350eb..000000000000 --- a/trunk/sound/pci/hda/alc861_quirks.c +++ /dev/null @@ -1,725 +0,0 @@ -/* - * ALC660/ALC861 quirk models - * included by patch_realtek.c - */ - -/* ALC861 models */ -enum { - ALC861_AUTO, - ALC861_3ST, - ALC660_3ST, - ALC861_3ST_DIG, - ALC861_6ST_DIG, - ALC861_UNIWILL_M31, - ALC861_TOSHIBA, - ALC861_ASUS, - ALC861_ASUS_LAPTOP, - ALC861_MODEL_LAST, -}; - -/* - * ALC861 channel source setting (2/6 channel selection for 3-stack) - */ - -/* - * set the path ways for 2 channel output - * need to set the codec line out and mic 1 pin widgets to inputs - */ -static const struct hda_verb alc861_threestack_ch2_init[] = { - /* set pin widget 1Ah (line in) for input */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* set pin widget 18h (mic1/2) for input, for mic also enable - * the vref - */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c }, -#if 0 - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/ - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/ -#endif - { } /* end */ -}; -/* - * 6ch mode - * need to set the codec line out and mic 1 pin widgets to outputs - */ -static const struct hda_verb alc861_threestack_ch6_init[] = { - /* set pin widget 1Ah (line in) for output (Back Surround)*/ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* set pin widget 18h (mic1) for output (CLFE)*/ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - - { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 }, - { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 }, - - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, -#if 0 - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/ - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/ -#endif - { } /* end */ -}; - -static const struct hda_channel_mode alc861_threestack_modes[2] = { - { 2, alc861_threestack_ch2_init }, - { 6, alc861_threestack_ch6_init }, -}; -/* Set mic1 as input and unmute the mixer */ -static const struct hda_verb alc861_uniwill_m31_ch2_init[] = { - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/ - { } /* end */ -}; -/* Set mic1 as output and mute mixer */ -static const struct hda_verb alc861_uniwill_m31_ch4_init[] = { - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/ - { } /* end */ -}; - -static const struct hda_channel_mode alc861_uniwill_m31_modes[2] = { - { 2, alc861_uniwill_m31_ch2_init }, - { 4, alc861_uniwill_m31_ch4_init }, -}; - -/* Set mic1 and line-in as input and unmute the mixer */ -static const struct hda_verb alc861_asus_ch2_init[] = { - /* set pin widget 1Ah (line in) for input */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* set pin widget 18h (mic1/2) for input, for mic also enable - * the vref - */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c }, -#if 0 - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/ - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/ -#endif - { } /* end */ -}; -/* Set mic1 nad line-in as output and mute mixer */ -static const struct hda_verb alc861_asus_ch6_init[] = { - /* set pin widget 1Ah (line in) for output (Back Surround)*/ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */ - /* set pin widget 18h (mic1) for output (CLFE)*/ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */ - { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 }, - { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 }, - - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, -#if 0 - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/ - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/ -#endif - { } /* end */ -}; - -static const struct hda_channel_mode alc861_asus_modes[2] = { - { 2, alc861_asus_ch2_init }, - { 6, alc861_asus_ch6_init }, -}; - -/* patch-ALC861 */ - -static const struct snd_kcontrol_new alc861_base_mixer[] = { - /* output mixer control */ - HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), - - /*Input mixer control */ - /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */ - HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT), - - { } /* end */ -}; - -static const struct snd_kcontrol_new alc861_3ST_mixer[] = { - /* output mixer control */ - HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), - /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */ - - /* Input mixer control */ - /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */ - HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT), - - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - .private_value = ARRAY_SIZE(alc861_threestack_modes), - }, - { } /* end */ -}; - -static const struct snd_kcontrol_new alc861_toshiba_mixer[] = { - /* output mixer control */ - HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), - - { } /* end */ -}; - -static const struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = { - /* output mixer control */ - HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), - /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */ - - /* Input mixer control */ - /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */ - HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT), - - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes), - }, - { } /* end */ -}; - -static const struct snd_kcontrol_new alc861_asus_mixer[] = { - /* output mixer control */ - HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), - - /* Input mixer control */ - HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT), - - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - .private_value = ARRAY_SIZE(alc861_asus_modes), - }, - { } -}; - -/* additional mixer */ -static const struct snd_kcontrol_new alc861_asus_laptop_mixer[] = { - HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), - { } -}; - -/* - * generic initialization of ADC, input mixers and output mixers - */ -static const struct hda_verb alc861_base_init_verbs[] = { - /* - * Unmute ADC0 and set the default input to mic-in - */ - /* port-A for surround (rear panel) */ - { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-B for mic-in (rear panel) with vref */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* port-C for line-in (rear panel) */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* port-D for Front */ - { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-E for HP out (front panel) */ - { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, - /* route front PCM to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-F for mic-in (front panel) with vref */ - { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* port-G for CLFE (rear panel) */ - { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-H for side (rear panel) */ - { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* CD-in */ - { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* route front mic to ADC1*/ - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Unmute DAC0~3 & spdif out*/ - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Unmute Mixer 14 (mic) 1c (Line in)*/ - {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - /* Unmute Stereo Mixer 15 */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */ - - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* hp used DAC 3 (Front) */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - - { } -}; - -static const struct hda_verb alc861_threestack_init_verbs[] = { - /* - * Unmute ADC0 and set the default input to mic-in - */ - /* port-A for surround (rear panel) */ - { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, - /* port-B for mic-in (rear panel) with vref */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* port-C for line-in (rear panel) */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* port-D for Front */ - { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-E for HP out (front panel) */ - { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, - /* route front PCM to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-F for mic-in (front panel) with vref */ - { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* port-G for CLFE (rear panel) */ - { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, - /* port-H for side (rear panel) */ - { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, - /* CD-in */ - { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* route front mic to ADC1*/ - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Unmute DAC0~3 & spdif out*/ - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Unmute Mixer 14 (mic) 1c (Line in)*/ - {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - /* Unmute Stereo Mixer 15 */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */ - - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* hp used DAC 3 (Front) */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - { } -}; - -static const struct hda_verb alc861_uniwill_m31_init_verbs[] = { - /* - * Unmute ADC0 and set the default input to mic-in - */ - /* port-A for surround (rear panel) */ - { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, - /* port-B for mic-in (rear panel) with vref */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* port-C for line-in (rear panel) */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* port-D for Front */ - { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-E for HP out (front panel) */ - /* this has to be set to VREF80 */ - { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* route front PCM to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-F for mic-in (front panel) with vref */ - { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* port-G for CLFE (rear panel) */ - { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, - /* port-H for side (rear panel) */ - { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, - /* CD-in */ - { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* route front mic to ADC1*/ - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Unmute DAC0~3 & spdif out*/ - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Unmute Mixer 14 (mic) 1c (Line in)*/ - {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - /* Unmute Stereo Mixer 15 */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */ - - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* hp used DAC 3 (Front) */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - { } -}; - -static const struct hda_verb alc861_asus_init_verbs[] = { - /* - * Unmute ADC0 and set the default input to mic-in - */ - /* port-A for surround (rear panel) - * according to codec#0 this is the HP jack - */ - { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */ - /* route front PCM to HP */ - { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 }, - /* port-B for mic-in (rear panel) with vref */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* port-C for line-in (rear panel) */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* port-D for Front */ - { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-E for HP out (front panel) */ - /* this has to be set to VREF80 */ - { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* route front PCM to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-F for mic-in (front panel) with vref */ - { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* port-G for CLFE (rear panel) */ - { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* port-H for side (rear panel) */ - { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* CD-in */ - { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* route front mic to ADC1*/ - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Unmute DAC0~3 & spdif out*/ - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Unmute Mixer 14 (mic) 1c (Line in)*/ - {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - /* Unmute Stereo Mixer 15 */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */ - - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* hp used DAC 3 (Front) */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - { } -}; - -/* additional init verbs for ASUS laptops */ -static const struct hda_verb alc861_asus_laptop_init_verbs[] = { - { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */ - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */ - { } -}; - -static const struct hda_verb alc861_toshiba_init_verbs[] = { - {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - - { } -}; - -/* toggle speaker-output according to the hp-jack state */ -static void alc861_toshiba_automute(struct hda_codec *codec) -{ - unsigned int present = snd_hda_jack_detect(codec, 0x0f); - - snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); - snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3, - HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE); -} - -static void alc861_toshiba_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) == ALC_HP_EVENT) - alc861_toshiba_automute(codec); -} - -#define ALC861_DIGOUT_NID 0x07 - -static const struct hda_channel_mode alc861_8ch_modes[1] = { - { 8, NULL } -}; - -static const hda_nid_t alc861_dac_nids[4] = { - /* front, surround, clfe, side */ - 0x03, 0x06, 0x05, 0x04 -}; - -static const hda_nid_t alc660_dac_nids[3] = { - /* front, clfe, surround */ - 0x03, 0x05, 0x06 -}; - -static const hda_nid_t alc861_adc_nids[1] = { - /* ADC0-2 */ - 0x08, -}; - -static const struct hda_input_mux alc861_capture_source = { - .num_items = 5, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x3 }, - { "Line", 0x1 }, - { "CD", 0x4 }, - { "Mixer", 0x5 }, - }, -}; - -/* - * configuration and preset - */ -static const char * const alc861_models[ALC861_MODEL_LAST] = { - [ALC861_3ST] = "3stack", - [ALC660_3ST] = "3stack-660", - [ALC861_3ST_DIG] = "3stack-dig", - [ALC861_6ST_DIG] = "6stack-dig", - [ALC861_UNIWILL_M31] = "uniwill-m31", - [ALC861_TOSHIBA] = "toshiba", - [ALC861_ASUS] = "asus", - [ALC861_ASUS_LAPTOP] = "asus-laptop", - [ALC861_AUTO] = "auto", -}; - -static const struct snd_pci_quirk alc861_cfg_tbl[] = { - SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST), - SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP), - SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP), - SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS), - SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP), - SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG), - SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA), - /* FIXME: the entry below breaks Toshiba A100 (model=auto works!) - * Any other models that need this preset? - */ - /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */ - SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST), - SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST), - SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31), - SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31), - SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP), - /* FIXME: the below seems conflict */ - /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */ - SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST), - SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST), - {} -}; - -static const struct alc_config_preset alc861_presets[] = { - [ALC861_3ST] = { - .mixers = { alc861_3ST_mixer }, - .init_verbs = { alc861_threestack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861_dac_nids), - .dac_nids = alc861_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), - .channel_mode = alc861_threestack_modes, - .need_dac_fix = 1, - .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), - .adc_nids = alc861_adc_nids, - .input_mux = &alc861_capture_source, - }, - [ALC861_3ST_DIG] = { - .mixers = { alc861_base_mixer }, - .init_verbs = { alc861_threestack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861_dac_nids), - .dac_nids = alc861_dac_nids, - .dig_out_nid = ALC861_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), - .channel_mode = alc861_threestack_modes, - .need_dac_fix = 1, - .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), - .adc_nids = alc861_adc_nids, - .input_mux = &alc861_capture_source, - }, - [ALC861_6ST_DIG] = { - .mixers = { alc861_base_mixer }, - .init_verbs = { alc861_base_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861_dac_nids), - .dac_nids = alc861_dac_nids, - .dig_out_nid = ALC861_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes), - .channel_mode = alc861_8ch_modes, - .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), - .adc_nids = alc861_adc_nids, - .input_mux = &alc861_capture_source, - }, - [ALC660_3ST] = { - .mixers = { alc861_3ST_mixer }, - .init_verbs = { alc861_threestack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc660_dac_nids), - .dac_nids = alc660_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), - .channel_mode = alc861_threestack_modes, - .need_dac_fix = 1, - .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), - .adc_nids = alc861_adc_nids, - .input_mux = &alc861_capture_source, - }, - [ALC861_UNIWILL_M31] = { - .mixers = { alc861_uniwill_m31_mixer }, - .init_verbs = { alc861_uniwill_m31_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861_dac_nids), - .dac_nids = alc861_dac_nids, - .dig_out_nid = ALC861_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes), - .channel_mode = alc861_uniwill_m31_modes, - .need_dac_fix = 1, - .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), - .adc_nids = alc861_adc_nids, - .input_mux = &alc861_capture_source, - }, - [ALC861_TOSHIBA] = { - .mixers = { alc861_toshiba_mixer }, - .init_verbs = { alc861_base_init_verbs, - alc861_toshiba_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861_dac_nids), - .dac_nids = alc861_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), - .adc_nids = alc861_adc_nids, - .input_mux = &alc861_capture_source, - .unsol_event = alc861_toshiba_unsol_event, - .init_hook = alc861_toshiba_automute, - }, - [ALC861_ASUS] = { - .mixers = { alc861_asus_mixer }, - .init_verbs = { alc861_asus_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861_dac_nids), - .dac_nids = alc861_dac_nids, - .dig_out_nid = ALC861_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc861_asus_modes), - .channel_mode = alc861_asus_modes, - .need_dac_fix = 1, - .hp_nid = 0x06, - .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), - .adc_nids = alc861_adc_nids, - .input_mux = &alc861_capture_source, - }, - [ALC861_ASUS_LAPTOP] = { - .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer }, - .init_verbs = { alc861_asus_init_verbs, - alc861_asus_laptop_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861_dac_nids), - .dac_nids = alc861_dac_nids, - .dig_out_nid = ALC861_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .need_dac_fix = 1, - .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), - .adc_nids = alc861_adc_nids, - .input_mux = &alc861_capture_source, - }, -}; - diff --git a/trunk/sound/pci/hda/alc861vd_quirks.c b/trunk/sound/pci/hda/alc861vd_quirks.c deleted file mode 100644 index 8f28450f41f8..000000000000 --- a/trunk/sound/pci/hda/alc861vd_quirks.c +++ /dev/null @@ -1,605 +0,0 @@ -/* - * ALC660-VD/ALC861-VD quirk models - * included by patch_realtek.c - */ - -/* ALC861-VD models */ -enum { - ALC861VD_AUTO, - ALC660VD_3ST, - ALC660VD_3ST_DIG, - ALC660VD_ASUS_V1S, - ALC861VD_3ST, - ALC861VD_3ST_DIG, - ALC861VD_6ST_DIG, - ALC861VD_LENOVO, - ALC861VD_DALLAS, - ALC861VD_HP, - ALC861VD_MODEL_LAST, -}; - -#define ALC861VD_DIGOUT_NID 0x06 - -static const hda_nid_t alc861vd_dac_nids[4] = { - /* front, surr, clfe, side surr */ - 0x02, 0x03, 0x04, 0x05 -}; - -/* dac_nids for ALC660vd are in a different order - according to - * Realtek's driver. - * This should probably result in a different mixer for 6stack models - * of ALC660vd codecs, but for now there is only 3stack mixer - * - and it is the same as in 861vd. - * adc_nids in ALC660vd are (is) the same as in 861vd - */ -static const hda_nid_t alc660vd_dac_nids[3] = { - /* front, rear, clfe, rear_surr */ - 0x02, 0x04, 0x03 -}; - -static const hda_nid_t alc861vd_adc_nids[1] = { - /* ADC0 */ - 0x09, -}; - -static const hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 }; - -/* input MUX */ -/* FIXME: should be a matrix-type input source selection */ -static const struct hda_input_mux alc861vd_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - -static const struct hda_input_mux alc861vd_dallas_capture_source = { - .num_items = 2, - .items = { - { "Mic", 0x0 }, - { "Internal Mic", 0x1 }, - }, -}; - -static const struct hda_input_mux alc861vd_hp_capture_source = { - .num_items = 2, - .items = { - { "Front Mic", 0x0 }, - { "ATAPI Mic", 0x1 }, - }, -}; - -/* - * 2ch mode - */ -static const struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = { - { 2, NULL } -}; - -/* - * 6ch mode - */ -static const struct hda_verb alc861vd_6stack_ch6_init[] = { - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, - { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { } /* end */ -}; - -/* - * 8ch mode - */ -static const struct hda_verb alc861vd_6stack_ch8_init[] = { - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { } /* end */ -}; - -static const struct hda_channel_mode alc861vd_6stack_modes[2] = { - { 6, alc861vd_6stack_ch6_init }, - { 8, alc861vd_6stack_ch8_init }, -}; - -static const struct snd_kcontrol_new alc861vd_chmode_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 - * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b - */ -static const struct snd_kcontrol_new alc861vd_6st_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - - HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, - HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, - HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - - HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), - - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - - { } /* end */ -}; - -static const struct snd_kcontrol_new alc861vd_3st_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - - { } /* end */ -}; - -static const struct snd_kcontrol_new alc861vd_lenovo_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), - /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/ - HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), - - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - - { } /* end */ -}; - -/* Pin assignment: Speaker=0x14, HP = 0x15, - * Mic=0x18, Internal Mic = 0x19, CD = 0x1c, PC Beep = 0x1d - */ -static const struct snd_kcontrol_new alc861vd_dallas_mixer[] = { - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -/* Pin assignment: Speaker=0x14, Line-out = 0x15, - * Front Mic=0x18, ATAPI Mic = 0x19, - */ -static const struct snd_kcontrol_new alc861vd_hp_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - - { } /* end */ -}; - -/* - * generic initialization of ADC, input mixers and output mixers - */ -static const struct hda_verb alc861vd_volume_init_verbs[] = { - /* - * Unmute ADC0 and set the default input to mic-in - */ - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of - * the analog-loopback mixer widget - */ - /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - - /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - - /* - * Set up output mixers (0x02 - 0x05) - */ - /* set vol=0 to output mixers */ - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* set up input amps for analog loopback */ - /* Amp Indices: DAC = 0, mixer = 1 */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - - { } -}; - -/* - * 3-stack pin configuration: - * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b - */ -static const struct hda_verb alc861vd_3stack_init_verbs[] = { - /* - * Set pin mode and muting - */ - /* set front pin widgets 0x14 for output */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Mic (rear) pin: input vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Front Mic pin: input vref at 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line In pin: input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line-2 In: Headphone output (output 0 - 0x0c) */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - { } -}; - -/* - * 6-stack pin configuration: - */ -static const struct hda_verb alc861vd_6stack_init_verbs[] = { - /* - * Set pin mode and muting - */ - /* set front pin widgets 0x14 for output */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Rear Pin: output 1 (0x0d) */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, - /* CLFE Pin: output 2 (0x0e) */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* Side Pin: output 3 (0x0f) */ - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, - - /* Mic (rear) pin: input vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Front Mic pin: input vref at 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line In pin: input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line-2 In: Headphone output (output 0 - 0x0c) */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - { } -}; - -static const struct hda_verb alc861vd_eapd_verbs[] = { - {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, - { } -}; - -static const struct hda_verb alc861vd_lenovo_unsol_verbs[] = { - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {} -}; - -static void alc861vd_lenovo_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc861vd_lenovo_init_hook(struct hda_codec *codec) -{ - alc_hp_automute(codec); - alc88x_simple_mic_automute(codec); -} - -static void alc861vd_lenovo_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case ALC_MIC_EVENT: - alc88x_simple_mic_automute(codec); - break; - default: - alc_sku_unsol_event(codec, res); - break; - } -} - -static const struct hda_verb alc861vd_dallas_verbs[] = { - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - - { } /* end */ -}; - -/* toggle speaker-output according to the hp-jack state */ -static void alc861vd_dallas_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -/* - * configuration and preset - */ -static const char * const alc861vd_models[ALC861VD_MODEL_LAST] = { - [ALC660VD_3ST] = "3stack-660", - [ALC660VD_3ST_DIG] = "3stack-660-digout", - [ALC660VD_ASUS_V1S] = "asus-v1s", - [ALC861VD_3ST] = "3stack", - [ALC861VD_3ST_DIG] = "3stack-digout", - [ALC861VD_6ST_DIG] = "6stack-digout", - [ALC861VD_LENOVO] = "lenovo", - [ALC861VD_DALLAS] = "dallas", - [ALC861VD_HP] = "hp", - [ALC861VD_AUTO] = "auto", -}; - -static const struct snd_pci_quirk alc861vd_cfg_tbl[] = { - SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST), - SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP), - SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST), - /*SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),*/ /* auto */ - SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S), - SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG), - SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST), - SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO), - /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/ - SND_PCI_QUIRK(0x1179, 0xff01, "Toshiba A135", ALC861VD_LENOVO), - SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO), - SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS), - SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG), - SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", ALC861VD_LENOVO), - SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG), - {} -}; - -static const struct alc_config_preset alc861vd_presets[] = { - [ALC660VD_3ST] = { - .mixers = { alc861vd_3st_mixer }, - .init_verbs = { alc861vd_volume_init_verbs, - alc861vd_3stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc660vd_dac_nids), - .dac_nids = alc660vd_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), - .channel_mode = alc861vd_3stack_2ch_modes, - .input_mux = &alc861vd_capture_source, - }, - [ALC660VD_3ST_DIG] = { - .mixers = { alc861vd_3st_mixer }, - .init_verbs = { alc861vd_volume_init_verbs, - alc861vd_3stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc660vd_dac_nids), - .dac_nids = alc660vd_dac_nids, - .dig_out_nid = ALC861VD_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), - .channel_mode = alc861vd_3stack_2ch_modes, - .input_mux = &alc861vd_capture_source, - }, - [ALC861VD_3ST] = { - .mixers = { alc861vd_3st_mixer }, - .init_verbs = { alc861vd_volume_init_verbs, - alc861vd_3stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), - .dac_nids = alc861vd_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), - .channel_mode = alc861vd_3stack_2ch_modes, - .input_mux = &alc861vd_capture_source, - }, - [ALC861VD_3ST_DIG] = { - .mixers = { alc861vd_3st_mixer }, - .init_verbs = { alc861vd_volume_init_verbs, - alc861vd_3stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), - .dac_nids = alc861vd_dac_nids, - .dig_out_nid = ALC861VD_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), - .channel_mode = alc861vd_3stack_2ch_modes, - .input_mux = &alc861vd_capture_source, - }, - [ALC861VD_6ST_DIG] = { - .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer }, - .init_verbs = { alc861vd_volume_init_verbs, - alc861vd_6stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), - .dac_nids = alc861vd_dac_nids, - .dig_out_nid = ALC861VD_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes), - .channel_mode = alc861vd_6stack_modes, - .input_mux = &alc861vd_capture_source, - }, - [ALC861VD_LENOVO] = { - .mixers = { alc861vd_lenovo_mixer }, - .init_verbs = { alc861vd_volume_init_verbs, - alc861vd_3stack_init_verbs, - alc861vd_eapd_verbs, - alc861vd_lenovo_unsol_verbs }, - .num_dacs = ARRAY_SIZE(alc660vd_dac_nids), - .dac_nids = alc660vd_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), - .channel_mode = alc861vd_3stack_2ch_modes, - .input_mux = &alc861vd_capture_source, - .unsol_event = alc861vd_lenovo_unsol_event, - .setup = alc861vd_lenovo_setup, - .init_hook = alc861vd_lenovo_init_hook, - }, - [ALC861VD_DALLAS] = { - .mixers = { alc861vd_dallas_mixer }, - .init_verbs = { alc861vd_dallas_verbs }, - .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), - .dac_nids = alc861vd_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), - .channel_mode = alc861vd_3stack_2ch_modes, - .input_mux = &alc861vd_dallas_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc861vd_dallas_setup, - .init_hook = alc_hp_automute, - }, - [ALC861VD_HP] = { - .mixers = { alc861vd_hp_mixer }, - .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs }, - .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), - .dac_nids = alc861vd_dac_nids, - .dig_out_nid = ALC861VD_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), - .channel_mode = alc861vd_3stack_2ch_modes, - .input_mux = &alc861vd_hp_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc861vd_dallas_setup, - .init_hook = alc_hp_automute, - }, - [ALC660VD_ASUS_V1S] = { - .mixers = { alc861vd_lenovo_mixer }, - .init_verbs = { alc861vd_volume_init_verbs, - alc861vd_3stack_init_verbs, - alc861vd_eapd_verbs, - alc861vd_lenovo_unsol_verbs }, - .num_dacs = ARRAY_SIZE(alc660vd_dac_nids), - .dac_nids = alc660vd_dac_nids, - .dig_out_nid = ALC861VD_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), - .channel_mode = alc861vd_3stack_2ch_modes, - .input_mux = &alc861vd_capture_source, - .unsol_event = alc861vd_lenovo_unsol_event, - .setup = alc861vd_lenovo_setup, - .init_hook = alc861vd_lenovo_init_hook, - }, -}; - diff --git a/trunk/sound/pci/hda/alc880_quirks.c b/trunk/sound/pci/hda/alc880_quirks.c deleted file mode 100644 index c844d2b59988..000000000000 --- a/trunk/sound/pci/hda/alc880_quirks.c +++ /dev/null @@ -1,1898 +0,0 @@ -/* - * ALC880 quirk models - * included by patch_realtek.c - */ - -/* ALC880 board config type */ -enum { - ALC880_AUTO, - ALC880_3ST, - ALC880_3ST_DIG, - ALC880_5ST, - ALC880_5ST_DIG, - ALC880_W810, - ALC880_Z71V, - ALC880_6ST, - ALC880_6ST_DIG, - ALC880_F1734, - ALC880_ASUS, - ALC880_ASUS_DIG, - ALC880_ASUS_W1V, - ALC880_ASUS_DIG2, - ALC880_FUJITSU, - ALC880_UNIWILL_DIG, - ALC880_UNIWILL, - ALC880_UNIWILL_P53, - ALC880_CLEVO, - ALC880_TCL_S700, - ALC880_LG, - ALC880_LG_LW, - ALC880_MEDION_RIM, -#ifdef CONFIG_SND_DEBUG - ALC880_TEST, -#endif - ALC880_MODEL_LAST /* last tag */ -}; - -/* - * ALC880 3-stack model - * - * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e) - * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18, - * F-Mic = 0x1b, HP = 0x19 - */ - -static const hda_nid_t alc880_dac_nids[4] = { - /* front, rear, clfe, rear_surr */ - 0x02, 0x05, 0x04, 0x03 -}; - -static const hda_nid_t alc880_adc_nids[3] = { - /* ADC0-2 */ - 0x07, 0x08, 0x09, -}; - -/* The datasheet says the node 0x07 is connected from inputs, - * but it shows zero connection in the real implementation on some devices. - * Note: this is a 915GAV bug, fixed on 915GLV - */ -static const hda_nid_t alc880_adc_nids_alt[2] = { - /* ADC1-2 */ - 0x08, 0x09, -}; - -#define ALC880_DIGOUT_NID 0x06 -#define ALC880_DIGIN_NID 0x0a -#define ALC880_PIN_CD_NID 0x1c - -static const struct hda_input_mux alc880_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x3 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - -/* channel source setting (2/6 channel selection for 3-stack) */ -/* 2ch mode */ -static const struct hda_verb alc880_threestack_ch2_init[] = { - /* set line-in to input, mute it */ - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - /* set mic-in to input vref 80%, mute it */ - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { } /* end */ -}; - -/* 6ch mode */ -static const struct hda_verb alc880_threestack_ch6_init[] = { - /* set line-in to output, unmute it */ - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - /* set mic-in to output, unmute it */ - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { } /* end */ -}; - -static const struct hda_channel_mode alc880_threestack_modes[2] = { - { 2, alc880_threestack_ch2_init }, - { 6, alc880_threestack_ch6_init }, -}; - -static const struct snd_kcontrol_new alc880_three_stack_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -/* - * ALC880 5-stack model - * - * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d), - * Side = 0x02 (0xd) - * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16 - * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19 - */ - -/* additional mixers to alc880_three_stack_mixer */ -static const struct snd_kcontrol_new alc880_five_stack_mixer[] = { - HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT), - { } /* end */ -}; - -/* channel source setting (6/8 channel selection for 5-stack) */ -/* 6ch mode */ -static const struct hda_verb alc880_fivestack_ch6_init[] = { - /* set line-in to input, mute it */ - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { } /* end */ -}; - -/* 8ch mode */ -static const struct hda_verb alc880_fivestack_ch8_init[] = { - /* set line-in to output, unmute it */ - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { } /* end */ -}; - -static const struct hda_channel_mode alc880_fivestack_modes[2] = { - { 6, alc880_fivestack_ch6_init }, - { 8, alc880_fivestack_ch8_init }, -}; - - -/* - * ALC880 6-stack model - * - * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e), - * Side = 0x05 (0x0f) - * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17, - * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b - */ - -static const hda_nid_t alc880_6st_dac_nids[4] = { - /* front, rear, clfe, rear_surr */ - 0x02, 0x03, 0x04, 0x05 -}; - -static const struct hda_input_mux alc880_6stack_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - -/* fixed 8-channels */ -static const struct hda_channel_mode alc880_sixstack_modes[1] = { - { 8, NULL }, -}; - -static const struct snd_kcontrol_new alc880_six_stack_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - - -/* - * ALC880 W810 model - * - * W810 has rear IO for: - * Front (DAC 02) - * Surround (DAC 03) - * Center/LFE (DAC 04) - * Digital out (06) - * - * The system also has a pair of internal speakers, and a headphone jack. - * These are both connected to Line2 on the codec, hence to DAC 02. - * - * There is a variable resistor to control the speaker or headphone - * volume. This is a hardware-only device without a software API. - * - * Plugging headphones in will disable the internal speakers. This is - * implemented in hardware, not via the driver using jack sense. In - * a similar fashion, plugging into the rear socket marked "front" will - * disable both the speakers and headphones. - * - * For input, there's a microphone jack, and an "audio in" jack. - * These may not do anything useful with this driver yet, because I - * haven't setup any initialization verbs for these yet... - */ - -static const hda_nid_t alc880_w810_dac_nids[3] = { - /* front, rear/surround, clfe */ - 0x02, 0x03, 0x04 -}; - -/* fixed 6 channels */ -static const struct hda_channel_mode alc880_w810_modes[1] = { - { 6, NULL } -}; - -/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */ -static const struct snd_kcontrol_new alc880_w810_base_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - { } /* end */ -}; - - -/* - * Z710V model - * - * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d) - * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?), - * Line = 0x1a - */ - -static const hda_nid_t alc880_z71v_dac_nids[1] = { - 0x02 -}; -#define ALC880_Z71V_HP_DAC 0x03 - -/* fixed 2 channels */ -static const struct hda_channel_mode alc880_2_jack_modes[1] = { - { 2, NULL } -}; - -static const struct snd_kcontrol_new alc880_z71v_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - - -/* - * ALC880 F1734 model - * - * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d) - * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18 - */ - -static const hda_nid_t alc880_f1734_dac_nids[1] = { - 0x03 -}; -#define ALC880_F1734_HP_DAC 0x02 - -static const struct snd_kcontrol_new alc880_f1734_mixer[] = { - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct hda_input_mux alc880_f1734_capture_source = { - .num_items = 2, - .items = { - { "Mic", 0x1 }, - { "CD", 0x4 }, - }, -}; - - -/* - * ALC880 ASUS model - * - * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e) - * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16, - * Mic = 0x18, Line = 0x1a - */ - -#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */ -#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */ - -static const struct snd_kcontrol_new alc880_asus_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -/* - * ALC880 ASUS W1V model - * - * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e) - * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16, - * Mic = 0x18, Line = 0x1a, Line2 = 0x1b - */ - -/* additional mixers to alc880_asus_mixer */ -static const struct snd_kcontrol_new alc880_asus_w1v_mixer[] = { - HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT), - HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT), - { } /* end */ -}; - -/* TCL S700 */ -static const struct snd_kcontrol_new alc880_tcl_s700_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - { } /* end */ -}; - -/* Uniwill */ -static const struct snd_kcontrol_new alc880_uniwill_mixer[] = { - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -static const struct snd_kcontrol_new alc880_fujitsu_mixer[] = { - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = { - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -/* - * initialize the codec volumes, etc - */ - -/* - * generic initialization of ADC, input mixers and output mixers - */ -static const struct hda_verb alc880_volume_init_verbs[] = { - /* - * Unmute ADC0-2 and set the default input to mic-in - */ - {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback - * mixer widget - * Note: PASD motherboards uses the Line In 2 as the input for front - * panel mic (mic 2) - */ - /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, - - /* - * Set up output mixers (0x0c - 0x0f) - */ - /* set vol=0 to output mixers */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* set up input amps for analog loopback */ - /* Amp Indices: DAC = 0, mixer = 1 */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - - { } -}; - -/* - * 3-stack pin configuration: - * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b - */ -static const struct hda_verb alc880_pin_3stack_init_verbs[] = { - /* - * preset connection lists of input pins - * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround - */ - {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ - {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ - {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */ - - /* - * Set pin mode and muting - */ - /* set front pin widgets 0x14 for output */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Mic2 (as headphone out) for HP output */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Line In pin widget for input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line2 (as front mic) pin widget for input and vref at 80% */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - { } -}; - -/* - * 5-stack pin configuration: - * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19, - * line-in/side = 0x1a, f-mic = 0x1b - */ -static const struct hda_verb alc880_pin_5stack_init_verbs[] = { - /* - * preset connection lists of input pins - * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround - */ - {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ - {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */ - - /* - * Set pin mode and muting - */ - /* set pin widgets 0x14-0x17 for output */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* unmute pins for output (no gain on this amp) */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Mic2 (as headphone out) for HP output */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Line In pin widget for input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line2 (as front mic) pin widget for input and vref at 80% */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - { } -}; - -/* - * W810 pin configuration: - * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b - */ -static const struct hda_verb alc880_pin_w810_init_verbs[] = { - /* hphone/speaker input selector: front DAC */ - {0x13, AC_VERB_SET_CONNECT_SEL, 0x0}, - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - { } -}; - -/* - * Z71V pin configuration: - * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?) - */ -static const struct hda_verb alc880_pin_z71v_init_verbs[] = { - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - { } -}; - -/* - * 6-stack pin configuration: - * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18, - * f-mic = 0x19, line = 0x1a, HP = 0x1b - */ -static const struct hda_verb alc880_pin_6stack_init_verbs[] = { - {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - { } -}; - -/* - * Uniwill pin configuration: - * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19, - * line = 0x1a - */ -static const struct hda_verb alc880_uniwill_init_verbs[] = { - {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */ - /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - - { } -}; - -/* -* Uniwill P53 -* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19, - */ -static const struct hda_verb alc880_uniwill_p53_init_verbs[] = { - {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_DCVOL_EVENT}, - - { } -}; - -static const struct hda_verb alc880_beep_init_verbs[] = { - { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) }, - { } -}; - -static void alc880_uniwill_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x16; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc880_uniwill_init_hook(struct hda_codec *codec) -{ - alc_hp_automute(codec); - alc88x_simple_mic_automute(codec); -} - -static void alc880_uniwill_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - /* Looks like the unsol event is incompatible with the standard - * definition. 4bit tag is placed at 28 bit! - */ - switch (res >> 28) { - case ALC_MIC_EVENT: - alc88x_simple_mic_automute(codec); - break; - default: - alc_sku_unsol_event(codec, res); - break; - } -} - -static void alc880_uniwill_p53_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x15; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec) -{ - unsigned int present; - - present = snd_hda_codec_read(codec, 0x21, 0, - AC_VERB_GET_VOLUME_KNOB_CONTROL, 0); - present &= HDA_AMP_VOLMASK; - snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0, - HDA_AMP_VOLMASK, present); - snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0, - HDA_AMP_VOLMASK, present); -} - -static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - /* Looks like the unsol event is incompatible with the standard - * definition. 4bit tag is placed at 28 bit! - */ - if ((res >> 28) == ALC_DCVOL_EVENT) - alc880_uniwill_p53_dcvol_automute(codec); - else - alc_sku_unsol_event(codec, res); -} - -/* - * F1734 pin configuration: - * HP = 0x14, speaker-out = 0x15, mic = 0x18 - */ -static const struct hda_verb alc880_pin_f1734_init_verbs[] = { - {0x07, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, - {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC_HP_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC_DCVOL_EVENT}, - - { } -}; - -/* - * ASUS pin configuration: - * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a - */ -static const struct hda_verb alc880_pin_asus_init_verbs[] = { - {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, - {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - { } -}; - -/* Enable GPIO mask and set output */ -#define alc880_gpio1_init_verbs alc_gpio1_init_verbs -#define alc880_gpio2_init_verbs alc_gpio2_init_verbs -#define alc880_gpio3_init_verbs alc_gpio3_init_verbs - -/* Clevo m520g init */ -static const struct hda_verb alc880_pin_clevo_init_verbs[] = { - /* headphone output */ - {0x11, AC_VERB_SET_CONNECT_SEL, 0x01}, - /* line-out */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Line-in */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* CD */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Mic1 (rear panel) */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Mic2 (front panel) */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* headphone */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* change to EAPD mode */ - {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, - {0x20, AC_VERB_SET_PROC_COEF, 0x3060}, - - { } -}; - -static const struct hda_verb alc880_pin_tcl_S700_init_verbs[] = { - /* change to EAPD mode */ - {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, - {0x20, AC_VERB_SET_PROC_COEF, 0x3060}, - - /* Headphone output */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* Front output*/ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Line In pin widget for input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - - /* change to EAPD mode */ - {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, - {0x20, AC_VERB_SET_PROC_COEF, 0x3070}, - - { } -}; - -/* - * LG m1 express dual - * - * Pin assignment: - * Rear Line-In/Out (blue): 0x14 - * Build-in Mic-In: 0x15 - * Speaker-out: 0x17 - * HP-Out (green): 0x1b - * Mic-In/Out (red): 0x19 - * SPDIF-Out: 0x1e - */ - -/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */ -static const hda_nid_t alc880_lg_dac_nids[3] = { - 0x05, 0x02, 0x03 -}; - -/* seems analog CD is not working */ -static const struct hda_input_mux alc880_lg_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x1 }, - { "Line", 0x5 }, - { "Internal Mic", 0x6 }, - }, -}; - -/* 2,4,6 channel modes */ -static const struct hda_verb alc880_lg_ch2_init[] = { - /* set line-in and mic-in to input */ - { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { } -}; - -static const struct hda_verb alc880_lg_ch4_init[] = { - /* set line-in to out and mic-in to input */ - { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { } -}; - -static const struct hda_verb alc880_lg_ch6_init[] = { - /* set line-in and mic-in to output */ - { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - { } -}; - -static const struct hda_channel_mode alc880_lg_ch_modes[3] = { - { 2, alc880_lg_ch2_init }, - { 4, alc880_lg_ch4_init }, - { 6, alc880_lg_ch6_init }, -}; - -static const struct snd_kcontrol_new alc880_lg_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -static const struct hda_verb alc880_lg_init_verbs[] = { - /* set capture source to mic-in */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* mute all amp mixer inputs */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, - /* line-in to input */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* built-in mic */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* speaker-out */ - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* mic-in to input */ - {0x11, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* HP-out */ - {0x13, AC_VERB_SET_CONNECT_SEL, 0x03}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* jack sense */ - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - { } -}; - -/* toggle speaker-output according to the hp-jack state */ -static void alc880_lg_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x17; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -/* - * LG LW20 - * - * Pin assignment: - * Speaker-out: 0x14 - * Mic-In: 0x18 - * Built-in Mic-In: 0x19 - * Line-In: 0x1b - * HP-Out: 0x1a - * SPDIF-Out: 0x1e - */ - -static const struct hda_input_mux alc880_lg_lw_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x0 }, - { "Internal Mic", 0x1 }, - { "Line In", 0x2 }, - }, -}; - -#define alc880_lg_lw_modes alc880_threestack_modes - -static const struct snd_kcontrol_new alc880_lg_lw_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -static const struct hda_verb alc880_lg_lw_init_verbs[] = { - {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ - {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ - {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */ - - /* set capture source to mic-in */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, - /* speaker-out */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* HP-out */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* mic-in to input */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* built-in mic */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* jack sense */ - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - { } -}; - -/* toggle speaker-output according to the hp-jack state */ -static void alc880_lg_lw_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static const struct snd_kcontrol_new alc880_medion_rim_mixer[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Internal Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct hda_input_mux alc880_medion_rim_capture_source = { - .num_items = 2, - .items = { - { "Mic", 0x0 }, - { "Internal Mic", 0x1 }, - }, -}; - -static const struct hda_verb alc880_medion_rim_init_verbs[] = { - {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Mic2 (as headphone out) for HP output */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Internal Speaker */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, - {0x20, AC_VERB_SET_PROC_COEF, 0x3060}, - - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - { } -}; - -/* toggle speaker-output according to the hp-jack state */ -static void alc880_medion_rim_automute(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - alc_hp_automute(codec); - /* toggle EAPD */ - if (spec->jack_present) - snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0); - else - snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2); -} - -static void alc880_medion_rim_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - /* Looks like the unsol event is incompatible with the standard - * definition. 4bit tag is placed at 28 bit! - */ - if ((res >> 28) == ALC_HP_EVENT) - alc880_medion_rim_automute(codec); -} - -static void alc880_medion_rim_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x1b; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -#ifdef CONFIG_SND_HDA_POWER_SAVE -static const struct hda_amp_list alc880_lg_loopbacks[] = { - { 0x0b, HDA_INPUT, 1 }, - { 0x0b, HDA_INPUT, 6 }, - { 0x0b, HDA_INPUT, 7 }, - { } /* end */ -}; -#endif - -/* - * Test configuration for debugging - * - * Almost all inputs/outputs are enabled. I/O pins can be configured via - * enum controls. - */ -#ifdef CONFIG_SND_DEBUG -static const hda_nid_t alc880_test_dac_nids[4] = { - 0x02, 0x03, 0x04, 0x05 -}; - -static const struct hda_input_mux alc880_test_capture_source = { - .num_items = 7, - .items = { - { "In-1", 0x0 }, - { "In-2", 0x1 }, - { "In-3", 0x2 }, - { "In-4", 0x3 }, - { "CD", 0x4 }, - { "Front", 0x5 }, - { "Surround", 0x6 }, - }, -}; - -static const struct hda_channel_mode alc880_test_modes[4] = { - { 2, NULL }, - { 4, NULL }, - { 6, NULL }, - { 8, NULL }, -}; - -static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - static const char * const texts[] = { - "N/A", "Line Out", "HP Out", - "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%" - }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 8; - if (uinfo->value.enumerated.item >= 8) - uinfo->value.enumerated.item = 7; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; -} - -static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = (hda_nid_t)kcontrol->private_value; - unsigned int pin_ctl, item = 0; - - pin_ctl = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - if (pin_ctl & AC_PINCTL_OUT_EN) { - if (pin_ctl & AC_PINCTL_HP_EN) - item = 2; - else - item = 1; - } else if (pin_ctl & AC_PINCTL_IN_EN) { - switch (pin_ctl & AC_PINCTL_VREFEN) { - case AC_PINCTL_VREF_HIZ: item = 3; break; - case AC_PINCTL_VREF_50: item = 4; break; - case AC_PINCTL_VREF_GRD: item = 5; break; - case AC_PINCTL_VREF_80: item = 6; break; - case AC_PINCTL_VREF_100: item = 7; break; - } - } - ucontrol->value.enumerated.item[0] = item; - return 0; -} - -static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = (hda_nid_t)kcontrol->private_value; - static const unsigned int ctls[] = { - 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN, - AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ, - AC_PINCTL_IN_EN | AC_PINCTL_VREF_50, - AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD, - AC_PINCTL_IN_EN | AC_PINCTL_VREF_80, - AC_PINCTL_IN_EN | AC_PINCTL_VREF_100, - }; - unsigned int old_ctl, new_ctl; - - old_ctl = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - new_ctl = ctls[ucontrol->value.enumerated.item[0]]; - if (old_ctl != new_ctl) { - int val; - snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - new_ctl); - val = ucontrol->value.enumerated.item[0] >= 3 ? - HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, val); - return 1; - } - return 0; -} - -static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - static const char * const texts[] = { - "Front", "Surround", "CLFE", "Side" - }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 4; - if (uinfo->value.enumerated.item >= 4) - uinfo->value.enumerated.item = 3; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; -} - -static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = (hda_nid_t)kcontrol->private_value; - unsigned int sel; - - sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0); - ucontrol->value.enumerated.item[0] = sel & 3; - return 0; -} - -static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = (hda_nid_t)kcontrol->private_value; - unsigned int sel; - - sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3; - if (ucontrol->value.enumerated.item[0] != sel) { - sel = ucontrol->value.enumerated.item[0] & 3; - snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_CONNECT_SEL, sel); - return 1; - } - return 0; -} - -#define PIN_CTL_TEST(xname,nid) { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ - .info = alc_test_pin_ctl_info, \ - .get = alc_test_pin_ctl_get, \ - .put = alc_test_pin_ctl_put, \ - .private_value = nid \ - } - -#define PIN_SRC_TEST(xname,nid) { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ - .info = alc_test_pin_src_info, \ - .get = alc_test_pin_src_get, \ - .put = alc_test_pin_src_put, \ - .private_value = nid \ - } - -static const struct snd_kcontrol_new alc880_test_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT), - HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), - PIN_CTL_TEST("Front Pin Mode", 0x14), - PIN_CTL_TEST("Surround Pin Mode", 0x15), - PIN_CTL_TEST("CLFE Pin Mode", 0x16), - PIN_CTL_TEST("Side Pin Mode", 0x17), - PIN_CTL_TEST("In-1 Pin Mode", 0x18), - PIN_CTL_TEST("In-2 Pin Mode", 0x19), - PIN_CTL_TEST("In-3 Pin Mode", 0x1a), - PIN_CTL_TEST("In-4 Pin Mode", 0x1b), - PIN_SRC_TEST("In-1 Pin Source", 0x18), - PIN_SRC_TEST("In-2 Pin Source", 0x19), - PIN_SRC_TEST("In-3 Pin Source", 0x1a), - PIN_SRC_TEST("In-4 Pin Source", 0x1b), - HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT), - HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT), - HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT), - HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -static const struct hda_verb alc880_test_init_verbs[] = { - /* Unmute inputs of 0x0c - 0x0f */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Vol output for 0x0c-0x0f */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* Set output pins 0x14-0x17 */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Unmute output pins 0x14-0x17 */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Set input pins 0x18-0x1c */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* Mute input pins 0x18-0x1b */ - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* ADC set up */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* Analog input/passthru */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - { } -}; -#endif - -/* - */ - -static const char * const alc880_models[ALC880_MODEL_LAST] = { - [ALC880_3ST] = "3stack", - [ALC880_TCL_S700] = "tcl", - [ALC880_3ST_DIG] = "3stack-digout", - [ALC880_CLEVO] = "clevo", - [ALC880_5ST] = "5stack", - [ALC880_5ST_DIG] = "5stack-digout", - [ALC880_W810] = "w810", - [ALC880_Z71V] = "z71v", - [ALC880_6ST] = "6stack", - [ALC880_6ST_DIG] = "6stack-digout", - [ALC880_ASUS] = "asus", - [ALC880_ASUS_W1V] = "asus-w1v", - [ALC880_ASUS_DIG] = "asus-dig", - [ALC880_ASUS_DIG2] = "asus-dig2", - [ALC880_UNIWILL_DIG] = "uniwill", - [ALC880_UNIWILL_P53] = "uniwill-p53", - [ALC880_FUJITSU] = "fujitsu", - [ALC880_F1734] = "F1734", - [ALC880_LG] = "lg", - [ALC880_LG_LW] = "lg-lw", - [ALC880_MEDION_RIM] = "medion", -#ifdef CONFIG_SND_DEBUG - [ALC880_TEST] = "test", -#endif - [ALC880_AUTO] = "auto", -}; - -static const struct snd_pci_quirk alc880_cfg_tbl[] = { - SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810), - SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST), - SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG), - SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG), - SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG), - SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG), - SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG), - SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST), - SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG), - SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V), - SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG), - SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG), - SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG), - SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG), - SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG), - SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V), - /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */ - SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG), - SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG), - SND_PCI_QUIRK(0x1043, 0x814e, "ASUS P5GD1 w/SPDIF", ALC880_6ST_DIG), - SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG), - SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST), - SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST), - SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_ASUS), /* default ASUS */ - SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST), - SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST), - SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST), - SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST), - SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST), - SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG), - SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG), - SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG), - SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG), - SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO), - SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO), - SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2), - SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG), - SND_PCI_QUIRK(0x1584, 0x9054, "Uniwill", ALC880_F1734), - SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL), - SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53), - SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810), - SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_MEDION_RIM), - SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734), - SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU), - SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_F1734), - SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU), - SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW), - SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG), - SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_LG), - SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG), - SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW), - SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700), - SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */ - SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG), - SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG), - SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG), - SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG), - SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG), - /* default Intel */ - SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_3ST), - SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG), - SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG), - {} -}; - -/* - * ALC880 codec presets - */ -static const struct alc_config_preset alc880_presets[] = { - [ALC880_3ST] = { - .mixers = { alc880_three_stack_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_3stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .dac_nids = alc880_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), - .channel_mode = alc880_threestack_modes, - .need_dac_fix = 1, - .input_mux = &alc880_capture_source, - }, - [ALC880_3ST_DIG] = { - .mixers = { alc880_three_stack_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_3stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .dac_nids = alc880_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), - .channel_mode = alc880_threestack_modes, - .need_dac_fix = 1, - .input_mux = &alc880_capture_source, - }, - [ALC880_TCL_S700] = { - .mixers = { alc880_tcl_s700_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_tcl_S700_init_verbs, - alc880_gpio2_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .dac_nids = alc880_dac_nids, - .adc_nids = alc880_adc_nids_alt, /* FIXME: correct? */ - .num_adc_nids = 1, /* single ADC */ - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), - .channel_mode = alc880_2_jack_modes, - .input_mux = &alc880_capture_source, - }, - [ALC880_5ST] = { - .mixers = { alc880_three_stack_mixer, - alc880_five_stack_mixer}, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_5stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .dac_nids = alc880_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes), - .channel_mode = alc880_fivestack_modes, - .input_mux = &alc880_capture_source, - }, - [ALC880_5ST_DIG] = { - .mixers = { alc880_three_stack_mixer, - alc880_five_stack_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_5stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .dac_nids = alc880_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes), - .channel_mode = alc880_fivestack_modes, - .input_mux = &alc880_capture_source, - }, - [ALC880_6ST] = { - .mixers = { alc880_six_stack_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_6stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids), - .dac_nids = alc880_6st_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes), - .channel_mode = alc880_sixstack_modes, - .input_mux = &alc880_6stack_capture_source, - }, - [ALC880_6ST_DIG] = { - .mixers = { alc880_six_stack_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_6stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids), - .dac_nids = alc880_6st_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes), - .channel_mode = alc880_sixstack_modes, - .input_mux = &alc880_6stack_capture_source, - }, - [ALC880_W810] = { - .mixers = { alc880_w810_base_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_w810_init_verbs, - alc880_gpio2_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids), - .dac_nids = alc880_w810_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_w810_modes), - .channel_mode = alc880_w810_modes, - .input_mux = &alc880_capture_source, - }, - [ALC880_Z71V] = { - .mixers = { alc880_z71v_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_z71v_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids), - .dac_nids = alc880_z71v_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), - .channel_mode = alc880_2_jack_modes, - .input_mux = &alc880_capture_source, - }, - [ALC880_F1734] = { - .mixers = { alc880_f1734_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_f1734_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids), - .dac_nids = alc880_f1734_dac_nids, - .hp_nid = 0x02, - .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), - .channel_mode = alc880_2_jack_modes, - .input_mux = &alc880_f1734_capture_source, - .unsol_event = alc880_uniwill_p53_unsol_event, - .setup = alc880_uniwill_p53_setup, - .init_hook = alc_hp_automute, - }, - [ALC880_ASUS] = { - .mixers = { alc880_asus_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_asus_init_verbs, - alc880_gpio1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), - .dac_nids = alc880_asus_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), - .channel_mode = alc880_asus_modes, - .need_dac_fix = 1, - .input_mux = &alc880_capture_source, - }, - [ALC880_ASUS_DIG] = { - .mixers = { alc880_asus_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_asus_init_verbs, - alc880_gpio1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), - .dac_nids = alc880_asus_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), - .channel_mode = alc880_asus_modes, - .need_dac_fix = 1, - .input_mux = &alc880_capture_source, - }, - [ALC880_ASUS_DIG2] = { - .mixers = { alc880_asus_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_asus_init_verbs, - alc880_gpio2_init_verbs }, /* use GPIO2 */ - .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), - .dac_nids = alc880_asus_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), - .channel_mode = alc880_asus_modes, - .need_dac_fix = 1, - .input_mux = &alc880_capture_source, - }, - [ALC880_ASUS_W1V] = { - .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_asus_init_verbs, - alc880_gpio1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), - .dac_nids = alc880_asus_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), - .channel_mode = alc880_asus_modes, - .need_dac_fix = 1, - .input_mux = &alc880_capture_source, - }, - [ALC880_UNIWILL_DIG] = { - .mixers = { alc880_asus_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_asus_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), - .dac_nids = alc880_asus_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), - .channel_mode = alc880_asus_modes, - .need_dac_fix = 1, - .input_mux = &alc880_capture_source, - }, - [ALC880_UNIWILL] = { - .mixers = { alc880_uniwill_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_uniwill_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), - .dac_nids = alc880_asus_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), - .channel_mode = alc880_threestack_modes, - .need_dac_fix = 1, - .input_mux = &alc880_capture_source, - .unsol_event = alc880_uniwill_unsol_event, - .setup = alc880_uniwill_setup, - .init_hook = alc880_uniwill_init_hook, - }, - [ALC880_UNIWILL_P53] = { - .mixers = { alc880_uniwill_p53_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_uniwill_p53_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), - .dac_nids = alc880_asus_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc880_w810_modes), - .channel_mode = alc880_threestack_modes, - .input_mux = &alc880_capture_source, - .unsol_event = alc880_uniwill_p53_unsol_event, - .setup = alc880_uniwill_p53_setup, - .init_hook = alc_hp_automute, - }, - [ALC880_FUJITSU] = { - .mixers = { alc880_fujitsu_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_uniwill_p53_init_verbs, - alc880_beep_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .dac_nids = alc880_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), - .channel_mode = alc880_2_jack_modes, - .input_mux = &alc880_capture_source, - .unsol_event = alc880_uniwill_p53_unsol_event, - .setup = alc880_uniwill_p53_setup, - .init_hook = alc_hp_automute, - }, - [ALC880_CLEVO] = { - .mixers = { alc880_three_stack_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_clevo_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .dac_nids = alc880_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), - .channel_mode = alc880_threestack_modes, - .need_dac_fix = 1, - .input_mux = &alc880_capture_source, - }, - [ALC880_LG] = { - .mixers = { alc880_lg_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_lg_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids), - .dac_nids = alc880_lg_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes), - .channel_mode = alc880_lg_ch_modes, - .need_dac_fix = 1, - .input_mux = &alc880_lg_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc880_lg_setup, - .init_hook = alc_hp_automute, -#ifdef CONFIG_SND_HDA_POWER_SAVE - .loopbacks = alc880_lg_loopbacks, -#endif - }, - [ALC880_LG_LW] = { - .mixers = { alc880_lg_lw_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_lg_lw_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .dac_nids = alc880_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes), - .channel_mode = alc880_lg_lw_modes, - .input_mux = &alc880_lg_lw_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc880_lg_lw_setup, - .init_hook = alc_hp_automute, - }, - [ALC880_MEDION_RIM] = { - .mixers = { alc880_medion_rim_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_medion_rim_init_verbs, - alc_gpio2_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .dac_nids = alc880_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), - .channel_mode = alc880_2_jack_modes, - .input_mux = &alc880_medion_rim_capture_source, - .unsol_event = alc880_medion_rim_unsol_event, - .setup = alc880_medion_rim_setup, - .init_hook = alc880_medion_rim_automute, - }, -#ifdef CONFIG_SND_DEBUG - [ALC880_TEST] = { - .mixers = { alc880_test_mixer }, - .init_verbs = { alc880_test_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_test_dac_nids), - .dac_nids = alc880_test_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_test_modes), - .channel_mode = alc880_test_modes, - .input_mux = &alc880_test_capture_source, - }, -#endif -}; - diff --git a/trunk/sound/pci/hda/alc882_quirks.c b/trunk/sound/pci/hda/alc882_quirks.c deleted file mode 100644 index 617d04723b82..000000000000 --- a/trunk/sound/pci/hda/alc882_quirks.c +++ /dev/null @@ -1,3755 +0,0 @@ -/* - * ALC882/ALC883/ALC888/ALC889 quirk models - * included by patch_realtek.c - */ - -/* ALC882 models */ -enum { - ALC882_AUTO, - ALC882_3ST_DIG, - ALC882_6ST_DIG, - ALC882_ARIMA, - ALC882_W2JC, - ALC882_TARGA, - ALC882_ASUS_A7J, - ALC882_ASUS_A7M, - ALC885_MACPRO, - ALC885_MBA21, - ALC885_MBP3, - ALC885_MB5, - ALC885_MACMINI3, - ALC885_IMAC24, - ALC885_IMAC91, - ALC883_3ST_2ch_DIG, - ALC883_3ST_6ch_DIG, - ALC883_3ST_6ch, - ALC883_6ST_DIG, - ALC883_TARGA_DIG, - ALC883_TARGA_2ch_DIG, - ALC883_TARGA_8ch_DIG, - ALC883_ACER, - ALC883_ACER_ASPIRE, - ALC888_ACER_ASPIRE_4930G, - ALC888_ACER_ASPIRE_6530G, - ALC888_ACER_ASPIRE_8930G, - ALC888_ACER_ASPIRE_7730G, - ALC883_MEDION, - ALC883_MEDION_WIM2160, - ALC883_LAPTOP_EAPD, - ALC883_LENOVO_101E_2ch, - ALC883_LENOVO_NB0763, - ALC888_LENOVO_MS7195_DIG, - ALC888_LENOVO_SKY, - ALC883_HAIER_W66, - ALC888_3ST_HP, - ALC888_6ST_DELL, - ALC883_MITAC, - ALC883_CLEVO_M540R, - ALC883_CLEVO_M720, - ALC883_FUJITSU_PI2515, - ALC888_FUJITSU_XA3530, - ALC883_3ST_6ch_INTEL, - ALC889A_INTEL, - ALC889_INTEL, - ALC888_ASUS_M90V, - ALC888_ASUS_EEE1601, - ALC889A_MB31, - ALC1200_ASUS_P5Q, - ALC883_SONY_VAIO_TT, - ALC882_MODEL_LAST, -}; - -/* - * 2ch mode - */ -static const struct hda_verb alc888_4ST_ch2_intel_init[] = { -/* Mic-in jack as mic in */ - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, -/* Line-in jack as Line in */ - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, -/* Line-Out as Front */ - { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00}, - { } /* end */ -}; - -/* - * 4ch mode - */ -static const struct hda_verb alc888_4ST_ch4_intel_init[] = { -/* Mic-in jack as mic in */ - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, -/* Line-in jack as Surround */ - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, -/* Line-Out as Front */ - { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00}, - { } /* end */ -}; - -/* - * 6ch mode - */ -static const struct hda_verb alc888_4ST_ch6_intel_init[] = { -/* Mic-in jack as CLFE */ - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, -/* Line-in jack as Surround */ - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, -/* Line-Out as CLFE (workaround because Mic-in is not loud enough) */ - { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, - { } /* end */ -}; - -/* - * 8ch mode - */ -static const struct hda_verb alc888_4ST_ch8_intel_init[] = { -/* Mic-in jack as CLFE */ - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, -/* Line-in jack as Surround */ - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, -/* Line-Out as Side */ - { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, - { } /* end */ -}; - -static const struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = { - { 2, alc888_4ST_ch2_intel_init }, - { 4, alc888_4ST_ch4_intel_init }, - { 6, alc888_4ST_ch6_intel_init }, - { 8, alc888_4ST_ch8_intel_init }, -}; - -/* - * ALC888 Fujitsu Siemens Amillo xa3530 - */ - -static const struct hda_verb alc888_fujitsu_xa3530_verbs[] = { -/* Front Mic: set to PIN_IN (empty by default) */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, -/* Connect Internal HP to Front */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, -/* Connect Bass HP to Front */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, -/* Connect Line-Out side jack (SPDIF) to Side */ - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, -/* Connect Mic jack to CLFE */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, -/* Connect Line-in jack to Surround */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, -/* Connect HP out jack to Front */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, -/* Enable unsolicited event for HP jack and Line-out jack */ - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - {} -}; - -static void alc889_automute_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x16; - spec->autocfg.speaker_pins[2] = 0x17; - spec->autocfg.speaker_pins[3] = 0x19; - spec->autocfg.speaker_pins[4] = 0x1a; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc889_intel_init_hook(struct hda_codec *codec) -{ - alc889_coef_init(codec); - alc_hp_automute(codec); -} - -static void alc888_fujitsu_xa3530_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x17; /* line-out */ - spec->autocfg.hp_pins[1] = 0x1b; /* hp */ - spec->autocfg.speaker_pins[0] = 0x14; /* speaker */ - spec->autocfg.speaker_pins[1] = 0x15; /* bass */ - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -/* - * ALC888 Acer Aspire 4930G model - */ - -static const struct hda_verb alc888_acer_aspire_4930g_verbs[] = { -/* Front Mic: set to PIN_IN (empty by default) */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, -/* Unselect Front Mic by default in input mixer 3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)}, -/* Enable unsolicited event for HP jack */ - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, -/* Connect Internal HP to front */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, -/* Connect HP out to front */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, - { } -}; - -/* - * ALC888 Acer Aspire 6530G model - */ - -static const struct hda_verb alc888_acer_aspire_6530g_verbs[] = { -/* Route to built-in subwoofer as well as speakers */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, -/* Bias voltage on for external mic port */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80}, -/* Front Mic: set to PIN_IN (empty by default) */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, -/* Unselect Front Mic by default in input mixer 3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)}, -/* Enable unsolicited event for HP jack */ - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, -/* Enable speaker output */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, -/* Enable headphone output */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, - { } -}; - -/* - *ALC888 Acer Aspire 7730G model - */ - -static const struct hda_verb alc888_acer_aspire_7730G_verbs[] = { -/* Bias voltage on for external mic port */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80}, -/* Front Mic: set to PIN_IN (empty by default) */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, -/* Unselect Front Mic by default in input mixer 3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)}, -/* Enable unsolicited event for HP jack */ - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, -/* Enable speaker output */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, -/* Enable headphone output */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, -/*Enable internal subwoofer */ - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_CONNECT_SEL, 0x02}, - {0x17, AC_VERB_SET_EAPD_BTLENABLE, 2}, - { } -}; - -/* - * ALC889 Acer Aspire 8930G model - */ - -static const struct hda_verb alc889_acer_aspire_8930g_verbs[] = { -/* Front Mic: set to PIN_IN (empty by default) */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, -/* Unselect Front Mic by default in input mixer 3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)}, -/* Enable unsolicited event for HP jack */ - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, -/* Connect Internal Front to Front */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, -/* Connect Internal Rear to Rear */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, -/* Connect Internal CLFE to CLFE */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, -/* Connect HP out to Front */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, -/* Enable all DACs */ -/* DAC DISABLE/MUTE 1? */ -/* setting bits 1-5 disables DAC nids 0x02-0x06 apparently. Init=0x38 */ - {0x20, AC_VERB_SET_COEF_INDEX, 0x03}, - {0x20, AC_VERB_SET_PROC_COEF, 0x0000}, -/* DAC DISABLE/MUTE 2? */ -/* some bit here disables the other DACs. Init=0x4900 */ - {0x20, AC_VERB_SET_COEF_INDEX, 0x08}, - {0x20, AC_VERB_SET_PROC_COEF, 0x0000}, -/* DMIC fix - * This laptop has a stereo digital microphone. The mics are only 1cm apart - * which makes the stereo useless. However, either the mic or the ALC889 - * makes the signal become a difference/sum signal instead of standard - * stereo, which is annoying. So instead we flip this bit which makes the - * codec replicate the sum signal to both channels, turning it into a - * normal mono mic. - */ -/* DMIC_CONTROL? Init value = 0x0001 */ - {0x20, AC_VERB_SET_COEF_INDEX, 0x0b}, - {0x20, AC_VERB_SET_PROC_COEF, 0x0003}, - { } -}; - -static const struct hda_input_mux alc888_2_capture_sources[2] = { - /* Front mic only available on one ADC */ - { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - { "Front Mic", 0xb }, - }, - }, - { - .num_items = 3, - .items = { - { "Mic", 0x0 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, - } -}; - -static const struct hda_input_mux alc888_acer_aspire_6530_sources[2] = { - /* Interal mic only available on one ADC */ - { - .num_items = 5, - .items = { - { "Mic", 0x0 }, - { "Line In", 0x2 }, - { "CD", 0x4 }, - { "Input Mix", 0xa }, - { "Internal Mic", 0xb }, - }, - }, - { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Line In", 0x2 }, - { "CD", 0x4 }, - { "Input Mix", 0xa }, - }, - } -}; - -static const struct hda_input_mux alc889_capture_sources[3] = { - /* Digital mic only available on first "ADC" */ - { - .num_items = 5, - .items = { - { "Mic", 0x0 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - { "Front Mic", 0xb }, - { "Input Mix", 0xa }, - }, - }, - { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - { "Input Mix", 0xa }, - }, - }, - { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - { "Input Mix", 0xa }, - }, - } -}; - -static const struct snd_kcontrol_new alc888_base_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, - HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, - HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Internal LFE Playback Volume", 0x0f, 1, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Internal LFE Playback Switch", 0x0f, 1, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, - HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - - -static void alc888_acer_aspire_4930g_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x16; - spec->autocfg.speaker_pins[2] = 0x17; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x16; - spec->autocfg.speaker_pins[2] = 0x17; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc888_acer_aspire_7730g_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x16; - spec->autocfg.speaker_pins[2] = 0x17; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x16; - spec->autocfg.speaker_pins[2] = 0x1b; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -#define ALC882_DIGOUT_NID 0x06 -#define ALC882_DIGIN_NID 0x0a -#define ALC883_DIGOUT_NID ALC882_DIGOUT_NID -#define ALC883_DIGIN_NID ALC882_DIGIN_NID -#define ALC1200_DIGOUT_NID 0x10 - - -static const struct hda_channel_mode alc882_ch_modes[1] = { - { 8, NULL } -}; - -/* DACs */ -static const hda_nid_t alc882_dac_nids[4] = { - /* front, rear, clfe, rear_surr */ - 0x02, 0x03, 0x04, 0x05 -}; -#define alc883_dac_nids alc882_dac_nids - -/* ADCs */ -#define alc882_adc_nids alc880_adc_nids -#define alc882_adc_nids_alt alc880_adc_nids_alt -#define alc883_adc_nids alc882_adc_nids_alt -static const hda_nid_t alc883_adc_nids_alt[1] = { 0x08 }; -static const hda_nid_t alc883_adc_nids_rev[2] = { 0x09, 0x08 }; -#define alc889_adc_nids alc880_adc_nids - -static const hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 }; -static const hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 }; -#define alc883_capsrc_nids alc882_capsrc_nids_alt -static const hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 }; -#define alc889_capsrc_nids alc882_capsrc_nids - -/* input MUX */ -/* FIXME: should be a matrix-type input source selection */ - -static const struct hda_input_mux alc882_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - -#define alc883_capture_source alc882_capture_source - -static const struct hda_input_mux alc889_capture_source = { - .num_items = 3, - .items = { - { "Front Mic", 0x0 }, - { "Mic", 0x3 }, - { "Line", 0x2 }, - }, -}; - -static const struct hda_input_mux mb5_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x1 }, - { "Line", 0x7 }, - { "CD", 0x4 }, - }, -}; - -static const struct hda_input_mux macmini3_capture_source = { - .num_items = 2, - .items = { - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - -static const struct hda_input_mux alc883_3stack_6ch_intel = { - .num_items = 4, - .items = { - { "Mic", 0x1 }, - { "Front Mic", 0x0 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - -static const struct hda_input_mux alc883_lenovo_101e_capture_source = { - .num_items = 2, - .items = { - { "Mic", 0x1 }, - { "Line", 0x2 }, - }, -}; - -static const struct hda_input_mux alc883_lenovo_nb0763_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Internal Mic", 0x1 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - -static const struct hda_input_mux alc883_fujitsu_pi2515_capture_source = { - .num_items = 2, - .items = { - { "Mic", 0x0 }, - { "Internal Mic", 0x1 }, - }, -}; - -static const struct hda_input_mux alc883_lenovo_sky_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x4 }, - }, -}; - -static const struct hda_input_mux alc883_asus_eee1601_capture_source = { - .num_items = 2, - .items = { - { "Mic", 0x0 }, - { "Line", 0x2 }, - }, -}; - -static const struct hda_input_mux alc889A_mb31_capture_source = { - .num_items = 2, - .items = { - { "Mic", 0x0 }, - /* Front Mic (0x01) unused */ - { "Line", 0x2 }, - /* Line 2 (0x03) unused */ - /* CD (0x04) unused? */ - }, -}; - -static const struct hda_input_mux alc889A_imac91_capture_source = { - .num_items = 2, - .items = { - { "Mic", 0x01 }, - { "Line", 0x2 }, /* Not sure! */ - }, -}; - -/* - * 2ch mode - */ -static const struct hda_channel_mode alc883_3ST_2ch_modes[1] = { - { 2, NULL } -}; - -/* - * 2ch mode - */ -static const struct hda_verb alc882_3ST_ch2_init[] = { - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { } /* end */ -}; - -/* - * 4ch mode - */ -static const struct hda_verb alc882_3ST_ch4_init[] = { - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { } /* end */ -}; - -/* - * 6ch mode - */ -static const struct hda_verb alc882_3ST_ch6_init[] = { - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { } /* end */ -}; - -static const struct hda_channel_mode alc882_3ST_6ch_modes[3] = { - { 2, alc882_3ST_ch2_init }, - { 4, alc882_3ST_ch4_init }, - { 6, alc882_3ST_ch6_init }, -}; - -#define alc883_3ST_6ch_modes alc882_3ST_6ch_modes - -/* - * 2ch mode - */ -static const struct hda_verb alc883_3ST_ch2_clevo_init[] = { - { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { } /* end */ -}; - -/* - * 4ch mode - */ -static const struct hda_verb alc883_3ST_ch4_clevo_init[] = { - { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { } /* end */ -}; - -/* - * 6ch mode - */ -static const struct hda_verb alc883_3ST_ch6_clevo_init[] = { - { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { } /* end */ -}; - -static const struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = { - { 2, alc883_3ST_ch2_clevo_init }, - { 4, alc883_3ST_ch4_clevo_init }, - { 6, alc883_3ST_ch6_clevo_init }, -}; - - -/* - * 6ch mode - */ -static const struct hda_verb alc882_sixstack_ch6_init[] = { - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, - { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { } /* end */ -}; - -/* - * 8ch mode - */ -static const struct hda_verb alc882_sixstack_ch8_init[] = { - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { } /* end */ -}; - -static const struct hda_channel_mode alc882_sixstack_modes[2] = { - { 6, alc882_sixstack_ch6_init }, - { 8, alc882_sixstack_ch8_init }, -}; - - -/* Macbook Air 2,1 */ - -static const struct hda_channel_mode alc885_mba21_ch_modes[1] = { - { 2, NULL }, -}; - -/* - * macbook pro ALC885 can switch LineIn to LineOut without losing Mic - */ - -/* - * 2ch mode - */ -static const struct hda_verb alc885_mbp_ch2_init[] = { - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - { } /* end */ -}; - -/* - * 4ch mode - */ -static const struct hda_verb alc885_mbp_ch4_init[] = { - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - { } /* end */ -}; - -static const struct hda_channel_mode alc885_mbp_4ch_modes[2] = { - { 2, alc885_mbp_ch2_init }, - { 4, alc885_mbp_ch4_init }, -}; - -/* - * 2ch - * Speakers/Woofer/HP = Front - * LineIn = Input - */ -static const struct hda_verb alc885_mb5_ch2_init[] = { - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - { } /* end */ -}; - -/* - * 6ch mode - * Speakers/HP = Front - * Woofer = LFE - * LineIn = Surround - */ -static const struct hda_verb alc885_mb5_ch6_init[] = { - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, - { } /* end */ -}; - -static const struct hda_channel_mode alc885_mb5_6ch_modes[2] = { - { 2, alc885_mb5_ch2_init }, - { 6, alc885_mb5_ch6_init }, -}; - -#define alc885_macmini3_6ch_modes alc885_mb5_6ch_modes - -/* - * 2ch mode - */ -static const struct hda_verb alc883_4ST_ch2_init[] = { - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { } /* end */ -}; - -/* - * 4ch mode - */ -static const struct hda_verb alc883_4ST_ch4_init[] = { - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { } /* end */ -}; - -/* - * 6ch mode - */ -static const struct hda_verb alc883_4ST_ch6_init[] = { - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { } /* end */ -}; - -/* - * 8ch mode - */ -static const struct hda_verb alc883_4ST_ch8_init[] = { - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 }, - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { } /* end */ -}; - -static const struct hda_channel_mode alc883_4ST_8ch_modes[4] = { - { 2, alc883_4ST_ch2_init }, - { 4, alc883_4ST_ch4_init }, - { 6, alc883_4ST_ch6_init }, - { 8, alc883_4ST_ch8_init }, -}; - - -/* - * 2ch mode - */ -static const struct hda_verb alc883_3ST_ch2_intel_init[] = { - { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { } /* end */ -}; - -/* - * 4ch mode - */ -static const struct hda_verb alc883_3ST_ch4_intel_init[] = { - { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { } /* end */ -}; - -/* - * 6ch mode - */ -static const struct hda_verb alc883_3ST_ch6_intel_init[] = { - { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { } /* end */ -}; - -static const struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = { - { 2, alc883_3ST_ch2_intel_init }, - { 4, alc883_3ST_ch4_intel_init }, - { 6, alc883_3ST_ch6_intel_init }, -}; - -/* - * 2ch mode - */ -static const struct hda_verb alc889_ch2_intel_init[] = { - { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 }, - { 0x19, AC_VERB_SET_CONNECT_SEL, 0x00 }, - { 0x16, AC_VERB_SET_CONNECT_SEL, 0x00 }, - { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00 }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { } /* end */ -}; - -/* - * 6ch mode - */ -static const struct hda_verb alc889_ch6_intel_init[] = { - { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 }, - { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 }, - { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { } /* end */ -}; - -/* - * 8ch mode - */ -static const struct hda_verb alc889_ch8_intel_init[] = { - { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 }, - { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 }, - { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 }, - { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x03 }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { } /* end */ -}; - -static const struct hda_channel_mode alc889_8ch_intel_modes[3] = { - { 2, alc889_ch2_intel_init }, - { 6, alc889_ch6_intel_init }, - { 8, alc889_ch8_intel_init }, -}; - -/* - * 6ch mode - */ -static const struct hda_verb alc883_sixstack_ch6_init[] = { - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, - { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { } /* end */ -}; - -/* - * 8ch mode - */ -static const struct hda_verb alc883_sixstack_ch8_init[] = { - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { } /* end */ -}; - -static const struct hda_channel_mode alc883_sixstack_modes[2] = { - { 6, alc883_sixstack_ch6_init }, - { 8, alc883_sixstack_ch8_init }, -}; - - -/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 - * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b - */ -static const struct snd_kcontrol_new alc882_base_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -/* Macbook Air 2,1 same control for HP and internal Speaker */ - -static const struct snd_kcontrol_new alc885_mba21_mixer[] = { - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_OUTPUT), - { } -}; - - -static const struct snd_kcontrol_new alc885_mbp3_mixer[] = { - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE ("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0e, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE ("Headphone Playback Switch", 0x0e, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT), - HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc885_mb5_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT), - HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0x00, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc885_macmini3_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT), - HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT), - HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc885_imac91_mixer[] = { - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT), - { } /* end */ -}; - - -static const struct snd_kcontrol_new alc882_w2jc_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc882_targa_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - { } /* end */ -}; - -/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ??? - * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c - */ -static const struct snd_kcontrol_new alc882_asus_a7j_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT), - HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc882_asus_a7m_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc882_chmode_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -static const struct hda_verb alc882_base_init_verbs[] = { - /* Front mixer: unmute input/output amp left and right (volume = 0) */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Rear mixer */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* CLFE mixer */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Side mixer */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - - /* Front Pin: output 0 (0x0c) */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* Rear Pin: output 1 (0x0d) */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, - /* CLFE Pin: output 2 (0x0e) */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* Side Pin: output 3 (0x0f) */ - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, - /* Mic (rear) pin: input vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Front Mic pin: input vref at 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line In pin: input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line-2 In: Headphone output (output 0 - 0x0c) */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - /* FIXME: use matrix-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ - /* Input mixer2 */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Input mixer3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* ADC2: mute amp left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* ADC3: mute amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - - { } -}; - -static const struct hda_verb alc882_adc1_init_verbs[] = { - /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* ADC1: mute amp left and right */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - { } -}; - -static const struct hda_verb alc882_eapd_verbs[] = { - /* change to EAPD mode */ - {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, - {0x20, AC_VERB_SET_PROC_COEF, 0x3060}, - { } -}; - -static const struct hda_verb alc889_eapd_verbs[] = { - {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, - {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, - { } -}; - -static const struct hda_verb alc_hp15_unsol_verbs[] = { - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {} -}; - -static const struct hda_verb alc885_init_verbs[] = { - /* Front mixer: unmute input/output amp left and right (volume = 0) */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Rear mixer */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* CLFE mixer */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Side mixer */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - /* Front HP Pin: output 0 (0x0c) */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* Front Pin: output 0 (0x0c) */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* Rear Pin: output 1 (0x0d) */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x19, AC_VERB_SET_CONNECT_SEL, 0x01}, - /* CLFE Pin: output 2 (0x0e) */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* Side Pin: output 3 (0x0f) */ - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, - /* Mic (rear) pin: input vref at 80% */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Front Mic pin: input vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line In pin: input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - /* Mixer elements: 0x18, , 0x1a, 0x1b */ - /* Input mixer1 */ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Input mixer2 */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Input mixer3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* ADC2: mute amp left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - /* ADC3: mute amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - - { } -}; - -static const struct hda_verb alc885_init_input_verbs[] = { - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - { } -}; - - -/* Unmute Selector 24h and set the default input to front mic */ -static const struct hda_verb alc889_init_input_verbs[] = { - {0x24, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - { } -}; - - -#define alc883_init_verbs alc882_base_init_verbs - -/* Mac Pro test */ -static const struct snd_kcontrol_new alc882_macpro_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT), - /* FIXME: this looks suspicious... - HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x02, HDA_INPUT), - */ - { } /* end */ -}; - -static const struct hda_verb alc882_macpro_init_verbs[] = { - /* Front mixer: unmute input/output amp left and right (volume = 0) */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Front Pin: output 0 (0x0c) */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* Front Mic pin: input vref at 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Speaker: output */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04}, - /* Headphone output (output 0 - 0x0c) */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x18, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* FIXME: use matrix-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ - /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* Input mixer2 */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* Input mixer3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* ADC1: mute amp left and right */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* ADC2: mute amp left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* ADC3: mute amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - - { } -}; - -/* Macbook 5,1 */ -static const struct hda_verb alc885_mb5_init_verbs[] = { - /* DACs */ - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Front mixer */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Surround mixer */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* LFE mixer */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* HP mixer */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Front Pin (0x0c) */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x18, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* LFE Pin (0x0e) */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* HP Pin (0x0f) */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x03}, - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - /* Front Mic pin: input vref at 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line In pin */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0x1)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x7)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x4)}, - { } -}; - -/* Macmini 3,1 */ -static const struct hda_verb alc885_macmini3_init_verbs[] = { - /* DACs */ - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Front mixer */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Surround mixer */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* LFE mixer */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* HP mixer */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Front Pin (0x0c) */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x18, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* LFE Pin (0x0e) */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* HP Pin (0x0f) */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x03}, - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - /* Line In pin */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - { } -}; - - -static const struct hda_verb alc885_mba21_init_verbs[] = { - /*Internal and HP Speaker Mixer*/ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /*Internal Speaker Pin (0x0c)*/ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) }, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x18, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* HP Pin: output 0 (0x0e) */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC_HP_EVENT | AC_USRSP_EN)}, - /* Line in (is hp when jack connected)*/ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - { } - }; - - -/* Macbook Pro rev3 */ -static const struct hda_verb alc885_mbp3_init_verbs[] = { - /* Front mixer: unmute input/output amp left and right (volume = 0) */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Rear mixer */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* HP mixer */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Front Pin: output 0 (0x0c) */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* HP Pin: output 0 (0x0e) */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x02}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - /* Mic (rear) pin: input vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Front Mic pin: input vref at 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line In pin: use output 1 when in LineOut mode */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, - - /* FIXME: use matrix-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ - /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* Input mixer2 */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* Input mixer3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* ADC1: mute amp left and right */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* ADC2: mute amp left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* ADC3: mute amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - - { } -}; - -/* iMac 9,1 */ -static const struct hda_verb alc885_imac91_init_verbs[] = { - /* Internal Speaker Pin (0x0c) */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) }, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x18, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) }, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* HP Pin: Rear */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC_HP_EVENT | AC_USRSP_EN)}, - /* Line in Rear */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Front Mic pin: input vref at 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Rear mixer */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Line-Out mixer: unmute input/output amp left and right (volume = 0) */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* 0x24 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* 0x23 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* 0x22 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* 0x07 [Audio Input] wcaps 0x10011b: Stereo Amp-In */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* 0x08 [Audio Input] wcaps 0x10011b: Stereo Amp-In */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* 0x09 [Audio Input] wcaps 0x10011b: Stereo Amp-In */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - { } -}; - -/* iMac 24 mixer. */ -static const struct snd_kcontrol_new alc885_imac24_mixer[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT), - HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT), - { } /* end */ -}; - -/* iMac 24 init verbs. */ -static const struct hda_verb alc885_imac24_init_verbs[] = { - /* Internal speakers: output 0 (0x0c) */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x18, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* Internal speakers: output 0 (0x0c) */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* Headphone: output 0 (0x0c) */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - /* Front Mic: input vref at 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - { } -}; - -/* Toggle speaker-output according to the hp-jack state */ -static void alc885_imac24_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x18; - spec->autocfg.speaker_pins[1] = 0x1a; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -#define alc885_mb5_setup alc885_imac24_setup -#define alc885_macmini3_setup alc885_imac24_setup - -/* Macbook Air 2,1 */ -static void alc885_mba21_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x18; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - - - -static void alc885_mbp3_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc885_imac91_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x18; - spec->autocfg.speaker_pins[1] = 0x1a; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static const struct hda_verb alc882_targa_verbs[] = { - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */ - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ - - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - { } /* end */ -}; - -/* toggle speaker-output according to the hp-jack state */ -static void alc882_targa_automute(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - alc_hp_automute(codec); - snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA, - spec->jack_present ? 1 : 3); -} - -static void alc882_targa_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x1b; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res) -{ - if ((res >> 26) == ALC_HP_EVENT) - alc882_targa_automute(codec); -} - -static const struct hda_verb alc882_asus_a7j_verbs[] = { - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */ - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ - {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */ - - {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */ - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ - { } /* end */ -}; - -static const struct hda_verb alc882_asus_a7m_verbs[] = { - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */ - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ - {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */ - - {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */ - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ - { } /* end */ -}; - -static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted) -{ - unsigned int gpiostate, gpiomask, gpiodir; - - gpiostate = snd_hda_codec_read(codec, codec->afg, 0, - AC_VERB_GET_GPIO_DATA, 0); - - if (!muted) - gpiostate |= (1 << pin); - else - gpiostate &= ~(1 << pin); - - gpiomask = snd_hda_codec_read(codec, codec->afg, 0, - AC_VERB_GET_GPIO_MASK, 0); - gpiomask |= (1 << pin); - - gpiodir = snd_hda_codec_read(codec, codec->afg, 0, - AC_VERB_GET_GPIO_DIRECTION, 0); - gpiodir |= (1 << pin); - - - snd_hda_codec_write(codec, codec->afg, 0, - AC_VERB_SET_GPIO_MASK, gpiomask); - snd_hda_codec_write(codec, codec->afg, 0, - AC_VERB_SET_GPIO_DIRECTION, gpiodir); - - msleep(1); - - snd_hda_codec_write(codec, codec->afg, 0, - AC_VERB_SET_GPIO_DATA, gpiostate); -} - -/* set up GPIO at initialization */ -static void alc885_macpro_init_hook(struct hda_codec *codec) -{ - alc882_gpio_mute(codec, 0, 0); - alc882_gpio_mute(codec, 1, 0); -} - -/* set up GPIO and update auto-muting at initialization */ -static void alc885_imac24_init_hook(struct hda_codec *codec) -{ - alc885_macpro_init_hook(codec); - alc_hp_automute(codec); -} - -/* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */ -static const struct hda_verb alc889A_mb31_ch2_init[] = { - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */ - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */ - { } /* end */ -}; - -/* 4ch mode (Speaker:front, Subwoofer:CLFE, Line:CLFE, Headphones:front) */ -static const struct hda_verb alc889A_mb31_ch4_init[] = { - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */ - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */ - { } /* end */ -}; - -/* 5ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:rear) */ -static const struct hda_verb alc889A_mb31_ch5_init[] = { - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as rear */ - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */ - { } /* end */ -}; - -/* 6ch mode (Speaker:front, Subwoofer:off, Line:CLFE, Headphones:Rear) */ -static const struct hda_verb alc889A_mb31_ch6_init[] = { - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as front */ - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Subwoofer off */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */ - { } /* end */ -}; - -static const struct hda_channel_mode alc889A_mb31_6ch_modes[4] = { - { 2, alc889A_mb31_ch2_init }, - { 4, alc889A_mb31_ch4_init }, - { 5, alc889A_mb31_ch5_init }, - { 6, alc889A_mb31_ch6_init }, -}; - -static const struct hda_verb alc883_medion_eapd_verbs[] = { - /* eanable EAPD on medion laptop */ - {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, - {0x20, AC_VERB_SET_PROC_COEF, 0x3070}, - { } -}; - -#define alc883_base_mixer alc882_base_mixer - -static const struct snd_kcontrol_new alc883_mitac_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc883_clevo_m720_mixer[] = { - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = { - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, - HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc885_8ch_intel_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, - HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Speaker Playback Switch", 0x0f, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x3, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x1b, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x3, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc883_fivestack_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc883_targa_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc883_targa_2ch_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc883_targa_8ch_mixer[] = { - HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = { - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc883_medion_wim2160_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x08, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct hda_verb alc883_medion_wim2160_verbs[] = { - /* Unmute front mixer */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - /* Set speaker pin to front mixer */ - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Init headphone pin */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - - { } /* end */ -}; - -/* toggle speaker-output according to the hp-jack state */ -static void alc883_medion_wim2160_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x1a; - spec->autocfg.speaker_pins[0] = 0x15; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static const struct snd_kcontrol_new alc883_acer_aspire_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("LFE Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", - 0x0d, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc889A_mb31_mixer[] = { - /* Output mixers */ - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x00, - HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x02, HDA_INPUT), - /* Output switches */ - HDA_CODEC_MUTE("Enable Speaker", 0x14, 0x00, HDA_OUTPUT), - HDA_CODEC_MUTE("Enable Headphones", 0x15, 0x00, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Enable LFE", 0x16, 2, 0x00, HDA_OUTPUT), - /* Boost mixers */ - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT), - /* Input mixers */ - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc883_vaiott_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct hda_bind_ctls alc883_bind_cap_vol = { - .ops = &snd_hda_bind_vol, - .values = { - HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT), - HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT), - 0 - }, -}; - -static const struct hda_bind_ctls alc883_bind_cap_switch = { - .ops = &snd_hda_bind_sw, - .values = { - HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT), - HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT), - 0 - }, -}; - -static const struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = { - HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol), - HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, - { } /* end */ -}; - -static const struct snd_kcontrol_new alc883_chmode_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -/* toggle speaker-output according to the hp-jack state */ -static void alc883_mitac_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x17; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static const struct hda_verb alc883_mitac_verbs[] = { - /* HP */ - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* Subwoofer */ - {0x17, AC_VERB_SET_CONNECT_SEL, 0x02}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - /* enable unsolicited event */ - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN}, */ - - { } /* end */ -}; - -static const struct hda_verb alc883_clevo_m540r_verbs[] = { - /* HP */ - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* Int speaker */ - /*{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},*/ - - /* enable unsolicited event */ - /* - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN}, - */ - - { } /* end */ -}; - -static const struct hda_verb alc883_clevo_m720_verbs[] = { - /* HP */ - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* Int speaker */ - {0x14, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - /* enable unsolicited event */ - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN}, - - { } /* end */ -}; - -static const struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = { - /* HP */ - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* Subwoofer */ - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - /* enable unsolicited event */ - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - - { } /* end */ -}; - -static const struct hda_verb alc883_targa_verbs[] = { - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - -/* Connect Line-Out side jack (SPDIF) to Side */ - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, -/* Connect Mic jack to CLFE */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, -/* Connect Line-in jack to Surround */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, -/* Connect HP out jack to Front */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - - { } /* end */ -}; - -static const struct hda_verb alc883_lenovo_101e_verbs[] = { - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_FRONT_EVENT|AC_USRSP_EN}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT|AC_USRSP_EN}, - { } /* end */ -}; - -static const struct hda_verb alc883_lenovo_nb0763_verbs[] = { - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - { } /* end */ -}; - -static const struct hda_verb alc888_lenovo_ms7195_verbs[] = { - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_FRONT_EVENT | AC_USRSP_EN}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - { } /* end */ -}; - -static const struct hda_verb alc883_haier_w66_verbs[] = { - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - { } /* end */ -}; - -static const struct hda_verb alc888_lenovo_sky_verbs[] = { - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - { } /* end */ -}; - -static const struct hda_verb alc888_6st_dell_verbs[] = { - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - { } -}; - -static const struct hda_verb alc883_vaiott_verbs[] = { - /* HP */ - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - - /* enable unsolicited event */ - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - - { } /* end */ -}; - -static void alc888_3st_hp_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x16; - spec->autocfg.speaker_pins[2] = 0x18; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static const struct hda_verb alc888_3st_hp_verbs[] = { - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */ - {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */ - {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */ - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - { } /* end */ -}; - -/* - * 2ch mode - */ -static const struct hda_verb alc888_3st_hp_2ch_init[] = { - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { } /* end */ -}; - -/* - * 4ch mode - */ -static const struct hda_verb alc888_3st_hp_4ch_init[] = { - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { } /* end */ -}; - -/* - * 6ch mode - */ -static const struct hda_verb alc888_3st_hp_6ch_init[] = { - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, - { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { } /* end */ -}; - -static const struct hda_channel_mode alc888_3st_hp_modes[3] = { - { 2, alc888_3st_hp_2ch_init }, - { 4, alc888_3st_hp_4ch_init }, - { 6, alc888_3st_hp_6ch_init }, -}; - -static void alc888_lenovo_ms7195_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.line_out_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x15; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -/* toggle speaker-output according to the hp-jack state */ -static void alc883_lenovo_nb0763_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x15; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -/* toggle speaker-output according to the hp-jack state */ -#define alc883_targa_init_hook alc882_targa_init_hook -#define alc883_targa_unsol_event alc882_targa_unsol_event - -static void alc883_clevo_m720_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc883_clevo_m720_init_hook(struct hda_codec *codec) -{ - alc_hp_automute(codec); - alc88x_simple_mic_automute(codec); -} - -static void alc883_clevo_m720_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case ALC_MIC_EVENT: - alc88x_simple_mic_automute(codec); - break; - default: - alc_sku_unsol_event(codec, res); - break; - } -} - -/* toggle speaker-output according to the hp-jack state */ -static void alc883_2ch_fujitsu_pi2515_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x15; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc883_haier_w66_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc883_lenovo_101e_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.line_out_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x15; - spec->automute = 1; - spec->detect_line = 1; - spec->automute_lines = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -/* toggle speaker-output according to the hp-jack state */ -static void alc883_acer_aspire_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x15; - spec->autocfg.speaker_pins[1] = 0x16; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static const struct hda_verb alc883_acer_eapd_verbs[] = { - /* HP Pin: output 0 (0x0c) */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* Front Pin: output 0 (0x0c) */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* eanable EAPD on medion laptop */ - {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, - {0x20, AC_VERB_SET_PROC_COEF, 0x3050}, - /* enable unsolicited event */ - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - { } -}; - -static void alc888_6st_dell_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x15; - spec->autocfg.speaker_pins[2] = 0x16; - spec->autocfg.speaker_pins[3] = 0x17; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc888_lenovo_sky_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x15; - spec->autocfg.speaker_pins[2] = 0x16; - spec->autocfg.speaker_pins[3] = 0x17; - spec->autocfg.speaker_pins[4] = 0x1a; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc883_vaiott_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x17; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static const struct hda_verb alc888_asus_m90v_verbs[] = { - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* enable unsolicited event */ - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN}, - { } /* end */ -}; - -static void alc883_mode2_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x15; - spec->autocfg.speaker_pins[2] = 0x16; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static const struct hda_verb alc888_asus_eee1601_verbs[] = { - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x20, AC_VERB_SET_COEF_INDEX, 0x0b}, - {0x20, AC_VERB_SET_PROC_COEF, 0x0838}, - /* enable unsolicited event */ - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - { } /* end */ -}; - -static void alc883_eee1601_inithook(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x1b; - alc_hp_automute(codec); -} - -static const struct hda_verb alc889A_mb31_verbs[] = { - /* Init rear pin (used as headphone output) */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, /* Apple Headphones */ - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Connect to front */ - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - /* Init line pin (used as output in 4ch and 6ch mode) */ - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Connect to CLFE */ - /* Init line 2 pin (used as headphone out by default) */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Use as input */ - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Mute output */ - { } /* end */ -}; - -/* Mute speakers according to the headphone jack state */ -static void alc889A_mb31_automute(struct hda_codec *codec) -{ - unsigned int present; - - /* Mute only in 2ch or 4ch mode */ - if (snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_CONNECT_SEL, 0) - == 0x00) { - present = snd_hda_jack_detect(codec, 0x15); - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); - snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); - } -} - -static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res) -{ - if ((res >> 26) == ALC_HP_EVENT) - alc889A_mb31_automute(codec); -} - -static const hda_nid_t alc883_slave_dig_outs[] = { - ALC1200_DIGOUT_NID, 0, -}; - -static const hda_nid_t alc1200_slave_dig_outs[] = { - ALC883_DIGOUT_NID, 0, -}; - -/* - * configuration and preset - */ -static const char * const alc882_models[ALC882_MODEL_LAST] = { - [ALC882_3ST_DIG] = "3stack-dig", - [ALC882_6ST_DIG] = "6stack-dig", - [ALC882_ARIMA] = "arima", - [ALC882_W2JC] = "w2jc", - [ALC882_TARGA] = "targa", - [ALC882_ASUS_A7J] = "asus-a7j", - [ALC882_ASUS_A7M] = "asus-a7m", - [ALC885_MACPRO] = "macpro", - [ALC885_MB5] = "mb5", - [ALC885_MACMINI3] = "macmini3", - [ALC885_MBA21] = "mba21", - [ALC885_MBP3] = "mbp3", - [ALC885_IMAC24] = "imac24", - [ALC885_IMAC91] = "imac91", - [ALC883_3ST_2ch_DIG] = "3stack-2ch-dig", - [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig", - [ALC883_3ST_6ch] = "3stack-6ch", - [ALC883_6ST_DIG] = "alc883-6stack-dig", - [ALC883_TARGA_DIG] = "targa-dig", - [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig", - [ALC883_TARGA_8ch_DIG] = "targa-8ch-dig", - [ALC883_ACER] = "acer", - [ALC883_ACER_ASPIRE] = "acer-aspire", - [ALC888_ACER_ASPIRE_4930G] = "acer-aspire-4930g", - [ALC888_ACER_ASPIRE_6530G] = "acer-aspire-6530g", - [ALC888_ACER_ASPIRE_8930G] = "acer-aspire-8930g", - [ALC888_ACER_ASPIRE_7730G] = "acer-aspire-7730g", - [ALC883_MEDION] = "medion", - [ALC883_MEDION_WIM2160] = "medion-wim2160", - [ALC883_LAPTOP_EAPD] = "laptop-eapd", - [ALC883_LENOVO_101E_2ch] = "lenovo-101e", - [ALC883_LENOVO_NB0763] = "lenovo-nb0763", - [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig", - [ALC888_LENOVO_SKY] = "lenovo-sky", - [ALC883_HAIER_W66] = "haier-w66", - [ALC888_3ST_HP] = "3stack-hp", - [ALC888_6ST_DELL] = "6stack-dell", - [ALC883_MITAC] = "mitac", - [ALC883_CLEVO_M540R] = "clevo-m540r", - [ALC883_CLEVO_M720] = "clevo-m720", - [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515", - [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530", - [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel", - [ALC889A_INTEL] = "intel-alc889a", - [ALC889_INTEL] = "intel-x58", - [ALC1200_ASUS_P5Q] = "asus-p5q", - [ALC889A_MB31] = "mb31", - [ALC883_SONY_VAIO_TT] = "sony-vaio-tt", - [ALC882_AUTO] = "auto", -}; - -static const struct snd_pci_quirk alc882_cfg_tbl[] = { - SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG), - - SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE), - SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE), - SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_ACER_ASPIRE), - SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE), - SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE), - SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE), - SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G", - ALC888_ACER_ASPIRE_4930G), - SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G", - ALC888_ACER_ASPIRE_4930G), - SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G", - ALC888_ACER_ASPIRE_8930G), - SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G", - ALC888_ACER_ASPIRE_8930G), - SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC882_AUTO), - SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC882_AUTO), - SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G", - ALC888_ACER_ASPIRE_6530G), - SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G", - ALC888_ACER_ASPIRE_6530G), - SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G", - ALC888_ACER_ASPIRE_7730G), - /* default Acer -- disabled as it causes more problems. - * model=auto should work fine now - */ - /* SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), */ - - SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL), - - SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavilion", ALC883_6ST_DIG), - SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP), - SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP), - SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG), - SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP), - SND_PCI_QUIRK(0x103c, 0x2a72, "HP Educ.ar", ALC888_3ST_HP), - - SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J), - SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J), - SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M), - SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V), - SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC), - SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG), - SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG), - SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG), - SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG), - SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q), - SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601), - - SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC883_SONY_VAIO_TT), - SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG), - SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG), - SND_PCI_QUIRK(0x1071, 0x8227, "Mitac 82801H", ALC883_MITAC), - SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC), - SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD), - SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL), - SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch), - SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG), - - SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG), - SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG), - SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG), - SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */ - SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC882_AUTO), - SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG), - SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG), - SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG), - SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG), - SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG), - SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG), - SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG), - SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG), - SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG), - SND_PCI_QUIRK(0x1462, 0x42cd, "MSI", ALC883_TARGA_DIG), - SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG), - SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG), - SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG), - SND_PCI_QUIRK(0x1462, 0x4570, "MSI Wind Top AE2220", ALC883_TARGA_DIG), - SND_PCI_QUIRK(0x1462, 0x6510, "MSI GX620", ALC883_TARGA_8ch_DIG), - SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG), - SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG), - SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG), - SND_PCI_QUIRK(0x1462, 0x7260, "MSI 7260", ALC883_TARGA_DIG), - SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG), - SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG), - SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG), - SND_PCI_QUIRK(0x1462, 0x7350, "MSI", ALC883_6ST_DIG), - SND_PCI_QUIRK(0x1462, 0x7437, "MSI NetOn AP1900", ALC883_TARGA_DIG), - SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG), - SND_PCI_QUIRK(0x1462, 0xaa08, "MSI", ALC883_TARGA_2ch_DIG), - - SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG), - SND_PCI_QUIRK(0x1558, 0x0571, "Clevo laptop M570U", ALC883_3ST_6ch_DIG), - SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720), - SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720), - SND_PCI_QUIRK(0x1558, 0x5409, "Clevo laptop M540R", ALC883_CLEVO_M540R), - SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD), - SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch), - /* SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), */ - SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION), - SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1100, "FSC AMILO Xi/Pi25xx", - ALC883_FUJITSU_PI2515), - SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1130, "Fujitsu AMILO Xa35xx", - ALC888_FUJITSU_XA3530), - SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch), - SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763), - SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763), - SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763), - SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY), - SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG), - SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG), - SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66), - - SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL), - SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL), - SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC), - SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_INTEL), - SND_PCI_QUIRK(0x8086, 0x0021, "Intel IbexPeak", ALC889A_INTEL), - SND_PCI_QUIRK(0x8086, 0x3b56, "Intel IbexPeak", ALC889A_INTEL), - SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC882_6ST_DIG), - - {} -}; - -/* codec SSID table for Intel Mac */ -static const struct snd_pci_quirk alc882_ssid_cfg_tbl[] = { - SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC885_MBP3), - SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC885_MBP3), - SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC885_MBP3), - SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_MACPRO), - SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24), - SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24), - SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3), - SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889A_MB31), - SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_ASUS_A7M), - SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC885_MBP3), - SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC885_MBA21), - SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31), - SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3), - SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24), - SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC885_IMAC91), - SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5), - SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC885_MB5), - /* FIXME: HP jack sense seems not working for MBP 5,1 or 5,2, - * so apparently no perfect solution yet - */ - SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC885_MB5), - SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC885_MB5), - SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC885_MACMINI3), - {} /* terminator */ -}; - -static const struct alc_config_preset alc882_presets[] = { - [ALC882_3ST_DIG] = { - .mixers = { alc882_base_mixer }, - .init_verbs = { alc882_base_init_verbs, - alc882_adc1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .dig_out_nid = ALC882_DIGOUT_NID, - .dig_in_nid = ALC882_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), - .channel_mode = alc882_ch_modes, - .need_dac_fix = 1, - .input_mux = &alc882_capture_source, - }, - [ALC882_6ST_DIG] = { - .mixers = { alc882_base_mixer, alc882_chmode_mixer }, - .init_verbs = { alc882_base_init_verbs, - alc882_adc1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .dig_out_nid = ALC882_DIGOUT_NID, - .dig_in_nid = ALC882_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes), - .channel_mode = alc882_sixstack_modes, - .input_mux = &alc882_capture_source, - }, - [ALC882_ARIMA] = { - .mixers = { alc882_base_mixer, alc882_chmode_mixer }, - .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs, - alc882_eapd_verbs }, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes), - .channel_mode = alc882_sixstack_modes, - .input_mux = &alc882_capture_source, - }, - [ALC882_W2JC] = { - .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer }, - .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs, - alc882_eapd_verbs, alc880_gpio1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), - .channel_mode = alc880_threestack_modes, - .need_dac_fix = 1, - .input_mux = &alc882_capture_source, - .dig_out_nid = ALC882_DIGOUT_NID, - }, - [ALC885_MBA21] = { - .mixers = { alc885_mba21_mixer }, - .init_verbs = { alc885_mba21_init_verbs, alc880_gpio1_init_verbs }, - .num_dacs = 2, - .dac_nids = alc882_dac_nids, - .channel_mode = alc885_mba21_ch_modes, - .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes), - .input_mux = &alc882_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc885_mba21_setup, - .init_hook = alc_hp_automute, - }, - [ALC885_MBP3] = { - .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer }, - .init_verbs = { alc885_mbp3_init_verbs, - alc880_gpio1_init_verbs }, - .num_dacs = 2, - .dac_nids = alc882_dac_nids, - .hp_nid = 0x04, - .channel_mode = alc885_mbp_4ch_modes, - .num_channel_mode = ARRAY_SIZE(alc885_mbp_4ch_modes), - .input_mux = &alc882_capture_source, - .dig_out_nid = ALC882_DIGOUT_NID, - .dig_in_nid = ALC882_DIGIN_NID, - .unsol_event = alc_sku_unsol_event, - .setup = alc885_mbp3_setup, - .init_hook = alc_hp_automute, - }, - [ALC885_MB5] = { - .mixers = { alc885_mb5_mixer, alc882_chmode_mixer }, - .init_verbs = { alc885_mb5_init_verbs, - alc880_gpio1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .channel_mode = alc885_mb5_6ch_modes, - .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes), - .input_mux = &mb5_capture_source, - .dig_out_nid = ALC882_DIGOUT_NID, - .dig_in_nid = ALC882_DIGIN_NID, - .unsol_event = alc_sku_unsol_event, - .setup = alc885_mb5_setup, - .init_hook = alc_hp_automute, - }, - [ALC885_MACMINI3] = { - .mixers = { alc885_macmini3_mixer, alc882_chmode_mixer }, - .init_verbs = { alc885_macmini3_init_verbs, - alc880_gpio1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .channel_mode = alc885_macmini3_6ch_modes, - .num_channel_mode = ARRAY_SIZE(alc885_macmini3_6ch_modes), - .input_mux = &macmini3_capture_source, - .dig_out_nid = ALC882_DIGOUT_NID, - .dig_in_nid = ALC882_DIGIN_NID, - .unsol_event = alc_sku_unsol_event, - .setup = alc885_macmini3_setup, - .init_hook = alc_hp_automute, - }, - [ALC885_MACPRO] = { - .mixers = { alc882_macpro_mixer }, - .init_verbs = { alc882_macpro_init_verbs }, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .dig_out_nid = ALC882_DIGOUT_NID, - .dig_in_nid = ALC882_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), - .channel_mode = alc882_ch_modes, - .input_mux = &alc882_capture_source, - .init_hook = alc885_macpro_init_hook, - }, - [ALC885_IMAC24] = { - .mixers = { alc885_imac24_mixer }, - .init_verbs = { alc885_imac24_init_verbs }, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .dig_out_nid = ALC882_DIGOUT_NID, - .dig_in_nid = ALC882_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), - .channel_mode = alc882_ch_modes, - .input_mux = &alc882_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc885_imac24_setup, - .init_hook = alc885_imac24_init_hook, - }, - [ALC885_IMAC91] = { - .mixers = {alc885_imac91_mixer}, - .init_verbs = { alc885_imac91_init_verbs, - alc880_gpio1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .channel_mode = alc885_mba21_ch_modes, - .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes), - .input_mux = &alc889A_imac91_capture_source, - .dig_out_nid = ALC882_DIGOUT_NID, - .dig_in_nid = ALC882_DIGIN_NID, - .unsol_event = alc_sku_unsol_event, - .setup = alc885_imac91_setup, - .init_hook = alc_hp_automute, - }, - [ALC882_TARGA] = { - .mixers = { alc882_targa_mixer, alc882_chmode_mixer }, - .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs, - alc880_gpio3_init_verbs, alc882_targa_verbs}, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .dig_out_nid = ALC882_DIGOUT_NID, - .num_adc_nids = ARRAY_SIZE(alc882_adc_nids), - .adc_nids = alc882_adc_nids, - .capsrc_nids = alc882_capsrc_nids, - .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes), - .channel_mode = alc882_3ST_6ch_modes, - .need_dac_fix = 1, - .input_mux = &alc882_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc882_targa_setup, - .init_hook = alc882_targa_automute, - }, - [ALC882_ASUS_A7J] = { - .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer }, - .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs, - alc882_asus_a7j_verbs}, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .dig_out_nid = ALC882_DIGOUT_NID, - .num_adc_nids = ARRAY_SIZE(alc882_adc_nids), - .adc_nids = alc882_adc_nids, - .capsrc_nids = alc882_capsrc_nids, - .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes), - .channel_mode = alc882_3ST_6ch_modes, - .need_dac_fix = 1, - .input_mux = &alc882_capture_source, - }, - [ALC882_ASUS_A7M] = { - .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer }, - .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs, - alc882_eapd_verbs, alc880_gpio1_init_verbs, - alc882_asus_a7m_verbs }, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .dig_out_nid = ALC882_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), - .channel_mode = alc880_threestack_modes, - .need_dac_fix = 1, - .input_mux = &alc882_capture_source, - }, - [ALC883_3ST_2ch_DIG] = { - .mixers = { alc883_3ST_2ch_mixer }, - .init_verbs = { alc883_init_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .dig_in_nid = ALC883_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .input_mux = &alc883_capture_source, - }, - [ALC883_3ST_6ch_DIG] = { - .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .dig_in_nid = ALC883_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), - .channel_mode = alc883_3ST_6ch_modes, - .need_dac_fix = 1, - .input_mux = &alc883_capture_source, - }, - [ALC883_3ST_6ch] = { - .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), - .channel_mode = alc883_3ST_6ch_modes, - .need_dac_fix = 1, - .input_mux = &alc883_capture_source, - }, - [ALC883_3ST_6ch_INTEL] = { - .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .dig_in_nid = ALC883_DIGIN_NID, - .slave_dig_outs = alc883_slave_dig_outs, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes), - .channel_mode = alc883_3ST_6ch_intel_modes, - .need_dac_fix = 1, - .input_mux = &alc883_3stack_6ch_intel, - }, - [ALC889A_INTEL] = { - .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer }, - .init_verbs = { alc885_init_verbs, alc885_init_input_verbs, - alc_hp15_unsol_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc889_adc_nids), - .adc_nids = alc889_adc_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .dig_in_nid = ALC883_DIGIN_NID, - .slave_dig_outs = alc883_slave_dig_outs, - .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes), - .channel_mode = alc889_8ch_intel_modes, - .capsrc_nids = alc889_capsrc_nids, - .input_mux = &alc889_capture_source, - .setup = alc889_automute_setup, - .init_hook = alc_hp_automute, - .unsol_event = alc_sku_unsol_event, - .need_dac_fix = 1, - }, - [ALC889_INTEL] = { - .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer }, - .init_verbs = { alc885_init_verbs, alc889_init_input_verbs, - alc889_eapd_verbs, alc_hp15_unsol_verbs}, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc889_adc_nids), - .adc_nids = alc889_adc_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .dig_in_nid = ALC883_DIGIN_NID, - .slave_dig_outs = alc883_slave_dig_outs, - .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes), - .channel_mode = alc889_8ch_intel_modes, - .capsrc_nids = alc889_capsrc_nids, - .input_mux = &alc889_capture_source, - .setup = alc889_automute_setup, - .init_hook = alc889_intel_init_hook, - .unsol_event = alc_sku_unsol_event, - .need_dac_fix = 1, - }, - [ALC883_6ST_DIG] = { - .mixers = { alc883_base_mixer, alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .dig_in_nid = ALC883_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), - .channel_mode = alc883_sixstack_modes, - .input_mux = &alc883_capture_source, - }, - [ALC883_TARGA_DIG] = { - .mixers = { alc883_targa_mixer, alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs, - alc883_targa_verbs}, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), - .channel_mode = alc883_3ST_6ch_modes, - .need_dac_fix = 1, - .input_mux = &alc883_capture_source, - .unsol_event = alc883_targa_unsol_event, - .setup = alc882_targa_setup, - .init_hook = alc882_targa_automute, - }, - [ALC883_TARGA_2ch_DIG] = { - .mixers = { alc883_targa_2ch_mixer}, - .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs, - alc883_targa_verbs}, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .adc_nids = alc883_adc_nids_alt, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt), - .capsrc_nids = alc883_capsrc_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .input_mux = &alc883_capture_source, - .unsol_event = alc883_targa_unsol_event, - .setup = alc882_targa_setup, - .init_hook = alc882_targa_automute, - }, - [ALC883_TARGA_8ch_DIG] = { - .mixers = { alc883_targa_mixer, alc883_targa_8ch_mixer, - alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs, - alc883_targa_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev), - .adc_nids = alc883_adc_nids_rev, - .capsrc_nids = alc883_capsrc_nids_rev, - .dig_out_nid = ALC883_DIGOUT_NID, - .dig_in_nid = ALC883_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc883_4ST_8ch_modes), - .channel_mode = alc883_4ST_8ch_modes, - .need_dac_fix = 1, - .input_mux = &alc883_capture_source, - .unsol_event = alc883_targa_unsol_event, - .setup = alc882_targa_setup, - .init_hook = alc882_targa_automute, - }, - [ALC883_ACER] = { - .mixers = { alc883_base_mixer }, - /* On TravelMate laptops, GPIO 0 enables the internal speaker - * and the headphone jack. Turn this on and rely on the - * standard mute methods whenever the user wants to turn - * these outputs off. - */ - .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .input_mux = &alc883_capture_source, - }, - [ALC883_ACER_ASPIRE] = { - .mixers = { alc883_acer_aspire_mixer }, - .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .input_mux = &alc883_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc883_acer_aspire_setup, - .init_hook = alc_hp_automute, - }, - [ALC888_ACER_ASPIRE_4930G] = { - .mixers = { alc888_acer_aspire_4930g_mixer, - alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs, - alc888_acer_aspire_4930g_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev), - .adc_nids = alc883_adc_nids_rev, - .capsrc_nids = alc883_capsrc_nids_rev, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), - .channel_mode = alc883_3ST_6ch_modes, - .need_dac_fix = 1, - .const_channel_count = 6, - .num_mux_defs = - ARRAY_SIZE(alc888_2_capture_sources), - .input_mux = alc888_2_capture_sources, - .unsol_event = alc_sku_unsol_event, - .setup = alc888_acer_aspire_4930g_setup, - .init_hook = alc_hp_automute, - }, - [ALC888_ACER_ASPIRE_6530G] = { - .mixers = { alc888_acer_aspire_6530_mixer }, - .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs, - alc888_acer_aspire_6530g_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev), - .adc_nids = alc883_adc_nids_rev, - .capsrc_nids = alc883_capsrc_nids_rev, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .num_mux_defs = - ARRAY_SIZE(alc888_2_capture_sources), - .input_mux = alc888_acer_aspire_6530_sources, - .unsol_event = alc_sku_unsol_event, - .setup = alc888_acer_aspire_6530g_setup, - .init_hook = alc_hp_automute, - }, - [ALC888_ACER_ASPIRE_8930G] = { - .mixers = { alc889_acer_aspire_8930g_mixer, - alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs, - alc889_acer_aspire_8930g_verbs, - alc889_eapd_verbs}, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc889_adc_nids), - .adc_nids = alc889_adc_nids, - .capsrc_nids = alc889_capsrc_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), - .channel_mode = alc883_3ST_6ch_modes, - .need_dac_fix = 1, - .const_channel_count = 6, - .num_mux_defs = - ARRAY_SIZE(alc889_capture_sources), - .input_mux = alc889_capture_sources, - .unsol_event = alc_sku_unsol_event, - .setup = alc889_acer_aspire_8930g_setup, - .init_hook = alc_hp_automute, -#ifdef CONFIG_SND_HDA_POWER_SAVE - .power_hook = alc_power_eapd, -#endif - }, - [ALC888_ACER_ASPIRE_7730G] = { - .mixers = { alc883_3ST_6ch_mixer, - alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs, - alc888_acer_aspire_7730G_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev), - .adc_nids = alc883_adc_nids_rev, - .capsrc_nids = alc883_capsrc_nids_rev, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), - .channel_mode = alc883_3ST_6ch_modes, - .need_dac_fix = 1, - .const_channel_count = 6, - .input_mux = &alc883_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc888_acer_aspire_7730g_setup, - .init_hook = alc_hp_automute, - }, - [ALC883_MEDION] = { - .mixers = { alc883_fivestack_mixer, - alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs, - alc883_medion_eapd_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .adc_nids = alc883_adc_nids_alt, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt), - .capsrc_nids = alc883_capsrc_nids, - .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), - .channel_mode = alc883_sixstack_modes, - .input_mux = &alc883_capture_source, - }, - [ALC883_MEDION_WIM2160] = { - .mixers = { alc883_medion_wim2160_mixer }, - .init_verbs = { alc883_init_verbs, alc883_medion_wim2160_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), - .adc_nids = alc883_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .input_mux = &alc883_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc883_medion_wim2160_setup, - .init_hook = alc_hp_automute, - }, - [ALC883_LAPTOP_EAPD] = { - .mixers = { alc883_base_mixer }, - .init_verbs = { alc883_init_verbs, alc882_eapd_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .input_mux = &alc883_capture_source, - }, - [ALC883_CLEVO_M540R] = { - .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs, alc883_clevo_m540r_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .dig_in_nid = ALC883_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_clevo_modes), - .channel_mode = alc883_3ST_6ch_clevo_modes, - .need_dac_fix = 1, - .input_mux = &alc883_capture_source, - /* This machine has the hardware HP auto-muting, thus - * we need no software mute via unsol event - */ - }, - [ALC883_CLEVO_M720] = { - .mixers = { alc883_clevo_m720_mixer }, - .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .input_mux = &alc883_capture_source, - .unsol_event = alc883_clevo_m720_unsol_event, - .setup = alc883_clevo_m720_setup, - .init_hook = alc883_clevo_m720_init_hook, - }, - [ALC883_LENOVO_101E_2ch] = { - .mixers = { alc883_lenovo_101e_2ch_mixer}, - .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs}, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .adc_nids = alc883_adc_nids_alt, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt), - .capsrc_nids = alc883_capsrc_nids, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .input_mux = &alc883_lenovo_101e_capture_source, - .setup = alc883_lenovo_101e_setup, - .unsol_event = alc_sku_unsol_event, - .init_hook = alc_inithook, - }, - [ALC883_LENOVO_NB0763] = { - .mixers = { alc883_lenovo_nb0763_mixer }, - .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs}, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .need_dac_fix = 1, - .input_mux = &alc883_lenovo_nb0763_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc883_lenovo_nb0763_setup, - .init_hook = alc_hp_automute, - }, - [ALC888_LENOVO_MS7195_DIG] = { - .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs}, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), - .channel_mode = alc883_3ST_6ch_modes, - .need_dac_fix = 1, - .input_mux = &alc883_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc888_lenovo_ms7195_setup, - .init_hook = alc_inithook, - }, - [ALC883_HAIER_W66] = { - .mixers = { alc883_targa_2ch_mixer}, - .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs}, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .input_mux = &alc883_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc883_haier_w66_setup, - .init_hook = alc_hp_automute, - }, - [ALC888_3ST_HP] = { - .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes), - .channel_mode = alc888_3st_hp_modes, - .need_dac_fix = 1, - .input_mux = &alc883_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc888_3st_hp_setup, - .init_hook = alc_hp_automute, - }, - [ALC888_6ST_DELL] = { - .mixers = { alc883_base_mixer, alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .dig_in_nid = ALC883_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), - .channel_mode = alc883_sixstack_modes, - .input_mux = &alc883_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc888_6st_dell_setup, - .init_hook = alc_hp_automute, - }, - [ALC883_MITAC] = { - .mixers = { alc883_mitac_mixer }, - .init_verbs = { alc883_init_verbs, alc883_mitac_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .input_mux = &alc883_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc883_mitac_setup, - .init_hook = alc_hp_automute, - }, - [ALC883_FUJITSU_PI2515] = { - .mixers = { alc883_2ch_fujitsu_pi2515_mixer }, - .init_verbs = { alc883_init_verbs, - alc883_2ch_fujitsu_pi2515_verbs}, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .input_mux = &alc883_fujitsu_pi2515_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc883_2ch_fujitsu_pi2515_setup, - .init_hook = alc_hp_automute, - }, - [ALC888_FUJITSU_XA3530] = { - .mixers = { alc888_base_mixer, alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs, - alc888_fujitsu_xa3530_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev), - .adc_nids = alc883_adc_nids_rev, - .capsrc_nids = alc883_capsrc_nids_rev, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc888_4ST_8ch_intel_modes), - .channel_mode = alc888_4ST_8ch_intel_modes, - .num_mux_defs = - ARRAY_SIZE(alc888_2_capture_sources), - .input_mux = alc888_2_capture_sources, - .unsol_event = alc_sku_unsol_event, - .setup = alc888_fujitsu_xa3530_setup, - .init_hook = alc_hp_automute, - }, - [ALC888_LENOVO_SKY] = { - .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs}, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), - .channel_mode = alc883_sixstack_modes, - .need_dac_fix = 1, - .input_mux = &alc883_lenovo_sky_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc888_lenovo_sky_setup, - .init_hook = alc_hp_automute, - }, - [ALC888_ASUS_M90V] = { - .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .dig_in_nid = ALC883_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), - .channel_mode = alc883_3ST_6ch_modes, - .need_dac_fix = 1, - .input_mux = &alc883_fujitsu_pi2515_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc883_mode2_setup, - .init_hook = alc_inithook, - }, - [ALC888_ASUS_EEE1601] = { - .mixers = { alc883_asus_eee1601_mixer }, - .cap_mixer = alc883_asus_eee1601_cap_mixer, - .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .dig_in_nid = ALC883_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .need_dac_fix = 1, - .input_mux = &alc883_asus_eee1601_capture_source, - .unsol_event = alc_sku_unsol_event, - .init_hook = alc883_eee1601_inithook, - }, - [ALC1200_ASUS_P5Q] = { - .mixers = { alc883_base_mixer, alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC1200_DIGOUT_NID, - .dig_in_nid = ALC883_DIGIN_NID, - .slave_dig_outs = alc1200_slave_dig_outs, - .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), - .channel_mode = alc883_sixstack_modes, - .input_mux = &alc883_capture_source, - }, - [ALC889A_MB31] = { - .mixers = { alc889A_mb31_mixer, alc883_chmode_mixer}, - .init_verbs = { alc883_init_verbs, alc889A_mb31_verbs, - alc880_gpio1_init_verbs }, - .adc_nids = alc883_adc_nids, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), - .capsrc_nids = alc883_capsrc_nids, - .dac_nids = alc883_dac_nids, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .channel_mode = alc889A_mb31_6ch_modes, - .num_channel_mode = ARRAY_SIZE(alc889A_mb31_6ch_modes), - .input_mux = &alc889A_mb31_capture_source, - .dig_out_nid = ALC883_DIGOUT_NID, - .unsol_event = alc889A_mb31_unsol_event, - .init_hook = alc889A_mb31_automute, - }, - [ALC883_SONY_VAIO_TT] = { - .mixers = { alc883_vaiott_mixer }, - .init_verbs = { alc883_init_verbs, alc883_vaiott_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .input_mux = &alc883_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc883_vaiott_setup, - .init_hook = alc_hp_automute, - }, -}; - - diff --git a/trunk/sound/pci/hda/alc_quirks.c b/trunk/sound/pci/hda/alc_quirks.c deleted file mode 100644 index 2be1129cf458..000000000000 --- a/trunk/sound/pci/hda/alc_quirks.c +++ /dev/null @@ -1,467 +0,0 @@ -/* - * Common codes for Realtek codec quirks - * included by patch_realtek.c - */ - -/* - * configuration template - to be copied to the spec instance - */ -struct alc_config_preset { - const struct snd_kcontrol_new *mixers[5]; /* should be identical size - * with spec - */ - const struct snd_kcontrol_new *cap_mixer; /* capture mixer */ - const struct hda_verb *init_verbs[5]; - unsigned int num_dacs; - const hda_nid_t *dac_nids; - hda_nid_t dig_out_nid; /* optional */ - hda_nid_t hp_nid; /* optional */ - const hda_nid_t *slave_dig_outs; - unsigned int num_adc_nids; - const hda_nid_t *adc_nids; - const hda_nid_t *capsrc_nids; - hda_nid_t dig_in_nid; - unsigned int num_channel_mode; - const struct hda_channel_mode *channel_mode; - int need_dac_fix; - int const_channel_count; - unsigned int num_mux_defs; - const struct hda_input_mux *input_mux; - void (*unsol_event)(struct hda_codec *, unsigned int); - void (*setup)(struct hda_codec *); - void (*init_hook)(struct hda_codec *); -#ifdef CONFIG_SND_HDA_POWER_SAVE - const struct hda_amp_list *loopbacks; - void (*power_hook)(struct hda_codec *codec); -#endif -}; - -/* - * channel mode setting - */ -static int alc_ch_mode_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode, - spec->num_channel_mode); -} - -static int alc_ch_mode_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode, - spec->num_channel_mode, - spec->ext_channel_count); -} - -static int alc_ch_mode_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, - spec->num_channel_mode, - &spec->ext_channel_count); - if (err >= 0 && !spec->const_channel_count) { - spec->multiout.max_channels = spec->ext_channel_count; - if (spec->need_dac_fix) - spec->multiout.num_dacs = spec->multiout.max_channels / 2; - } - return err; -} - -/* - * Control the mode of pin widget settings via the mixer. "pc" is used - * instead of "%" to avoid consequences of accidentally treating the % as - * being part of a format specifier. Maximum allowed length of a value is - * 63 characters plus NULL terminator. - * - * Note: some retasking pin complexes seem to ignore requests for input - * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these - * are requested. Therefore order this list so that this behaviour will not - * cause problems when mixer clients move through the enum sequentially. - * NIDs 0x0f and 0x10 have been observed to have this behaviour as of - * March 2006. - */ -static const char * const alc_pin_mode_names[] = { - "Mic 50pc bias", "Mic 80pc bias", - "Line in", "Line out", "Headphone out", -}; -static const unsigned char alc_pin_mode_values[] = { - PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP, -}; -/* The control can present all 5 options, or it can limit the options based - * in the pin being assumed to be exclusively an input or an output pin. In - * addition, "input" pins may or may not process the mic bias option - * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to - * accept requests for bias as of chip versions up to March 2006) and/or - * wiring in the computer. - */ -#define ALC_PIN_DIR_IN 0x00 -#define ALC_PIN_DIR_OUT 0x01 -#define ALC_PIN_DIR_INOUT 0x02 -#define ALC_PIN_DIR_IN_NOMICBIAS 0x03 -#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04 - -/* Info about the pin modes supported by the different pin direction modes. - * For each direction the minimum and maximum values are given. - */ -static const signed char alc_pin_mode_dir_info[5][2] = { - { 0, 2 }, /* ALC_PIN_DIR_IN */ - { 3, 4 }, /* ALC_PIN_DIR_OUT */ - { 0, 4 }, /* ALC_PIN_DIR_INOUT */ - { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */ - { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */ -}; -#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0]) -#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1]) -#define alc_pin_mode_n_items(_dir) \ - (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1) - -static int alc_pin_mode_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - unsigned int item_num = uinfo->value.enumerated.item; - unsigned char dir = (kcontrol->private_value >> 16) & 0xff; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = alc_pin_mode_n_items(dir); - - if (item_numalc_pin_mode_max(dir)) - item_num = alc_pin_mode_min(dir); - strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]); - return 0; -} - -static int alc_pin_mode_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - unsigned int i; - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = kcontrol->private_value & 0xffff; - unsigned char dir = (kcontrol->private_value >> 16) & 0xff; - long *valp = ucontrol->value.integer.value; - unsigned int pinctl = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, - 0x00); - - /* Find enumerated value for current pinctl setting */ - i = alc_pin_mode_min(dir); - while (i <= alc_pin_mode_max(dir) && alc_pin_mode_values[i] != pinctl) - i++; - *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir); - return 0; -} - -static int alc_pin_mode_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - signed int change; - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = kcontrol->private_value & 0xffff; - unsigned char dir = (kcontrol->private_value >> 16) & 0xff; - long val = *ucontrol->value.integer.value; - unsigned int pinctl = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, - 0x00); - - if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir)) - val = alc_pin_mode_min(dir); - - change = pinctl != alc_pin_mode_values[val]; - if (change) { - /* Set pin mode to that requested */ - snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - alc_pin_mode_values[val]); - - /* Also enable the retasking pin's input/output as required - * for the requested pin mode. Enum values of 2 or less are - * input modes. - * - * Dynamically switching the input/output buffers probably - * reduces noise slightly (particularly on input) so we'll - * do it. However, having both input and output buffers - * enabled simultaneously doesn't seem to be problematic if - * this turns out to be necessary in the future. - */ - if (val <= 2) { - snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, HDA_AMP_MUTE); - snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0, - HDA_AMP_MUTE, 0); - } else { - snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0, - HDA_AMP_MUTE, HDA_AMP_MUTE); - snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, 0); - } - } - return change; -} - -#define ALC_PIN_MODE(xname, nid, dir) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ - .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ - .info = alc_pin_mode_info, \ - .get = alc_pin_mode_get, \ - .put = alc_pin_mode_put, \ - .private_value = nid | (dir<<16) } - -/* A switch control for ALC260 GPIO pins. Multiple GPIOs can be ganged - * together using a mask with more than one bit set. This control is - * currently used only by the ALC260 test model. At this stage they are not - * needed for any "production" models. - */ -#ifdef CONFIG_SND_DEBUG -#define alc_gpio_data_info snd_ctl_boolean_mono_info - -static int alc_gpio_data_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = kcontrol->private_value & 0xffff; - unsigned char mask = (kcontrol->private_value >> 16) & 0xff; - long *valp = ucontrol->value.integer.value; - unsigned int val = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_GPIO_DATA, 0x00); - - *valp = (val & mask) != 0; - return 0; -} -static int alc_gpio_data_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - signed int change; - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = kcontrol->private_value & 0xffff; - unsigned char mask = (kcontrol->private_value >> 16) & 0xff; - long val = *ucontrol->value.integer.value; - unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_GPIO_DATA, - 0x00); - - /* Set/unset the masked GPIO bit(s) as needed */ - change = (val == 0 ? 0 : mask) != (gpio_data & mask); - if (val == 0) - gpio_data &= ~mask; - else - gpio_data |= mask; - snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_GPIO_DATA, gpio_data); - - return change; -} -#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ - .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ - .info = alc_gpio_data_info, \ - .get = alc_gpio_data_get, \ - .put = alc_gpio_data_put, \ - .private_value = nid | (mask<<16) } -#endif /* CONFIG_SND_DEBUG */ - -/* A switch control to allow the enabling of the digital IO pins on the - * ALC260. This is incredibly simplistic; the intention of this control is - * to provide something in the test model allowing digital outputs to be - * identified if present. If models are found which can utilise these - * outputs a more complete mixer control can be devised for those models if - * necessary. - */ -#ifdef CONFIG_SND_DEBUG -#define alc_spdif_ctrl_info snd_ctl_boolean_mono_info - -static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = kcontrol->private_value & 0xffff; - unsigned char mask = (kcontrol->private_value >> 16) & 0xff; - long *valp = ucontrol->value.integer.value; - unsigned int val = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_DIGI_CONVERT_1, 0x00); - - *valp = (val & mask) != 0; - return 0; -} -static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - signed int change; - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = kcontrol->private_value & 0xffff; - unsigned char mask = (kcontrol->private_value >> 16) & 0xff; - long val = *ucontrol->value.integer.value; - unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_DIGI_CONVERT_1, - 0x00); - - /* Set/unset the masked control bit(s) as needed */ - change = (val == 0 ? 0 : mask) != (ctrl_data & mask); - if (val==0) - ctrl_data &= ~mask; - else - ctrl_data |= mask; - snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, - ctrl_data); - - return change; -} -#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ - .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ - .info = alc_spdif_ctrl_info, \ - .get = alc_spdif_ctrl_get, \ - .put = alc_spdif_ctrl_put, \ - .private_value = nid | (mask<<16) } -#endif /* CONFIG_SND_DEBUG */ - -/* A switch control to allow the enabling EAPD digital outputs on the ALC26x. - * Again, this is only used in the ALC26x test models to help identify when - * the EAPD line must be asserted for features to work. - */ -#ifdef CONFIG_SND_DEBUG -#define alc_eapd_ctrl_info snd_ctl_boolean_mono_info - -static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = kcontrol->private_value & 0xffff; - unsigned char mask = (kcontrol->private_value >> 16) & 0xff; - long *valp = ucontrol->value.integer.value; - unsigned int val = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_EAPD_BTLENABLE, 0x00); - - *valp = (val & mask) != 0; - return 0; -} - -static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - int change; - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = kcontrol->private_value & 0xffff; - unsigned char mask = (kcontrol->private_value >> 16) & 0xff; - long val = *ucontrol->value.integer.value; - unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_EAPD_BTLENABLE, - 0x00); - - /* Set/unset the masked control bit(s) as needed */ - change = (!val ? 0 : mask) != (ctrl_data & mask); - if (!val) - ctrl_data &= ~mask; - else - ctrl_data |= mask; - snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE, - ctrl_data); - - return change; -} - -#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ - .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ - .info = alc_eapd_ctrl_info, \ - .get = alc_eapd_ctrl_get, \ - .put = alc_eapd_ctrl_put, \ - .private_value = nid | (mask<<16) } -#endif /* CONFIG_SND_DEBUG */ - -static void alc_fixup_autocfg_pin_nums(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - - if (!cfg->line_outs) { - while (cfg->line_outs < AUTO_CFG_MAX_OUTS && - cfg->line_out_pins[cfg->line_outs]) - cfg->line_outs++; - } - if (!cfg->speaker_outs) { - while (cfg->speaker_outs < AUTO_CFG_MAX_OUTS && - cfg->speaker_pins[cfg->speaker_outs]) - cfg->speaker_outs++; - } - if (!cfg->hp_outs) { - while (cfg->hp_outs < AUTO_CFG_MAX_OUTS && - cfg->hp_pins[cfg->hp_outs]) - cfg->hp_outs++; - } -} - -/* - * set up from the preset table - */ -static void setup_preset(struct hda_codec *codec, - const struct alc_config_preset *preset) -{ - struct alc_spec *spec = codec->spec; - int i; - - for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++) - add_mixer(spec, preset->mixers[i]); - spec->cap_mixer = preset->cap_mixer; - for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i]; - i++) - add_verb(spec, preset->init_verbs[i]); - - spec->channel_mode = preset->channel_mode; - spec->num_channel_mode = preset->num_channel_mode; - spec->need_dac_fix = preset->need_dac_fix; - spec->const_channel_count = preset->const_channel_count; - - if (preset->const_channel_count) - spec->multiout.max_channels = preset->const_channel_count; - else - spec->multiout.max_channels = spec->channel_mode[0].channels; - spec->ext_channel_count = spec->channel_mode[0].channels; - - spec->multiout.num_dacs = preset->num_dacs; - spec->multiout.dac_nids = preset->dac_nids; - spec->multiout.dig_out_nid = preset->dig_out_nid; - spec->multiout.slave_dig_outs = preset->slave_dig_outs; - spec->multiout.hp_nid = preset->hp_nid; - - spec->num_mux_defs = preset->num_mux_defs; - if (!spec->num_mux_defs) - spec->num_mux_defs = 1; - spec->input_mux = preset->input_mux; - - spec->num_adc_nids = preset->num_adc_nids; - spec->adc_nids = preset->adc_nids; - spec->capsrc_nids = preset->capsrc_nids; - spec->dig_in_nid = preset->dig_in_nid; - - spec->unsol_event = preset->unsol_event; - spec->init_hook = preset->init_hook; -#ifdef CONFIG_SND_HDA_POWER_SAVE - spec->power_hook = preset->power_hook; - spec->loopback.amplist = preset->loopbacks; -#endif - - if (preset->setup) - preset->setup(codec); - - alc_fixup_autocfg_pin_nums(codec); -} - - -/* auto-toggle front mic */ -static void alc88x_simple_mic_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_jack_detect(codec, 0x18); - bits = present ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits); -} - diff --git a/trunk/sound/pci/hda/hda_codec.c b/trunk/sound/pci/hda/hda_codec.c index 9c27a3a4c4d5..45b4a8d70e08 100644 --- a/trunk/sound/pci/hda/hda_codec.c +++ b/trunk/sound/pci/hda/hda_codec.c @@ -243,8 +243,7 @@ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, { unsigned cmd = make_codec_cmd(codec, nid, direct, verb, parm); unsigned int res; - if (codec_exec_verb(codec, cmd, &res)) - return -1; + codec_exec_verb(codec, cmd, &res); return res; } EXPORT_SYMBOL_HDA(snd_hda_codec_read); @@ -308,107 +307,63 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, } EXPORT_SYMBOL_HDA(snd_hda_get_sub_nodes); -/* look up the cached results */ -static hda_nid_t *lookup_conn_list(struct snd_array *array, hda_nid_t nid) -{ - int i, len; - for (i = 0; i < array->used; ) { - hda_nid_t *p = snd_array_elem(array, i); - if (nid == *p) - return p; - len = p[1]; - i += len + 2; - } - return NULL; -} +static int _hda_get_connections(struct hda_codec *codec, hda_nid_t nid, + hda_nid_t *conn_list, int max_conns); +static bool add_conn_list(struct snd_array *array, hda_nid_t nid); +static int copy_conn_list(hda_nid_t nid, hda_nid_t *dst, int max_dst, + hda_nid_t *src, int len); /** - * snd_hda_get_conn_list - get connection list + * snd_hda_get_connections - get connection list * @codec: the HDA codec * @nid: NID to parse - * @listp: the pointer to store NID list + * @conn_list: connection list array + * @max_conns: max. number of connections to store * * Parses the connection list of the given widget and stores the list * of NIDs. * * Returns the number of connections, or a negative error code. */ -int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid, - const hda_nid_t **listp) +int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, + hda_nid_t *conn_list, int max_conns) { struct snd_array *array = &codec->conn_lists; - int len, err; + int i, len, old_used; hda_nid_t list[HDA_MAX_CONNECTIONS]; - hda_nid_t *p; - bool added = false; - again: - /* if the connection-list is already cached, read it */ - p = lookup_conn_list(array, nid); - if (p) { - if (listp) - *listp = p + 2; - return p[1]; + /* look up the cached results */ + for (i = 0; i < array->used; ) { + hda_nid_t *p = snd_array_elem(array, i); + len = p[1]; + if (nid == *p) + return copy_conn_list(nid, conn_list, max_conns, + p + 2, len); + i += len + 2; } - if (snd_BUG_ON(added)) - return -EINVAL; - /* read the connection and add to the cache */ - len = snd_hda_get_raw_connections(codec, nid, list, HDA_MAX_CONNECTIONS); + len = _hda_get_connections(codec, nid, list, HDA_MAX_CONNECTIONS); if (len < 0) return len; - err = snd_hda_override_conn_list(codec, nid, len, list); - if (err < 0) - return err; - added = true; - goto again; -} -EXPORT_SYMBOL_HDA(snd_hda_get_conn_list); -/** - * snd_hda_get_connections - copy connection list - * @codec: the HDA codec - * @nid: NID to parse - * @conn_list: connection list array - * @max_conns: max. number of connections to store - * - * Parses the connection list of the given widget and stores the list - * of NIDs. - * - * Returns the number of connections, or a negative error code. - */ -int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, - hda_nid_t *conn_list, int max_conns) -{ - const hda_nid_t *list; - int len = snd_hda_get_conn_list(codec, nid, &list); + /* add to the cache */ + old_used = array->used; + if (!add_conn_list(array, nid) || !add_conn_list(array, len)) + goto error_add; + for (i = 0; i < len; i++) + if (!add_conn_list(array, list[i])) + goto error_add; - if (len <= 0) - return len; - if (len > max_conns) { - snd_printk(KERN_ERR "hda_codec: " - "Too many connections %d for NID 0x%x\n", - len, nid); - return -EINVAL; - } - memcpy(conn_list, list, len * sizeof(hda_nid_t)); - return len; + return copy_conn_list(nid, conn_list, max_conns, list, len); + + error_add: + array->used = old_used; + return -ENOMEM; } EXPORT_SYMBOL_HDA(snd_hda_get_connections); -/** - * snd_hda_get_raw_connections - copy connection list without cache - * @codec: the HDA codec - * @nid: NID to parse - * @conn_list: connection list array - * @max_conns: max. number of connections to store - * - * Like snd_hda_get_connections(), copy the connection list but without - * checking through the connection-list cache. - * Currently called only from hda_proc.c, so not exported. - */ -int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid, - hda_nid_t *conn_list, int max_conns) +static int _hda_get_connections(struct hda_codec *codec, hda_nid_t nid, + hda_nid_t *conn_list, int max_conns) { unsigned int parm; int i, conn_len, conns; @@ -421,8 +376,11 @@ int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid, wcaps = get_wcaps(codec, nid); if (!(wcaps & AC_WCAP_CONN_LIST) && - get_wcaps_type(wcaps) != AC_WID_VOL_KNB) - return 0; + get_wcaps_type(wcaps) != AC_WID_VOL_KNB) { + snd_printk(KERN_WARNING "hda_codec: " + "connection list not available for 0x%x\n", nid); + return -EINVAL; + } parm = snd_hda_param_read(codec, nid, AC_PAR_CONNLIST_LEN); if (parm & AC_CLIST_LONG) { @@ -512,77 +470,18 @@ static bool add_conn_list(struct snd_array *array, hda_nid_t nid) return true; } -/** - * snd_hda_override_conn_list - add/modify the connection-list to cache - * @codec: the HDA codec - * @nid: NID to parse - * @len: number of connection list entries - * @list: the list of connection entries - * - * Add or modify the given connection-list to the cache. If the corresponding - * cache already exists, invalidate it and append a new one. - * - * Returns zero or a negative error code. - */ -int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int len, - const hda_nid_t *list) +static int copy_conn_list(hda_nid_t nid, hda_nid_t *dst, int max_dst, + hda_nid_t *src, int len) { - struct snd_array *array = &codec->conn_lists; - hda_nid_t *p; - int i, old_used; - - p = lookup_conn_list(array, nid); - if (p) - *p = -1; /* invalidate the old entry */ - - old_used = array->used; - if (!add_conn_list(array, nid) || !add_conn_list(array, len)) - goto error_add; - for (i = 0; i < len; i++) - if (!add_conn_list(array, list[i])) - goto error_add; - return 0; - - error_add: - array->used = old_used; - return -ENOMEM; -} -EXPORT_SYMBOL_HDA(snd_hda_override_conn_list); - -/** - * snd_hda_get_conn_index - get the connection index of the given NID - * @codec: the HDA codec - * @mux: NID containing the list - * @nid: NID to select - * @recursive: 1 when searching NID recursively, otherwise 0 - * - * Parses the connection list of the widget @mux and checks whether the - * widget @nid is present. If it is, return the connection index. - * Otherwise it returns -1. - */ -int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux, - hda_nid_t nid, int recursive) -{ - hda_nid_t conn[HDA_MAX_NUM_INPUTS]; - int i, nums; - - nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn)); - for (i = 0; i < nums; i++) - if (conn[i] == nid) - return i; - if (!recursive) - return -1; - if (recursive > 5) { - snd_printd("hda_codec: too deep connection for 0x%x\n", nid); - return -1; + if (len > max_dst) { + snd_printk(KERN_ERR "hda_codec: " + "Too many connections %d for NID 0x%x\n", + len, nid); + return -EINVAL; } - recursive++; - for (i = 0; i < nums; i++) - if (snd_hda_get_conn_index(codec, conn[i], nid, recursive) >= 0) - return i; - return -1; + memcpy(dst, src, len * sizeof(hda_nid_t)); + return len; } -EXPORT_SYMBOL_HDA(snd_hda_get_conn_index); /** * snd_hda_queue_unsol_event - add an unsolicited event to queue @@ -1184,7 +1083,6 @@ static void snd_hda_codec_free(struct hda_codec *codec) snd_array_free(&codec->mixers); snd_array_free(&codec->nids); snd_array_free(&codec->conn_lists); - snd_array_free(&codec->spdif_out); codec->bus->caddr_tbl[codec->addr] = NULL; if (codec->patch_ops.free) codec->patch_ops.free(codec); @@ -1246,7 +1144,6 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16); snd_array_init(&codec->cvt_setups, sizeof(struct hda_cvt_setup), 8); snd_array_init(&codec->conn_lists, sizeof(hda_nid_t), 64); - snd_array_init(&codec->spdif_out, sizeof(struct hda_spdif_out), 16); if (codec->bus->modelname) { codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL); if (!codec->modelname) { @@ -2658,13 +2555,11 @@ static int snd_hda_spdif_default_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - int idx = kcontrol->private_value; - struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx); - ucontrol->value.iec958.status[0] = spdif->status & 0xff; - ucontrol->value.iec958.status[1] = (spdif->status >> 8) & 0xff; - ucontrol->value.iec958.status[2] = (spdif->status >> 16) & 0xff; - ucontrol->value.iec958.status[3] = (spdif->status >> 24) & 0xff; + ucontrol->value.iec958.status[0] = codec->spdif_status & 0xff; + ucontrol->value.iec958.status[1] = (codec->spdif_status >> 8) & 0xff; + ucontrol->value.iec958.status[2] = (codec->spdif_status >> 16) & 0xff; + ucontrol->value.iec958.status[3] = (codec->spdif_status >> 24) & 0xff; return 0; } @@ -2749,23 +2644,23 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - int idx = kcontrol->private_value; - struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx); - hda_nid_t nid = spdif->nid; + hda_nid_t nid = kcontrol->private_value; unsigned short val; int change; mutex_lock(&codec->spdif_mutex); - spdif->status = ucontrol->value.iec958.status[0] | + codec->spdif_status = ucontrol->value.iec958.status[0] | ((unsigned int)ucontrol->value.iec958.status[1] << 8) | ((unsigned int)ucontrol->value.iec958.status[2] << 16) | ((unsigned int)ucontrol->value.iec958.status[3] << 24); - val = convert_from_spdif_status(spdif->status); - val |= spdif->ctls & 1; - change = spdif->ctls != val; - spdif->ctls = val; - if (change && nid != (u16)-1) + val = convert_from_spdif_status(codec->spdif_status); + val |= codec->spdif_ctls & 1; + change = codec->spdif_ctls != val; + codec->spdif_ctls = val; + + if (change) set_dig_out_convert(codec, nid, val & 0xff, (val >> 8) & 0xff); + mutex_unlock(&codec->spdif_mutex); return change; } @@ -2776,42 +2671,33 @@ static int snd_hda_spdif_out_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - int idx = kcontrol->private_value; - struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx); - ucontrol->value.integer.value[0] = spdif->ctls & AC_DIG1_ENABLE; + ucontrol->value.integer.value[0] = codec->spdif_ctls & AC_DIG1_ENABLE; return 0; } -static inline void set_spdif_ctls(struct hda_codec *codec, hda_nid_t nid, - int dig1, int dig2) -{ - set_dig_out_convert(codec, nid, dig1, dig2); - /* unmute amp switch (if any) */ - if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) && - (dig1 & AC_DIG1_ENABLE)) - snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, 0); -} - static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - int idx = kcontrol->private_value; - struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx); - hda_nid_t nid = spdif->nid; + hda_nid_t nid = kcontrol->private_value; unsigned short val; int change; mutex_lock(&codec->spdif_mutex); - val = spdif->ctls & ~AC_DIG1_ENABLE; + val = codec->spdif_ctls & ~AC_DIG1_ENABLE; if (ucontrol->value.integer.value[0]) val |= AC_DIG1_ENABLE; - change = spdif->ctls != val; - spdif->ctls = val; - if (change && nid != (u16)-1) - set_spdif_ctls(codec, nid, val & 0xff, -1); + change = codec->spdif_ctls != val; + if (change) { + codec->spdif_ctls = val; + set_dig_out_convert(codec, nid, val & 0xff, -1); + /* unmute amp switch (if any) */ + if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) && + (val & AC_DIG1_ENABLE)) + snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, 0); + } mutex_unlock(&codec->spdif_mutex); return change; } @@ -2858,79 +2744,36 @@ static struct snd_kcontrol_new dig_mixes[] = { * * Returns 0 if successful, or a negative error code. */ -int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, - hda_nid_t associated_nid, - hda_nid_t cvt_nid) +int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid) { int err; struct snd_kcontrol *kctl; struct snd_kcontrol_new *dig_mix; int idx; - struct hda_spdif_out *spdif; idx = find_empty_mixer_ctl_idx(codec, "IEC958 Playback Switch"); if (idx < 0) { printk(KERN_ERR "hda_codec: too many IEC958 outputs\n"); return -EBUSY; } - spdif = snd_array_new(&codec->spdif_out); for (dig_mix = dig_mixes; dig_mix->name; dig_mix++) { kctl = snd_ctl_new1(dig_mix, codec); if (!kctl) return -ENOMEM; kctl->id.index = idx; - kctl->private_value = codec->spdif_out.used - 1; - err = snd_hda_ctl_add(codec, associated_nid, kctl); + kctl->private_value = nid; + err = snd_hda_ctl_add(codec, nid, kctl); if (err < 0) return err; } - spdif->nid = cvt_nid; - spdif->ctls = snd_hda_codec_read(codec, cvt_nid, 0, - AC_VERB_GET_DIGI_CONVERT_1, 0); - spdif->status = convert_to_spdif_status(spdif->ctls); + codec->spdif_ctls = + snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_DIGI_CONVERT_1, 0); + codec->spdif_status = convert_to_spdif_status(codec->spdif_ctls); return 0; } EXPORT_SYMBOL_HDA(snd_hda_create_spdif_out_ctls); -struct hda_spdif_out *snd_hda_spdif_out_of_nid(struct hda_codec *codec, - hda_nid_t nid) -{ - int i; - for (i = 0; i < codec->spdif_out.used; i++) { - struct hda_spdif_out *spdif = - snd_array_elem(&codec->spdif_out, i); - if (spdif->nid == nid) - return spdif; - } - return NULL; -} -EXPORT_SYMBOL_HDA(snd_hda_spdif_out_of_nid); - -void snd_hda_spdif_ctls_unassign(struct hda_codec *codec, int idx) -{ - struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx); - - mutex_lock(&codec->spdif_mutex); - spdif->nid = (u16)-1; - mutex_unlock(&codec->spdif_mutex); -} -EXPORT_SYMBOL_HDA(snd_hda_spdif_ctls_unassign); - -void snd_hda_spdif_ctls_assign(struct hda_codec *codec, int idx, hda_nid_t nid) -{ - struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx); - unsigned short val; - - mutex_lock(&codec->spdif_mutex); - if (spdif->nid != nid) { - spdif->nid = nid; - val = spdif->ctls; - set_spdif_ctls(codec, nid, val & 0xff, (val >> 8) & 0xff); - } - mutex_unlock(&codec->spdif_mutex); -} -EXPORT_SYMBOL_HDA(snd_hda_spdif_ctls_assign); - /* * SPDIF sharing with analog output */ @@ -3513,7 +3356,7 @@ static unsigned int query_stream_param(struct hda_codec *codec, hda_nid_t nid) * * Returns 0 if successful, otherwise a negative error code. */ -int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, +static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, u32 *ratesp, u64 *formatsp, unsigned int *bpsp) { unsigned int i, val, wcaps; @@ -3605,7 +3448,6 @@ int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, return 0; } -EXPORT_SYMBOL_HDA(snd_hda_query_supported_pcm); /** * snd_hda_is_supported_format - Check the validity of the format @@ -4335,12 +4177,10 @@ EXPORT_SYMBOL_HDA(snd_hda_input_mux_put); static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid, unsigned int stream_tag, unsigned int format) { - struct hda_spdif_out *spdif = snd_hda_spdif_out_of_nid(codec, nid); - /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */ - if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE)) + if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) set_dig_out_convert(codec, nid, - spdif->ctls & ~AC_DIG1_ENABLE & 0xff, + codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff, -1); snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format); if (codec->slave_dig_outs) { @@ -4350,9 +4190,9 @@ static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid, format); } /* turn on again (if needed) */ - if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE)) + if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) set_dig_out_convert(codec, nid, - spdif->ctls & 0xff, -1); + codec->spdif_ctls & 0xff, -1); } static void cleanup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid) @@ -4508,8 +4348,6 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, { const hda_nid_t *nids = mout->dac_nids; int chs = substream->runtime->channels; - struct hda_spdif_out *spdif = - snd_hda_spdif_out_of_nid(codec, mout->dig_out_nid); int i; mutex_lock(&codec->spdif_mutex); @@ -4518,7 +4356,7 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, if (chs == 2 && snd_hda_is_supported_format(codec, mout->dig_out_nid, format) && - !(spdif->status & IEC958_AES0_NONAUDIO)) { + !(codec->spdif_status & IEC958_AES0_NONAUDIO)) { mout->dig_out_used = HDA_DIG_ANALOG_DUP; setup_dig_out_stream(codec, mout->dig_out_nid, stream_tag, format); @@ -4690,7 +4528,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, unsigned int wid_caps = get_wcaps(codec, nid); unsigned int wid_type = get_wcaps_type(wid_caps); unsigned int def_conf; - short assoc, loc, conn, dev; + short assoc, loc; /* read all default configuration for pin complex */ if (wid_type != AC_WID_PIN) @@ -4700,19 +4538,10 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, continue; def_conf = snd_hda_codec_get_pincfg(codec, nid); - conn = get_defcfg_connect(def_conf); - if (conn == AC_JACK_PORT_NONE) + if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) continue; loc = get_defcfg_location(def_conf); - dev = get_defcfg_device(def_conf); - - /* workaround for buggy BIOS setups */ - if (dev == AC_JACK_LINE_OUT) { - if (conn == AC_JACK_PORT_FIXED) - dev = AC_JACK_SPEAKER; - } - - switch (dev) { + switch (get_defcfg_device(def_conf)) { case AC_JACK_LINE_OUT: seq = get_defcfg_sequence(def_conf); assoc = get_defcfg_association(def_conf); @@ -5128,15 +4957,17 @@ void *snd_array_new(struct snd_array *array) { if (array->used >= array->alloced) { int num = array->alloced + array->alloc_align; - int size = (num + 1) * array->elem_size; - int oldsize = array->alloced * array->elem_size; void *nlist; if (snd_BUG_ON(num >= 4096)) return NULL; - nlist = krealloc(array->list, size, GFP_KERNEL); + nlist = kcalloc(num + 1, array->elem_size, GFP_KERNEL); if (!nlist) return NULL; - memset(nlist + oldsize, 0, size - oldsize); + if (array->list) { + memcpy(nlist, array->list, + array->elem_size * array->alloced); + kfree(array->list); + } array->list = nlist; array->alloced = num; } diff --git a/trunk/sound/pci/hda/hda_codec.h b/trunk/sound/pci/hda/hda_codec.h index f465e07a4879..59c97306c1de 100644 --- a/trunk/sound/pci/hda/hda_codec.h +++ b/trunk/sound/pci/hda/hda_codec.h @@ -829,7 +829,8 @@ struct hda_codec { struct mutex spdif_mutex; struct mutex control_mutex; - struct snd_array spdif_out; + unsigned int spdif_status; /* IEC958 status bits */ + unsigned short spdif_ctls; /* SPDIF control bits */ unsigned int spdif_in_enable; /* SPDIF input enable? */ const hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */ struct snd_array init_pins; /* initial (BIOS) pin configurations */ @@ -903,16 +904,6 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, hda_nid_t *start_id); int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, hda_nid_t *conn_list, int max_conns); -int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid, - hda_nid_t *conn_list, int max_conns); -int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid, - const hda_nid_t **listp); -int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int nums, - const hda_nid_t *list); -int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux, - hda_nid_t nid, int recursive); -int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, - u32 *ratesp, u64 *formatsp, unsigned int *bpsp); struct hda_verb { hda_nid_t nid; @@ -956,17 +947,6 @@ int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list, hda_nid_t nid, unsigned int cfg); /* for hwdep */ void snd_hda_shutup_pins(struct hda_codec *codec); -/* SPDIF controls */ -struct hda_spdif_out { - hda_nid_t nid; /* Converter nid values relate to */ - unsigned int status; /* IEC958 status bits */ - unsigned short ctls; /* SPDIF control bits */ -}; -struct hda_spdif_out *snd_hda_spdif_out_of_nid(struct hda_codec *codec, - hda_nid_t nid); -void snd_hda_spdif_ctls_unassign(struct hda_codec *codec, int idx); -void snd_hda_spdif_ctls_assign(struct hda_codec *codec, int idx, hda_nid_t nid); - /* * Mixer */ @@ -1017,15 +997,17 @@ int snd_hda_suspend(struct hda_bus *bus); int snd_hda_resume(struct hda_bus *bus); #endif +#ifdef CONFIG_SND_HDA_POWER_SAVE static inline int hda_call_check_power_status(struct hda_codec *codec, hda_nid_t nid) { -#ifdef CONFIG_SND_HDA_POWER_SAVE if (codec->patch_ops.check_power_status) return codec->patch_ops.check_power_status(codec, nid); -#endif return 0; } +#else +#define hda_call_check_power_status(codec, nid) 0 +#endif /* * get widget information diff --git a/trunk/sound/pci/hda/hda_eld.c b/trunk/sound/pci/hda/hda_eld.c index 28ce17d09c33..e3e853153d14 100644 --- a/trunk/sound/pci/hda/hda_eld.c +++ b/trunk/sound/pci/hda/hda_eld.c @@ -580,45 +580,43 @@ void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld) #endif /* CONFIG_PROC_FS */ /* update PCM info based on ELD */ -void snd_hdmi_eld_update_pcm_info(struct hdmi_eld *eld, - struct hda_pcm_stream *hinfo) +void hdmi_eld_update_pcm_info(struct hdmi_eld *eld, struct hda_pcm_stream *pcm, + struct hda_pcm_stream *codec_pars) { - u32 rates; - u64 formats; - unsigned int maxbps; - unsigned int channels_max; int i; /* assume basic audio support (the basic audio flag is not in ELD; * however, all audio capable sinks are required to support basic * audio) */ - rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000; - formats = SNDRV_PCM_FMTBIT_S16_LE; - maxbps = 16; - channels_max = 2; + pcm->rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000; + pcm->formats = SNDRV_PCM_FMTBIT_S16_LE; + pcm->maxbps = 16; + pcm->channels_max = 2; for (i = 0; i < eld->sad_count; i++) { struct cea_sad *a = &eld->sad[i]; - rates |= a->rates; - if (a->channels > channels_max) - channels_max = a->channels; + pcm->rates |= a->rates; + if (a->channels > pcm->channels_max) + pcm->channels_max = a->channels; if (a->format == AUDIO_CODING_TYPE_LPCM) { if (a->sample_bits & AC_SUPPCM_BITS_20) { - formats |= SNDRV_PCM_FMTBIT_S32_LE; - if (maxbps < 20) - maxbps = 20; + pcm->formats |= SNDRV_PCM_FMTBIT_S32_LE; + if (pcm->maxbps < 20) + pcm->maxbps = 20; } if (a->sample_bits & AC_SUPPCM_BITS_24) { - formats |= SNDRV_PCM_FMTBIT_S32_LE; - if (maxbps < 24) - maxbps = 24; + pcm->formats |= SNDRV_PCM_FMTBIT_S32_LE; + if (pcm->maxbps < 24) + pcm->maxbps = 24; } } } + if (!codec_pars) + return; + /* restrict the parameters by the values the codec provides */ - hinfo->rates &= rates; - hinfo->formats &= formats; - hinfo->maxbps = min(hinfo->maxbps, maxbps); - hinfo->channels_max = min(hinfo->channels_max, channels_max); + pcm->rates &= codec_pars->rates; + pcm->formats &= codec_pars->formats; + pcm->channels_max = min(pcm->channels_max, codec_pars->channels_max); + pcm->maxbps = min(pcm->maxbps, codec_pars->maxbps); } diff --git a/trunk/sound/pci/hda/hda_intel.c b/trunk/sound/pci/hda/hda_intel.c index be6982289c0d..486f6deb3eee 100644 --- a/trunk/sound/pci/hda/hda_intel.c +++ b/trunk/sound/pci/hda/hda_intel.c @@ -177,8 +177,7 @@ MODULE_DESCRIPTION("Intel HDA driver"); #define ICH6_REG_INTCTL 0x20 #define ICH6_REG_INTSTS 0x24 #define ICH6_REG_WALLCLK 0x30 /* 24Mhz source */ -#define ICH6_REG_OLD_SSYNC 0x34 /* SSYNC for old ICH */ -#define ICH6_REG_SSYNC 0x38 +#define ICH6_REG_SYNC 0x34 #define ICH6_REG_CORBLBASE 0x40 #define ICH6_REG_CORBUBASE 0x44 #define ICH6_REG_CORBWP 0x48 @@ -480,7 +479,6 @@ enum { #define AZX_DCAPS_POSFIX_VIA (1 << 17) /* Use VIACOMBO as default */ #define AZX_DCAPS_NO_64BIT (1 << 18) /* No 64bit address */ #define AZX_DCAPS_SYNC_WRITE (1 << 19) /* sync each cmd write */ -#define AZX_DCAPS_OLD_SSYNC (1 << 20) /* Old SSYNC reg for ICH */ /* quirks for ATI SB / AMD Hudson */ #define AZX_DCAPS_PRESET_ATI_SB \ @@ -1708,16 +1706,13 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; unsigned int bufsize, period_bytes, format_val, stream_tag; int err; - struct hda_spdif_out *spdif = - snd_hda_spdif_out_of_nid(apcm->codec, hinfo->nid); - unsigned short ctls = spdif ? spdif->ctls : 0; azx_stream_reset(chip, azx_dev); format_val = snd_hda_calc_stream_format(runtime->rate, runtime->channels, runtime->format, hinfo->maxbps, - ctls); + apcm->codec->spdif_ctls); if (!format_val) { snd_printk(KERN_ERR SFX "invalid format_val, rate=%d, ch=%d, format=%d\n", @@ -1797,11 +1792,7 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) spin_lock(&chip->reg_lock); if (nsync > 1) { /* first, set SYNC bits of corresponding streams */ - if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC) - azx_writel(chip, OLD_SSYNC, - azx_readl(chip, OLD_SSYNC) | sbits); - else - azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) | sbits); + azx_writel(chip, SYNC, azx_readl(chip, SYNC) | sbits); } snd_pcm_group_for_each_entry(s, substream) { if (s->pcm->card != substream->pcm->card) @@ -1857,11 +1848,7 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) if (nsync > 1) { spin_lock(&chip->reg_lock); /* reset SYNC bits */ - if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC) - azx_writel(chip, OLD_SSYNC, - azx_readl(chip, OLD_SSYNC) & ~sbits); - else - azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) & ~sbits); + azx_writel(chip, SYNC, azx_readl(chip, SYNC) & ~sbits); spin_unlock(&chip->reg_lock); } return 0; @@ -1876,7 +1863,7 @@ static unsigned int azx_via_get_position(struct azx *chip, unsigned int fifo_size; link_pos = azx_sd_readl(azx_dev, SD_LPIB); - if (azx_dev->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + if (azx_dev->index >= 4) { /* Playback, no problem using link position */ return link_pos; } @@ -1940,17 +1927,6 @@ static unsigned int azx_get_position(struct azx *chip, default: /* use the position buffer */ pos = le32_to_cpu(*azx_dev->posbuf); - if (chip->position_fix[stream] == POS_FIX_AUTO) { - if (!pos || pos == (u32)-1) { - printk(KERN_WARNING - "hda-intel: Invalid position buffer, " - "using LPIB read method instead.\n"); - chip->position_fix[stream] = POS_FIX_LPIB; - pos = azx_sd_readl(azx_dev, SD_LPIB); - } else - chip->position_fix[stream] = POS_FIX_POSBUF; - } - break; } if (pos >= azx_dev->bufsize) @@ -1988,6 +1964,16 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) stream = azx_dev->substream->stream; pos = azx_get_position(chip, azx_dev); + if (chip->position_fix[stream] == POS_FIX_AUTO) { + if (!pos) { + printk(KERN_WARNING + "hda-intel: Invalid position buffer, " + "using LPIB read method instead.\n"); + chip->position_fix[stream] = POS_FIX_LPIB; + pos = azx_get_position(chip, azx_dev); + } else + chip->position_fix[stream] = POS_FIX_POSBUF; + } if (WARN_ONCE(!azx_dev->period_bytes, "hda-intel: zero azx_dev->period_bytes")) @@ -2075,8 +2061,6 @@ static void azx_pcm_free(struct snd_pcm *pcm) } } -#define MAX_PREALLOC_SIZE (32 * 1024 * 1024) - static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, struct hda_pcm *cpcm) @@ -2085,7 +2069,6 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, struct snd_pcm *pcm; struct azx_pcm *apcm; int pcm_dev = cpcm->device; - unsigned int size; int s, err; if (pcm_dev >= HDA_MAX_PCMS) { @@ -2121,12 +2104,9 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, snd_pcm_set_ops(pcm, s, &azx_pcm_ops); } /* buffer pre-allocation */ - size = CONFIG_SND_HDA_PREALLOC_SIZE * 1024; - if (size > MAX_PREALLOC_SIZE) - size = MAX_PREALLOC_SIZE; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(chip->pci), - size, MAX_PREALLOC_SIZE); + 1024 * 64, 32 * 1024 * 1024); return 0; } @@ -2169,7 +2149,7 @@ static int azx_acquire_irq(struct azx *chip, int do_disconnect) { if (request_irq(chip->pci->irq, azx_interrupt, chip->msi ? 0 : IRQF_SHARED, - KBUILD_MODNAME, chip)) { + "hda_intel", chip)) { printk(KERN_ERR "hda-intel: unable to grab IRQ %d, " "disabling device\n", chip->pci->irq); if (do_disconnect) @@ -2367,20 +2347,28 @@ static int azx_dev_free(struct snd_device *device) * white/black-listing for position_fix */ static struct snd_pci_quirk position_fix_list[] __devinitdata = { + SND_PCI_QUIRK(0x1025, 0x009f, "Acer Aspire 5110", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1025, 0x026f, "Acer Aspire 5538", POS_FIX_LPIB), SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_LPIB), SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1028, 0x01f6, "Dell Latitude 131L", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1028, 0x0470, "Dell Inspiron 1120", POS_FIX_LPIB), SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB), SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB), SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS", POS_FIX_LPIB), SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS M2V", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1043, 0x8410, "ASUS", POS_FIX_LPIB), SND_PCI_QUIRK(0x104d, 0x9069, "Sony VPCS11V9E", POS_FIX_LPIB), SND_PCI_QUIRK(0x1106, 0x3288, "ASUS M2V-MX SE", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba A100-259", POS_FIX_LPIB), SND_PCI_QUIRK(0x1297, 0x3166, "Shuttle", POS_FIX_LPIB), SND_PCI_QUIRK(0x1458, 0xa022, "ga-ma770-ud3", POS_FIX_LPIB), SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1565, 0x820f, "Biostar Microtech", POS_FIX_LPIB), SND_PCI_QUIRK(0x1565, 0x8218, "Biostar Microtech", POS_FIX_LPIB), SND_PCI_QUIRK(0x1849, 0x0888, "775Dual-VSTA", POS_FIX_LPIB), SND_PCI_QUIRK(0x8086, 0x2503, "DG965OT AAD63733-203", POS_FIX_LPIB), + SND_PCI_QUIRK(0x8086, 0xd601, "eMachines T5212", POS_FIX_LPIB), {} }; @@ -2827,22 +2815,6 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { /* SCH */ { PCI_DEVICE(0x8086, 0x811b), .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP }, - { PCI_DEVICE(0x8086, 0x2668), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH6 */ - { PCI_DEVICE(0x8086, 0x27d8), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH7 */ - { PCI_DEVICE(0x8086, 0x269a), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ESB2 */ - { PCI_DEVICE(0x8086, 0x284b), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH8 */ - { PCI_DEVICE(0x8086, 0x293e), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH9 */ - { PCI_DEVICE(0x8086, 0x293f), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH9 */ - { PCI_DEVICE(0x8086, 0x3a3e), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH10 */ - { PCI_DEVICE(0x8086, 0x3a6e), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH10 */ /* Generic Intel */ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ANY_ID), .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, @@ -2936,7 +2908,7 @@ MODULE_DEVICE_TABLE(pci, azx_ids); /* pci_driver definition */ static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "HDA Intel", .id_table = azx_ids, .probe = azx_probe, .remove = __devexit_p(azx_remove), diff --git a/trunk/sound/pci/hda/hda_local.h b/trunk/sound/pci/hda/hda_local.h index 88b277e97409..08ec073444e2 100644 --- a/trunk/sound/pci/hda/hda_local.h +++ b/trunk/sound/pci/hda/hda_local.h @@ -212,9 +212,7 @@ int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag, /* * SPDIF I/O */ -int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, - hda_nid_t associated_nid, - hda_nid_t cvt_nid); +int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid); int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid); /* @@ -565,6 +563,7 @@ int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key) * power-management */ +#ifdef CONFIG_SND_HDA_POWER_SAVE void snd_hda_schedule_power_save(struct hda_codec *codec); struct hda_amp_list { @@ -581,6 +580,7 @@ struct hda_loopback_check { int snd_hda_check_amp_list_power(struct hda_codec *codec, struct hda_loopback_check *check, hda_nid_t nid); +#endif /* CONFIG_SND_HDA_POWER_SAVE */ /* * AMP control callbacks @@ -639,8 +639,8 @@ struct hdmi_eld { int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid); int snd_hdmi_get_eld(struct hdmi_eld *, struct hda_codec *, hda_nid_t); void snd_hdmi_show_eld(struct hdmi_eld *eld); -void snd_hdmi_eld_update_pcm_info(struct hdmi_eld *eld, - struct hda_pcm_stream *hinfo); +void hdmi_eld_update_pcm_info(struct hdmi_eld *eld, struct hda_pcm_stream *pcm, + struct hda_pcm_stream *codec_pars); #ifdef CONFIG_PROC_FS int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld, diff --git a/trunk/sound/pci/hda/hda_proc.c b/trunk/sound/pci/hda/hda_proc.c index 2be57b051aa2..bfe74c2fb079 100644 --- a/trunk/sound/pci/hda/hda_proc.c +++ b/trunk/sound/pci/hda/hda_proc.c @@ -636,7 +636,7 @@ static void print_codec_info(struct snd_info_entry *entry, wid_caps |= AC_WCAP_CONN_LIST; if (wid_caps & AC_WCAP_CONN_LIST) - conn_len = snd_hda_get_raw_connections(codec, nid, conn, + conn_len = snd_hda_get_connections(codec, nid, conn, HDA_MAX_CONNECTIONS); if (wid_caps & AC_WCAP_IN_AMP) { diff --git a/trunk/sound/pci/hda/patch_analog.c b/trunk/sound/pci/hda/patch_analog.c index 1362c8ba4d1f..d694e9d4921d 100644 --- a/trunk/sound/pci/hda/patch_analog.c +++ b/trunk/sound/pci/hda/patch_analog.c @@ -213,9 +213,7 @@ static int ad198x_build_controls(struct hda_codec *codec) return err; } if (spec->multiout.dig_out_nid) { - err = snd_hda_create_spdif_out_ctls(codec, - spec->multiout.dig_out_nid, - spec->multiout.dig_out_nid); + err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); if (err < 0) return err; err = snd_hda_create_spdif_share_sw(codec, @@ -1922,8 +1920,7 @@ static int patch_ad1981(struct hda_codec *codec) spec->mixers[0] = ad1981_hp_mixers; spec->num_init_verbs = 2; spec->init_verbs[1] = ad1981_hp_init_verbs; - if (!is_jack_available(codec, 0x0a)) - spec->multiout.dig_out_nid = 0; + spec->multiout.dig_out_nid = 0; spec->input_mux = &ad1981_hp_capture_source; codec->patch_ops.init = ad1981_hp_init; diff --git a/trunk/sound/pci/hda/patch_ca0110.c b/trunk/sound/pci/hda/patch_ca0110.c index 6b406840846e..61b92634b161 100644 --- a/trunk/sound/pci/hda/patch_ca0110.c +++ b/trunk/sound/pci/hda/patch_ca0110.c @@ -240,8 +240,7 @@ static int ca0110_build_controls(struct hda_codec *codec) } if (spec->dig_out) { - err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out, - spec->dig_out); + err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out); if (err < 0) return err; err = snd_hda_create_spdif_share_sw(codec, &spec->multiout); diff --git a/trunk/sound/pci/hda/patch_ca0132.c b/trunk/sound/pci/hda/patch_ca0132.c deleted file mode 100644 index d9a2254ceef6..000000000000 --- a/trunk/sound/pci/hda/patch_ca0132.c +++ /dev/null @@ -1,1097 +0,0 @@ -/* - * HD audio interface patch for Creative CA0132 chip - * - * Copyright (c) 2011, Creative Technology Ltd. - * - * Based on patch_ca0110.c - * Copyright (c) 2008 Takashi Iwai - * - * This driver 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 driver is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include "hda_codec.h" -#include "hda_local.h" - -#define WIDGET_CHIP_CTRL 0x15 -#define WIDGET_DSP_CTRL 0x16 - -#define WUH_MEM_CONNID 10 -#define DSP_MEM_CONNID 16 - -enum hda_cmd_vendor_io { - /* for DspIO node */ - VENDOR_DSPIO_SCP_WRITE_DATA_LOW = 0x000, - VENDOR_DSPIO_SCP_WRITE_DATA_HIGH = 0x100, - - VENDOR_DSPIO_STATUS = 0xF01, - VENDOR_DSPIO_SCP_POST_READ_DATA = 0x702, - VENDOR_DSPIO_SCP_READ_DATA = 0xF02, - VENDOR_DSPIO_DSP_INIT = 0x703, - VENDOR_DSPIO_SCP_POST_COUNT_QUERY = 0x704, - VENDOR_DSPIO_SCP_READ_COUNT = 0xF04, - - /* for ChipIO node */ - VENDOR_CHIPIO_ADDRESS_LOW = 0x000, - VENDOR_CHIPIO_ADDRESS_HIGH = 0x100, - VENDOR_CHIPIO_STREAM_FORMAT = 0x200, - VENDOR_CHIPIO_DATA_LOW = 0x300, - VENDOR_CHIPIO_DATA_HIGH = 0x400, - - VENDOR_CHIPIO_GET_PARAMETER = 0xF00, - VENDOR_CHIPIO_STATUS = 0xF01, - VENDOR_CHIPIO_HIC_POST_READ = 0x702, - VENDOR_CHIPIO_HIC_READ_DATA = 0xF03, - - VENDOR_CHIPIO_CT_EXTENSIONS_ENABLE = 0x70A, - - VENDOR_CHIPIO_PLL_PMU_WRITE = 0x70C, - VENDOR_CHIPIO_PLL_PMU_READ = 0xF0C, - VENDOR_CHIPIO_8051_ADDRESS_LOW = 0x70D, - VENDOR_CHIPIO_8051_ADDRESS_HIGH = 0x70E, - VENDOR_CHIPIO_FLAG_SET = 0x70F, - VENDOR_CHIPIO_FLAGS_GET = 0xF0F, - VENDOR_CHIPIO_PARAMETER_SET = 0x710, - VENDOR_CHIPIO_PARAMETER_GET = 0xF10, - - VENDOR_CHIPIO_PORT_ALLOC_CONFIG_SET = 0x711, - VENDOR_CHIPIO_PORT_ALLOC_SET = 0x712, - VENDOR_CHIPIO_PORT_ALLOC_GET = 0xF12, - VENDOR_CHIPIO_PORT_FREE_SET = 0x713, - - VENDOR_CHIPIO_PARAMETER_EX_ID_GET = 0xF17, - VENDOR_CHIPIO_PARAMETER_EX_ID_SET = 0x717, - VENDOR_CHIPIO_PARAMETER_EX_VALUE_GET = 0xF18, - VENDOR_CHIPIO_PARAMETER_EX_VALUE_SET = 0x718 -}; - -/* - * Control flag IDs - */ -enum control_flag_id { - /* Connection manager stream setup is bypassed/enabled */ - CONTROL_FLAG_C_MGR = 0, - /* DSP DMA is bypassed/enabled */ - CONTROL_FLAG_DMA = 1, - /* 8051 'idle' mode is disabled/enabled */ - CONTROL_FLAG_IDLE_ENABLE = 2, - /* Tracker for the SPDIF-in path is bypassed/enabled */ - CONTROL_FLAG_TRACKER = 3, - /* DigitalOut to Spdif2Out connection is disabled/enabled */ - CONTROL_FLAG_SPDIF2OUT = 4, - /* Digital Microphone is disabled/enabled */ - CONTROL_FLAG_DMIC = 5, - /* ADC_B rate is 48 kHz/96 kHz */ - CONTROL_FLAG_ADC_B_96KHZ = 6, - /* ADC_C rate is 48 kHz/96 kHz */ - CONTROL_FLAG_ADC_C_96KHZ = 7, - /* DAC rate is 48 kHz/96 kHz (affects all DACs) */ - CONTROL_FLAG_DAC_96KHZ = 8, - /* DSP rate is 48 kHz/96 kHz */ - CONTROL_FLAG_DSP_96KHZ = 9, - /* SRC clock is 98 MHz/196 MHz (196 MHz forces rate to 96 KHz) */ - CONTROL_FLAG_SRC_CLOCK_196MHZ = 10, - /* SRC rate is 48 kHz/96 kHz (48 kHz disabled when clock is 196 MHz) */ - CONTROL_FLAG_SRC_RATE_96KHZ = 11, - /* Decode Loop (DSP->SRC->DSP) is disabled/enabled */ - CONTROL_FLAG_DECODE_LOOP = 12, - /* De-emphasis filter on DAC-1 disabled/enabled */ - CONTROL_FLAG_DAC1_DEEMPHASIS = 13, - /* De-emphasis filter on DAC-2 disabled/enabled */ - CONTROL_FLAG_DAC2_DEEMPHASIS = 14, - /* De-emphasis filter on DAC-3 disabled/enabled */ - CONTROL_FLAG_DAC3_DEEMPHASIS = 15, - /* High-pass filter on ADC_B disabled/enabled */ - CONTROL_FLAG_ADC_B_HIGH_PASS = 16, - /* High-pass filter on ADC_C disabled/enabled */ - CONTROL_FLAG_ADC_C_HIGH_PASS = 17, - /* Common mode on Port_A disabled/enabled */ - CONTROL_FLAG_PORT_A_COMMON_MODE = 18, - /* Common mode on Port_D disabled/enabled */ - CONTROL_FLAG_PORT_D_COMMON_MODE = 19, - /* Impedance for ramp generator on Port_A 16 Ohm/10K Ohm */ - CONTROL_FLAG_PORT_A_10KOHM_LOAD = 20, - /* Impedance for ramp generator on Port_D, 16 Ohm/10K Ohm */ - CONTROL_FLAG_PORT_D_10K0HM_LOAD = 21, - /* ASI rate is 48kHz/96kHz */ - CONTROL_FLAG_ASI_96KHZ = 22, - /* DAC power settings able to control attached ports no/yes */ - CONTROL_FLAG_DACS_CONTROL_PORTS = 23, - /* Clock Stop OK reporting is disabled/enabled */ - CONTROL_FLAG_CONTROL_STOP_OK_ENABLE = 24, - /* Number of control flags */ - CONTROL_FLAGS_MAX = (CONTROL_FLAG_CONTROL_STOP_OK_ENABLE+1) -}; - -/* - * Control parameter IDs - */ -enum control_parameter_id { - /* 0: force HDA, 1: allow DSP if HDA Spdif1Out stream is idle */ - CONTROL_PARAM_SPDIF1_SOURCE = 2, - - /* Stream Control */ - - /* Select stream with the given ID */ - CONTROL_PARAM_STREAM_ID = 24, - /* Source connection point for the selected stream */ - CONTROL_PARAM_STREAM_SOURCE_CONN_POINT = 25, - /* Destination connection point for the selected stream */ - CONTROL_PARAM_STREAM_DEST_CONN_POINT = 26, - /* Number of audio channels in the selected stream */ - CONTROL_PARAM_STREAMS_CHANNELS = 27, - /*Enable control for the selected stream */ - CONTROL_PARAM_STREAM_CONTROL = 28, - - /* Connection Point Control */ - - /* Select connection point with the given ID */ - CONTROL_PARAM_CONN_POINT_ID = 29, - /* Connection point sample rate */ - CONTROL_PARAM_CONN_POINT_SAMPLE_RATE = 30, - - /* Node Control */ - - /* Select HDA node with the given ID */ - CONTROL_PARAM_NODE_ID = 31 -}; - -/* - * Dsp Io Status codes - */ -enum hda_vendor_status_dspio { - /* Success */ - VENDOR_STATUS_DSPIO_OK = 0x00, - /* Busy, unable to accept new command, the host must retry */ - VENDOR_STATUS_DSPIO_BUSY = 0x01, - /* SCP command queue is full */ - VENDOR_STATUS_DSPIO_SCP_COMMAND_QUEUE_FULL = 0x02, - /* SCP response queue is empty */ - VENDOR_STATUS_DSPIO_SCP_RESPONSE_QUEUE_EMPTY = 0x03 -}; - -/* - * Chip Io Status codes - */ -enum hda_vendor_status_chipio { - /* Success */ - VENDOR_STATUS_CHIPIO_OK = 0x00, - /* Busy, unable to accept new command, the host must retry */ - VENDOR_STATUS_CHIPIO_BUSY = 0x01 -}; - -/* - * CA0132 sample rate - */ -enum ca0132_sample_rate { - SR_6_000 = 0x00, - SR_8_000 = 0x01, - SR_9_600 = 0x02, - SR_11_025 = 0x03, - SR_16_000 = 0x04, - SR_22_050 = 0x05, - SR_24_000 = 0x06, - SR_32_000 = 0x07, - SR_44_100 = 0x08, - SR_48_000 = 0x09, - SR_88_200 = 0x0A, - SR_96_000 = 0x0B, - SR_144_000 = 0x0C, - SR_176_400 = 0x0D, - SR_192_000 = 0x0E, - SR_384_000 = 0x0F, - - SR_COUNT = 0x10, - - SR_RATE_UNKNOWN = 0x1F -}; - -/* - * Scp Helper function - */ -enum get_set { - IS_SET = 0, - IS_GET = 1, -}; - -/* - * Duplicated from ca0110 codec - */ - -static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac) -{ - if (pin) { - snd_hda_codec_write(codec, pin, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP); - if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP) - snd_hda_codec_write(codec, pin, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_UNMUTE); - } - if (dac) - snd_hda_codec_write(codec, dac, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO); -} - -static void init_input(struct hda_codec *codec, hda_nid_t pin, hda_nid_t adc) -{ - if (pin) { - snd_hda_codec_write(codec, pin, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - PIN_VREF80); - if (get_wcaps(codec, pin) & AC_WCAP_IN_AMP) - snd_hda_codec_write(codec, pin, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_UNMUTE(0)); - } - if (adc) - snd_hda_codec_write(codec, adc, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_UNMUTE(0)); -} - -static char *dirstr[2] = { "Playback", "Capture" }; - -static int _add_switch(struct hda_codec *codec, hda_nid_t nid, const char *pfx, - int chan, int dir) -{ - char namestr[44]; - int type = dir ? HDA_INPUT : HDA_OUTPUT; - struct snd_kcontrol_new knew = - HDA_CODEC_MUTE_MONO(namestr, nid, chan, 0, type); - sprintf(namestr, "%s %s Switch", pfx, dirstr[dir]); - return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec)); -} - -static int _add_volume(struct hda_codec *codec, hda_nid_t nid, const char *pfx, - int chan, int dir) -{ - char namestr[44]; - int type = dir ? HDA_INPUT : HDA_OUTPUT; - struct snd_kcontrol_new knew = - HDA_CODEC_VOLUME_MONO(namestr, nid, chan, 0, type); - sprintf(namestr, "%s %s Volume", pfx, dirstr[dir]); - return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec)); -} - -#define add_out_switch(codec, nid, pfx) _add_switch(codec, nid, pfx, 3, 0) -#define add_out_volume(codec, nid, pfx) _add_volume(codec, nid, pfx, 3, 0) -#define add_in_switch(codec, nid, pfx) _add_switch(codec, nid, pfx, 3, 1) -#define add_in_volume(codec, nid, pfx) _add_volume(codec, nid, pfx, 3, 1) -#define add_mono_switch(codec, nid, pfx, chan) \ - _add_switch(codec, nid, pfx, chan, 0) -#define add_mono_volume(codec, nid, pfx, chan) \ - _add_volume(codec, nid, pfx, chan, 0) -#define add_in_mono_switch(codec, nid, pfx, chan) \ - _add_switch(codec, nid, pfx, chan, 1) -#define add_in_mono_volume(codec, nid, pfx, chan) \ - _add_volume(codec, nid, pfx, chan, 1) - - -/* - * CA0132 specific - */ - -struct ca0132_spec { - struct auto_pin_cfg autocfg; - struct hda_multi_out multiout; - hda_nid_t out_pins[AUTO_CFG_MAX_OUTS]; - hda_nid_t dacs[AUTO_CFG_MAX_OUTS]; - hda_nid_t hp_dac; - hda_nid_t input_pins[AUTO_PIN_LAST]; - hda_nid_t adcs[AUTO_PIN_LAST]; - hda_nid_t dig_out; - hda_nid_t dig_in; - unsigned int num_inputs; - long curr_hp_switch; - long curr_hp_volume[2]; - long curr_speaker_switch; - struct mutex chipio_mutex; - const char *input_labels[AUTO_PIN_LAST]; - struct hda_pcm pcm_rec[2]; /* PCM information */ -}; - -/* Chip access helper function */ -static int chipio_send(struct hda_codec *codec, - unsigned int reg, - unsigned int data) -{ - unsigned int res; - int retry = 50; - - /* send bits of data specified by reg */ - do { - res = snd_hda_codec_read(codec, WIDGET_CHIP_CTRL, 0, - reg, data); - if (res == VENDOR_STATUS_CHIPIO_OK) - return 0; - } while (--retry); - return -EIO; -} - -/* - * Write chip address through the vendor widget -- NOT protected by the Mutex! - */ -static int chipio_write_address(struct hda_codec *codec, - unsigned int chip_addx) -{ - int res; - - /* send low 16 bits of the address */ - res = chipio_send(codec, VENDOR_CHIPIO_ADDRESS_LOW, - chip_addx & 0xffff); - - if (res != -EIO) { - /* send high 16 bits of the address */ - res = chipio_send(codec, VENDOR_CHIPIO_ADDRESS_HIGH, - chip_addx >> 16); - } - - return res; -} - -/* - * Write data through the vendor widget -- NOT protected by the Mutex! - */ - -static int chipio_write_data(struct hda_codec *codec, unsigned int data) -{ - int res; - - /* send low 16 bits of the data */ - res = chipio_send(codec, VENDOR_CHIPIO_DATA_LOW, data & 0xffff); - - if (res != -EIO) { - /* send high 16 bits of the data */ - res = chipio_send(codec, VENDOR_CHIPIO_DATA_HIGH, - data >> 16); - } - - return res; -} - -/* - * Read data through the vendor widget -- NOT protected by the Mutex! - */ -static int chipio_read_data(struct hda_codec *codec, unsigned int *data) -{ - int res; - - /* post read */ - res = chipio_send(codec, VENDOR_CHIPIO_HIC_POST_READ, 0); - - if (res != -EIO) { - /* read status */ - res = chipio_send(codec, VENDOR_CHIPIO_STATUS, 0); - } - - if (res != -EIO) { - /* read data */ - *data = snd_hda_codec_read(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_HIC_READ_DATA, - 0); - } - - return res; -} - -/* - * Write given value to the given address through the chip I/O widget. - * protected by the Mutex - */ -static int chipio_write(struct hda_codec *codec, - unsigned int chip_addx, const unsigned int data) -{ - struct ca0132_spec *spec = codec->spec; - int err; - - mutex_lock(&spec->chipio_mutex); - - /* write the address, and if successful proceed to write data */ - err = chipio_write_address(codec, chip_addx); - if (err < 0) - goto exit; - - err = chipio_write_data(codec, data); - if (err < 0) - goto exit; - -exit: - mutex_unlock(&spec->chipio_mutex); - return err; -} - -/* - * Read the given address through the chip I/O widget - * protected by the Mutex - */ -static int chipio_read(struct hda_codec *codec, - unsigned int chip_addx, unsigned int *data) -{ - struct ca0132_spec *spec = codec->spec; - int err; - - mutex_lock(&spec->chipio_mutex); - - /* write the address, and if successful proceed to write data */ - err = chipio_write_address(codec, chip_addx); - if (err < 0) - goto exit; - - err = chipio_read_data(codec, data); - if (err < 0) - goto exit; - -exit: - mutex_unlock(&spec->chipio_mutex); - return err; -} - -/* - * PCM stuffs - */ -static void ca0132_setup_stream(struct hda_codec *codec, hda_nid_t nid, - u32 stream_tag, - int channel_id, int format) -{ - unsigned int oldval, newval; - - if (!nid) - return; - - snd_printdd("ca0132_setup_stream: " - "NID=0x%x, stream=0x%x, channel=%d, format=0x%x\n", - nid, stream_tag, channel_id, format); - - /* update the format-id if changed */ - oldval = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_STREAM_FORMAT, - 0); - if (oldval != format) { - msleep(20); - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_STREAM_FORMAT, - format); - } - - oldval = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0); - newval = (stream_tag << 4) | channel_id; - if (oldval != newval) { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_CHANNEL_STREAMID, - newval); - } -} - -static void ca0132_cleanup_stream(struct hda_codec *codec, hda_nid_t nid) -{ - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, 0); - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0); -} - -/* - * PCM callbacks - */ -static int ca0132_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct ca0132_spec *spec = codec->spec; - - ca0132_setup_stream(codec, spec->dacs[0], stream_tag, 0, format); - - return 0; -} - -static int ca0132_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ca0132_spec *spec = codec->spec; - - ca0132_cleanup_stream(codec, spec->dacs[0]); - - return 0; -} - -/* - * Digital out - */ -static int ca0132_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct ca0132_spec *spec = codec->spec; - - ca0132_setup_stream(codec, spec->dig_out, stream_tag, 0, format); - - return 0; -} - -static int ca0132_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ca0132_spec *spec = codec->spec; - - ca0132_cleanup_stream(codec, spec->dig_out); - - return 0; -} - -/* - * Analog capture - */ -static int ca0132_capture_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct ca0132_spec *spec = codec->spec; - - ca0132_setup_stream(codec, spec->adcs[substream->number], - stream_tag, 0, format); - - return 0; -} - -static int ca0132_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ca0132_spec *spec = codec->spec; - - ca0132_cleanup_stream(codec, spec->adcs[substream->number]); - - return 0; -} - -/* - * Digital capture - */ -static int ca0132_dig_capture_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct ca0132_spec *spec = codec->spec; - - ca0132_setup_stream(codec, spec->dig_in, stream_tag, 0, format); - - return 0; -} - -static int ca0132_dig_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ca0132_spec *spec = codec->spec; - - ca0132_cleanup_stream(codec, spec->dig_in); - - return 0; -} - -/* - */ -static struct hda_pcm_stream ca0132_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .ops = { - .prepare = ca0132_playback_pcm_prepare, - .cleanup = ca0132_playback_pcm_cleanup - }, -}; - -static struct hda_pcm_stream ca0132_pcm_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .ops = { - .prepare = ca0132_capture_pcm_prepare, - .cleanup = ca0132_capture_pcm_cleanup - }, -}; - -static struct hda_pcm_stream ca0132_pcm_digital_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .ops = { - .prepare = ca0132_dig_playback_pcm_prepare, - .cleanup = ca0132_dig_playback_pcm_cleanup - }, -}; - -static struct hda_pcm_stream ca0132_pcm_digital_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .ops = { - .prepare = ca0132_dig_capture_pcm_prepare, - .cleanup = ca0132_dig_capture_pcm_cleanup - }, -}; - -static int ca0132_build_pcms(struct hda_codec *codec) -{ - struct ca0132_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; - - codec->pcm_info = info; - codec->num_pcms = 0; - - info->name = "CA0132 Analog"; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ca0132_pcm_analog_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dacs[0]; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = - spec->multiout.max_channels; - info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_inputs; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0]; - codec->num_pcms++; - - if (!spec->dig_out && !spec->dig_in) - return 0; - - info++; - info->name = "CA0132 Digital"; - info->pcm_type = HDA_PCM_TYPE_SPDIF; - if (spec->dig_out) { - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = - ca0132_pcm_digital_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dig_out; - } - if (spec->dig_in) { - info->stream[SNDRV_PCM_STREAM_CAPTURE] = - ca0132_pcm_digital_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in; - } - codec->num_pcms++; - - return 0; -} - -#define REG_CODEC_MUTE 0x18b014 -#define REG_CODEC_HP_VOL_L 0x18b070 -#define REG_CODEC_HP_VOL_R 0x18b074 - -static int ca0132_hp_switch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ca0132_spec *spec = codec->spec; - long *valp = ucontrol->value.integer.value; - - *valp = spec->curr_hp_switch; - return 0; -} - -static int ca0132_hp_switch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ca0132_spec *spec = codec->spec; - long *valp = ucontrol->value.integer.value; - unsigned int data; - int err; - - /* any change? */ - if (spec->curr_hp_switch == *valp) - return 0; - - snd_hda_power_up(codec); - - err = chipio_read(codec, REG_CODEC_MUTE, &data); - if (err < 0) - return err; - - /* *valp 0 is mute, 1 is unmute */ - data = (data & 0x7f) | (*valp ? 0 : 0x80); - chipio_write(codec, REG_CODEC_MUTE, data); - if (err < 0) - return err; - - spec->curr_hp_switch = *valp; - - snd_hda_power_down(codec); - return 1; -} - -static int ca0132_speaker_switch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ca0132_spec *spec = codec->spec; - long *valp = ucontrol->value.integer.value; - - *valp = spec->curr_speaker_switch; - return 0; -} - -static int ca0132_speaker_switch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ca0132_spec *spec = codec->spec; - long *valp = ucontrol->value.integer.value; - unsigned int data; - int err; - - /* any change? */ - if (spec->curr_speaker_switch == *valp) - return 0; - - snd_hda_power_up(codec); - - err = chipio_read(codec, REG_CODEC_MUTE, &data); - if (err < 0) - return err; - - /* *valp 0 is mute, 1 is unmute */ - data = (data & 0xef) | (*valp ? 0 : 0x10); - chipio_write(codec, REG_CODEC_MUTE, data); - if (err < 0) - return err; - - spec->curr_speaker_switch = *valp; - - snd_hda_power_down(codec); - return 1; -} - -static int ca0132_hp_volume_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ca0132_spec *spec = codec->spec; - long *valp = ucontrol->value.integer.value; - - *valp++ = spec->curr_hp_volume[0]; - *valp = spec->curr_hp_volume[1]; - return 0; -} - -static int ca0132_hp_volume_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ca0132_spec *spec = codec->spec; - long *valp = ucontrol->value.integer.value; - long left_vol, right_vol; - unsigned int data; - int val; - int err; - - left_vol = *valp++; - right_vol = *valp; - - /* any change? */ - if ((spec->curr_hp_volume[0] == left_vol) && - (spec->curr_hp_volume[1] == right_vol)) - return 0; - - snd_hda_power_up(codec); - - err = chipio_read(codec, REG_CODEC_HP_VOL_L, &data); - if (err < 0) - return err; - - val = 31 - left_vol; - data = (data & 0xe0) | val; - chipio_write(codec, REG_CODEC_HP_VOL_L, data); - if (err < 0) - return err; - - val = 31 - right_vol; - data = (data & 0xe0) | val; - chipio_write(codec, REG_CODEC_HP_VOL_R, data); - if (err < 0) - return err; - - spec->curr_hp_volume[0] = left_vol; - spec->curr_hp_volume[1] = right_vol; - - snd_hda_power_down(codec); - return 1; -} - -static int add_hp_switch(struct hda_codec *codec, hda_nid_t nid) -{ - struct snd_kcontrol_new knew = - HDA_CODEC_MUTE_MONO("Headphone Playback Switch", - nid, 1, 0, HDA_OUTPUT); - knew.get = ca0132_hp_switch_get; - knew.put = ca0132_hp_switch_put; - return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec)); -} - -static int add_hp_volume(struct hda_codec *codec, hda_nid_t nid) -{ - struct snd_kcontrol_new knew = - HDA_CODEC_VOLUME_MONO("Headphone Playback Volume", - nid, 3, 0, HDA_OUTPUT); - knew.get = ca0132_hp_volume_get; - knew.put = ca0132_hp_volume_put; - return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec)); -} - -static int add_speaker_switch(struct hda_codec *codec, hda_nid_t nid) -{ - struct snd_kcontrol_new knew = - HDA_CODEC_MUTE_MONO("Speaker Playback Switch", - nid, 1, 0, HDA_OUTPUT); - knew.get = ca0132_speaker_switch_get; - knew.put = ca0132_speaker_switch_put; - return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec)); -} - -static void ca0132_fix_hp_caps(struct hda_codec *codec) -{ - struct ca0132_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - unsigned int caps; - - /* set mute-capable, 1db step, 32 steps, ofs 6 */ - caps = 0x80031f06; - snd_hda_override_amp_caps(codec, cfg->hp_pins[0], HDA_OUTPUT, caps); -} - -static int ca0132_build_controls(struct hda_codec *codec) -{ - struct ca0132_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i, err; - - if (spec->multiout.num_dacs) { - err = add_speaker_switch(codec, spec->out_pins[0]); - if (err < 0) - return err; - } - - if (cfg->hp_outs) { - ca0132_fix_hp_caps(codec); - err = add_hp_switch(codec, cfg->hp_pins[0]); - if (err < 0) - return err; - err = add_hp_volume(codec, cfg->hp_pins[0]); - if (err < 0) - return err; - } - - for (i = 0; i < spec->num_inputs; i++) { - const char *label = spec->input_labels[i]; - - err = add_in_switch(codec, spec->adcs[i], label); - if (err < 0) - return err; - err = add_in_volume(codec, spec->adcs[i], label); - if (err < 0) - return err; - if (cfg->inputs[i].type == AUTO_PIN_MIC) { - /* add Mic-Boost */ - err = add_in_mono_volume(codec, spec->input_pins[i], - "Mic Boost", 1); - if (err < 0) - return err; - } - } - - if (spec->dig_out) { - err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out, - spec->dig_out); - if (err < 0) - return err; - err = add_out_volume(codec, spec->dig_out, "IEC958"); - if (err < 0) - return err; - } - - if (spec->dig_in) { - err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in); - if (err < 0) - return err; - err = add_in_volume(codec, spec->dig_in, "IEC958"); - } - return 0; -} - - -static void ca0132_set_ct_ext(struct hda_codec *codec, int enable) -{ - /* Set Creative extension */ - snd_printdd("SET CREATIVE EXTENSION\n"); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_CT_EXTENSIONS_ENABLE, - enable); - msleep(20); -} - - -static void ca0132_config(struct hda_codec *codec) -{ - struct ca0132_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - - /* line-outs */ - cfg->line_outs = 1; - cfg->line_out_pins[0] = 0x0b; /* front */ - cfg->line_out_type = AUTO_PIN_LINE_OUT; - - spec->dacs[0] = 0x02; - spec->out_pins[0] = 0x0b; - spec->multiout.dac_nids = spec->dacs; - spec->multiout.num_dacs = 1; - spec->multiout.max_channels = 2; - - /* headphone */ - cfg->hp_outs = 1; - cfg->hp_pins[0] = 0x0f; - - spec->hp_dac = 0; - spec->multiout.hp_nid = 0; - - /* inputs */ - cfg->num_inputs = 2; /* Mic-in and line-in */ - cfg->inputs[0].pin = 0x12; - cfg->inputs[0].type = AUTO_PIN_MIC; - cfg->inputs[1].pin = 0x11; - cfg->inputs[1].type = AUTO_PIN_LINE_IN; - - /* Mic-in */ - spec->input_pins[0] = 0x12; - spec->input_labels[0] = "Mic-In"; - spec->adcs[0] = 0x07; - - /* Line-In */ - spec->input_pins[1] = 0x11; - spec->input_labels[1] = "Line-In"; - spec->adcs[1] = 0x08; - spec->num_inputs = 2; -} - -static void ca0132_init_chip(struct hda_codec *codec) -{ - struct ca0132_spec *spec = codec->spec; - - mutex_init(&spec->chipio_mutex); -} - -static void ca0132_exit_chip(struct hda_codec *codec) -{ - /* put any chip cleanup stuffs here. */ -} - -static int ca0132_init(struct hda_codec *codec) -{ - struct ca0132_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i; - - for (i = 0; i < spec->multiout.num_dacs; i++) { - init_output(codec, spec->out_pins[i], - spec->multiout.dac_nids[i]); - } - init_output(codec, cfg->hp_pins[0], spec->hp_dac); - init_output(codec, cfg->dig_out_pins[0], spec->dig_out); - - for (i = 0; i < spec->num_inputs; i++) - init_input(codec, spec->input_pins[i], spec->adcs[i]); - - init_input(codec, cfg->dig_in_pin, spec->dig_in); - - ca0132_set_ct_ext(codec, 1); - - return 0; -} - - -static void ca0132_free(struct hda_codec *codec) -{ - ca0132_set_ct_ext(codec, 0); - ca0132_exit_chip(codec); - kfree(codec->spec); -} - -static struct hda_codec_ops ca0132_patch_ops = { - .build_controls = ca0132_build_controls, - .build_pcms = ca0132_build_pcms, - .init = ca0132_init, - .free = ca0132_free, -}; - - - -static int patch_ca0132(struct hda_codec *codec) -{ - struct ca0132_spec *spec; - - snd_printdd("patch_ca0132\n"); - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (!spec) - return -ENOMEM; - codec->spec = spec; - - ca0132_init_chip(codec); - - ca0132_config(codec); - - codec->patch_ops = ca0132_patch_ops; - - return 0; -} - -/* - * patch entries - */ -static struct hda_codec_preset snd_hda_preset_ca0132[] = { - { .id = 0x11020011, .name = "CA0132", .patch = patch_ca0132 }, - {} /* terminator */ -}; - -MODULE_ALIAS("snd-hda-codec-id:11020011"); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Creative CA0132, CA0132 HD-audio codec"); - -static struct hda_codec_preset_list ca0132_list = { - .preset = snd_hda_preset_ca0132, - .owner = THIS_MODULE, -}; - -static int __init patch_ca0132_init(void) -{ - return snd_hda_add_codec_preset(&ca0132_list); -} - -static void __exit patch_ca0132_exit(void) -{ - snd_hda_delete_codec_preset(&ca0132_list); -} - -module_init(patch_ca0132_init) -module_exit(patch_ca0132_exit) diff --git a/trunk/sound/pci/hda/patch_cirrus.c b/trunk/sound/pci/hda/patch_cirrus.c index 7f93739b1e33..26a1521045bb 100644 --- a/trunk/sound/pci/hda/patch_cirrus.c +++ b/trunk/sound/pci/hda/patch_cirrus.c @@ -346,15 +346,21 @@ static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin, nid = codec->start_nid; for (i = 0; i < codec->num_nodes; i++, nid++) { + hda_nid_t pins[2]; unsigned int type; - int idx; + int j, nums; type = get_wcaps_type(get_wcaps(codec, nid)); if (type != AC_WID_AUD_IN) continue; - idx = snd_hda_get_conn_index(codec, nid, pin, 0); - if (idx >= 0) { - *idxp = idx; - return nid; + nums = snd_hda_get_connections(codec, nid, pins, + ARRAY_SIZE(pins)); + if (nums <= 0) + continue; + for (j = 0; j < nums; j++) { + if (pins[j] == pin) { + *idxp = j; + return nid; + } } } return 0; @@ -815,8 +821,7 @@ static int build_digital_output(struct hda_codec *codec) if (!spec->multiout.dig_out_nid) return 0; - err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid, - spec->multiout.dig_out_nid); + err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); if (err < 0) return err; err = snd_hda_create_spdif_share_sw(codec, &spec->multiout); diff --git a/trunk/sound/pci/hda/patch_cmedia.c b/trunk/sound/pci/hda/patch_cmedia.c index cd2cf5e94e81..ab3308daa960 100644 --- a/trunk/sound/pci/hda/patch_cmedia.c +++ b/trunk/sound/pci/hda/patch_cmedia.c @@ -327,9 +327,7 @@ static int cmi9880_build_controls(struct hda_codec *codec) return err; } if (spec->multiout.dig_out_nid) { - err = snd_hda_create_spdif_out_ctls(codec, - spec->multiout.dig_out_nid, - spec->multiout.dig_out_nid); + err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); if (err < 0) return err; err = snd_hda_create_spdif_share_sw(codec, @@ -398,11 +396,12 @@ static int cmi9880_fill_multi_init(struct hda_codec *codec, const struct auto_pi { struct cmi_spec *spec = codec->spec; hda_nid_t nid; - int i, j, k; + int i, j, k, len; /* clear the table, only one c-media dac assumed here */ memset(spec->multi_init, 0, sizeof(spec->multi_init)); for (j = 0, i = 0; i < cfg->line_outs; i++) { + hda_nid_t conn[4]; nid = cfg->line_out_pins[i]; /* set as output */ spec->multi_init[j].nid = nid; @@ -415,10 +414,12 @@ static int cmi9880_fill_multi_init(struct hda_codec *codec, const struct auto_pi spec->multi_init[j].verb = AC_VERB_SET_CONNECT_SEL; spec->multi_init[j].param = 0; /* find the index in connect list */ - k = snd_hda_get_conn_index(codec, nid, - spec->dac_nids[i], 0); - if (k >= 0) - spec->multi_init[j].param = k; + len = snd_hda_get_connections(codec, nid, conn, 4); + for (k = 0; k < len; k++) + if (conn[k] == spec->dac_nids[i]) { + spec->multi_init[j].param = k; + break; + } j++; } } diff --git a/trunk/sound/pci/hda/patch_conexant.c b/trunk/sound/pci/hda/patch_conexant.c index 884f67b8f4e0..7bbc5f237a5e 100644 --- a/trunk/sound/pci/hda/patch_conexant.c +++ b/trunk/sound/pci/hda/patch_conexant.c @@ -155,10 +155,6 @@ struct conexant_spec { unsigned int mic_boost; /* offset into cxt5066_analog_mic_boost */ unsigned int beep_amp; - - /* extra EAPD pins */ - unsigned int num_eapds; - hda_nid_t eapds[4]; }; static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, @@ -514,7 +510,6 @@ static int conexant_build_controls(struct hda_codec *codec) } if (spec->multiout.dig_out_nid) { err = snd_hda_create_spdif_out_ctls(codec, - spec->multiout.dig_out_nid, spec->multiout.dig_out_nid); if (err < 0) return err; @@ -1128,8 +1123,10 @@ static int patch_cxt5045(struct hda_codec *codec) board_config = snd_hda_check_board_config(codec, CXT5045_MODELS, cxt5045_models, cxt5045_cfg_tbl); +#if 0 /* use the old method just for safety */ if (board_config < 0) - board_config = CXT5045_AUTO; /* model=auto as default */ + board_config = CXT5045_AUTO; +#endif if (board_config == CXT5045_AUTO) return patch_conexant_auto(codec); @@ -1567,8 +1564,10 @@ static int patch_cxt5047(struct hda_codec *codec) board_config = snd_hda_check_board_config(codec, CXT5047_MODELS, cxt5047_models, cxt5047_cfg_tbl); +#if 0 /* not enabled as default, as BIOS often broken for this codec */ if (board_config < 0) - board_config = CXT5047_AUTO; /* model=auto as default */ + board_config = CXT5047_AUTO; +#endif if (board_config == CXT5047_AUTO) return patch_conexant_auto(codec); @@ -1994,8 +1993,10 @@ static int patch_cxt5051(struct hda_codec *codec) board_config = snd_hda_check_board_config(codec, CXT5051_MODELS, cxt5051_models, cxt5051_cfg_tbl); +#if 0 /* use the old method just for safety */ if (board_config < 0) - board_config = CXT5051_AUTO; /* model=auto as default */ + board_config = CXT5051_AUTO; +#endif if (board_config == CXT5051_AUTO) return patch_conexant_auto(codec); @@ -3113,8 +3114,10 @@ static int patch_cxt5066(struct hda_codec *codec) board_config = snd_hda_check_board_config(codec, CXT5066_MODELS, cxt5066_models, cxt5066_cfg_tbl); +#if 0 /* use the old method just for safety */ if (board_config < 0) - board_config = CXT5066_AUTO; /* model=auto as default */ + board_config = CXT5066_AUTO; +#endif if (board_config == CXT5066_AUTO) return patch_conexant_auto(codec); @@ -3305,8 +3308,19 @@ static const struct hda_pcm_stream cx_auto_pcm_analog_capture = { static const hda_nid_t cx_auto_adc_nids[] = { 0x14 }; -#define get_connection_index(codec, mux, nid)\ - snd_hda_get_conn_index(codec, mux, nid, 0) +/* get the connection index of @nid in the widget @mux */ +static int get_connection_index(struct hda_codec *codec, hda_nid_t mux, + hda_nid_t nid) +{ + hda_nid_t conn[HDA_MAX_NUM_INPUTS]; + int i, nums; + + nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn)); + for (i = 0; i < nums; i++) + if (conn[i] == nid) + return i; + return -1; +} /* get an unassigned DAC from the given list. * Return the nid if found and reduce the DAC list, or return zero if @@ -3905,38 +3919,6 @@ static void cx_auto_parse_beep(struct hda_codec *codec) #define cx_auto_parse_beep(codec) #endif -static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) -{ - int i; - for (i = 0; i < nums; i++) - if (list[i] == nid) - return true; - return false; -} - -/* parse extra-EAPD that aren't assigned to any pins */ -static void cx_auto_parse_eapd(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t nid, end_nid; - - end_nid = codec->start_nid + codec->num_nodes; - for (nid = codec->start_nid; nid < end_nid; nid++) { - if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN) - continue; - if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)) - continue; - if (found_in_nid_list(nid, cfg->line_out_pins, cfg->line_outs) || - found_in_nid_list(nid, cfg->hp_pins, cfg->hp_outs) || - found_in_nid_list(nid, cfg->speaker_pins, cfg->speaker_outs)) - continue; - spec->eapds[spec->num_eapds++] = nid; - if (spec->num_eapds >= ARRAY_SIZE(spec->eapds)) - break; - } -} - static int cx_auto_parse_auto_config(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; @@ -3950,7 +3932,6 @@ static int cx_auto_parse_auto_config(struct hda_codec *codec) cx_auto_parse_input(codec); cx_auto_parse_digital(codec); cx_auto_parse_beep(codec); - cx_auto_parse_eapd(codec); return 0; } @@ -4038,8 +4019,6 @@ static void cx_auto_init_output(struct hda_codec *codec) } } cx_auto_update_speakers(codec); - /* turn on/off extra EAPDs, too */ - cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true); } static void cx_auto_init_input(struct hda_codec *codec) diff --git a/trunk/sound/pci/hda/patch_hdmi.c b/trunk/sound/pci/hda/patch_hdmi.c index 19cb72db9c38..bd0ae697f9c4 100644 --- a/trunk/sound/pci/hda/patch_hdmi.c +++ b/trunk/sound/pci/hda/patch_hdmi.c @@ -43,7 +43,7 @@ MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info"); /* * The HDMI/DisplayPort configuration can be highly dynamic. A graphics device - * could support N independent pipes, each of them can be connected to one or + * could support two independent pipes, each of them can be connected to one or * more ports (DVI, HDMI or DisplayPort). * * The HDA correspondence of pipes/ports are converter/pin nodes. @@ -51,33 +51,30 @@ MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info"); #define MAX_HDMI_CVTS 4 #define MAX_HDMI_PINS 4 -struct hdmi_spec_per_cvt { - hda_nid_t cvt_nid; - int assigned; - unsigned int channels_min; - unsigned int channels_max; - u32 rates; - u64 formats; - unsigned int maxbps; -}; - -struct hdmi_spec_per_pin { - hda_nid_t pin_nid; - int num_mux_nids; - hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; - struct hdmi_eld sink_eld; -}; - struct hdmi_spec { int num_cvts; - struct hdmi_spec_per_cvt cvts[MAX_HDMI_CVTS]; - int num_pins; - struct hdmi_spec_per_pin pins[MAX_HDMI_PINS]; - struct hda_pcm pcm_rec[MAX_HDMI_PINS]; + hda_nid_t cvt[MAX_HDMI_CVTS+1]; /* audio sources */ + hda_nid_t pin[MAX_HDMI_PINS+1]; /* audio sinks */ + + /* + * source connection for each pin + */ + hda_nid_t pin_cvt[MAX_HDMI_PINS+1]; /* - * Non-generic ATI/NVIDIA specific + * HDMI sink attached to each pin + */ + struct hdmi_eld sink_eld[MAX_HDMI_PINS]; + + /* + * export one pcm per pipe + */ + struct hda_pcm pcm_rec[MAX_HDMI_CVTS]; + struct hda_pcm_stream codec_pcm_pars[MAX_HDMI_CVTS]; + + /* + * ati/nvhdmi specific */ struct hda_multi_out multiout; const struct hda_pcm_stream *pcm_playback; @@ -287,40 +284,15 @@ static struct cea_channel_speaker_allocation channel_allocations[] = { * HDMI routines */ -static int pin_nid_to_pin_index(struct hdmi_spec *spec, hda_nid_t pin_nid) -{ - int pin_idx; - - for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) - if (spec->pins[pin_idx].pin_nid == pin_nid) - return pin_idx; - - snd_printk(KERN_WARNING "HDMI: pin nid %d not registered\n", pin_nid); - return -EINVAL; -} - -static int hinfo_to_pin_index(struct hdmi_spec *spec, - struct hda_pcm_stream *hinfo) -{ - int pin_idx; - - for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) - if (&spec->pcm_rec[pin_idx].stream[0] == hinfo) - return pin_idx; - - snd_printk(KERN_WARNING "HDMI: hinfo %p not registered\n", hinfo); - return -EINVAL; -} - -static int cvt_nid_to_cvt_index(struct hdmi_spec *spec, hda_nid_t cvt_nid) +static int hda_node_index(hda_nid_t *nids, hda_nid_t nid) { - int cvt_idx; + int i; - for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) - if (spec->cvts[cvt_idx].cvt_nid == cvt_nid) - return cvt_idx; + for (i = 0; nids[i]; i++) + if (nids[i] == nid) + return i; - snd_printk(KERN_WARNING "HDMI: cvt nid %d not registered\n", cvt_nid); + snd_printk(KERN_WARNING "HDMI: nid %d not registered\n", nid); return -EINVAL; } @@ -354,28 +326,28 @@ static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t pin_nid, snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_DATA, val); } -static void hdmi_init_pin(struct hda_codec *codec, hda_nid_t pin_nid) +static void hdmi_enable_output(struct hda_codec *codec, hda_nid_t pin_nid) { /* Unmute */ if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP) snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); - /* Disable pin out until stream is active*/ + /* Enable pin out */ snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, 0); + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); } -static int hdmi_get_channel_count(struct hda_codec *codec, hda_nid_t cvt_nid) +static int hdmi_get_channel_count(struct hda_codec *codec, hda_nid_t nid) { - return 1 + snd_hda_codec_read(codec, cvt_nid, 0, + return 1 + snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CVT_CHAN_COUNT, 0); } static void hdmi_set_channel_count(struct hda_codec *codec, - hda_nid_t cvt_nid, int chs) + hda_nid_t nid, int chs) { - if (chs != hdmi_get_channel_count(codec, cvt_nid)) - snd_hda_codec_write(codec, cvt_nid, 0, + if (chs != hdmi_get_channel_count(codec, nid)) + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CVT_CHAN_COUNT, chs - 1); } @@ -412,8 +384,11 @@ static void init_channel_allocations(void) * * TODO: it could select the wrong CA from multiple candidates. */ -static int hdmi_channel_allocation(struct hdmi_eld *eld, int channels) +static int hdmi_channel_allocation(struct hda_codec *codec, hda_nid_t nid, + int channels) { + struct hdmi_spec *spec = codec->spec; + struct hdmi_eld *eld; int i; int ca = 0; int spk_mask = 0; @@ -425,6 +400,19 @@ static int hdmi_channel_allocation(struct hdmi_eld *eld, int channels) if (channels <= 2) return 0; + i = hda_node_index(spec->pin_cvt, nid); + if (i < 0) + return 0; + eld = &spec->sink_eld[i]; + + /* + * HDMI sink's ELD info cannot always be retrieved for now, e.g. + * in console or for audio devices. Assume the highest speakers + * configuration, to _not_ prohibit multi-channel audio playback. + */ + if (!eld->spk_alloc) + eld->spk_alloc = 0xffff; + /* * expand ELD's speaker allocation mask * @@ -620,63 +608,67 @@ static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid, return true; } -static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx, +static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid, struct snd_pcm_substream *substream) { struct hdmi_spec *spec = codec->spec; - struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; - hda_nid_t pin_nid = per_pin->pin_nid; + hda_nid_t pin_nid; int channels = substream->runtime->channels; - struct hdmi_eld *eld; int ca; + int i; union audio_infoframe ai; - eld = &spec->pins[pin_idx].sink_eld; - if (!eld->monitor_present) - return; + ca = hdmi_channel_allocation(codec, nid, channels); - ca = hdmi_channel_allocation(eld, channels); - - memset(&ai, 0, sizeof(ai)); - if (eld->conn_type == 0) { /* HDMI */ - struct hdmi_audio_infoframe *hdmi_ai = &ai.hdmi; - - hdmi_ai->type = 0x84; - hdmi_ai->ver = 0x01; - hdmi_ai->len = 0x0a; - hdmi_ai->CC02_CT47 = channels - 1; - hdmi_ai->CA = ca; - hdmi_checksum_audio_infoframe(hdmi_ai); - } else if (eld->conn_type == 1) { /* DisplayPort */ - struct dp_audio_infoframe *dp_ai = &ai.dp; - - dp_ai->type = 0x84; - dp_ai->len = 0x1b; - dp_ai->ver = 0x11 << 2; - dp_ai->CC02_CT47 = channels - 1; - dp_ai->CA = ca; - } else { - snd_printd("HDMI: unknown connection type at pin %d\n", - pin_nid); - return; - } + for (i = 0; i < spec->num_pins; i++) { + if (spec->pin_cvt[i] != nid) + continue; + if (!spec->sink_eld[i].monitor_present) + continue; - /* - * sizeof(ai) is used instead of sizeof(*hdmi_ai) or - * sizeof(*dp_ai) to avoid partial match/update problems when - * the user switches between HDMI/DP monitors. - */ - if (!hdmi_infoframe_uptodate(codec, pin_nid, ai.bytes, - sizeof(ai))) { - snd_printdd("hdmi_setup_audio_infoframe: " - "pin=%d channels=%d\n", - pin_nid, - channels); - hdmi_setup_channel_mapping(codec, pin_nid, ca); - hdmi_stop_infoframe_trans(codec, pin_nid); - hdmi_fill_audio_infoframe(codec, pin_nid, - ai.bytes, sizeof(ai)); - hdmi_start_infoframe_trans(codec, pin_nid); + pin_nid = spec->pin[i]; + + memset(&ai, 0, sizeof(ai)); + if (spec->sink_eld[i].conn_type == 0) { /* HDMI */ + struct hdmi_audio_infoframe *hdmi_ai = &ai.hdmi; + + hdmi_ai->type = 0x84; + hdmi_ai->ver = 0x01; + hdmi_ai->len = 0x0a; + hdmi_ai->CC02_CT47 = channels - 1; + hdmi_ai->CA = ca; + hdmi_checksum_audio_infoframe(hdmi_ai); + } else if (spec->sink_eld[i].conn_type == 1) { /* DisplayPort */ + struct dp_audio_infoframe *dp_ai = &ai.dp; + + dp_ai->type = 0x84; + dp_ai->len = 0x1b; + dp_ai->ver = 0x11 << 2; + dp_ai->CC02_CT47 = channels - 1; + dp_ai->CA = ca; + } else { + snd_printd("HDMI: unknown connection type at pin %d\n", + pin_nid); + continue; + } + + /* + * sizeof(ai) is used instead of sizeof(*hdmi_ai) or + * sizeof(*dp_ai) to avoid partial match/update problems when + * the user switches between HDMI/DP monitors. + */ + if (!hdmi_infoframe_uptodate(codec, pin_nid, ai.bytes, + sizeof(ai))) { + snd_printdd("hdmi_setup_audio_infoframe: " + "cvt=%d pin=%d channels=%d\n", + nid, pin_nid, + channels); + hdmi_setup_channel_mapping(codec, pin_nid, ca); + hdmi_stop_infoframe_trans(codec, pin_nid); + hdmi_fill_audio_infoframe(codec, pin_nid, + ai.bytes, sizeof(ai)); + hdmi_start_infoframe_trans(codec, pin_nid); + } } } @@ -694,27 +686,17 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) int pin_nid = res >> AC_UNSOL_RES_TAG_SHIFT; int pd = !!(res & AC_UNSOL_RES_PD); int eldv = !!(res & AC_UNSOL_RES_ELDV); - int pin_idx; - struct hdmi_eld *eld; + int index; printk(KERN_INFO - "HDMI hot plug event: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n", - codec->addr, pin_nid, pd, eldv); + "HDMI hot plug event: Pin=%d Presence_Detect=%d ELD_Valid=%d\n", + pin_nid, pd, eldv); - pin_idx = pin_nid_to_pin_index(spec, pin_nid); - if (pin_idx < 0) + index = hda_node_index(spec->pin, pin_nid); + if (index < 0) return; - eld = &spec->pins[pin_idx].sink_eld; - hdmi_present_sense(codec, pin_nid, eld); - - /* - * HDMI sink's ELD info cannot always be retrieved for now, e.g. - * in console or for audio devices. Assume the highest speakers - * configuration, to _not_ prohibit multi-channel audio playback. - */ - if (!eld->spk_alloc) - eld->spk_alloc = 0xffff; + hdmi_present_sense(codec, pin_nid, &spec->sink_eld[index]); } static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) @@ -725,8 +707,7 @@ static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) int cp_ready = !!(res & AC_UNSOL_RES_CP_READY); printk(KERN_INFO - "HDMI CP event: CODEC=%d PIN=%d SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n", - codec->addr, + "HDMI CP event: PIN=%d SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n", tag, subtag, cp_state, @@ -746,7 +727,7 @@ static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res) int tag = res >> AC_UNSOL_RES_TAG_SHIFT; int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; - if (pin_nid_to_pin_index(spec, tag) < 0) { + if (hda_node_index(spec->pin, tag) < 0) { snd_printd(KERN_INFO "Unexpected HDMI event tag 0x%x\n", tag); return; } @@ -765,14 +746,21 @@ static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res) #define is_hbr_format(format) \ ((format & AC_FMT_TYPE_NON_PCM) && (format & AC_FMT_CHAN_MASK) == 7) -static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid, - hda_nid_t pin_nid, u32 stream_tag, int format) +static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t nid, + u32 stream_tag, int format) { + struct hdmi_spec *spec = codec->spec; int pinctl; int new_pinctl = 0; + int i; + + for (i = 0; i < spec->num_pins; i++) { + if (spec->pin_cvt[i] != nid) + continue; + if (!(snd_hda_query_pin_caps(codec, spec->pin[i]) & AC_PINCAP_HBR)) + continue; - if (snd_hda_query_pin_caps(codec, pin_nid) & AC_PINCAP_HBR) { - pinctl = snd_hda_codec_read(codec, pin_nid, 0, + pinctl = snd_hda_codec_read(codec, spec->pin[i], 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); new_pinctl = pinctl & ~AC_PINCTL_EPT; @@ -783,22 +771,22 @@ static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid, snd_printdd("hdmi_setup_stream: " "NID=0x%x, %spinctl=0x%x\n", - pin_nid, + spec->pin[i], pinctl == new_pinctl ? "" : "new-", new_pinctl); if (pinctl != new_pinctl) - snd_hda_codec_write(codec, pin_nid, 0, + snd_hda_codec_write(codec, spec->pin[i], 0, AC_VERB_SET_PIN_WIDGET_CONTROL, new_pinctl); - } + if (is_hbr_format(format) && !new_pinctl) { snd_printdd("hdmi_setup_stream: HBR is not supported\n"); return -EINVAL; } - snd_hda_codec_setup_stream(codec, cvt_nid, stream_tag, 0, format); + snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format); return 0; } @@ -810,70 +798,37 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) { struct hdmi_spec *spec = codec->spec; - struct snd_pcm_runtime *runtime = substream->runtime; - int pin_idx, cvt_idx, mux_idx = 0; - struct hdmi_spec_per_pin *per_pin; struct hdmi_eld *eld; - struct hdmi_spec_per_cvt *per_cvt = NULL; - int pinctl; + struct hda_pcm_stream *codec_pars; + struct snd_pcm_runtime *runtime = substream->runtime; + unsigned int idx; - /* Validate hinfo */ - pin_idx = hinfo_to_pin_index(spec, hinfo); - if (snd_BUG_ON(pin_idx < 0)) + for (idx = 0; idx < spec->num_cvts; idx++) + if (hinfo->nid == spec->cvt[idx]) + break; + if (snd_BUG_ON(idx >= spec->num_cvts) || + snd_BUG_ON(idx >= spec->num_pins)) return -EINVAL; - per_pin = &spec->pins[pin_idx]; - eld = &per_pin->sink_eld; - /* Dynamically assign converter to stream */ - for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) { - per_cvt = &spec->cvts[cvt_idx]; + /* save the PCM info the codec provides */ + codec_pars = &spec->codec_pcm_pars[idx]; + if (!codec_pars->rates) + *codec_pars = *hinfo; - /* Must not already be assigned */ - if (per_cvt->assigned) - continue; - /* Must be in pin's mux's list of converters */ - for (mux_idx = 0; mux_idx < per_pin->num_mux_nids; mux_idx++) - if (per_pin->mux_nids[mux_idx] == per_cvt->cvt_nid) - break; - /* Not in mux list */ - if (mux_idx == per_pin->num_mux_nids) - continue; - break; - } - /* No free converters */ - if (cvt_idx == spec->num_cvts) - return -ENODEV; - - /* Claim converter */ - per_cvt->assigned = 1; - hinfo->nid = per_cvt->cvt_nid; - - snd_hda_codec_write(codec, per_pin->pin_nid, 0, - AC_VERB_SET_CONNECT_SEL, - mux_idx); - pinctl = snd_hda_codec_read(codec, per_pin->pin_nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - snd_hda_codec_write(codec, per_pin->pin_nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - pinctl | PIN_OUT); - snd_hda_spdif_ctls_assign(codec, pin_idx, per_cvt->cvt_nid); - - /* Initially set the converter's capabilities */ - hinfo->channels_min = per_cvt->channels_min; - hinfo->channels_max = per_cvt->channels_max; - hinfo->rates = per_cvt->rates; - hinfo->formats = per_cvt->formats; - hinfo->maxbps = per_cvt->maxbps; - - /* Restrict capabilities by ELD if this isn't disabled */ - if (!static_hdmi_pcm && eld->eld_valid) { - snd_hdmi_eld_update_pcm_info(eld, hinfo); + eld = &spec->sink_eld[idx]; + if (!static_hdmi_pcm && eld->eld_valid && eld->sad_count > 0) { + hdmi_eld_update_pcm_info(eld, hinfo, codec_pars); if (hinfo->channels_min > hinfo->channels_max || !hinfo->rates || !hinfo->formats) return -ENODEV; + } else { + /* fallback to the codec default */ + hinfo->channels_max = codec_pars->channels_max; + hinfo->rates = codec_pars->rates; + hinfo->formats = codec_pars->formats; + hinfo->maxbps = codec_pars->maxbps; } - - /* Store the updated parameters */ + /* store the updated parameters */ runtime->hw.channels_min = hinfo->channels_min; runtime->hw.channels_max = hinfo->channels_max; runtime->hw.formats = hinfo->formats; @@ -887,11 +842,12 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, /* * HDA/HDMI auto parsing */ -static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx) +static int hdmi_read_pin_conn(struct hda_codec *codec, hda_nid_t pin_nid) { struct hdmi_spec *spec = codec->spec; - struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; - hda_nid_t pin_nid = per_pin->pin_nid; + hda_nid_t conn_list[HDA_MAX_CONNECTIONS]; + int conn_len, curr; + int index; if (!(get_wcaps(codec, pin_nid) & AC_WCAP_CONN_LIST)) { snd_printk(KERN_WARNING @@ -901,9 +857,19 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx) return -EINVAL; } - per_pin->num_mux_nids = snd_hda_get_connections(codec, pin_nid, - per_pin->mux_nids, - HDA_MAX_CONNECTIONS); + conn_len = snd_hda_get_connections(codec, pin_nid, conn_list, + HDA_MAX_CONNECTIONS); + if (conn_len > 1) + curr = snd_hda_codec_read(codec, pin_nid, 0, + AC_VERB_GET_CONNECT_SEL, 0); + else + curr = 0; + + index = hda_node_index(spec->pin, pin_nid); + if (index < 0) + return -EINVAL; + + spec->pin_cvt[index] = conn_list[curr]; return 0; } @@ -930,8 +896,8 @@ static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid, eld->eld_valid = 0; printk(KERN_INFO - "HDMI status: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n", - codec->addr, pin_nid, eld->monitor_present, eld->eld_valid); + "HDMI status: Pin=%d Presence_Detect=%d ELD_Valid=%d\n", + pin_nid, eld->monitor_present, eld->eld_valid); if (eld->eld_valid) if (!snd_hdmi_get_eld(eld, codec, pin_nid)) @@ -943,75 +909,47 @@ static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid, static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) { struct hdmi_spec *spec = codec->spec; - unsigned int caps, config; - int pin_idx; - struct hdmi_spec_per_pin *per_pin; - struct hdmi_eld *eld; int err; - caps = snd_hda_param_read(codec, pin_nid, AC_PAR_PIN_CAP); - if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP))) - return 0; - - config = snd_hda_codec_read(codec, pin_nid, 0, - AC_VERB_GET_CONFIG_DEFAULT, 0); - if (get_defcfg_connect(config) == AC_JACK_PORT_NONE) - return 0; - - if (snd_BUG_ON(spec->num_pins >= MAX_HDMI_PINS)) + if (spec->num_pins >= MAX_HDMI_PINS) { + snd_printk(KERN_WARNING + "HDMI: no space for pin %d\n", pin_nid); return -E2BIG; - - pin_idx = spec->num_pins; - per_pin = &spec->pins[pin_idx]; - eld = &per_pin->sink_eld; - - per_pin->pin_nid = pin_nid; + } err = snd_hda_input_jack_add(codec, pin_nid, SND_JACK_VIDEOOUT, NULL); if (err < 0) return err; - err = hdmi_read_pin_conn(codec, pin_idx); - if (err < 0) - return err; + hdmi_present_sense(codec, pin_nid, &spec->sink_eld[spec->num_pins]); + spec->pin[spec->num_pins] = pin_nid; spec->num_pins++; - hdmi_present_sense(codec, pin_nid, eld); - - return 0; + return hdmi_read_pin_conn(codec, pin_nid); } -static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid) +static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t nid) { + int i, found_pin = 0; struct hdmi_spec *spec = codec->spec; - int cvt_idx; - struct hdmi_spec_per_cvt *per_cvt; - unsigned int chans; - int err; - - if (snd_BUG_ON(spec->num_cvts >= MAX_HDMI_CVTS)) - return -E2BIG; - - chans = get_wcaps(codec, cvt_nid); - chans = get_wcaps_channels(chans); - cvt_idx = spec->num_cvts; - per_cvt = &spec->cvts[cvt_idx]; + for (i = 0; i < spec->num_pins; i++) + if (nid == spec->pin_cvt[i]) { + found_pin = 1; + break; + } - per_cvt->cvt_nid = cvt_nid; - per_cvt->channels_min = 2; - if (chans <= 16) - per_cvt->channels_max = chans; + if (!found_pin) { + snd_printdd("HDMI: Skipping node %d (no connection)\n", nid); + return -EINVAL; + } - err = snd_hda_query_supported_pcm(codec, cvt_nid, - &per_cvt->rates, - &per_cvt->formats, - &per_cvt->maxbps); - if (err < 0) - return err; + if (snd_BUG_ON(spec->num_cvts >= MAX_HDMI_CVTS)) + return -E2BIG; + spec->cvt[spec->num_cvts] = nid; spec->num_cvts++; return 0; @@ -1021,6 +959,8 @@ static int hdmi_parse_codec(struct hda_codec *codec) { hda_nid_t nid; int i, nodes; + int num_tmp_cvts = 0; + hda_nid_t tmp_cvt[MAX_HDMI_CVTS]; nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid); if (!nid || nodes < 0) { @@ -1031,6 +971,7 @@ static int hdmi_parse_codec(struct hda_codec *codec) for (i = 0; i < nodes; i++, nid++) { unsigned int caps; unsigned int type; + unsigned int config; caps = snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP); type = get_wcaps_type(caps); @@ -1040,14 +981,32 @@ static int hdmi_parse_codec(struct hda_codec *codec) switch (type) { case AC_WID_AUD_OUT: - hdmi_add_cvt(codec, nid); + if (num_tmp_cvts >= MAX_HDMI_CVTS) { + snd_printk(KERN_WARNING + "HDMI: no space for converter %d\n", nid); + continue; + } + tmp_cvt[num_tmp_cvts] = nid; + num_tmp_cvts++; break; case AC_WID_PIN: + caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); + if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP))) + continue; + + config = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_CONFIG_DEFAULT, 0); + if (get_defcfg_connect(config) == AC_JACK_PORT_NONE) + continue; + hdmi_add_pin(codec, nid); break; } } + for (i = 0; i < num_tmp_cvts; i++) + hdmi_add_cvt(codec, tmp_cvt[i]); + /* * G45/IbexPeak don't support EPSS: the unsolicited pin hot plug event * can be lost and presence sense verb will become inaccurate if the @@ -1064,7 +1023,7 @@ static int hdmi_parse_codec(struct hda_codec *codec) /* */ -static char *generic_hdmi_pcm_names[MAX_HDMI_PINS] = { +static char *generic_hdmi_pcm_names[MAX_HDMI_CVTS] = { "HDMI 0", "HDMI 1", "HDMI 2", @@ -1081,84 +1040,51 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, unsigned int format, struct snd_pcm_substream *substream) { - hda_nid_t cvt_nid = hinfo->nid; - struct hdmi_spec *spec = codec->spec; - int pin_idx = hinfo_to_pin_index(spec, hinfo); - hda_nid_t pin_nid = spec->pins[pin_idx].pin_nid; - - hdmi_set_channel_count(codec, cvt_nid, substream->runtime->channels); + hdmi_set_channel_count(codec, hinfo->nid, + substream->runtime->channels); - hdmi_setup_audio_infoframe(codec, pin_idx, substream); + hdmi_setup_audio_infoframe(codec, hinfo->nid, substream); - return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format); + return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format); } -static int generic_hdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct hdmi_spec *spec = codec->spec; - int cvt_idx, pin_idx; - struct hdmi_spec_per_cvt *per_cvt; - struct hdmi_spec_per_pin *per_pin; - int pinctl; - - snd_hda_codec_cleanup_stream(codec, hinfo->nid); - - if (hinfo->nid) { - cvt_idx = cvt_nid_to_cvt_index(spec, hinfo->nid); - if (snd_BUG_ON(cvt_idx < 0)) - return -EINVAL; - per_cvt = &spec->cvts[cvt_idx]; - - snd_BUG_ON(!per_cvt->assigned); - per_cvt->assigned = 0; - hinfo->nid = 0; - - pin_idx = hinfo_to_pin_index(spec, hinfo); - if (snd_BUG_ON(pin_idx < 0)) - return -EINVAL; - per_pin = &spec->pins[pin_idx]; - - pinctl = snd_hda_codec_read(codec, per_pin->pin_nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - snd_hda_codec_write(codec, per_pin->pin_nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - pinctl & ~PIN_OUT); - snd_hda_spdif_ctls_unassign(codec, pin_idx); - } - - return 0; -} - -static const struct hda_pcm_ops generic_ops = { - .open = hdmi_pcm_open, - .prepare = generic_hdmi_playback_pcm_prepare, - .cleanup = generic_hdmi_playback_pcm_cleanup, +static const struct hda_pcm_stream generic_hdmi_pcm_playback = { + .substreams = 1, + .channels_min = 2, + .ops = { + .open = hdmi_pcm_open, + .prepare = generic_hdmi_playback_pcm_prepare, + }, }; static int generic_hdmi_build_pcms(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; - int pin_idx; + struct hda_pcm *info = spec->pcm_rec; + int i; - for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { - struct hda_pcm *info; + codec->num_pcms = spec->num_cvts; + codec->pcm_info = info; + + for (i = 0; i < codec->num_pcms; i++, info++) { + unsigned int chans; struct hda_pcm_stream *pstr; - info = &spec->pcm_rec[pin_idx]; - info->name = generic_hdmi_pcm_names[pin_idx]; - info->pcm_type = HDA_PCM_TYPE_HDMI; + chans = get_wcaps(codec, spec->cvt[i]); + chans = get_wcaps_channels(chans); + info->name = generic_hdmi_pcm_names[i]; + info->pcm_type = HDA_PCM_TYPE_HDMI; pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK]; - pstr->substreams = 1; - pstr->ops = generic_ops; - /* other pstr fields are set in open */ + if (spec->pcm_playback) + *pstr = *spec->pcm_playback; + else + *pstr = generic_hdmi_pcm_playback; + pstr->nid = spec->cvt[i]; + if (pstr->channels_max <= 2 && chans && chans <= 16) + pstr->channels_max = chans; } - codec->num_pcms = spec->num_pins; - codec->pcm_info = spec->pcm_rec; - return 0; } @@ -1166,16 +1092,12 @@ static int generic_hdmi_build_controls(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; int err; - int pin_idx; + int i; - for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { - struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; - err = snd_hda_create_spdif_out_ctls(codec, - per_pin->pin_nid, - per_pin->mux_nids[0]); + for (i = 0; i < codec->num_pcms; i++) { + err = snd_hda_create_spdif_out_ctls(codec, spec->cvt[i]); if (err < 0) return err; - snd_hda_spdif_ctls_unassign(codec, pin_idx); } return 0; @@ -1184,19 +1106,13 @@ static int generic_hdmi_build_controls(struct hda_codec *codec) static int generic_hdmi_init(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; - int pin_idx; - - for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { - struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; - hda_nid_t pin_nid = per_pin->pin_nid; - struct hdmi_eld *eld = &per_pin->sink_eld; + int i; - hdmi_init_pin(codec, pin_nid); - snd_hda_codec_write(codec, pin_nid, 0, + for (i = 0; spec->pin[i]; i++) { + hdmi_enable_output(codec, spec->pin[i]); + snd_hda_codec_write(codec, spec->pin[i], 0, AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | pin_nid); - - snd_hda_eld_proc_new(codec, eld, pin_idx); + AC_USRSP_EN | spec->pin[i]); } return 0; } @@ -1204,14 +1120,10 @@ static int generic_hdmi_init(struct hda_codec *codec) static void generic_hdmi_free(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; - int pin_idx; - - for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { - struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; - struct hdmi_eld *eld = &per_pin->sink_eld; + int i; - snd_hda_eld_proc_free(codec, eld); - } + for (i = 0; i < spec->num_pins; i++) + snd_hda_eld_proc_free(codec, &spec->sink_eld[i]); snd_hda_input_jack_free(codec); kfree(spec); @@ -1228,6 +1140,7 @@ static const struct hda_codec_ops generic_hdmi_patch_ops = { static int patch_generic_hdmi(struct hda_codec *codec) { struct hdmi_spec *spec; + int i; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) @@ -1241,68 +1154,14 @@ static int patch_generic_hdmi(struct hda_codec *codec) } codec->patch_ops = generic_hdmi_patch_ops; - init_channel_allocations(); - - return 0; -} - -/* - * Shared non-generic implementations - */ - -static int simple_playback_build_pcms(struct hda_codec *codec) -{ - struct hdmi_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; - int i; - - codec->num_pcms = spec->num_cvts; - codec->pcm_info = info; - - for (i = 0; i < codec->num_pcms; i++, info++) { - unsigned int chans; - struct hda_pcm_stream *pstr; - - chans = get_wcaps(codec, spec->cvts[i].cvt_nid); - chans = get_wcaps_channels(chans); - - info->name = generic_hdmi_pcm_names[i]; - info->pcm_type = HDA_PCM_TYPE_HDMI; - pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK]; - snd_BUG_ON(!spec->pcm_playback); - *pstr = *spec->pcm_playback; - pstr->nid = spec->cvts[i].cvt_nid; - if (pstr->channels_max <= 2 && chans && chans <= 16) - pstr->channels_max = chans; - } - - return 0; -} - -static int simple_playback_build_controls(struct hda_codec *codec) -{ - struct hdmi_spec *spec = codec->spec; - int err; - int i; + for (i = 0; i < spec->num_pins; i++) + snd_hda_eld_proc_new(codec, &spec->sink_eld[i], i); - for (i = 0; i < codec->num_pcms; i++) { - err = snd_hda_create_spdif_out_ctls(codec, - spec->cvts[i].cvt_nid, - spec->cvts[i].cvt_nid); - if (err < 0) - return err; - } + init_channel_allocations(); return 0; } -static void simple_playback_free(struct hda_codec *codec) -{ - struct hdmi_spec *spec = codec->spec; - - kfree(spec); -} - /* * Nvidia specific implementations */ @@ -1493,9 +1352,6 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo, int chs; unsigned int dataDCC1, dataDCC2, channel_id; int i; - struct hdmi_spec *spec = codec->spec; - struct hda_spdif_out *spdif = - snd_hda_spdif_out_of_nid(codec, spec->cvts[0].cvt_nid); mutex_lock(&codec->spdif_mutex); @@ -1505,12 +1361,12 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo, dataDCC2 = 0x2; /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */ - if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE)) + if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0, AC_VERB_SET_DIGI_CONVERT_1, - spdif->ctls & ~AC_DIG1_ENABLE & 0xff); + codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff); /* set the stream id */ snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0, @@ -1522,12 +1378,12 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo, /* turn on again (if needed) */ /* enable and set the channel status audio/data flag */ - if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE)) { + if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) { snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0, AC_VERB_SET_DIGI_CONVERT_1, - spdif->ctls & 0xff); + codec->spdif_ctls & 0xff); snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0, @@ -1544,12 +1400,12 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo, *otherwise the IEC958 bits won't be updated */ if (codec->spdif_status_reset && - (spdif->ctls & AC_DIG1_ENABLE)) + (codec->spdif_ctls & AC_DIG1_ENABLE)) snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0, AC_VERB_SET_DIGI_CONVERT_1, - spdif->ctls & ~AC_DIG1_ENABLE & 0xff); + codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff); /* set the stream id */ snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], @@ -1565,12 +1421,12 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo, /* turn on again (if needed) */ /* enable and set the channel status audio/data flag */ if (codec->spdif_status_reset && - (spdif->ctls & AC_DIG1_ENABLE)) { + (codec->spdif_ctls & AC_DIG1_ENABLE)) { snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0, AC_VERB_SET_DIGI_CONVERT_1, - spdif->ctls & 0xff); + codec->spdif_ctls & 0xff); snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0, @@ -1615,17 +1471,17 @@ static const struct hda_pcm_stream nvhdmi_pcm_playback_2ch = { }; static const struct hda_codec_ops nvhdmi_patch_ops_8ch_7x = { - .build_controls = simple_playback_build_controls, - .build_pcms = simple_playback_build_pcms, + .build_controls = generic_hdmi_build_controls, + .build_pcms = generic_hdmi_build_pcms, .init = nvhdmi_7x_init, - .free = simple_playback_free, + .free = generic_hdmi_free, }; static const struct hda_codec_ops nvhdmi_patch_ops_2ch = { - .build_controls = simple_playback_build_controls, - .build_pcms = simple_playback_build_pcms, + .build_controls = generic_hdmi_build_controls, + .build_pcms = generic_hdmi_build_pcms, .init = nvhdmi_7x_init, - .free = simple_playback_free, + .free = generic_hdmi_free, }; static int patch_nvhdmi_2ch(struct hda_codec *codec) @@ -1642,7 +1498,7 @@ static int patch_nvhdmi_2ch(struct hda_codec *codec) spec->multiout.max_channels = 2; spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x; spec->num_cvts = 1; - spec->cvts[0].cvt_nid = nvhdmi_master_con_nid_7x; + spec->cvt[0] = nvhdmi_master_con_nid_7x; spec->pcm_playback = &nvhdmi_pcm_playback_2ch; codec->patch_ops = nvhdmi_patch_ops_2ch; @@ -1693,11 +1549,11 @@ static int atihdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, substream); if (err < 0) return err; - snd_hda_codec_write(codec, spec->cvts[0].cvt_nid, 0, - AC_VERB_SET_CVT_CHAN_COUNT, chans - 1); + snd_hda_codec_write(codec, spec->cvt[0], 0, AC_VERB_SET_CVT_CHAN_COUNT, + chans - 1); /* FIXME: XXX */ for (i = 0; i < chans; i++) { - snd_hda_codec_write(codec, spec->cvts[0].cvt_nid, 0, + snd_hda_codec_write(codec, spec->cvt[0], 0, AC_VERB_SET_HDMI_CHAN_SLOT, (i << 4) | i); } @@ -1728,18 +1584,18 @@ static int atihdmi_init(struct hda_codec *codec) snd_hda_sequence_write(codec, atihdmi_basic_init); /* SI codec requires to unmute the pin */ - if (get_wcaps(codec, spec->pins[0].pin_nid) & AC_WCAP_OUT_AMP) - snd_hda_codec_write(codec, spec->pins[0].pin_nid, 0, + if (get_wcaps(codec, spec->pin[0]) & AC_WCAP_OUT_AMP) + snd_hda_codec_write(codec, spec->pin[0], 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); return 0; } static const struct hda_codec_ops atihdmi_patch_ops = { - .build_controls = simple_playback_build_controls, - .build_pcms = simple_playback_build_pcms, + .build_controls = generic_hdmi_build_controls, + .build_pcms = generic_hdmi_build_pcms, .init = atihdmi_init, - .free = simple_playback_free, + .free = generic_hdmi_free, }; @@ -1757,8 +1613,8 @@ static int patch_atihdmi(struct hda_codec *codec) spec->multiout.max_channels = 2; spec->multiout.dig_out_nid = ATIHDMI_CVT_NID; spec->num_cvts = 1; - spec->cvts[0].cvt_nid = ATIHDMI_CVT_NID; - spec->pins[0].pin_nid = ATIHDMI_PIN_NID; + spec->cvt[0] = ATIHDMI_CVT_NID; + spec->pin[0] = ATIHDMI_PIN_NID; spec->pcm_playback = &atihdmi_pcm_digital_playback; codec->patch_ops = atihdmi_patch_ops; diff --git a/trunk/sound/pci/hda/patch_realtek.c b/trunk/sound/pci/hda/patch_realtek.c index 52ce07534e5b..b48fb43b5448 100644 --- a/trunk/sound/pci/hda/patch_realtek.c +++ b/trunk/sound/pci/hda/patch_realtek.c @@ -1,7 +1,7 @@ /* * Universal Interface for Intel High Definition Audio Codec * - * HD audio interface patch for Realtek ALC codecs + * HD audio interface patch for ALC 260/880/882 codecs * * Copyright (c) 2004 Kailang Yang * PeiSen Hou @@ -33,11 +33,236 @@ #include "hda_local.h" #include "hda_beep.h" -/* unsol event tags */ -#define ALC_FRONT_EVENT 0x01 -#define ALC_DCVOL_EVENT 0x02 -#define ALC_HP_EVENT 0x04 -#define ALC_MIC_EVENT 0x08 +#define ALC880_FRONT_EVENT 0x01 +#define ALC880_DCVOL_EVENT 0x02 +#define ALC880_HP_EVENT 0x04 +#define ALC880_MIC_EVENT 0x08 + +/* ALC880 board config type */ +enum { + ALC880_3ST, + ALC880_3ST_DIG, + ALC880_5ST, + ALC880_5ST_DIG, + ALC880_W810, + ALC880_Z71V, + ALC880_6ST, + ALC880_6ST_DIG, + ALC880_F1734, + ALC880_ASUS, + ALC880_ASUS_DIG, + ALC880_ASUS_W1V, + ALC880_ASUS_DIG2, + ALC880_FUJITSU, + ALC880_UNIWILL_DIG, + ALC880_UNIWILL, + ALC880_UNIWILL_P53, + ALC880_CLEVO, + ALC880_TCL_S700, + ALC880_LG, + ALC880_LG_LW, + ALC880_MEDION_RIM, +#ifdef CONFIG_SND_DEBUG + ALC880_TEST, +#endif + ALC880_AUTO, + ALC880_MODEL_LAST /* last tag */ +}; + +/* ALC260 models */ +enum { + ALC260_BASIC, + ALC260_HP, + ALC260_HP_DC7600, + ALC260_HP_3013, + ALC260_FUJITSU_S702X, + ALC260_ACER, + ALC260_WILL, + ALC260_REPLACER_672V, + ALC260_FAVORIT100, +#ifdef CONFIG_SND_DEBUG + ALC260_TEST, +#endif + ALC260_AUTO, + ALC260_MODEL_LAST /* last tag */ +}; + +/* ALC262 models */ +enum { + ALC262_BASIC, + ALC262_HIPPO, + ALC262_HIPPO_1, + ALC262_FUJITSU, + ALC262_HP_BPC, + ALC262_HP_BPC_D7000_WL, + ALC262_HP_BPC_D7000_WF, + ALC262_HP_TC_T5735, + ALC262_HP_RP5700, + ALC262_BENQ_ED8, + ALC262_SONY_ASSAMD, + ALC262_BENQ_T31, + ALC262_ULTRA, + ALC262_LENOVO_3000, + ALC262_NEC, + ALC262_TOSHIBA_S06, + ALC262_TOSHIBA_RX1, + ALC262_TYAN, + ALC262_AUTO, + ALC262_MODEL_LAST /* last tag */ +}; + +/* ALC268 models */ +enum { + ALC267_QUANTA_IL1, + ALC268_3ST, + ALC268_TOSHIBA, + ALC268_ACER, + ALC268_ACER_DMIC, + ALC268_ACER_ASPIRE_ONE, + ALC268_DELL, + ALC268_ZEPTO, +#ifdef CONFIG_SND_DEBUG + ALC268_TEST, +#endif + ALC268_AUTO, + ALC268_MODEL_LAST /* last tag */ +}; + +/* ALC269 models */ +enum { + ALC269_BASIC, + ALC269_QUANTA_FL1, + ALC269_AMIC, + ALC269_DMIC, + ALC269VB_AMIC, + ALC269VB_DMIC, + ALC269_FUJITSU, + ALC269_LIFEBOOK, + ALC271_ACER, + ALC269_AUTO, + ALC269_MODEL_LAST /* last tag */ +}; + +/* ALC861 models */ +enum { + ALC861_3ST, + ALC660_3ST, + ALC861_3ST_DIG, + ALC861_6ST_DIG, + ALC861_UNIWILL_M31, + ALC861_TOSHIBA, + ALC861_ASUS, + ALC861_ASUS_LAPTOP, + ALC861_AUTO, + ALC861_MODEL_LAST, +}; + +/* ALC861-VD models */ +enum { + ALC660VD_3ST, + ALC660VD_3ST_DIG, + ALC660VD_ASUS_V1S, + ALC861VD_3ST, + ALC861VD_3ST_DIG, + ALC861VD_6ST_DIG, + ALC861VD_LENOVO, + ALC861VD_DALLAS, + ALC861VD_HP, + ALC861VD_AUTO, + ALC861VD_MODEL_LAST, +}; + +/* ALC662 models */ +enum { + ALC662_3ST_2ch_DIG, + ALC662_3ST_6ch_DIG, + ALC662_3ST_6ch, + ALC662_5ST_DIG, + ALC662_LENOVO_101E, + ALC662_ASUS_EEEPC_P701, + ALC662_ASUS_EEEPC_EP20, + ALC663_ASUS_M51VA, + ALC663_ASUS_G71V, + ALC663_ASUS_H13, + ALC663_ASUS_G50V, + ALC662_ECS, + ALC663_ASUS_MODE1, + ALC662_ASUS_MODE2, + ALC663_ASUS_MODE3, + ALC663_ASUS_MODE4, + ALC663_ASUS_MODE5, + ALC663_ASUS_MODE6, + ALC663_ASUS_MODE7, + ALC663_ASUS_MODE8, + ALC272_DELL, + ALC272_DELL_ZM1, + ALC272_SAMSUNG_NC10, + ALC662_AUTO, + ALC662_MODEL_LAST, +}; + +/* ALC882 models */ +enum { + ALC882_3ST_DIG, + ALC882_6ST_DIG, + ALC882_ARIMA, + ALC882_W2JC, + ALC882_TARGA, + ALC882_ASUS_A7J, + ALC882_ASUS_A7M, + ALC885_MACPRO, + ALC885_MBA21, + ALC885_MBP3, + ALC885_MB5, + ALC885_MACMINI3, + ALC885_IMAC24, + ALC885_IMAC91, + ALC883_3ST_2ch_DIG, + ALC883_3ST_6ch_DIG, + ALC883_3ST_6ch, + ALC883_6ST_DIG, + ALC883_TARGA_DIG, + ALC883_TARGA_2ch_DIG, + ALC883_TARGA_8ch_DIG, + ALC883_ACER, + ALC883_ACER_ASPIRE, + ALC888_ACER_ASPIRE_4930G, + ALC888_ACER_ASPIRE_6530G, + ALC888_ACER_ASPIRE_8930G, + ALC888_ACER_ASPIRE_7730G, + ALC883_MEDION, + ALC883_MEDION_WIM2160, + ALC883_LAPTOP_EAPD, + ALC883_LENOVO_101E_2ch, + ALC883_LENOVO_NB0763, + ALC888_LENOVO_MS7195_DIG, + ALC888_LENOVO_SKY, + ALC883_HAIER_W66, + ALC888_3ST_HP, + ALC888_6ST_DELL, + ALC883_MITAC, + ALC883_CLEVO_M540R, + ALC883_CLEVO_M720, + ALC883_FUJITSU_PI2515, + ALC888_FUJITSU_XA3530, + ALC883_3ST_6ch_INTEL, + ALC889A_INTEL, + ALC889_INTEL, + ALC888_ASUS_M90V, + ALC888_ASUS_EEE1601, + ALC889A_MB31, + ALC1200_ASUS_P5Q, + ALC883_SONY_VAIO_TT, + ALC882_AUTO, + ALC882_MODEL_LAST, +}; + +/* ALC680 models */ +enum { + ALC680_BASE, + ALC680_AUTO, + ALC680_MODEL_LAST, +}; /* for GPIO Poll */ #define GPIO_MASK 0x03 @@ -51,6 +276,14 @@ enum { ALC_INIT_GPIO3, }; +struct alc_mic_route { + hda_nid_t pin; + unsigned char mux_idx; + unsigned char amix_idx; +}; + +#define MUX_IDX_UNDEF ((unsigned char)-1) + struct alc_customize_define { unsigned int sku_cfg; unsigned char port_connectivity; @@ -115,9 +348,9 @@ struct alc_spec { const hda_nid_t *adc_nids; const hda_nid_t *capsrc_nids; hda_nid_t dig_in_nid; /* digital-in NID; optional */ - hda_nid_t mixer_nid; /* analog-mixer NID */ /* capture setup for dynamic dual-adc switch */ + unsigned int cur_adc_idx; hda_nid_t cur_adc; unsigned int cur_adc_stream_tag; unsigned int cur_adc_format; @@ -126,9 +359,9 @@ struct alc_spec { unsigned int num_mux_defs; const struct hda_input_mux *input_mux; unsigned int cur_mux[3]; - hda_nid_t ext_mic_pin; - hda_nid_t dock_mic_pin; - hda_nid_t int_mic_pin; + struct alc_mic_route ext_mic; + struct alc_mic_route dock_mic; + struct alc_mic_route int_mic; /* channel model */ const struct hda_channel_mode *channel_mode; @@ -148,9 +381,6 @@ struct alc_spec { hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; hda_nid_t private_adc_nids[AUTO_CFG_MAX_OUTS]; hda_nid_t private_capsrc_nids[AUTO_CFG_MAX_OUTS]; - hda_nid_t imux_pins[HDA_MAX_NUM_INPUTS]; - unsigned int dyn_adc_idx[HDA_MAX_NUM_INPUTS]; - int int_mic_idx, ext_mic_idx, dock_mic_idx; /* for auto-mic */ /* hooks */ void (*init_hook)(struct hda_codec *codec); @@ -165,7 +395,6 @@ struct alc_spec { unsigned int line_jack_present:1; unsigned int master_mute:1; unsigned int auto_mic:1; - unsigned int auto_mic_valid_imux:1; /* valid imux for auto-mic */ unsigned int automute:1; /* HP automute enabled */ unsigned int detect_line:1; /* Line-out detection enabled */ unsigned int automute_lines:1; /* automute line-out as well */ @@ -173,9 +402,8 @@ struct alc_spec { /* other flags */ unsigned int no_analog :1; /* digital I/O only */ - unsigned int dyn_adc_switch:1; /* switch ADCs (for ALC275) */ + unsigned int dual_adc_switch:1; /* switch ADCs (for ALC275) */ unsigned int single_input_src:1; - unsigned int vol_in_capsrc:1; /* use capsrc volume (ADC has no vol) */ /* auto-mute control */ int automute_mode; @@ -204,23 +432,39 @@ struct alc_spec { struct alc_multi_io multi_io[4]; }; -#define ALC_MODEL_AUTO 0 /* common for all chips */ - -static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid, - int dir, unsigned int bits) -{ - if (!nid) - return false; - if (get_wcaps(codec, nid) & (1 << (dir + 1))) - if (query_amp_caps(codec, nid, dir) & bits) - return true; - return false; -} +/* + * configuration template - to be copied to the spec instance + */ +struct alc_config_preset { + const struct snd_kcontrol_new *mixers[5]; /* should be identical size + * with spec + */ + const struct snd_kcontrol_new *cap_mixer; /* capture mixer */ + const struct hda_verb *init_verbs[5]; + unsigned int num_dacs; + const hda_nid_t *dac_nids; + hda_nid_t dig_out_nid; /* optional */ + hda_nid_t hp_nid; /* optional */ + const hda_nid_t *slave_dig_outs; + unsigned int num_adc_nids; + const hda_nid_t *adc_nids; + const hda_nid_t *capsrc_nids; + hda_nid_t dig_in_nid; + unsigned int num_channel_mode; + const struct hda_channel_mode *channel_mode; + int need_dac_fix; + int const_channel_count; + unsigned int num_mux_defs; + const struct hda_input_mux *input_mux; + void (*unsol_event)(struct hda_codec *, unsigned int); + void (*setup)(struct hda_codec *); + void (*init_hook)(struct hda_codec *); +#ifdef CONFIG_SND_HDA_POWER_SAVE + const struct hda_amp_list *loopbacks; + void (*power_hook)(struct hda_codec *codec); +#endif +}; -#define nid_has_mute(codec, nid, dir) \ - check_amp_caps(codec, nid, dir, AC_AMPCAP_MUTE) -#define nid_has_volume(codec, nid, dir) \ - check_amp_caps(codec, nid, dir, AC_AMPCAP_NUM_STEPS) /* * input MUX handling @@ -249,83 +493,388 @@ static int alc_mux_enum_get(struct snd_kcontrol *kcontrol, return 0; } -static bool alc_dyn_adc_pcm_resetup(struct hda_codec *codec, int cur) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t new_adc = spec->adc_nids[spec->dyn_adc_idx[cur]]; - - if (spec->cur_adc && spec->cur_adc != new_adc) { - /* stream is running, let's swap the current ADC */ - __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); - spec->cur_adc = new_adc; - snd_hda_codec_setup_stream(codec, new_adc, - spec->cur_adc_stream_tag, 0, - spec->cur_adc_format); - return true; - } - return false; -} - -/* select the given imux item; either unmute exclusively or select the route */ -static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx, - unsigned int idx, bool force) +static int alc_mux_enum_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; const struct hda_input_mux *imux; + unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); unsigned int mux_idx; - int i, type; - hda_nid_t nid; + hda_nid_t nid = spec->capsrc_nids ? + spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx]; + unsigned int type; mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx; imux = &spec->input_mux[mux_idx]; if (!imux->num_items && mux_idx > 0) imux = &spec->input_mux[0]; - if (idx >= imux->num_items) - idx = imux->num_items - 1; - if (spec->cur_mux[adc_idx] == idx && !force) - return 0; - spec->cur_mux[adc_idx] = idx; - - if (spec->dyn_adc_switch) { - alc_dyn_adc_pcm_resetup(codec, idx); - adc_idx = spec->dyn_adc_idx[idx]; - } - - nid = spec->capsrc_nids ? - spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx]; - - /* no selection? */ - if (snd_hda_get_conn_list(codec, nid, NULL) <= 1) - return 1; - type = get_wcaps_type(get_wcaps(codec, nid)); if (type == AC_WID_AUD_MIX) { /* Matrix-mixer style (e.g. ALC882) */ + unsigned int *cur_val = &spec->cur_mux[adc_idx]; + unsigned int i, idx; + + idx = ucontrol->value.enumerated.item[0]; + if (idx >= imux->num_items) + idx = imux->num_items - 1; + if (*cur_val == idx) + return 0; for (i = 0; i < imux->num_items; i++) { unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE; snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, imux->items[i].index, HDA_AMP_MUTE, v); } + *cur_val = idx; + return 1; } else { /* MUX style (e.g. ALC880) */ - snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_CONNECT_SEL, - imux->items[idx].index); + return snd_hda_input_mux_put(codec, imux, ucontrol, nid, + &spec->cur_mux[adc_idx]); } - return 1; } -static int alc_mux_enum_put(struct snd_kcontrol *kcontrol, +/* + * channel mode setting + */ +static int alc_ch_mode_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode, + spec->num_channel_mode); +} + +static int alc_ch_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode, + spec->num_channel_mode, + spec->ext_channel_count); +} + +static int alc_ch_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, + spec->num_channel_mode, + &spec->ext_channel_count); + if (err >= 0 && !spec->const_channel_count) { + spec->multiout.max_channels = spec->ext_channel_count; + if (spec->need_dac_fix) + spec->multiout.num_dacs = spec->multiout.max_channels / 2; + } + return err; +} + +/* + * Control the mode of pin widget settings via the mixer. "pc" is used + * instead of "%" to avoid consequences of accidentally treating the % as + * being part of a format specifier. Maximum allowed length of a value is + * 63 characters plus NULL terminator. + * + * Note: some retasking pin complexes seem to ignore requests for input + * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these + * are requested. Therefore order this list so that this behaviour will not + * cause problems when mixer clients move through the enum sequentially. + * NIDs 0x0f and 0x10 have been observed to have this behaviour as of + * March 2006. + */ +static const char * const alc_pin_mode_names[] = { + "Mic 50pc bias", "Mic 80pc bias", + "Line in", "Line out", "Headphone out", +}; +static const unsigned char alc_pin_mode_values[] = { + PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP, +}; +/* The control can present all 5 options, or it can limit the options based + * in the pin being assumed to be exclusively an input or an output pin. In + * addition, "input" pins may or may not process the mic bias option + * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to + * accept requests for bias as of chip versions up to March 2006) and/or + * wiring in the computer. + */ +#define ALC_PIN_DIR_IN 0x00 +#define ALC_PIN_DIR_OUT 0x01 +#define ALC_PIN_DIR_INOUT 0x02 +#define ALC_PIN_DIR_IN_NOMICBIAS 0x03 +#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04 + +/* Info about the pin modes supported by the different pin direction modes. + * For each direction the minimum and maximum values are given. + */ +static const signed char alc_pin_mode_dir_info[5][2] = { + { 0, 2 }, /* ALC_PIN_DIR_IN */ + { 3, 4 }, /* ALC_PIN_DIR_OUT */ + { 0, 4 }, /* ALC_PIN_DIR_INOUT */ + { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */ + { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */ +}; +#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0]) +#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1]) +#define alc_pin_mode_n_items(_dir) \ + (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1) + +static int alc_pin_mode_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + unsigned int item_num = uinfo->value.enumerated.item; + unsigned char dir = (kcontrol->private_value >> 16) & 0xff; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = alc_pin_mode_n_items(dir); + + if (item_numalc_pin_mode_max(dir)) + item_num = alc_pin_mode_min(dir); + strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]); + return 0; +} + +static int alc_pin_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { + unsigned int i; struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - return alc_mux_select(codec, adc_idx, - ucontrol->value.enumerated.item[0], false); + hda_nid_t nid = kcontrol->private_value & 0xffff; + unsigned char dir = (kcontrol->private_value >> 16) & 0xff; + long *valp = ucontrol->value.integer.value; + unsigned int pinctl = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, + 0x00); + + /* Find enumerated value for current pinctl setting */ + i = alc_pin_mode_min(dir); + while (i <= alc_pin_mode_max(dir) && alc_pin_mode_values[i] != pinctl) + i++; + *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir); + return 0; +} + +static int alc_pin_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + signed int change; + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value & 0xffff; + unsigned char dir = (kcontrol->private_value >> 16) & 0xff; + long val = *ucontrol->value.integer.value; + unsigned int pinctl = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, + 0x00); + + if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir)) + val = alc_pin_mode_min(dir); + + change = pinctl != alc_pin_mode_values[val]; + if (change) { + /* Set pin mode to that requested */ + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + alc_pin_mode_values[val]); + + /* Also enable the retasking pin's input/output as required + * for the requested pin mode. Enum values of 2 or less are + * input modes. + * + * Dynamically switching the input/output buffers probably + * reduces noise slightly (particularly on input) so we'll + * do it. However, having both input and output buffers + * enabled simultaneously doesn't seem to be problematic if + * this turns out to be necessary in the future. + */ + if (val <= 2) { + snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); + snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0, + HDA_AMP_MUTE, 0); + } else { + snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); + snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, 0); + } + } + return change; +} + +#define ALC_PIN_MODE(xname, nid, dir) \ + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ + .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ + .info = alc_pin_mode_info, \ + .get = alc_pin_mode_get, \ + .put = alc_pin_mode_put, \ + .private_value = nid | (dir<<16) } + +/* A switch control for ALC260 GPIO pins. Multiple GPIOs can be ganged + * together using a mask with more than one bit set. This control is + * currently used only by the ALC260 test model. At this stage they are not + * needed for any "production" models. + */ +#ifdef CONFIG_SND_DEBUG +#define alc_gpio_data_info snd_ctl_boolean_mono_info + +static int alc_gpio_data_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value & 0xffff; + unsigned char mask = (kcontrol->private_value >> 16) & 0xff; + long *valp = ucontrol->value.integer.value; + unsigned int val = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_GPIO_DATA, 0x00); + + *valp = (val & mask) != 0; + return 0; +} +static int alc_gpio_data_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + signed int change; + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value & 0xffff; + unsigned char mask = (kcontrol->private_value >> 16) & 0xff; + long val = *ucontrol->value.integer.value; + unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_GPIO_DATA, + 0x00); + + /* Set/unset the masked GPIO bit(s) as needed */ + change = (val == 0 ? 0 : mask) != (gpio_data & mask); + if (val == 0) + gpio_data &= ~mask; + else + gpio_data |= mask; + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_GPIO_DATA, gpio_data); + + return change; +} +#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \ + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ + .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ + .info = alc_gpio_data_info, \ + .get = alc_gpio_data_get, \ + .put = alc_gpio_data_put, \ + .private_value = nid | (mask<<16) } +#endif /* CONFIG_SND_DEBUG */ + +/* A switch control to allow the enabling of the digital IO pins on the + * ALC260. This is incredibly simplistic; the intention of this control is + * to provide something in the test model allowing digital outputs to be + * identified if present. If models are found which can utilise these + * outputs a more complete mixer control can be devised for those models if + * necessary. + */ +#ifdef CONFIG_SND_DEBUG +#define alc_spdif_ctrl_info snd_ctl_boolean_mono_info + +static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value & 0xffff; + unsigned char mask = (kcontrol->private_value >> 16) & 0xff; + long *valp = ucontrol->value.integer.value; + unsigned int val = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_DIGI_CONVERT_1, 0x00); + + *valp = (val & mask) != 0; + return 0; +} +static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + signed int change; + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value & 0xffff; + unsigned char mask = (kcontrol->private_value >> 16) & 0xff; + long val = *ucontrol->value.integer.value; + unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_DIGI_CONVERT_1, + 0x00); + + /* Set/unset the masked control bit(s) as needed */ + change = (val == 0 ? 0 : mask) != (ctrl_data & mask); + if (val==0) + ctrl_data &= ~mask; + else + ctrl_data |= mask; + snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, + ctrl_data); + + return change; +} +#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \ + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ + .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ + .info = alc_spdif_ctrl_info, \ + .get = alc_spdif_ctrl_get, \ + .put = alc_spdif_ctrl_put, \ + .private_value = nid | (mask<<16) } +#endif /* CONFIG_SND_DEBUG */ + +/* A switch control to allow the enabling EAPD digital outputs on the ALC26x. + * Again, this is only used in the ALC26x test models to help identify when + * the EAPD line must be asserted for features to work. + */ +#ifdef CONFIG_SND_DEBUG +#define alc_eapd_ctrl_info snd_ctl_boolean_mono_info + +static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value & 0xffff; + unsigned char mask = (kcontrol->private_value >> 16) & 0xff; + long *valp = ucontrol->value.integer.value; + unsigned int val = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_EAPD_BTLENABLE, 0x00); + + *valp = (val & mask) != 0; + return 0; +} + +static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int change; + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value & 0xffff; + unsigned char mask = (kcontrol->private_value >> 16) & 0xff; + long val = *ucontrol->value.integer.value; + unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_EAPD_BTLENABLE, + 0x00); + + /* Set/unset the masked control bit(s) as needed */ + change = (!val ? 0 : mask) != (ctrl_data & mask); + if (!val) + ctrl_data &= ~mask; + else + ctrl_data |= mask; + snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE, + ctrl_data); + + return change; } +#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \ + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ + .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ + .info = alc_eapd_ctrl_info, \ + .get = alc_eapd_ctrl_get, \ + .put = alc_eapd_ctrl_put, \ + .private_value = nid | (mask<<16) } +#endif /* CONFIG_SND_DEBUG */ + /* * set up the input pin config (depending on the given auto-pin type) */ @@ -354,10 +903,29 @@ static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid, snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val); } +static void alc_fixup_autocfg_pin_nums(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + + if (!cfg->line_outs) { + while (cfg->line_outs < AUTO_CFG_MAX_OUTS && + cfg->line_out_pins[cfg->line_outs]) + cfg->line_outs++; + } + if (!cfg->speaker_outs) { + while (cfg->speaker_outs < AUTO_CFG_MAX_OUTS && + cfg->speaker_pins[cfg->speaker_outs]) + cfg->speaker_outs++; + } + if (!cfg->hp_outs) { + while (cfg->hp_outs < AUTO_CFG_MAX_OUTS && + cfg->hp_pins[cfg->hp_outs]) + cfg->hp_outs++; + } +} + /* - * Append the given mixer and verb elements for the later use - * The mixer array is referred in build_controls(), and init_verbs are - * called in init(). */ static void add_mixer(struct alc_spec *spec, const struct snd_kcontrol_new *mix) { @@ -374,8 +942,61 @@ static void add_verb(struct alc_spec *spec, const struct hda_verb *verb) } /* - * GPIO setup tables, used in initialization + * set up from the preset table */ +static void setup_preset(struct hda_codec *codec, + const struct alc_config_preset *preset) +{ + struct alc_spec *spec = codec->spec; + int i; + + for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++) + add_mixer(spec, preset->mixers[i]); + spec->cap_mixer = preset->cap_mixer; + for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i]; + i++) + add_verb(spec, preset->init_verbs[i]); + + spec->channel_mode = preset->channel_mode; + spec->num_channel_mode = preset->num_channel_mode; + spec->need_dac_fix = preset->need_dac_fix; + spec->const_channel_count = preset->const_channel_count; + + if (preset->const_channel_count) + spec->multiout.max_channels = preset->const_channel_count; + else + spec->multiout.max_channels = spec->channel_mode[0].channels; + spec->ext_channel_count = spec->channel_mode[0].channels; + + spec->multiout.num_dacs = preset->num_dacs; + spec->multiout.dac_nids = preset->dac_nids; + spec->multiout.dig_out_nid = preset->dig_out_nid; + spec->multiout.slave_dig_outs = preset->slave_dig_outs; + spec->multiout.hp_nid = preset->hp_nid; + + spec->num_mux_defs = preset->num_mux_defs; + if (!spec->num_mux_defs) + spec->num_mux_defs = 1; + spec->input_mux = preset->input_mux; + + spec->num_adc_nids = preset->num_adc_nids; + spec->adc_nids = preset->adc_nids; + spec->capsrc_nids = preset->capsrc_nids; + spec->dig_in_nid = preset->dig_in_nid; + + spec->unsol_event = preset->unsol_event; + spec->init_hook = preset->init_hook; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->power_hook = preset->power_hook; + spec->loopback.amplist = preset->loopbacks; +#endif + + if (preset->setup) + preset->setup(codec); + + alc_fixup_autocfg_pin_nums(codec); +} + /* Enable GPIO mask and set output */ static const struct hda_verb alc_gpio1_init_verbs[] = { {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, @@ -430,19 +1051,14 @@ static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid, alc_fix_pll(codec); } -/* - * Jack-reporting via input-jack layer - */ - -/* initialization of jacks; currently checks only a few known pins */ static int alc_init_jacks(struct hda_codec *codec) { #ifdef CONFIG_SND_HDA_INPUT_JACK struct alc_spec *spec = codec->spec; int err; unsigned int hp_nid = spec->autocfg.hp_pins[0]; - unsigned int mic_nid = spec->ext_mic_pin; - unsigned int dock_nid = spec->dock_mic_pin; + unsigned int mic_nid = spec->ext_mic.pin; + unsigned int dock_nid = spec->dock_mic.pin; if (hp_nid) { err = snd_hda_input_jack_add(codec, hp_nid, @@ -470,12 +1086,7 @@ static int alc_init_jacks(struct hda_codec *codec) return 0; } -/* - * Jack detections for HP auto-mute and mic-switch - */ - -/* check each pin in the given array; returns true if any of them is plugged */ -static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) +static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) { int i, present = 0; @@ -489,7 +1100,6 @@ static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) return present; } -/* standard HP/line-out auto-mute helper */ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, bool mute, bool hp_out) { @@ -560,7 +1170,6 @@ static void update_speakers(struct hda_codec *codec) spec->autocfg.line_out_pins, on, false); } -/* standard HP-automute helper */ static void alc_hp_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -573,7 +1182,6 @@ static void alc_hp_automute(struct hda_codec *codec) update_speakers(codec); } -/* standard line-out-automute helper */ static void alc_line_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -586,33 +1194,106 @@ static void alc_line_automute(struct hda_codec *codec) update_speakers(codec); } -#define get_connection_index(codec, mux, nid) \ - snd_hda_get_conn_index(codec, mux, nid, 0) +static int get_connection_index(struct hda_codec *codec, hda_nid_t mux, + hda_nid_t nid) +{ + hda_nid_t conn[HDA_MAX_NUM_INPUTS]; + int i, nums; + + nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn)); + for (i = 0; i < nums; i++) + if (conn[i] == nid) + return i; + return -1; +} + +/* switch the current ADC according to the jack state */ +static void alc_dual_mic_adc_auto_switch(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + unsigned int present; + hda_nid_t new_adc; + + present = snd_hda_jack_detect(codec, spec->ext_mic.pin); + if (present) + spec->cur_adc_idx = 1; + else + spec->cur_adc_idx = 0; + new_adc = spec->adc_nids[spec->cur_adc_idx]; + if (spec->cur_adc && spec->cur_adc != new_adc) { + /* stream is running, let's swap the current ADC */ + __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); + spec->cur_adc = new_adc; + snd_hda_codec_setup_stream(codec, new_adc, + spec->cur_adc_stream_tag, 0, + spec->cur_adc_format); + } +} -/* standard mic auto-switch helper */ static void alc_mic_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - hda_nid_t *pins = spec->imux_pins; + struct alc_mic_route *dead1, *dead2, *alive; + unsigned int present, type; + hda_nid_t cap_nid; - if (!spec->auto_mic || !spec->auto_mic_valid_imux) + if (!spec->auto_mic) + return; + if (!spec->int_mic.pin || !spec->ext_mic.pin) return; if (snd_BUG_ON(!spec->adc_nids)) return; - if (snd_BUG_ON(spec->int_mic_idx < 0 || spec->ext_mic_idx < 0)) + + if (spec->dual_adc_switch) { + alc_dual_mic_adc_auto_switch(codec); return; + } - if (snd_hda_jack_detect(codec, pins[spec->ext_mic_idx])) - alc_mux_select(codec, 0, spec->ext_mic_idx, false); - else if (spec->dock_mic_idx >= 0 && - snd_hda_jack_detect(codec, pins[spec->dock_mic_idx])) - alc_mux_select(codec, 0, spec->dock_mic_idx, false); - else - alc_mux_select(codec, 0, spec->int_mic_idx, false); + cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0]; + + alive = &spec->int_mic; + dead1 = &spec->ext_mic; + dead2 = &spec->dock_mic; + + present = snd_hda_jack_detect(codec, spec->ext_mic.pin); + if (present) { + alive = &spec->ext_mic; + dead1 = &spec->int_mic; + dead2 = &spec->dock_mic; + } + if (!present && spec->dock_mic.pin > 0) { + present = snd_hda_jack_detect(codec, spec->dock_mic.pin); + if (present) { + alive = &spec->dock_mic; + dead1 = &spec->int_mic; + dead2 = &spec->ext_mic; + } + snd_hda_input_jack_report(codec, spec->dock_mic.pin); + } + + type = get_wcaps_type(get_wcaps(codec, cap_nid)); + if (type == AC_WID_AUD_MIX) { + /* Matrix-mixer style (e.g. ALC882) */ + snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT, + alive->mux_idx, + HDA_AMP_MUTE, 0); + if (dead1->pin > 0) + snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT, + dead1->mux_idx, + HDA_AMP_MUTE, HDA_AMP_MUTE); + if (dead2->pin > 0) + snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT, + dead2->mux_idx, + HDA_AMP_MUTE, HDA_AMP_MUTE); + } else { + /* MUX style (e.g. ALC880) */ + snd_hda_codec_write_cache(codec, cap_nid, 0, + AC_VERB_SET_CONNECT_SEL, + alive->mux_idx); + } + snd_hda_input_jack_report(codec, spec->ext_mic.pin); - snd_hda_input_jack_report(codec, pins[spec->ext_mic_idx]); - if (spec->dock_mic_idx >= 0) - snd_hda_input_jack_report(codec, pins[spec->dock_mic_idx]); + /* FIXME: analog mixer */ } /* unsolicited event for HP jack sensing */ @@ -623,19 +1304,18 @@ static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res) else res >>= 26; switch (res) { - case ALC_HP_EVENT: + case ALC880_HP_EVENT: alc_hp_automute(codec); break; - case ALC_FRONT_EVENT: + case ALC880_FRONT_EVENT: alc_line_automute(codec); break; - case ALC_MIC_EVENT: + case ALC880_MIC_EVENT: alc_mic_automute(codec); break; } } -/* call init functions of standard auto-mute helpers */ static void alc_inithook(struct hda_codec *codec) { alc_hp_automute(codec); @@ -661,7 +1341,6 @@ static void alc888_coef_init(struct hda_codec *codec) AC_VERB_SET_PROC_COEF, 0x3030); } -/* additional initialization for ALC889 variants */ static void alc889_coef_init(struct hda_codec *codec) { unsigned int tmp; @@ -686,12 +1365,28 @@ static void set_eapd(struct hda_codec *codec, hda_nid_t nid, int on) static void alc_auto_setup_eapd(struct hda_codec *codec, bool on) { /* We currently only handle front, HP */ - static hda_nid_t pins[] = { - 0x0f, 0x10, 0x14, 0x15, 0 - }; - hda_nid_t *p; - for (p = pins; *p; p++) - set_eapd(codec, *p, on); + switch (codec->vendor_id) { + case 0x10ec0260: + set_eapd(codec, 0x0f, on); + set_eapd(codec, 0x10, on); + break; + case 0x10ec0262: + case 0x10ec0267: + case 0x10ec0268: + case 0x10ec0269: + case 0x10ec0270: + case 0x10ec0272: + case 0x10ec0660: + case 0x10ec0662: + case 0x10ec0663: + case 0x10ec0665: + case 0x10ec0862: + case 0x10ec0889: + case 0x10ec0892: + set_eapd(codec, 0x14, on); + set_eapd(codec, 0x15, on); + break; + } } /* generic shutup callback; @@ -703,12 +1398,10 @@ static void alc_eapd_shutup(struct hda_codec *codec) msleep(200); } -/* generic EAPD initialization */ static void alc_auto_init_amp(struct hda_codec *codec, int type) { unsigned int tmp; - alc_auto_setup_eapd(codec, true); switch (type) { case ALC_INIT_GPIO1: snd_hda_sequence_write(codec, alc_gpio1_init_verbs); @@ -720,6 +1413,7 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type) snd_hda_sequence_write(codec, alc_gpio3_init_verbs); break; case ALC_INIT_DEFAULT: + alc_auto_setup_eapd(codec, true); switch (codec->vendor_id) { case 0x10ec0260: snd_hda_codec_write(codec, 0x1a, 0, @@ -763,9 +1457,6 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type) } } -/* - * Auto-Mute mode mixer enum support - */ static int alc_automute_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -852,11 +1543,7 @@ static const struct snd_kcontrol_new alc_automute_mode_enum = { .put = alc_automute_mode_put, }; -static struct snd_kcontrol_new *alc_kcontrol_new(struct alc_spec *spec) -{ - snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32); - return snd_array_new(&spec->kctls); -} +static struct snd_kcontrol_new *alc_kcontrol_new(struct alc_spec *spec); static int alc_add_automute_mode_enum(struct hda_codec *codec) { @@ -873,10 +1560,6 @@ static int alc_add_automute_mode_enum(struct hda_codec *codec) return 0; } -/* - * Check the availability of HP/line-out auto-mute; - * Set up appropriately if really supported - */ static void alc_init_auto_hp(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -915,7 +1598,7 @@ static void alc_init_auto_hp(struct hda_codec *codec) nid); snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | ALC_HP_EVENT); + AC_USRSP_EN | ALC880_HP_EVENT); spec->automute = 1; spec->automute_mode = ALC_AUTOMUTE_PIN; } @@ -930,7 +1613,7 @@ static void alc_init_auto_hp(struct hda_codec *codec) "on NID 0x%x\n", nid); snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | ALC_FRONT_EVENT); + AC_USRSP_EN | ALC880_FRONT_EVENT); spec->detect_line = 1; } spec->automute_lines = spec->detect_line; @@ -943,132 +1626,6 @@ static void alc_init_auto_hp(struct hda_codec *codec) } } -/* return the position of NID in the list, or -1 if not found */ -static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) -{ - int i; - for (i = 0; i < nums; i++) - if (list[i] == nid) - return i; - return -1; -} - -/* check whether dynamic ADC-switching is available */ -static bool alc_check_dyn_adc_switch(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - struct hda_input_mux *imux = &spec->private_imux[0]; - int i, n, idx; - hda_nid_t cap, pin; - - if (imux != spec->input_mux) /* no dynamic imux? */ - return false; - - for (n = 0; n < spec->num_adc_nids; n++) { - cap = spec->private_capsrc_nids[n]; - for (i = 0; i < imux->num_items; i++) { - pin = spec->imux_pins[i]; - if (!pin) - return false; - if (get_connection_index(codec, cap, pin) < 0) - break; - } - if (i >= imux->num_items) - return true; /* no ADC-switch is needed */ - } - - for (i = 0; i < imux->num_items; i++) { - pin = spec->imux_pins[i]; - for (n = 0; n < spec->num_adc_nids; n++) { - cap = spec->private_capsrc_nids[n]; - idx = get_connection_index(codec, cap, pin); - if (idx >= 0) { - imux->items[i].index = idx; - spec->dyn_adc_idx[i] = n; - break; - } - } - } - - snd_printdd("realtek: enabling ADC switching\n"); - spec->dyn_adc_switch = 1; - return true; -} - -/* rebuild imux for matching with the given auto-mic pins (if not yet) */ -static bool alc_rebuild_imux_for_auto_mic(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - struct hda_input_mux *imux; - static char * const texts[3] = { - "Mic", "Internal Mic", "Dock Mic" - }; - int i; - - if (!spec->auto_mic) - return false; - imux = &spec->private_imux[0]; - if (spec->input_mux == imux) - return true; - spec->imux_pins[0] = spec->ext_mic_pin; - spec->imux_pins[1] = spec->int_mic_pin; - spec->imux_pins[2] = spec->dock_mic_pin; - for (i = 0; i < 3; i++) { - strcpy(imux->items[i].label, texts[i]); - if (spec->imux_pins[i]) - imux->num_items = i + 1; - } - spec->num_mux_defs = 1; - spec->input_mux = imux; - return true; -} - -/* check whether all auto-mic pins are valid; setup indices if OK */ -static bool alc_auto_mic_check_imux(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - const struct hda_input_mux *imux; - - if (!spec->auto_mic) - return false; - if (spec->auto_mic_valid_imux) - return true; /* already checked */ - - /* fill up imux indices */ - if (!alc_check_dyn_adc_switch(codec)) { - spec->auto_mic = 0; - return false; - } - - imux = spec->input_mux; - spec->ext_mic_idx = find_idx_in_nid_list(spec->ext_mic_pin, - spec->imux_pins, imux->num_items); - spec->int_mic_idx = find_idx_in_nid_list(spec->int_mic_pin, - spec->imux_pins, imux->num_items); - spec->dock_mic_idx = find_idx_in_nid_list(spec->dock_mic_pin, - spec->imux_pins, imux->num_items); - if (spec->ext_mic_idx < 0 || spec->int_mic_idx < 0) { - spec->auto_mic = 0; - return false; /* no corresponding imux */ - } - - snd_hda_codec_write_cache(codec, spec->ext_mic_pin, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | ALC_MIC_EVENT); - if (spec->dock_mic_pin) - snd_hda_codec_write_cache(codec, spec->dock_mic_pin, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | ALC_MIC_EVENT); - - spec->auto_mic_valid_imux = 1; - spec->auto_mic = 1; - return true; -} - -/* - * Check the availability of auto-mic switch; - * Set up if really supported - */ static void alc_init_auto_mic(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -1076,8 +1633,6 @@ static void alc_init_auto_mic(struct hda_codec *codec) hda_nid_t fixed, ext, dock; int i; - spec->ext_mic_idx = spec->int_mic_idx = spec->dock_mic_idx = -1; - fixed = ext = dock = 0; for (i = 0; i < cfg->num_inputs; i++) { hda_nid_t nid = cfg->inputs[i].pin; @@ -1119,32 +1674,21 @@ static void alc_init_auto_mic(struct hda_codec *codec) return; /* no unsol support */ if (dock && !is_jack_detectable(codec, dock)) return; /* no unsol support */ - - /* check imux indices */ - spec->ext_mic_pin = ext; - spec->int_mic_pin = fixed; - spec->dock_mic_pin = dock; - - spec->auto_mic = 1; - if (!alc_auto_mic_check_imux(codec)) - return; - snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n", ext, fixed, dock); + spec->ext_mic.pin = ext; + spec->dock_mic.pin = dock; + spec->int_mic.pin = fixed; + spec->ext_mic.mux_idx = MUX_IDX_UNDEF; /* set later */ + spec->dock_mic.mux_idx = MUX_IDX_UNDEF; /* set later */ + spec->int_mic.mux_idx = MUX_IDX_UNDEF; /* set later */ + spec->auto_mic = 1; + snd_hda_codec_write_cache(codec, spec->ext_mic.pin, 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | ALC880_MIC_EVENT); spec->unsol_event = alc_sku_unsol_event; } -/* check the availabilities of auto-mute and auto-mic switches */ -static void alc_auto_check_switches(struct hda_codec *codec) -{ - alc_init_auto_hp(codec); - alc_init_auto_mic(codec); -} - -/* - * Realtek SSID verification - */ - /* Could be any non-zero and even value. When used as fixup, tells * the driver to ignore any present sku defines. */ @@ -1215,12 +1759,6 @@ static int alc_auto_parse_customize_define(struct hda_codec *codec) return 0; } -/* return true if the given NID is found in the list */ -static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) -{ - return find_idx_in_nid_list(nid, list, nums) >= 0; -} - /* check subsystem ID and set up device-specific initialization; * return 1 if initialized, 0 if invalid SSID */ @@ -1330,24 +1868,27 @@ static int alc_subsystem_id(struct hda_codec *codec, nid = porti; else return 1; - if (found_in_nid_list(nid, spec->autocfg.line_out_pins, - spec->autocfg.line_outs)) - return 1; + for (i = 0; i < spec->autocfg.line_outs; i++) + if (spec->autocfg.line_out_pins[i] == nid) + return 1; spec->autocfg.hp_pins[0] = nid; } return 1; } -/* Check the validity of ALC subsystem-id - * ports contains an array of 4 pin NIDs for port-A, E, D and I */ -static void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports) +static void alc_ssid_check(struct hda_codec *codec, + hda_nid_t porta, hda_nid_t porte, + hda_nid_t portd, hda_nid_t porti) { - if (!alc_subsystem_id(codec, ports[0], ports[1], ports[2], ports[3])) { + if (!alc_subsystem_id(codec, porta, porte, portd, porti)) { struct alc_spec *spec = codec->spec; snd_printd("realtek: " "Enable default setup for auto mode as fallback\n"); spec->init_amp = ALC_INIT_DEFAULT; } + + alc_init_auto_hp(codec); + alc_init_auto_mic(codec); } /* @@ -1495,9 +2036,6 @@ static void alc_pick_fixup(struct hda_codec *codec, } } -/* - * COEF access helper functions - */ static int alc_read_coef_idx(struct hda_codec *codec, unsigned int coef_idx) { @@ -1518,32 +2056,20 @@ static void alc_write_coef_idx(struct hda_codec *codec, unsigned int coef_idx, coef_val); } -/* - * Digital I/O handling - */ - /* set right pin controls for digital I/O */ static void alc_auto_init_digital(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; int i; - hda_nid_t pin, dac; + hda_nid_t pin; for (i = 0; i < spec->autocfg.dig_outs; i++) { pin = spec->autocfg.dig_out_pins[i]; - if (!pin) - continue; - snd_hda_codec_write(codec, pin, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); - if (!i) - dac = spec->multiout.dig_out_nid; - else - dac = spec->slave_dig_outs[i - 1]; - if (!dac || !(get_wcaps(codec, dac) & AC_WCAP_OUT_AMP)) - continue; - snd_hda_codec_write(codec, dac, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_UNMUTE); + if (pin) { + snd_hda_codec_write(codec, pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + PIN_OUT); + } } pin = spec->autocfg.dig_in_pin; if (pin) @@ -1561,13 +2087,11 @@ static void alc_auto_parse_digital(struct hda_codec *codec) /* support multiple SPDIFs; the secondary is set up as a slave */ for (i = 0; i < spec->autocfg.dig_outs; i++) { - hda_nid_t conn[4]; err = snd_hda_get_connections(codec, spec->autocfg.dig_out_pins[i], - conn, ARRAY_SIZE(conn)); + &dig_nid, 1); if (err < 0) continue; - dig_nid = conn[0]; /* assume the first element is audio-out */ if (!i) { spec->multiout.dig_out_nid = dig_nid; spec->dig_out_type = spec->autocfg.dig_out_type[0]; @@ -1600,1790 +2124,13960 @@ static void alc_auto_parse_digital(struct hda_codec *codec) } /* - * capture mixer elements + * ALC888 */ -static int alc_cap_vol_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - unsigned long val; - int err; - mutex_lock(&codec->control_mutex); - if (spec->vol_in_capsrc) - val = HDA_COMPOSE_AMP_VAL(spec->capsrc_nids[0], 3, 0, HDA_OUTPUT); - else - val = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0, HDA_INPUT); - kcontrol->private_value = val; - err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo); - mutex_unlock(&codec->control_mutex); - return err; -} +/* + * 2ch mode + */ +static const struct hda_verb alc888_4ST_ch2_intel_init[] = { +/* Mic-in jack as mic in */ + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, +/* Line-in jack as Line in */ + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, +/* Line-Out as Front */ + { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00}, + { } /* end */ +}; -static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, - unsigned int size, unsigned int __user *tlv) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - unsigned long val; - int err; +/* + * 4ch mode + */ +static const struct hda_verb alc888_4ST_ch4_intel_init[] = { +/* Mic-in jack as mic in */ + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, +/* Line-in jack as Surround */ + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, +/* Line-Out as Front */ + { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00}, + { } /* end */ +}; - mutex_lock(&codec->control_mutex); - if (spec->vol_in_capsrc) - val = HDA_COMPOSE_AMP_VAL(spec->capsrc_nids[0], 3, 0, HDA_OUTPUT); - else - val = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0, HDA_INPUT); - kcontrol->private_value = val; - err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv); - mutex_unlock(&codec->control_mutex); - return err; -} +/* + * 6ch mode + */ +static const struct hda_verb alc888_4ST_ch6_intel_init[] = { +/* Mic-in jack as CLFE */ + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, +/* Line-in jack as Surround */ + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, +/* Line-Out as CLFE (workaround because Mic-in is not loud enough) */ + { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, + { } /* end */ +}; -typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); +/* + * 8ch mode + */ +static const struct hda_verb alc888_4ST_ch8_intel_init[] = { +/* Mic-in jack as CLFE */ + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, +/* Line-in jack as Surround */ + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, +/* Line-Out as Side */ + { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, + { } /* end */ +}; -static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol, - getput_call_t func, bool check_adc_switch) +static const struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = { + { 2, alc888_4ST_ch2_intel_init }, + { 4, alc888_4ST_ch4_intel_init }, + { 6, alc888_4ST_ch6_intel_init }, + { 8, alc888_4ST_ch8_intel_init }, +}; + +/* + * ALC888 Fujitsu Siemens Amillo xa3530 + */ + +static const struct hda_verb alc888_fujitsu_xa3530_verbs[] = { +/* Front Mic: set to PIN_IN (empty by default) */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, +/* Connect Internal HP to Front */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, +/* Connect Bass HP to Front */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, +/* Connect Line-Out side jack (SPDIF) to Side */ + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, +/* Connect Mic jack to CLFE */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, +/* Connect Line-in jack to Surround */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, +/* Connect HP out jack to Front */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, +/* Enable unsolicited event for HP jack and Line-out jack */ + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {} +}; + +static void alc889_automute_setup(struct hda_codec *codec) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; - int i, err = 0; - mutex_lock(&codec->control_mutex); - if (check_adc_switch && spec->dyn_adc_switch) { - for (i = 0; i < spec->num_adc_nids; i++) { - kcontrol->private_value = - HDA_COMPOSE_AMP_VAL(spec->adc_nids[i], - 3, 0, HDA_INPUT); - err = func(kcontrol, ucontrol); - if (err < 0) - goto error; - } - } else { - i = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - if (spec->vol_in_capsrc) - kcontrol->private_value = - HDA_COMPOSE_AMP_VAL(spec->capsrc_nids[i], - 3, 0, HDA_OUTPUT); - else - kcontrol->private_value = - HDA_COMPOSE_AMP_VAL(spec->adc_nids[i], - 3, 0, HDA_INPUT); - err = func(kcontrol, ucontrol); - } - error: - mutex_unlock(&codec->control_mutex); - return err; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x16; + spec->autocfg.speaker_pins[2] = 0x17; + spec->autocfg.speaker_pins[3] = 0x19; + spec->autocfg.speaker_pins[4] = 0x1a; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } -static int alc_cap_vol_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static void alc889_intel_init_hook(struct hda_codec *codec) { - return alc_cap_getput_caller(kcontrol, ucontrol, - snd_hda_mixer_amp_volume_get, false); + alc889_coef_init(codec); + alc_hp_automute(codec); } -static int alc_cap_vol_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static void alc888_fujitsu_xa3530_setup(struct hda_codec *codec) { - return alc_cap_getput_caller(kcontrol, ucontrol, - snd_hda_mixer_amp_volume_put, true); + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x17; /* line-out */ + spec->autocfg.hp_pins[1] = 0x1b; /* hp */ + spec->autocfg.speaker_pins[0] = 0x14; /* speaker */ + spec->autocfg.speaker_pins[1] = 0x15; /* bass */ + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } -/* capture mixer elements */ -#define alc_cap_sw_info snd_ctl_boolean_stereo_info +/* + * ALC888 Acer Aspire 4930G model + */ -static int alc_cap_sw_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - return alc_cap_getput_caller(kcontrol, ucontrol, - snd_hda_mixer_amp_switch_get, false); -} +static const struct hda_verb alc888_acer_aspire_4930g_verbs[] = { +/* Front Mic: set to PIN_IN (empty by default) */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, +/* Unselect Front Mic by default in input mixer 3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)}, +/* Enable unsolicited event for HP jack */ + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, +/* Connect Internal HP to front */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, +/* Connect HP out to front */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, + { } +}; -static int alc_cap_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - return alc_cap_getput_caller(kcontrol, ucontrol, - snd_hda_mixer_amp_switch_put, true); -} +/* + * ALC888 Acer Aspire 6530G model + */ -#define _DEFINE_CAPMIX(num) \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = "Capture Switch", \ - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ - .count = num, \ - .info = alc_cap_sw_info, \ - .get = alc_cap_sw_get, \ - .put = alc_cap_sw_put, \ - }, \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = "Capture Volume", \ - .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | \ - SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ - SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), \ - .count = num, \ - .info = alc_cap_vol_info, \ - .get = alc_cap_vol_get, \ - .put = alc_cap_vol_put, \ - .tlv = { .c = alc_cap_vol_tlv }, \ - } +static const struct hda_verb alc888_acer_aspire_6530g_verbs[] = { +/* Route to built-in subwoofer as well as speakers */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, +/* Bias voltage on for external mic port */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80}, +/* Front Mic: set to PIN_IN (empty by default) */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, +/* Unselect Front Mic by default in input mixer 3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)}, +/* Enable unsolicited event for HP jack */ + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, +/* Enable speaker output */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, +/* Enable headphone output */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, + { } +}; -#define _DEFINE_CAPSRC(num) \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - /* .name = "Capture Source", */ \ - .name = "Input Source", \ - .count = num, \ - .info = alc_mux_enum_info, \ - .get = alc_mux_enum_get, \ - .put = alc_mux_enum_put, \ - } +/* + *ALC888 Acer Aspire 7730G model + */ -#define DEFINE_CAPMIX(num) \ -static const struct snd_kcontrol_new alc_capture_mixer ## num[] = { \ - _DEFINE_CAPMIX(num), \ - _DEFINE_CAPSRC(num), \ - { } /* end */ \ -} - -#define DEFINE_CAPMIX_NOSRC(num) \ -static const struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \ - _DEFINE_CAPMIX(num), \ - { } /* end */ \ -} - -/* up to three ADCs */ -DEFINE_CAPMIX(1); -DEFINE_CAPMIX(2); -DEFINE_CAPMIX(3); -DEFINE_CAPMIX_NOSRC(1); -DEFINE_CAPMIX_NOSRC(2); -DEFINE_CAPMIX_NOSRC(3); +static const struct hda_verb alc888_acer_aspire_7730G_verbs[] = { +/* Bias voltage on for external mic port */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80}, +/* Front Mic: set to PIN_IN (empty by default) */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, +/* Unselect Front Mic by default in input mixer 3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)}, +/* Enable unsolicited event for HP jack */ + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, +/* Enable speaker output */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, +/* Enable headphone output */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, +/*Enable internal subwoofer */ + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_CONNECT_SEL, 0x02}, + {0x17, AC_VERB_SET_EAPD_BTLENABLE, 2}, + { } +}; /* - * virtual master controls + * ALC889 Acer Aspire 8930G model */ -/* - * slave controls for virtual master +static const struct hda_verb alc889_acer_aspire_8930g_verbs[] = { +/* Front Mic: set to PIN_IN (empty by default) */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, +/* Unselect Front Mic by default in input mixer 3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)}, +/* Enable unsolicited event for HP jack */ + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, +/* Connect Internal Front to Front */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, +/* Connect Internal Rear to Rear */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, +/* Connect Internal CLFE to CLFE */ + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, +/* Connect HP out to Front */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, +/* Enable all DACs */ +/* DAC DISABLE/MUTE 1? */ +/* setting bits 1-5 disables DAC nids 0x02-0x06 apparently. Init=0x38 */ + {0x20, AC_VERB_SET_COEF_INDEX, 0x03}, + {0x20, AC_VERB_SET_PROC_COEF, 0x0000}, +/* DAC DISABLE/MUTE 2? */ +/* some bit here disables the other DACs. Init=0x4900 */ + {0x20, AC_VERB_SET_COEF_INDEX, 0x08}, + {0x20, AC_VERB_SET_PROC_COEF, 0x0000}, +/* DMIC fix + * This laptop has a stereo digital microphone. The mics are only 1cm apart + * which makes the stereo useless. However, either the mic or the ALC889 + * makes the signal become a difference/sum signal instead of standard + * stereo, which is annoying. So instead we flip this bit which makes the + * codec replicate the sum signal to both channels, turning it into a + * normal mono mic. */ -static const char * const alc_slave_vols[] = { - "Front Playback Volume", - "Surround Playback Volume", - "Center Playback Volume", - "LFE Playback Volume", - "Side Playback Volume", - "Headphone Playback Volume", - "Speaker Playback Volume", - "Mono Playback Volume", - "Line-Out Playback Volume", - NULL, +/* DMIC_CONTROL? Init value = 0x0001 */ + {0x20, AC_VERB_SET_COEF_INDEX, 0x0b}, + {0x20, AC_VERB_SET_PROC_COEF, 0x0003}, + { } }; -static const char * const alc_slave_sws[] = { - "Front Playback Switch", - "Surround Playback Switch", - "Center Playback Switch", - "LFE Playback Switch", - "Side Playback Switch", - "Headphone Playback Switch", - "Speaker Playback Switch", - "Mono Playback Switch", - "IEC958 Playback Switch", - "Line-Out Playback Switch", - NULL, +static const struct hda_input_mux alc888_2_capture_sources[2] = { + /* Front mic only available on one ADC */ + { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + { "Front Mic", 0xb }, + }, + }, + { + .num_items = 3, + .items = { + { "Mic", 0x0 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + }, + } }; -/* - * build control elements - */ +static const struct hda_input_mux alc888_acer_aspire_6530_sources[2] = { + /* Interal mic only available on one ADC */ + { + .num_items = 5, + .items = { + { "Mic", 0x0 }, + { "Line In", 0x2 }, + { "CD", 0x4 }, + { "Input Mix", 0xa }, + { "Internal Mic", 0xb }, + }, + }, + { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Line In", 0x2 }, + { "CD", 0x4 }, + { "Input Mix", 0xa }, + }, + } +}; -#define NID_MAPPING (-1) +static const struct hda_input_mux alc889_capture_sources[3] = { + /* Digital mic only available on first "ADC" */ + { + .num_items = 5, + .items = { + { "Mic", 0x0 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + { "Front Mic", 0xb }, + { "Input Mix", 0xa }, + }, + }, + { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + { "Input Mix", 0xa }, + }, + }, + { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + { "Input Mix", 0xa }, + }, + } +}; -#define SUBDEV_SPEAKER_ (0 << 6) -#define SUBDEV_HP_ (1 << 6) -#define SUBDEV_LINE_ (2 << 6) -#define SUBDEV_SPEAKER(x) (SUBDEV_SPEAKER_ | ((x) & 0x3f)) -#define SUBDEV_HP(x) (SUBDEV_HP_ | ((x) & 0x3f)) -#define SUBDEV_LINE(x) (SUBDEV_LINE_ | ((x) & 0x3f)) +static const struct snd_kcontrol_new alc888_base_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, + HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; -static void alc_free_kctls(struct hda_codec *codec); +static const struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, + HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Internal LFE Playback Volume", 0x0f, 1, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Internal LFE Playback Switch", 0x0f, 1, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; -#ifdef CONFIG_SND_HDA_INPUT_BEEP -/* additional beep mixers; the actual parameters are overwritten at build */ -static const struct snd_kcontrol_new alc_beep_mixer[] = { - HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT), - HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT), +static const struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, + HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), { } /* end */ }; -#endif -static int alc_build_controls(struct hda_codec *codec) + +static void alc888_acer_aspire_4930g_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - struct snd_kcontrol *kctl = NULL; - const struct snd_kcontrol_new *knew; - int i, j, err; - unsigned int u; - hda_nid_t nid; - for (i = 0; i < spec->num_mixers; i++) { - err = snd_hda_add_new_ctls(codec, spec->mixers[i]); - if (err < 0) - return err; - } - if (spec->cap_mixer) { - err = snd_hda_add_new_ctls(codec, spec->cap_mixer); - if (err < 0) - return err; - } - if (spec->multiout.dig_out_nid) { - err = snd_hda_create_spdif_out_ctls(codec, - spec->multiout.dig_out_nid, - spec->multiout.dig_out_nid); - if (err < 0) - return err; - if (!spec->no_analog) { - err = snd_hda_create_spdif_share_sw(codec, - &spec->multiout); - if (err < 0) - return err; - spec->multiout.share_spdif = 1; - } - } - if (spec->dig_in_nid) { - err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); - if (err < 0) - return err; - } + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x16; + spec->autocfg.speaker_pins[2] = 0x17; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} -#ifdef CONFIG_SND_HDA_INPUT_BEEP - /* create beep controls if needed */ - if (spec->beep_amp) { - const struct snd_kcontrol_new *knew; - for (knew = alc_beep_mixer; knew->name; knew++) { - struct snd_kcontrol *kctl; - kctl = snd_ctl_new1(knew, codec); - if (!kctl) - return -ENOMEM; - kctl->private_value = spec->beep_amp; - err = snd_hda_ctl_add(codec, 0, kctl); - if (err < 0) - return err; - } - } -#endif +static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; - /* if we have no master control, let's create it */ - if (!spec->no_analog && - !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { - unsigned int vmaster_tlv[4]; - snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, - HDA_OUTPUT, vmaster_tlv); - err = snd_hda_add_vmaster(codec, "Master Playback Volume", - vmaster_tlv, alc_slave_vols); - if (err < 0) - return err; - } - if (!spec->no_analog && - !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { - err = snd_hda_add_vmaster(codec, "Master Playback Switch", - NULL, alc_slave_sws); - if (err < 0) - return err; - } + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x16; + spec->autocfg.speaker_pins[2] = 0x17; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} - /* assign Capture Source enums to NID */ - if (spec->capsrc_nids || spec->adc_nids) { - kctl = snd_hda_find_mixer_ctl(codec, "Capture Source"); - if (!kctl) - kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); - for (i = 0; kctl && i < kctl->count; i++) { - const hda_nid_t *nids = spec->capsrc_nids; - if (!nids) - nids = spec->adc_nids; - err = snd_hda_add_nid(codec, kctl, i, nids[i]); - if (err < 0) - return err; - } - } - if (spec->cap_mixer) { - const char *kname = kctl ? kctl->id.name : NULL; - for (knew = spec->cap_mixer; knew->name; knew++) { - if (kname && strcmp(knew->name, kname) == 0) - continue; - kctl = snd_hda_find_mixer_ctl(codec, knew->name); - for (i = 0; kctl && i < kctl->count; i++) { - err = snd_hda_add_nid(codec, kctl, i, - spec->adc_nids[i]); - if (err < 0) - return err; - } - } - } +static void alc888_acer_aspire_7730g_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; - /* other nid->control mapping */ - for (i = 0; i < spec->num_mixers; i++) { - for (knew = spec->mixers[i]; knew->name; knew++) { - if (knew->iface != NID_MAPPING) - continue; - kctl = snd_hda_find_mixer_ctl(codec, knew->name); - if (kctl == NULL) - continue; - u = knew->subdevice; - for (j = 0; j < 4; j++, u >>= 8) { - nid = u & 0x3f; - if (nid == 0) - continue; - switch (u & 0xc0) { - case SUBDEV_SPEAKER_: - nid = spec->autocfg.speaker_pins[nid]; - break; - case SUBDEV_LINE_: - nid = spec->autocfg.line_out_pins[nid]; - break; - case SUBDEV_HP_: - nid = spec->autocfg.hp_pins[nid]; - break; - default: - continue; - } - err = snd_hda_add_nid(codec, kctl, 0, nid); - if (err < 0) - return err; - } - u = knew->private_value; - for (j = 0; j < 4; j++, u >>= 8) { - nid = u & 0xff; - if (nid == 0) - continue; - err = snd_hda_add_nid(codec, kctl, 0, nid); - if (err < 0) - return err; - } - } - } + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x16; + spec->autocfg.speaker_pins[2] = 0x17; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} - alc_free_kctls(codec); /* no longer needed */ +static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; - return 0; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x16; + spec->autocfg.speaker_pins[2] = 0x1b; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } - /* - * Common callbacks + * ALC880 3-stack model + * + * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e) + * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18, + * F-Mic = 0x1b, HP = 0x19 */ -static void alc_init_special_input_src(struct hda_codec *codec); +static const hda_nid_t alc880_dac_nids[4] = { + /* front, rear, clfe, rear_surr */ + 0x02, 0x05, 0x04, 0x03 +}; -static int alc_init(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - unsigned int i; +static const hda_nid_t alc880_adc_nids[3] = { + /* ADC0-2 */ + 0x07, 0x08, 0x09, +}; - alc_fix_pll(codec); - alc_auto_init_amp(codec, spec->init_amp); +/* The datasheet says the node 0x07 is connected from inputs, + * but it shows zero connection in the real implementation on some devices. + * Note: this is a 915GAV bug, fixed on 915GLV + */ +static const hda_nid_t alc880_adc_nids_alt[2] = { + /* ADC1-2 */ + 0x08, 0x09, +}; - for (i = 0; i < spec->num_init_verbs; i++) - snd_hda_sequence_write(codec, spec->init_verbs[i]); - alc_init_special_input_src(codec); +#define ALC880_DIGOUT_NID 0x06 +#define ALC880_DIGIN_NID 0x0a - if (spec->init_hook) - spec->init_hook(codec); +static const struct hda_input_mux alc880_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x3 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + }, +}; - alc_apply_fixup(codec, ALC_FIXUP_ACT_INIT); +/* channel source setting (2/6 channel selection for 3-stack) */ +/* 2ch mode */ +static const struct hda_verb alc880_threestack_ch2_init[] = { + /* set line-in to input, mute it */ + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + /* set mic-in to input vref 80%, mute it */ + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { } /* end */ +}; - hda_call_check_power_status(codec, 0x01); - return 0; -} +/* 6ch mode */ +static const struct hda_verb alc880_threestack_ch6_init[] = { + /* set line-in to output, unmute it */ + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + /* set mic-in to output, unmute it */ + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { } /* end */ +}; -static void alc_unsol_event(struct hda_codec *codec, unsigned int res) -{ - struct alc_spec *spec = codec->spec; +static const struct hda_channel_mode alc880_threestack_modes[2] = { + { 2, alc880_threestack_ch2_init }, + { 6, alc880_threestack_ch6_init }, +}; - if (spec->unsol_event) - spec->unsol_event(codec, res); -} +static const struct snd_kcontrol_new alc880_three_stack_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + }, + { } /* end */ +}; -#ifdef CONFIG_SND_HDA_POWER_SAVE -static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid) +/* capture mixer elements */ +static int alc_cap_vol_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) { + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; - return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); -} -#endif + int err; -/* - * Analog playback callbacks - */ -static int alc_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; - return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, - hinfo); + mutex_lock(&codec->control_mutex); + kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0, + HDA_INPUT); + err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo); + mutex_unlock(&codec->control_mutex); + return err; } -static int alc_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) +static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, + unsigned int size, unsigned int __user *tlv) { + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; - return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, - stream_tag, format, substream); -} + int err; -static int alc_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; - return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); + mutex_lock(&codec->control_mutex); + kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0, + HDA_INPUT); + err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv); + mutex_unlock(&codec->control_mutex); + return err; } -/* - * Digital out - */ -static int alc_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) +typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol, + getput_call_t func, bool check_adc_switch) { + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; - return snd_hda_multi_out_dig_open(codec, &spec->multiout); + int i, err = 0; + + mutex_lock(&codec->control_mutex); + if (check_adc_switch && spec->dual_adc_switch) { + for (i = 0; i < spec->num_adc_nids; i++) { + kcontrol->private_value = + HDA_COMPOSE_AMP_VAL(spec->adc_nids[i], + 3, 0, HDA_INPUT); + err = func(kcontrol, ucontrol); + if (err < 0) + goto error; + } + } else { + i = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + kcontrol->private_value = + HDA_COMPOSE_AMP_VAL(spec->adc_nids[i], + 3, 0, HDA_INPUT); + err = func(kcontrol, ucontrol); + } + error: + mutex_unlock(&codec->control_mutex); + return err; } -static int alc_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) +static int alc_cap_vol_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - struct alc_spec *spec = codec->spec; - return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, - stream_tag, format, substream); + return alc_cap_getput_caller(kcontrol, ucontrol, + snd_hda_mixer_amp_volume_get, false); } -static int alc_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) +static int alc_cap_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - struct alc_spec *spec = codec->spec; - return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); + return alc_cap_getput_caller(kcontrol, ucontrol, + snd_hda_mixer_amp_volume_put, true); } -static int alc_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) +/* capture mixer elements */ +#define alc_cap_sw_info snd_ctl_boolean_stereo_info + +static int alc_cap_sw_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - struct alc_spec *spec = codec->spec; - return snd_hda_multi_out_dig_close(codec, &spec->multiout); + return alc_cap_getput_caller(kcontrol, ucontrol, + snd_hda_mixer_amp_switch_get, false); } -/* - * Analog capture - */ -static int alc_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) +static int alc_cap_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - struct alc_spec *spec = codec->spec; - - snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1], - stream_tag, 0, format); - return 0; + return alc_cap_getput_caller(kcontrol, ucontrol, + snd_hda_mixer_amp_switch_put, true); } -static int alc_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; +#define _DEFINE_CAPMIX(num) \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = "Capture Switch", \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .count = num, \ + .info = alc_cap_sw_info, \ + .get = alc_cap_sw_get, \ + .put = alc_cap_sw_put, \ + }, \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = "Capture Volume", \ + .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | \ + SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ + SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), \ + .count = num, \ + .info = alc_cap_vol_info, \ + .get = alc_cap_vol_get, \ + .put = alc_cap_vol_put, \ + .tlv = { .c = alc_cap_vol_tlv }, \ + } - snd_hda_codec_cleanup_stream(codec, - spec->adc_nids[substream->number + 1]); - return 0; -} +#define _DEFINE_CAPSRC(num) \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + /* .name = "Capture Source", */ \ + .name = "Input Source", \ + .count = num, \ + .info = alc_mux_enum_info, \ + .get = alc_mux_enum_get, \ + .put = alc_mux_enum_put, \ + } -/* analog capture with dynamic dual-adc changes */ -static int dyn_adc_capture_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; - spec->cur_adc = spec->adc_nids[spec->dyn_adc_idx[spec->cur_mux[0]]]; - spec->cur_adc_stream_tag = stream_tag; - spec->cur_adc_format = format; - snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); - return 0; +#define DEFINE_CAPMIX(num) \ +static const struct snd_kcontrol_new alc_capture_mixer ## num[] = { \ + _DEFINE_CAPMIX(num), \ + _DEFINE_CAPSRC(num), \ + { } /* end */ \ } -static int dyn_adc_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; - snd_hda_codec_cleanup_stream(codec, spec->cur_adc); - spec->cur_adc = 0; - return 0; +#define DEFINE_CAPMIX_NOSRC(num) \ +static const struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \ + _DEFINE_CAPMIX(num), \ + { } /* end */ \ } -static const struct hda_pcm_stream dyn_adc_pcm_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = 0, /* fill later */ - .ops = { - .prepare = dyn_adc_capture_pcm_prepare, - .cleanup = dyn_adc_capture_pcm_cleanup - }, -}; +/* up to three ADCs */ +DEFINE_CAPMIX(1); +DEFINE_CAPMIX(2); +DEFINE_CAPMIX(3); +DEFINE_CAPMIX_NOSRC(1); +DEFINE_CAPMIX_NOSRC(2); +DEFINE_CAPMIX_NOSRC(3); /* + * ALC880 5-stack model + * + * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d), + * Side = 0x02 (0xd) + * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16 + * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19 */ -static const struct hda_pcm_stream alc_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 8, - /* NID is set in alc_build_pcms */ - .ops = { - .open = alc_playback_pcm_open, - .prepare = alc_playback_pcm_prepare, - .cleanup = alc_playback_pcm_cleanup - }, + +/* additional mixers to alc880_three_stack_mixer */ +static const struct snd_kcontrol_new alc880_five_stack_mixer[] = { + HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT), + { } /* end */ }; -static const struct hda_pcm_stream alc_pcm_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in alc_build_pcms */ +/* channel source setting (6/8 channel selection for 5-stack) */ +/* 6ch mode */ +static const struct hda_verb alc880_fivestack_ch6_init[] = { + /* set line-in to input, mute it */ + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { } /* end */ }; -static const struct hda_pcm_stream alc_pcm_analog_alt_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in alc_build_pcms */ +/* 8ch mode */ +static const struct hda_verb alc880_fivestack_ch8_init[] = { + /* set line-in to output, unmute it */ + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { } /* end */ }; -static const struct hda_pcm_stream alc_pcm_analog_alt_capture = { - .substreams = 2, /* can be overridden */ - .channels_min = 2, - .channels_max = 2, - /* NID is set in alc_build_pcms */ - .ops = { - .prepare = alc_alt_capture_pcm_prepare, - .cleanup = alc_alt_capture_pcm_cleanup - }, +static const struct hda_channel_mode alc880_fivestack_modes[2] = { + { 6, alc880_fivestack_ch6_init }, + { 8, alc880_fivestack_ch8_init }, }; -static const struct hda_pcm_stream alc_pcm_digital_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in alc_build_pcms */ - .ops = { - .open = alc_dig_playback_pcm_open, - .close = alc_dig_playback_pcm_close, - .prepare = alc_dig_playback_pcm_prepare, - .cleanup = alc_dig_playback_pcm_cleanup + +/* + * ALC880 6-stack model + * + * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e), + * Side = 0x05 (0x0f) + * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17, + * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b + */ + +static const hda_nid_t alc880_6st_dac_nids[4] = { + /* front, rear, clfe, rear_surr */ + 0x02, 0x03, 0x04, 0x05 +}; + +static const struct hda_input_mux alc880_6stack_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x1 }, + { "Line", 0x2 }, + { "CD", 0x4 }, }, }; -static const struct hda_pcm_stream alc_pcm_digital_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in alc_build_pcms */ +/* fixed 8-channels */ +static const struct hda_channel_mode alc880_sixstack_modes[1] = { + { 8, NULL }, }; -/* Used by alc_build_pcms to flag that a PCM has no playback stream */ -static const struct hda_pcm_stream alc_pcm_null_stream = { - .substreams = 0, - .channels_min = 0, - .channels_max = 0, +static const struct snd_kcontrol_new alc880_six_stack_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + }, + { } /* end */ }; -static int alc_build_pcms(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; - const struct hda_pcm_stream *p; - int i; - codec->num_pcms = 1; - codec->pcm_info = info; +/* + * ALC880 W810 model + * + * W810 has rear IO for: + * Front (DAC 02) + * Surround (DAC 03) + * Center/LFE (DAC 04) + * Digital out (06) + * + * The system also has a pair of internal speakers, and a headphone jack. + * These are both connected to Line2 on the codec, hence to DAC 02. + * + * There is a variable resistor to control the speaker or headphone + * volume. This is a hardware-only device without a software API. + * + * Plugging headphones in will disable the internal speakers. This is + * implemented in hardware, not via the driver using jack sense. In + * a similar fashion, plugging into the rear socket marked "front" will + * disable both the speakers and headphones. + * + * For input, there's a microphone jack, and an "audio in" jack. + * These may not do anything useful with this driver yet, because I + * haven't setup any initialization verbs for these yet... + */ - if (spec->no_analog) - goto skip_analog; +static const hda_nid_t alc880_w810_dac_nids[3] = { + /* front, rear/surround, clfe */ + 0x02, 0x03, 0x04 +}; - snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog), - "%s Analog", codec->chip_name); - info->name = spec->stream_name_analog; +/* fixed 6 channels */ +static const struct hda_channel_mode alc880_w810_modes[1] = { + { 6, NULL } +}; - if (spec->multiout.dac_nids > 0) { - p = spec->stream_analog_playback; - if (!p) - p = &alc_pcm_analog_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; - } - if (spec->adc_nids) { - p = spec->stream_analog_capture; - if (!p) { - if (spec->dyn_adc_switch) - p = &dyn_adc_pcm_analog_capture; - else - p = &alc_pcm_analog_capture; - } - info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; - } +/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */ +static const struct snd_kcontrol_new alc880_w810_base_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + { } /* end */ +}; - if (spec->channel_mode) { - info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0; - for (i = 0; i < spec->num_channel_mode; i++) { - if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) { - info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels; - } - } - } - skip_analog: - /* SPDIF for stream index #1 */ - if (spec->multiout.dig_out_nid || spec->dig_in_nid) { - snprintf(spec->stream_name_digital, - sizeof(spec->stream_name_digital), - "%s Digital", codec->chip_name); - codec->num_pcms = 2; - codec->slave_dig_outs = spec->multiout.slave_dig_outs; - info = spec->pcm_rec + 1; - info->name = spec->stream_name_digital; - if (spec->dig_out_type) - info->pcm_type = spec->dig_out_type; - else - info->pcm_type = HDA_PCM_TYPE_SPDIF; - if (spec->multiout.dig_out_nid) { - p = spec->stream_digital_playback; - if (!p) - p = &alc_pcm_digital_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; - } - if (spec->dig_in_nid) { - p = spec->stream_digital_capture; - if (!p) - p = &alc_pcm_digital_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; - } - /* FIXME: do we need this for all Realtek codec models? */ - codec->spdif_status_reset = 1; - } +/* + * Z710V model + * + * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d) + * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?), + * Line = 0x1a + */ - if (spec->no_analog) - return 0; +static const hda_nid_t alc880_z71v_dac_nids[1] = { + 0x02 +}; +#define ALC880_Z71V_HP_DAC 0x03 - /* If the use of more than one ADC is requested for the current - * model, configure a second analog capture-only PCM. - */ - /* Additional Analaog capture for index #2 */ - if (spec->alt_dac_nid || spec->num_adc_nids > 1) { - codec->num_pcms = 3; - info = spec->pcm_rec + 2; - info->name = spec->stream_name_analog; - if (spec->alt_dac_nid) { - p = spec->stream_analog_alt_playback; - if (!p) - p = &alc_pcm_analog_alt_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = - spec->alt_dac_nid; - } else { - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = - alc_pcm_null_stream; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0; - } - if (spec->num_adc_nids > 1) { - p = spec->stream_analog_alt_capture; - if (!p) - p = &alc_pcm_analog_alt_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = - spec->adc_nids[1]; - info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = - spec->num_adc_nids - 1; - } else { - info->stream[SNDRV_PCM_STREAM_CAPTURE] = - alc_pcm_null_stream; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0; - } - } +/* fixed 2 channels */ +static const struct hda_channel_mode alc880_2_jack_modes[1] = { + { 2, NULL } +}; - return 0; -} +static const struct snd_kcontrol_new alc880_z71v_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; -static inline void alc_shutup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - if (spec && spec->shutup) - spec->shutup(codec); - snd_hda_shutup_pins(codec); -} +/* + * ALC880 F1734 model + * + * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d) + * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18 + */ -static void alc_free_kctls(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; +static const hda_nid_t alc880_f1734_dac_nids[1] = { + 0x03 +}; +#define ALC880_F1734_HP_DAC 0x02 + +static const struct snd_kcontrol_new alc880_f1734_mixer[] = { + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; - if (spec->kctls.list) { - struct snd_kcontrol_new *kctl = spec->kctls.list; - int i; - for (i = 0; i < spec->kctls.used; i++) - kfree(kctl[i].name); - } - snd_array_free(&spec->kctls); -} +static const struct hda_input_mux alc880_f1734_capture_source = { + .num_items = 2, + .items = { + { "Mic", 0x1 }, + { "CD", 0x4 }, + }, +}; -static void alc_free(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - if (!spec) - return; +/* + * ALC880 ASUS model + * + * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e) + * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16, + * Mic = 0x18, Line = 0x1a + */ - alc_shutup(codec); - snd_hda_input_jack_free(codec); - alc_free_kctls(codec); - kfree(spec); - snd_hda_detach_beep_device(codec); -} +#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */ +#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */ + +static const struct snd_kcontrol_new alc880_asus_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + }, + { } /* end */ +}; -#ifdef CONFIG_SND_HDA_POWER_SAVE -static void alc_power_eapd(struct hda_codec *codec) -{ - alc_auto_setup_eapd(codec, false); -} +/* + * ALC880 ASUS W1V model + * + * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e) + * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16, + * Mic = 0x18, Line = 0x1a, Line2 = 0x1b + */ -static int alc_suspend(struct hda_codec *codec, pm_message_t state) -{ - struct alc_spec *spec = codec->spec; - alc_shutup(codec); - if (spec && spec->power_hook) - spec->power_hook(codec); - return 0; -} -#endif +/* additional mixers to alc880_asus_mixer */ +static const struct snd_kcontrol_new alc880_asus_w1v_mixer[] = { + HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT), + HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT), + { } /* end */ +}; -#ifdef SND_HDA_NEEDS_RESUME -static int alc_resume(struct hda_codec *codec) -{ - msleep(150); /* to avoid pop noise */ - codec->patch_ops.init(codec); - snd_hda_codec_resume_amp(codec); - snd_hda_codec_resume_cache(codec); - hda_call_check_power_status(codec, 0x01); - return 0; -} -#endif +/* TCL S700 */ +static const struct snd_kcontrol_new alc880_tcl_s700_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + { } /* end */ +}; -/* - */ -static const struct hda_codec_ops alc_patch_ops = { - .build_controls = alc_build_controls, - .build_pcms = alc_build_pcms, - .init = alc_init, - .free = alc_free, - .unsol_event = alc_unsol_event, -#ifdef SND_HDA_NEEDS_RESUME - .resume = alc_resume, -#endif -#ifdef CONFIG_SND_HDA_POWER_SAVE - .suspend = alc_suspend, - .check_power_status = alc_check_power_status, -#endif - .reboot_notify = alc_shutup, +/* Uniwill */ +static const struct snd_kcontrol_new alc880_uniwill_mixer[] = { + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + }, + { } /* end */ }; -/* replace the codec chip_name with the given string */ -static int alc_codec_rename(struct hda_codec *codec, const char *name) -{ - kfree(codec->chip_name); - codec->chip_name = kstrdup(name, GFP_KERNEL); - if (!codec->chip_name) { - alc_free(codec); - return -ENOMEM; - } - return 0; -} +static const struct snd_kcontrol_new alc880_fujitsu_mixer[] = { + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = { + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; /* - * Automatic parse of I/O pins from the BIOS configuration + * virtual master controls */ -enum { - ALC_CTL_WIDGET_VOL, - ALC_CTL_WIDGET_MUTE, - ALC_CTL_BIND_MUTE, -}; -static const struct snd_kcontrol_new alc_control_templates[] = { - HDA_CODEC_VOLUME(NULL, 0, 0, 0), - HDA_CODEC_MUTE(NULL, 0, 0, 0), - HDA_BIND_MUTE(NULL, 0, 0, 0), +/* + * slave controls for virtual master + */ +static const char * const alc_slave_vols[] = { + "Front Playback Volume", + "Surround Playback Volume", + "Center Playback Volume", + "LFE Playback Volume", + "Side Playback Volume", + "Headphone Playback Volume", + "Speaker Playback Volume", + "Mono Playback Volume", + "Line-Out Playback Volume", + NULL, }; -/* add dynamic controls */ -static int add_control(struct alc_spec *spec, int type, const char *name, - int cidx, unsigned long val) -{ - struct snd_kcontrol_new *knew; - - knew = alc_kcontrol_new(spec); +static const char * const alc_slave_sws[] = { + "Front Playback Switch", + "Surround Playback Switch", + "Center Playback Switch", + "LFE Playback Switch", + "Side Playback Switch", + "Headphone Playback Switch", + "Speaker Playback Switch", + "Mono Playback Switch", + "IEC958 Playback Switch", + "Line-Out Playback Switch", + NULL, +}; + +/* + * build control elements + */ + +#define NID_MAPPING (-1) + +#define SUBDEV_SPEAKER_ (0 << 6) +#define SUBDEV_HP_ (1 << 6) +#define SUBDEV_LINE_ (2 << 6) +#define SUBDEV_SPEAKER(x) (SUBDEV_SPEAKER_ | ((x) & 0x3f)) +#define SUBDEV_HP(x) (SUBDEV_HP_ | ((x) & 0x3f)) +#define SUBDEV_LINE(x) (SUBDEV_LINE_ | ((x) & 0x3f)) + +static void alc_free_kctls(struct hda_codec *codec); + +#ifdef CONFIG_SND_HDA_INPUT_BEEP +/* additional beep mixers; the actual parameters are overwritten at build */ +static const struct snd_kcontrol_new alc_beep_mixer[] = { + HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT), + HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT), + { } /* end */ +}; +#endif + +static int alc_build_controls(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + struct snd_kcontrol *kctl = NULL; + const struct snd_kcontrol_new *knew; + int i, j, err; + unsigned int u; + hda_nid_t nid; + + for (i = 0; i < spec->num_mixers; i++) { + err = snd_hda_add_new_ctls(codec, spec->mixers[i]); + if (err < 0) + return err; + } + if (spec->cap_mixer) { + err = snd_hda_add_new_ctls(codec, spec->cap_mixer); + if (err < 0) + return err; + } + if (spec->multiout.dig_out_nid) { + err = snd_hda_create_spdif_out_ctls(codec, + spec->multiout.dig_out_nid); + if (err < 0) + return err; + if (!spec->no_analog) { + err = snd_hda_create_spdif_share_sw(codec, + &spec->multiout); + if (err < 0) + return err; + spec->multiout.share_spdif = 1; + } + } + if (spec->dig_in_nid) { + err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); + if (err < 0) + return err; + } + +#ifdef CONFIG_SND_HDA_INPUT_BEEP + /* create beep controls if needed */ + if (spec->beep_amp) { + const struct snd_kcontrol_new *knew; + for (knew = alc_beep_mixer; knew->name; knew++) { + struct snd_kcontrol *kctl; + kctl = snd_ctl_new1(knew, codec); + if (!kctl) + return -ENOMEM; + kctl->private_value = spec->beep_amp; + err = snd_hda_ctl_add(codec, 0, kctl); + if (err < 0) + return err; + } + } +#endif + + /* if we have no master control, let's create it */ + if (!spec->no_analog && + !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { + unsigned int vmaster_tlv[4]; + snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, + HDA_OUTPUT, vmaster_tlv); + err = snd_hda_add_vmaster(codec, "Master Playback Volume", + vmaster_tlv, alc_slave_vols); + if (err < 0) + return err; + } + if (!spec->no_analog && + !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { + err = snd_hda_add_vmaster(codec, "Master Playback Switch", + NULL, alc_slave_sws); + if (err < 0) + return err; + } + + /* assign Capture Source enums to NID */ + if (spec->capsrc_nids || spec->adc_nids) { + kctl = snd_hda_find_mixer_ctl(codec, "Capture Source"); + if (!kctl) + kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); + for (i = 0; kctl && i < kctl->count; i++) { + const hda_nid_t *nids = spec->capsrc_nids; + if (!nids) + nids = spec->adc_nids; + err = snd_hda_add_nid(codec, kctl, i, nids[i]); + if (err < 0) + return err; + } + } + if (spec->cap_mixer) { + const char *kname = kctl ? kctl->id.name : NULL; + for (knew = spec->cap_mixer; knew->name; knew++) { + if (kname && strcmp(knew->name, kname) == 0) + continue; + kctl = snd_hda_find_mixer_ctl(codec, knew->name); + for (i = 0; kctl && i < kctl->count; i++) { + err = snd_hda_add_nid(codec, kctl, i, + spec->adc_nids[i]); + if (err < 0) + return err; + } + } + } + + /* other nid->control mapping */ + for (i = 0; i < spec->num_mixers; i++) { + for (knew = spec->mixers[i]; knew->name; knew++) { + if (knew->iface != NID_MAPPING) + continue; + kctl = snd_hda_find_mixer_ctl(codec, knew->name); + if (kctl == NULL) + continue; + u = knew->subdevice; + for (j = 0; j < 4; j++, u >>= 8) { + nid = u & 0x3f; + if (nid == 0) + continue; + switch (u & 0xc0) { + case SUBDEV_SPEAKER_: + nid = spec->autocfg.speaker_pins[nid]; + break; + case SUBDEV_LINE_: + nid = spec->autocfg.line_out_pins[nid]; + break; + case SUBDEV_HP_: + nid = spec->autocfg.hp_pins[nid]; + break; + default: + continue; + } + err = snd_hda_add_nid(codec, kctl, 0, nid); + if (err < 0) + return err; + } + u = knew->private_value; + for (j = 0; j < 4; j++, u >>= 8) { + nid = u & 0xff; + if (nid == 0) + continue; + err = snd_hda_add_nid(codec, kctl, 0, nid); + if (err < 0) + return err; + } + } + } + + alc_free_kctls(codec); /* no longer needed */ + + return 0; +} + + +/* + * initialize the codec volumes, etc + */ + +/* + * generic initialization of ADC, input mixers and output mixers + */ +static const struct hda_verb alc880_volume_init_verbs[] = { + /* + * Unmute ADC0-2 and set the default input to mic-in + */ + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + * Note: PASD motherboards uses the Line In 2 as the input for front + * panel mic (mic 2) + */ + /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, + + /* + * Set up output mixers (0x0c - 0x0f) + */ + /* set vol=0 to output mixers */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* set up input amps for analog loopback */ + /* Amp Indices: DAC = 0, mixer = 1 */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + + { } +}; + +/* + * 3-stack pin configuration: + * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b + */ +static const struct hda_verb alc880_pin_3stack_init_verbs[] = { + /* + * preset connection lists of input pins + * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround + */ + {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ + {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */ + + /* + * Set pin mode and muting + */ + /* set front pin widgets 0x14 for output */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Mic1 (rear panel) pin widget for input and vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Mic2 (as headphone out) for HP output */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Line In pin widget for input */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line2 (as front mic) pin widget for input and vref at 80% */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* CD pin widget for input */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + { } +}; + +/* + * 5-stack pin configuration: + * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19, + * line-in/side = 0x1a, f-mic = 0x1b + */ +static const struct hda_verb alc880_pin_5stack_init_verbs[] = { + /* + * preset connection lists of input pins + * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround + */ + {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */ + + /* + * Set pin mode and muting + */ + /* set pin widgets 0x14-0x17 for output */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + /* unmute pins for output (no gain on this amp) */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Mic1 (rear panel) pin widget for input and vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Mic2 (as headphone out) for HP output */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Line In pin widget for input */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line2 (as front mic) pin widget for input and vref at 80% */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* CD pin widget for input */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + { } +}; + +/* + * W810 pin configuration: + * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b + */ +static const struct hda_verb alc880_pin_w810_init_verbs[] = { + /* hphone/speaker input selector: front DAC */ + {0x13, AC_VERB_SET_CONNECT_SEL, 0x0}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + + { } +}; + +/* + * Z71V pin configuration: + * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?) + */ +static const struct hda_verb alc880_pin_z71v_init_verbs[] = { + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + { } +}; + +/* + * 6-stack pin configuration: + * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18, + * f-mic = 0x19, line = 0x1a, HP = 0x1b + */ +static const struct hda_verb alc880_pin_6stack_init_verbs[] = { + {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + { } +}; + +/* + * Uniwill pin configuration: + * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19, + * line = 0x1a + */ +static const struct hda_verb alc880_uniwill_init_verbs[] = { + {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */ + /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + + { } +}; + +/* +* Uniwill P53 +* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19, + */ +static const struct hda_verb alc880_uniwill_p53_init_verbs[] = { + {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT}, + + { } +}; + +static const struct hda_verb alc880_beep_init_verbs[] = { + { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) }, + { } +}; + +/* auto-toggle front mic */ +static void alc88x_simple_mic_automute(struct hda_codec *codec) +{ + unsigned int present; + unsigned char bits; + + present = snd_hda_jack_detect(codec, 0x18); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits); +} + +static void alc880_uniwill_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x16; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static void alc880_uniwill_init_hook(struct hda_codec *codec) +{ + alc_hp_automute(codec); + alc88x_simple_mic_automute(codec); +} + +static void alc880_uniwill_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + /* Looks like the unsol event is incompatible with the standard + * definition. 4bit tag is placed at 28 bit! + */ + switch (res >> 28) { + case ALC880_MIC_EVENT: + alc88x_simple_mic_automute(codec); + break; + default: + alc_sku_unsol_event(codec, res); + break; + } +} + +static void alc880_uniwill_p53_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_codec_read(codec, 0x21, 0, + AC_VERB_GET_VOLUME_KNOB_CONTROL, 0); + present &= HDA_AMP_VOLMASK; + snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0, + HDA_AMP_VOLMASK, present); + snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0, + HDA_AMP_VOLMASK, present); +} + +static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + /* Looks like the unsol event is incompatible with the standard + * definition. 4bit tag is placed at 28 bit! + */ + if ((res >> 28) == ALC880_DCVOL_EVENT) + alc880_uniwill_p53_dcvol_automute(codec); + else + alc_sku_unsol_event(codec, res); +} + +/* + * F1734 pin configuration: + * HP = 0x14, speaker-out = 0x15, mic = 0x18 + */ +static const struct hda_verb alc880_pin_f1734_init_verbs[] = { + {0x07, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, + {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_DCVOL_EVENT}, + + { } +}; + +/* + * ASUS pin configuration: + * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a + */ +static const struct hda_verb alc880_pin_asus_init_verbs[] = { + {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, + {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + { } +}; + +/* Enable GPIO mask and set output */ +#define alc880_gpio1_init_verbs alc_gpio1_init_verbs +#define alc880_gpio2_init_verbs alc_gpio2_init_verbs +#define alc880_gpio3_init_verbs alc_gpio3_init_verbs + +/* Clevo m520g init */ +static const struct hda_verb alc880_pin_clevo_init_verbs[] = { + /* headphone output */ + {0x11, AC_VERB_SET_CONNECT_SEL, 0x01}, + /* line-out */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Line-in */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* CD */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Mic1 (rear panel) */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Mic2 (front panel) */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* headphone */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* change to EAPD mode */ + {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, + {0x20, AC_VERB_SET_PROC_COEF, 0x3060}, + + { } +}; + +static const struct hda_verb alc880_pin_tcl_S700_init_verbs[] = { + /* change to EAPD mode */ + {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, + {0x20, AC_VERB_SET_PROC_COEF, 0x3060}, + + /* Headphone output */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + /* Front output*/ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Line In pin widget for input */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + /* CD pin widget for input */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + /* Mic1 (rear panel) pin widget for input and vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + + /* change to EAPD mode */ + {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, + {0x20, AC_VERB_SET_PROC_COEF, 0x3070}, + + { } +}; + +/* + * LG m1 express dual + * + * Pin assignment: + * Rear Line-In/Out (blue): 0x14 + * Build-in Mic-In: 0x15 + * Speaker-out: 0x17 + * HP-Out (green): 0x1b + * Mic-In/Out (red): 0x19 + * SPDIF-Out: 0x1e + */ + +/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */ +static const hda_nid_t alc880_lg_dac_nids[3] = { + 0x05, 0x02, 0x03 +}; + +/* seems analog CD is not working */ +static const struct hda_input_mux alc880_lg_capture_source = { + .num_items = 3, + .items = { + { "Mic", 0x1 }, + { "Line", 0x5 }, + { "Internal Mic", 0x6 }, + }, +}; + +/* 2,4,6 channel modes */ +static const struct hda_verb alc880_lg_ch2_init[] = { + /* set line-in and mic-in to input */ + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { } +}; + +static const struct hda_verb alc880_lg_ch4_init[] = { + /* set line-in to out and mic-in to input */ + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, + { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { } +}; + +static const struct hda_verb alc880_lg_ch6_init[] = { + /* set line-in and mic-in to output */ + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, + { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, + { } +}; + +static const struct hda_channel_mode alc880_lg_ch_modes[3] = { + { 2, alc880_lg_ch2_init }, + { 4, alc880_lg_ch4_init }, + { 6, alc880_lg_ch6_init }, +}; + +static const struct snd_kcontrol_new alc880_lg_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + }, + { } /* end */ +}; + +static const struct hda_verb alc880_lg_init_verbs[] = { + /* set capture source to mic-in */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + /* mute all amp mixer inputs */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, + /* line-in to input */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* built-in mic */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* speaker-out */ + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* mic-in to input */ + {0x11, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* HP-out */ + {0x13, AC_VERB_SET_CONNECT_SEL, 0x03}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* jack sense */ + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + { } +}; + +/* toggle speaker-output according to the hp-jack state */ +static void alc880_lg_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x17; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +/* + * LG LW20 + * + * Pin assignment: + * Speaker-out: 0x14 + * Mic-In: 0x18 + * Built-in Mic-In: 0x19 + * Line-In: 0x1b + * HP-Out: 0x1a + * SPDIF-Out: 0x1e + */ + +static const struct hda_input_mux alc880_lg_lw_capture_source = { + .num_items = 3, + .items = { + { "Mic", 0x0 }, + { "Internal Mic", 0x1 }, + { "Line In", 0x2 }, + }, +}; + +#define alc880_lg_lw_modes alc880_threestack_modes + +static const struct snd_kcontrol_new alc880_lg_lw_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + }, + { } /* end */ +}; + +static const struct hda_verb alc880_lg_lw_init_verbs[] = { + {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ + {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */ + + /* set capture source to mic-in */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, + /* speaker-out */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* HP-out */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* mic-in to input */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* built-in mic */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* jack sense */ + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + { } +}; + +/* toggle speaker-output according to the hp-jack state */ +static void alc880_lg_lw_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static const struct snd_kcontrol_new alc880_medion_rim_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct hda_input_mux alc880_medion_rim_capture_source = { + .num_items = 2, + .items = { + { "Mic", 0x0 }, + { "Internal Mic", 0x1 }, + }, +}; + +static const struct hda_verb alc880_medion_rim_init_verbs[] = { + {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Mic1 (rear panel) pin widget for input and vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Mic2 (as headphone out) for HP output */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Internal Speaker */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, + {0x20, AC_VERB_SET_PROC_COEF, 0x3060}, + + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + { } +}; + +/* toggle speaker-output according to the hp-jack state */ +static void alc880_medion_rim_automute(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + alc_hp_automute(codec); + /* toggle EAPD */ + if (spec->jack_present) + snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0); + else + snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2); +} + +static void alc880_medion_rim_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + /* Looks like the unsol event is incompatible with the standard + * definition. 4bit tag is placed at 28 bit! + */ + if ((res >> 28) == ALC880_HP_EVENT) + alc880_medion_rim_automute(codec); +} + +static void alc880_medion_rim_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x1b; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +#ifdef CONFIG_SND_HDA_POWER_SAVE +static const struct hda_amp_list alc880_loopbacks[] = { + { 0x0b, HDA_INPUT, 0 }, + { 0x0b, HDA_INPUT, 1 }, + { 0x0b, HDA_INPUT, 2 }, + { 0x0b, HDA_INPUT, 3 }, + { 0x0b, HDA_INPUT, 4 }, + { } /* end */ +}; + +static const struct hda_amp_list alc880_lg_loopbacks[] = { + { 0x0b, HDA_INPUT, 1 }, + { 0x0b, HDA_INPUT, 6 }, + { 0x0b, HDA_INPUT, 7 }, + { } /* end */ +}; +#endif + +/* + * Common callbacks + */ + +static void alc_init_special_input_src(struct hda_codec *codec); + +static int alc_init(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + unsigned int i; + + alc_fix_pll(codec); + alc_auto_init_amp(codec, spec->init_amp); + + for (i = 0; i < spec->num_init_verbs; i++) + snd_hda_sequence_write(codec, spec->init_verbs[i]); + alc_init_special_input_src(codec); + + if (spec->init_hook) + spec->init_hook(codec); + + alc_apply_fixup(codec, ALC_FIXUP_ACT_INIT); + + hda_call_check_power_status(codec, 0x01); + return 0; +} + +static void alc_unsol_event(struct hda_codec *codec, unsigned int res) +{ + struct alc_spec *spec = codec->spec; + + if (spec->unsol_event) + spec->unsol_event(codec, res); +} + +#ifdef CONFIG_SND_HDA_POWER_SAVE +static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid) +{ + struct alc_spec *spec = codec->spec; + return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); +} +#endif + +/* + * Analog playback callbacks + */ +static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct alc_spec *spec = codec->spec; + return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, + hinfo); +} + +static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + struct alc_spec *spec = codec->spec; + return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, + stream_tag, format, substream); +} + +static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct alc_spec *spec = codec->spec; + return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); +} + +/* + * Digital out + */ +static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct alc_spec *spec = codec->spec; + return snd_hda_multi_out_dig_open(codec, &spec->multiout); +} + +static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + struct alc_spec *spec = codec->spec; + return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, + stream_tag, format, substream); +} + +static int alc880_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct alc_spec *spec = codec->spec; + return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); +} + +static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct alc_spec *spec = codec->spec; + return snd_hda_multi_out_dig_close(codec, &spec->multiout); +} + +/* + * Analog capture + */ +static int alc880_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + struct alc_spec *spec = codec->spec; + + snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1], + stream_tag, 0, format); + return 0; +} + +static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct alc_spec *spec = codec->spec; + + snd_hda_codec_cleanup_stream(codec, + spec->adc_nids[substream->number + 1]); + return 0; +} + +/* analog capture with dynamic dual-adc changes */ +static int dualmic_capture_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + struct alc_spec *spec = codec->spec; + spec->cur_adc = spec->adc_nids[spec->cur_adc_idx]; + spec->cur_adc_stream_tag = stream_tag; + spec->cur_adc_format = format; + snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); + return 0; +} + +static int dualmic_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct alc_spec *spec = codec->spec; + snd_hda_codec_cleanup_stream(codec, spec->cur_adc); + spec->cur_adc = 0; + return 0; +} + +static const struct hda_pcm_stream dualmic_pcm_analog_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + .nid = 0, /* fill later */ + .ops = { + .prepare = dualmic_capture_pcm_prepare, + .cleanup = dualmic_capture_pcm_cleanup + }, +}; + +/* + */ +static const struct hda_pcm_stream alc880_pcm_analog_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 8, + /* NID is set in alc_build_pcms */ + .ops = { + .open = alc880_playback_pcm_open, + .prepare = alc880_playback_pcm_prepare, + .cleanup = alc880_playback_pcm_cleanup + }, +}; + +static const struct hda_pcm_stream alc880_pcm_analog_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in alc_build_pcms */ +}; + +static const struct hda_pcm_stream alc880_pcm_analog_alt_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in alc_build_pcms */ +}; + +static const struct hda_pcm_stream alc880_pcm_analog_alt_capture = { + .substreams = 2, /* can be overridden */ + .channels_min = 2, + .channels_max = 2, + /* NID is set in alc_build_pcms */ + .ops = { + .prepare = alc880_alt_capture_pcm_prepare, + .cleanup = alc880_alt_capture_pcm_cleanup + }, +}; + +static const struct hda_pcm_stream alc880_pcm_digital_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in alc_build_pcms */ + .ops = { + .open = alc880_dig_playback_pcm_open, + .close = alc880_dig_playback_pcm_close, + .prepare = alc880_dig_playback_pcm_prepare, + .cleanup = alc880_dig_playback_pcm_cleanup + }, +}; + +static const struct hda_pcm_stream alc880_pcm_digital_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in alc_build_pcms */ +}; + +/* Used by alc_build_pcms to flag that a PCM has no playback stream */ +static const struct hda_pcm_stream alc_pcm_null_stream = { + .substreams = 0, + .channels_min = 0, + .channels_max = 0, +}; + +static int alc_build_pcms(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + struct hda_pcm *info = spec->pcm_rec; + int i; + + codec->num_pcms = 1; + codec->pcm_info = info; + + if (spec->no_analog) + goto skip_analog; + + snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog), + "%s Analog", codec->chip_name); + info->name = spec->stream_name_analog; + + if (spec->stream_analog_playback) { + if (snd_BUG_ON(!spec->multiout.dac_nids)) + return -EINVAL; + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback); + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; + } + if (spec->stream_analog_capture) { + if (snd_BUG_ON(!spec->adc_nids)) + return -EINVAL; + info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture); + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; + } + + if (spec->channel_mode) { + info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0; + for (i = 0; i < spec->num_channel_mode; i++) { + if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) { + info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels; + } + } + } + + skip_analog: + /* SPDIF for stream index #1 */ + if (spec->multiout.dig_out_nid || spec->dig_in_nid) { + snprintf(spec->stream_name_digital, + sizeof(spec->stream_name_digital), + "%s Digital", codec->chip_name); + codec->num_pcms = 2; + codec->slave_dig_outs = spec->multiout.slave_dig_outs; + info = spec->pcm_rec + 1; + info->name = spec->stream_name_digital; + if (spec->dig_out_type) + info->pcm_type = spec->dig_out_type; + else + info->pcm_type = HDA_PCM_TYPE_SPDIF; + if (spec->multiout.dig_out_nid && + spec->stream_digital_playback) { + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback); + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; + } + if (spec->dig_in_nid && + spec->stream_digital_capture) { + info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture); + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; + } + /* FIXME: do we need this for all Realtek codec models? */ + codec->spdif_status_reset = 1; + } + + if (spec->no_analog) + return 0; + + /* If the use of more than one ADC is requested for the current + * model, configure a second analog capture-only PCM. + */ + /* Additional Analaog capture for index #2 */ + if ((spec->alt_dac_nid && spec->stream_analog_alt_playback) || + (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture)) { + codec->num_pcms = 3; + info = spec->pcm_rec + 2; + info->name = spec->stream_name_analog; + if (spec->alt_dac_nid) { + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = + *spec->stream_analog_alt_playback; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = + spec->alt_dac_nid; + } else { + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = + alc_pcm_null_stream; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0; + } + if (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture) { + info->stream[SNDRV_PCM_STREAM_CAPTURE] = + *spec->stream_analog_alt_capture; + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = + spec->adc_nids[1]; + info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = + spec->num_adc_nids - 1; + } else { + info->stream[SNDRV_PCM_STREAM_CAPTURE] = + alc_pcm_null_stream; + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0; + } + } + + return 0; +} + +static inline void alc_shutup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + if (spec && spec->shutup) + spec->shutup(codec); + snd_hda_shutup_pins(codec); +} + +static void alc_free_kctls(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + if (spec->kctls.list) { + struct snd_kcontrol_new *kctl = spec->kctls.list; + int i; + for (i = 0; i < spec->kctls.used; i++) + kfree(kctl[i].name); + } + snd_array_free(&spec->kctls); +} + +static void alc_free(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + if (!spec) + return; + + alc_shutup(codec); + snd_hda_input_jack_free(codec); + alc_free_kctls(codec); + kfree(spec); + snd_hda_detach_beep_device(codec); +} + +#ifdef CONFIG_SND_HDA_POWER_SAVE +static void alc_power_eapd(struct hda_codec *codec) +{ + alc_auto_setup_eapd(codec, false); +} + +static int alc_suspend(struct hda_codec *codec, pm_message_t state) +{ + struct alc_spec *spec = codec->spec; + alc_shutup(codec); + if (spec && spec->power_hook) + spec->power_hook(codec); + return 0; +} +#endif + +#ifdef SND_HDA_NEEDS_RESUME +static int alc_resume(struct hda_codec *codec) +{ + msleep(150); /* to avoid pop noise */ + codec->patch_ops.init(codec); + snd_hda_codec_resume_amp(codec); + snd_hda_codec_resume_cache(codec); + hda_call_check_power_status(codec, 0x01); + return 0; +} +#endif + +/* + */ +static const struct hda_codec_ops alc_patch_ops = { + .build_controls = alc_build_controls, + .build_pcms = alc_build_pcms, + .init = alc_init, + .free = alc_free, + .unsol_event = alc_unsol_event, +#ifdef SND_HDA_NEEDS_RESUME + .resume = alc_resume, +#endif +#ifdef CONFIG_SND_HDA_POWER_SAVE + .suspend = alc_suspend, + .check_power_status = alc_check_power_status, +#endif + .reboot_notify = alc_shutup, +}; + +/* replace the codec chip_name with the given string */ +static int alc_codec_rename(struct hda_codec *codec, const char *name) +{ + kfree(codec->chip_name); + codec->chip_name = kstrdup(name, GFP_KERNEL); + if (!codec->chip_name) { + alc_free(codec); + return -ENOMEM; + } + return 0; +} + +/* + * Test configuration for debugging + * + * Almost all inputs/outputs are enabled. I/O pins can be configured via + * enum controls. + */ +#ifdef CONFIG_SND_DEBUG +static const hda_nid_t alc880_test_dac_nids[4] = { + 0x02, 0x03, 0x04, 0x05 +}; + +static const struct hda_input_mux alc880_test_capture_source = { + .num_items = 7, + .items = { + { "In-1", 0x0 }, + { "In-2", 0x1 }, + { "In-3", 0x2 }, + { "In-4", 0x3 }, + { "CD", 0x4 }, + { "Front", 0x5 }, + { "Surround", 0x6 }, + }, +}; + +static const struct hda_channel_mode alc880_test_modes[4] = { + { 2, NULL }, + { 4, NULL }, + { 6, NULL }, + { 8, NULL }, +}; + +static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static const char * const texts[] = { + "N/A", "Line Out", "HP Out", + "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%" + }; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 8; + if (uinfo->value.enumerated.item >= 8) + uinfo->value.enumerated.item = 7; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = (hda_nid_t)kcontrol->private_value; + unsigned int pin_ctl, item = 0; + + pin_ctl = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + if (pin_ctl & AC_PINCTL_OUT_EN) { + if (pin_ctl & AC_PINCTL_HP_EN) + item = 2; + else + item = 1; + } else if (pin_ctl & AC_PINCTL_IN_EN) { + switch (pin_ctl & AC_PINCTL_VREFEN) { + case AC_PINCTL_VREF_HIZ: item = 3; break; + case AC_PINCTL_VREF_50: item = 4; break; + case AC_PINCTL_VREF_GRD: item = 5; break; + case AC_PINCTL_VREF_80: item = 6; break; + case AC_PINCTL_VREF_100: item = 7; break; + } + } + ucontrol->value.enumerated.item[0] = item; + return 0; +} + +static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = (hda_nid_t)kcontrol->private_value; + static const unsigned int ctls[] = { + 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN, + AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ, + AC_PINCTL_IN_EN | AC_PINCTL_VREF_50, + AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD, + AC_PINCTL_IN_EN | AC_PINCTL_VREF_80, + AC_PINCTL_IN_EN | AC_PINCTL_VREF_100, + }; + unsigned int old_ctl, new_ctl; + + old_ctl = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + new_ctl = ctls[ucontrol->value.enumerated.item[0]]; + if (old_ctl != new_ctl) { + int val; + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + new_ctl); + val = ucontrol->value.enumerated.item[0] >= 3 ? + HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, val); + return 1; + } + return 0; +} + +static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static const char * const texts[] = { + "Front", "Surround", "CLFE", "Side" + }; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 4; + if (uinfo->value.enumerated.item >= 4) + uinfo->value.enumerated.item = 3; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = (hda_nid_t)kcontrol->private_value; + unsigned int sel; + + sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0); + ucontrol->value.enumerated.item[0] = sel & 3; + return 0; +} + +static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = (hda_nid_t)kcontrol->private_value; + unsigned int sel; + + sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3; + if (ucontrol->value.enumerated.item[0] != sel) { + sel = ucontrol->value.enumerated.item[0] & 3; + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_CONNECT_SEL, sel); + return 1; + } + return 0; +} + +#define PIN_CTL_TEST(xname,nid) { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ + .info = alc_test_pin_ctl_info, \ + .get = alc_test_pin_ctl_get, \ + .put = alc_test_pin_ctl_put, \ + .private_value = nid \ + } + +#define PIN_SRC_TEST(xname,nid) { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ + .info = alc_test_pin_src_info, \ + .get = alc_test_pin_src_get, \ + .put = alc_test_pin_src_put, \ + .private_value = nid \ + } + +static const struct snd_kcontrol_new alc880_test_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT), + HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), + PIN_CTL_TEST("Front Pin Mode", 0x14), + PIN_CTL_TEST("Surround Pin Mode", 0x15), + PIN_CTL_TEST("CLFE Pin Mode", 0x16), + PIN_CTL_TEST("Side Pin Mode", 0x17), + PIN_CTL_TEST("In-1 Pin Mode", 0x18), + PIN_CTL_TEST("In-2 Pin Mode", 0x19), + PIN_CTL_TEST("In-3 Pin Mode", 0x1a), + PIN_CTL_TEST("In-4 Pin Mode", 0x1b), + PIN_SRC_TEST("In-1 Pin Source", 0x18), + PIN_SRC_TEST("In-2 Pin Source", 0x19), + PIN_SRC_TEST("In-3 Pin Source", 0x1a), + PIN_SRC_TEST("In-4 Pin Source", 0x1b), + HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT), + HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT), + HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT), + HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + }, + { } /* end */ +}; + +static const struct hda_verb alc880_test_init_verbs[] = { + /* Unmute inputs of 0x0c - 0x0f */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + /* Vol output for 0x0c-0x0f */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* Set output pins 0x14-0x17 */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + /* Unmute output pins 0x14-0x17 */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Set input pins 0x18-0x1c */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + /* Mute input pins 0x18-0x1b */ + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* ADC set up */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* Analog input/passthru */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + { } +}; +#endif + +/* + */ + +static const char * const alc880_models[ALC880_MODEL_LAST] = { + [ALC880_3ST] = "3stack", + [ALC880_TCL_S700] = "tcl", + [ALC880_3ST_DIG] = "3stack-digout", + [ALC880_CLEVO] = "clevo", + [ALC880_5ST] = "5stack", + [ALC880_5ST_DIG] = "5stack-digout", + [ALC880_W810] = "w810", + [ALC880_Z71V] = "z71v", + [ALC880_6ST] = "6stack", + [ALC880_6ST_DIG] = "6stack-digout", + [ALC880_ASUS] = "asus", + [ALC880_ASUS_W1V] = "asus-w1v", + [ALC880_ASUS_DIG] = "asus-dig", + [ALC880_ASUS_DIG2] = "asus-dig2", + [ALC880_UNIWILL_DIG] = "uniwill", + [ALC880_UNIWILL_P53] = "uniwill-p53", + [ALC880_FUJITSU] = "fujitsu", + [ALC880_F1734] = "F1734", + [ALC880_LG] = "lg", + [ALC880_LG_LW] = "lg-lw", + [ALC880_MEDION_RIM] = "medion", +#ifdef CONFIG_SND_DEBUG + [ALC880_TEST] = "test", +#endif + [ALC880_AUTO] = "auto", +}; + +static const struct snd_pci_quirk alc880_cfg_tbl[] = { + SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810), + SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST), + SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG), + SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG), + SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG), + SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG), + SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG), + SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST), + SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG), + SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V), + SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG), + SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG), + SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG), + SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG), + SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG), + SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V), + /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */ + SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG), + SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG), + SND_PCI_QUIRK(0x1043, 0x814e, "ASUS P5GD1 w/SPDIF", ALC880_6ST_DIG), + SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG), + SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST), + SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST), + SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_ASUS), /* default ASUS */ + SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST), + SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST), + SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST), + SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST), + SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST), + SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG), + SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG), + SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG), + SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG), + SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO), + SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO), + SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2), + SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG), + SND_PCI_QUIRK(0x1584, 0x9054, "Uniwill", ALC880_F1734), + SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL), + SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53), + SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810), + SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_MEDION_RIM), + SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734), + SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU), + SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_F1734), + SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU), + SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW), + SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG), + SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_LG), + SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG), + SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW), + SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700), + SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */ + SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG), + SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG), + SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG), + SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG), + SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG), + /* default Intel */ + SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_3ST), + SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG), + SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG), + {} +}; + +/* + * ALC880 codec presets + */ +static const struct alc_config_preset alc880_presets[] = { + [ALC880_3ST] = { + .mixers = { alc880_three_stack_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_3stack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_dac_nids), + .dac_nids = alc880_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), + .channel_mode = alc880_threestack_modes, + .need_dac_fix = 1, + .input_mux = &alc880_capture_source, + }, + [ALC880_3ST_DIG] = { + .mixers = { alc880_three_stack_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_3stack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_dac_nids), + .dac_nids = alc880_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), + .channel_mode = alc880_threestack_modes, + .need_dac_fix = 1, + .input_mux = &alc880_capture_source, + }, + [ALC880_TCL_S700] = { + .mixers = { alc880_tcl_s700_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_tcl_S700_init_verbs, + alc880_gpio2_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_dac_nids), + .dac_nids = alc880_dac_nids, + .adc_nids = alc880_adc_nids_alt, /* FIXME: correct? */ + .num_adc_nids = 1, /* single ADC */ + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), + .channel_mode = alc880_2_jack_modes, + .input_mux = &alc880_capture_source, + }, + [ALC880_5ST] = { + .mixers = { alc880_three_stack_mixer, + alc880_five_stack_mixer}, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_5stack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_dac_nids), + .dac_nids = alc880_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes), + .channel_mode = alc880_fivestack_modes, + .input_mux = &alc880_capture_source, + }, + [ALC880_5ST_DIG] = { + .mixers = { alc880_three_stack_mixer, + alc880_five_stack_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_5stack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_dac_nids), + .dac_nids = alc880_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes), + .channel_mode = alc880_fivestack_modes, + .input_mux = &alc880_capture_source, + }, + [ALC880_6ST] = { + .mixers = { alc880_six_stack_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_6stack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids), + .dac_nids = alc880_6st_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes), + .channel_mode = alc880_sixstack_modes, + .input_mux = &alc880_6stack_capture_source, + }, + [ALC880_6ST_DIG] = { + .mixers = { alc880_six_stack_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_6stack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids), + .dac_nids = alc880_6st_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes), + .channel_mode = alc880_sixstack_modes, + .input_mux = &alc880_6stack_capture_source, + }, + [ALC880_W810] = { + .mixers = { alc880_w810_base_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_w810_init_verbs, + alc880_gpio2_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids), + .dac_nids = alc880_w810_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_w810_modes), + .channel_mode = alc880_w810_modes, + .input_mux = &alc880_capture_source, + }, + [ALC880_Z71V] = { + .mixers = { alc880_z71v_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_z71v_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids), + .dac_nids = alc880_z71v_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), + .channel_mode = alc880_2_jack_modes, + .input_mux = &alc880_capture_source, + }, + [ALC880_F1734] = { + .mixers = { alc880_f1734_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_f1734_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids), + .dac_nids = alc880_f1734_dac_nids, + .hp_nid = 0x02, + .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), + .channel_mode = alc880_2_jack_modes, + .input_mux = &alc880_f1734_capture_source, + .unsol_event = alc880_uniwill_p53_unsol_event, + .setup = alc880_uniwill_p53_setup, + .init_hook = alc_hp_automute, + }, + [ALC880_ASUS] = { + .mixers = { alc880_asus_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_asus_init_verbs, + alc880_gpio1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), + .dac_nids = alc880_asus_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), + .channel_mode = alc880_asus_modes, + .need_dac_fix = 1, + .input_mux = &alc880_capture_source, + }, + [ALC880_ASUS_DIG] = { + .mixers = { alc880_asus_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_asus_init_verbs, + alc880_gpio1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), + .dac_nids = alc880_asus_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), + .channel_mode = alc880_asus_modes, + .need_dac_fix = 1, + .input_mux = &alc880_capture_source, + }, + [ALC880_ASUS_DIG2] = { + .mixers = { alc880_asus_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_asus_init_verbs, + alc880_gpio2_init_verbs }, /* use GPIO2 */ + .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), + .dac_nids = alc880_asus_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), + .channel_mode = alc880_asus_modes, + .need_dac_fix = 1, + .input_mux = &alc880_capture_source, + }, + [ALC880_ASUS_W1V] = { + .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_asus_init_verbs, + alc880_gpio1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), + .dac_nids = alc880_asus_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), + .channel_mode = alc880_asus_modes, + .need_dac_fix = 1, + .input_mux = &alc880_capture_source, + }, + [ALC880_UNIWILL_DIG] = { + .mixers = { alc880_asus_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_asus_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), + .dac_nids = alc880_asus_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), + .channel_mode = alc880_asus_modes, + .need_dac_fix = 1, + .input_mux = &alc880_capture_source, + }, + [ALC880_UNIWILL] = { + .mixers = { alc880_uniwill_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_uniwill_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), + .dac_nids = alc880_asus_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), + .channel_mode = alc880_threestack_modes, + .need_dac_fix = 1, + .input_mux = &alc880_capture_source, + .unsol_event = alc880_uniwill_unsol_event, + .setup = alc880_uniwill_setup, + .init_hook = alc880_uniwill_init_hook, + }, + [ALC880_UNIWILL_P53] = { + .mixers = { alc880_uniwill_p53_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_uniwill_p53_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), + .dac_nids = alc880_asus_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc880_w810_modes), + .channel_mode = alc880_threestack_modes, + .input_mux = &alc880_capture_source, + .unsol_event = alc880_uniwill_p53_unsol_event, + .setup = alc880_uniwill_p53_setup, + .init_hook = alc_hp_automute, + }, + [ALC880_FUJITSU] = { + .mixers = { alc880_fujitsu_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_uniwill_p53_init_verbs, + alc880_beep_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_dac_nids), + .dac_nids = alc880_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), + .channel_mode = alc880_2_jack_modes, + .input_mux = &alc880_capture_source, + .unsol_event = alc880_uniwill_p53_unsol_event, + .setup = alc880_uniwill_p53_setup, + .init_hook = alc_hp_automute, + }, + [ALC880_CLEVO] = { + .mixers = { alc880_three_stack_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_clevo_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_dac_nids), + .dac_nids = alc880_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), + .channel_mode = alc880_threestack_modes, + .need_dac_fix = 1, + .input_mux = &alc880_capture_source, + }, + [ALC880_LG] = { + .mixers = { alc880_lg_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_lg_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids), + .dac_nids = alc880_lg_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes), + .channel_mode = alc880_lg_ch_modes, + .need_dac_fix = 1, + .input_mux = &alc880_lg_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc880_lg_setup, + .init_hook = alc_hp_automute, +#ifdef CONFIG_SND_HDA_POWER_SAVE + .loopbacks = alc880_lg_loopbacks, +#endif + }, + [ALC880_LG_LW] = { + .mixers = { alc880_lg_lw_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_lg_lw_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_dac_nids), + .dac_nids = alc880_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes), + .channel_mode = alc880_lg_lw_modes, + .input_mux = &alc880_lg_lw_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc880_lg_lw_setup, + .init_hook = alc_hp_automute, + }, + [ALC880_MEDION_RIM] = { + .mixers = { alc880_medion_rim_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_medion_rim_init_verbs, + alc_gpio2_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_dac_nids), + .dac_nids = alc880_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), + .channel_mode = alc880_2_jack_modes, + .input_mux = &alc880_medion_rim_capture_source, + .unsol_event = alc880_medion_rim_unsol_event, + .setup = alc880_medion_rim_setup, + .init_hook = alc880_medion_rim_automute, + }, +#ifdef CONFIG_SND_DEBUG + [ALC880_TEST] = { + .mixers = { alc880_test_mixer }, + .init_verbs = { alc880_test_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_test_dac_nids), + .dac_nids = alc880_test_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_test_modes), + .channel_mode = alc880_test_modes, + .input_mux = &alc880_test_capture_source, + }, +#endif +}; + +/* + * Automatic parse of I/O pins from the BIOS configuration + */ + +enum { + ALC_CTL_WIDGET_VOL, + ALC_CTL_WIDGET_MUTE, + ALC_CTL_BIND_MUTE, +}; +static const struct snd_kcontrol_new alc880_control_templates[] = { + HDA_CODEC_VOLUME(NULL, 0, 0, 0), + HDA_CODEC_MUTE(NULL, 0, 0, 0), + HDA_BIND_MUTE(NULL, 0, 0, 0), +}; + +static struct snd_kcontrol_new *alc_kcontrol_new(struct alc_spec *spec) +{ + snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32); + return snd_array_new(&spec->kctls); +} + +/* add dynamic controls */ +static int add_control(struct alc_spec *spec, int type, const char *name, + int cidx, unsigned long val) +{ + struct snd_kcontrol_new *knew; + + knew = alc_kcontrol_new(spec); if (!knew) return -ENOMEM; - *knew = alc_control_templates[type]; - knew->name = kstrdup(name, GFP_KERNEL); - if (!knew->name) + *knew = alc880_control_templates[type]; + knew->name = kstrdup(name, GFP_KERNEL); + if (!knew->name) + return -ENOMEM; + knew->index = cidx; + if (get_amp_nid_(val)) + knew->subdevice = HDA_SUBDEV_AMP_FLAG; + knew->private_value = val; + return 0; +} + +static int add_control_with_pfx(struct alc_spec *spec, int type, + const char *pfx, const char *dir, + const char *sfx, int cidx, unsigned long val) +{ + char name[32]; + snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx); + return add_control(spec, type, name, cidx, val); +} + +#define add_pb_vol_ctrl(spec, type, pfx, val) \ + add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val) +#define add_pb_sw_ctrl(spec, type, pfx, val) \ + add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val) +#define __add_pb_vol_ctrl(spec, type, pfx, cidx, val) \ + add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val) +#define __add_pb_sw_ctrl(spec, type, pfx, cidx, val) \ + add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val) + +#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17) +#define alc880_fixed_pin_idx(nid) ((nid) - 0x14) +#define alc880_is_multi_pin(nid) ((nid) >= 0x18) +#define alc880_multi_pin_idx(nid) ((nid) - 0x18) +#define alc880_idx_to_dac(nid) ((nid) + 0x02) +#define alc880_dac_to_idx(nid) ((nid) - 0x02) +#define alc880_idx_to_mixer(nid) ((nid) + 0x0c) +#define alc880_idx_to_selector(nid) ((nid) + 0x10) +#define ALC880_PIN_CD_NID 0x1c + +/* fill in the dac_nids table from the parsed pin configuration */ +static int alc880_auto_fill_dac_nids(struct alc_spec *spec, + const struct auto_pin_cfg *cfg) +{ + hda_nid_t nid; + int assigned[4]; + int i, j; + + memset(assigned, 0, sizeof(assigned)); + spec->multiout.dac_nids = spec->private_dac_nids; + + /* check the pins hardwired to audio widget */ + for (i = 0; i < cfg->line_outs; i++) { + nid = cfg->line_out_pins[i]; + if (alc880_is_fixed_pin(nid)) { + int idx = alc880_fixed_pin_idx(nid); + spec->private_dac_nids[i] = alc880_idx_to_dac(idx); + assigned[idx] = 1; + } + } + /* left pins can be connect to any audio widget */ + for (i = 0; i < cfg->line_outs; i++) { + nid = cfg->line_out_pins[i]; + if (alc880_is_fixed_pin(nid)) + continue; + /* search for an empty channel */ + for (j = 0; j < cfg->line_outs; j++) { + if (!assigned[j]) { + spec->private_dac_nids[i] = + alc880_idx_to_dac(j); + assigned[j] = 1; + break; + } + } + } + spec->multiout.num_dacs = cfg->line_outs; + return 0; +} + +static const char *alc_get_line_out_pfx(struct alc_spec *spec, + bool can_be_master) +{ + struct auto_pin_cfg *cfg = &spec->autocfg; + + if (cfg->line_outs == 1 && !spec->multi_ios && + !cfg->hp_outs && !cfg->speaker_outs && can_be_master) + return "Master"; + + switch (cfg->line_out_type) { + case AUTO_PIN_SPEAKER_OUT: + if (cfg->line_outs == 1) + return "Speaker"; + break; + case AUTO_PIN_HP_OUT: + return "Headphone"; + default: + if (cfg->line_outs == 1 && !spec->multi_ios) + return "PCM"; + break; + } + return NULL; +} + +/* add playback controls from the parsed DAC table */ +static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec, + const struct auto_pin_cfg *cfg) +{ + static const char * const chname[4] = { + "Front", "Surround", NULL /*CLFE*/, "Side" + }; + const char *pfx = alc_get_line_out_pfx(spec, false); + hda_nid_t nid; + int i, err, noutputs; + + noutputs = cfg->line_outs; + if (spec->multi_ios > 0) + noutputs += spec->multi_ios; + + for (i = 0; i < noutputs; i++) { + if (!spec->multiout.dac_nids[i]) + continue; + nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i])); + if (!pfx && i == 2) { + /* Center/LFE */ + err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, + "Center", + HDA_COMPOSE_AMP_VAL(nid, 1, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, + "LFE", + HDA_COMPOSE_AMP_VAL(nid, 2, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, + "Center", + HDA_COMPOSE_AMP_VAL(nid, 1, 2, + HDA_INPUT)); + if (err < 0) + return err; + err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, + "LFE", + HDA_COMPOSE_AMP_VAL(nid, 2, 2, + HDA_INPUT)); + if (err < 0) + return err; + } else { + const char *name = pfx; + int index = i; + if (!name) { + name = chname[i]; + index = 0; + } + err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, + name, index, + HDA_COMPOSE_AMP_VAL(nid, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = __add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, + name, index, + HDA_COMPOSE_AMP_VAL(nid, 3, 2, + HDA_INPUT)); + if (err < 0) + return err; + } + } + return 0; +} + +/* add playback controls for speaker and HP outputs */ +static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin, + const char *pfx) +{ + hda_nid_t nid; + int err; + + if (!pin) + return 0; + + if (alc880_is_fixed_pin(pin)) { + nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin)); + /* specify the DAC as the extra output */ + if (!spec->multiout.hp_nid) + spec->multiout.hp_nid = nid; + else + spec->multiout.extra_out_nid[0] = nid; + /* control HP volume/switch on the output mixer amp */ + nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin)); + err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, + HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx, + HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT)); + if (err < 0) + return err; + } else if (alc880_is_multi_pin(pin)) { + /* set manual connection */ + /* we have only a switch on HP-out PIN */ + err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + } + return 0; +} + +/* create input playback/capture controls for the given pin */ +static int new_analog_input(struct alc_spec *spec, hda_nid_t pin, + const char *ctlname, int ctlidx, + int idx, hda_nid_t mix_nid) +{ + int err; + + err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, ctlidx, + HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); + if (err < 0) + return err; + err = __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, ctlidx, + HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); + if (err < 0) + return err; + return 0; +} + +static int alc_is_input_pin(struct hda_codec *codec, hda_nid_t nid) +{ + unsigned int pincap = snd_hda_query_pin_caps(codec, nid); + return (pincap & AC_PINCAP_IN) != 0; +} + +/* create playback/capture controls for input pins */ +static int alc_auto_create_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg, + hda_nid_t mixer, + hda_nid_t cap1, hda_nid_t cap2) +{ + struct alc_spec *spec = codec->spec; + struct hda_input_mux *imux = &spec->private_imux[0]; + int i, err, idx, type_idx = 0; + const char *prev_label = NULL; + + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t pin; + const char *label; + + pin = cfg->inputs[i].pin; + if (!alc_is_input_pin(codec, pin)) + continue; + + label = hda_get_autocfg_input_label(codec, cfg, i); + if (prev_label && !strcmp(label, prev_label)) + type_idx++; + else + type_idx = 0; + prev_label = label; + + if (mixer) { + idx = get_connection_index(codec, mixer, pin); + if (idx >= 0) { + err = new_analog_input(spec, pin, + label, type_idx, + idx, mixer); + if (err < 0) + return err; + } + } + + if (!cap1) + continue; + idx = get_connection_index(codec, cap1, pin); + if (idx < 0 && cap2) + idx = get_connection_index(codec, cap2, pin); + if (idx >= 0) + snd_hda_add_imux_item(imux, label, idx, NULL); + } + return 0; +} + +static int alc880_auto_create_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) +{ + return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x08, 0x09); +} + +static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid, + unsigned int pin_type) +{ + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + pin_type); + /* unmute pin */ + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, + AMP_OUT_UNMUTE); +} + +static void alc880_auto_set_output_and_unmute(struct hda_codec *codec, + hda_nid_t nid, int pin_type, + int dac_idx) +{ + alc_set_pin_output(codec, nid, pin_type); + /* need the manual connection? */ + if (alc880_is_multi_pin(nid)) { + struct alc_spec *spec = codec->spec; + int idx = alc880_multi_pin_idx(nid); + snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0, + AC_VERB_SET_CONNECT_SEL, + alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx])); + } +} + +static int get_pin_type(int line_out_type) +{ + if (line_out_type == AUTO_PIN_HP_OUT) + return PIN_HP; + else + return PIN_OUT; +} + +static void alc880_auto_init_multi_out(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int i; + + for (i = 0; i < spec->autocfg.line_outs; i++) { + hda_nid_t nid = spec->autocfg.line_out_pins[i]; + int pin_type = get_pin_type(spec->autocfg.line_out_type); + alc880_auto_set_output_and_unmute(codec, nid, pin_type, i); + } +} + +static void alc880_auto_init_extra_out(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t pin; + + pin = spec->autocfg.speaker_pins[0]; + if (pin) /* connect to front */ + alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0); + pin = spec->autocfg.hp_pins[0]; + if (pin) /* connect to front */ + alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); +} + +static void alc880_auto_init_analog_input(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i; + + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; + if (alc_is_input_pin(codec, nid)) { + alc_set_input_pin(codec, nid, cfg->inputs[i].type); + if (nid != ALC880_PIN_CD_NID && + (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)) + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_OUT_MUTE); + } + } +} + +static void alc880_auto_init_input_src(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int c; + + for (c = 0; c < spec->num_adc_nids; c++) { + unsigned int mux_idx; + const struct hda_input_mux *imux; + mux_idx = c >= spec->num_mux_defs ? 0 : c; + imux = &spec->input_mux[mux_idx]; + if (!imux->num_items && mux_idx > 0) + imux = &spec->input_mux[0]; + if (imux) + snd_hda_codec_write(codec, spec->adc_nids[c], 0, + AC_VERB_SET_CONNECT_SEL, + imux->items[0].index); + } +} + +static int alc_auto_add_multi_channel_mode(struct hda_codec *codec); + +/* parse the BIOS configuration and set up the alc_spec */ +/* return 1 if successful, 0 if the proper config is not found, + * or a negative error code + */ +static int alc880_parse_auto_config(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int err; + static const hda_nid_t alc880_ignore[] = { 0x1d, 0 }; + + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, + alc880_ignore); + if (err < 0) + return err; + if (!spec->autocfg.line_outs) + return 0; /* can't find valid BIOS pin config */ + + err = alc880_auto_fill_dac_nids(spec, &spec->autocfg); + if (err < 0) + return err; + err = alc_auto_add_multi_channel_mode(codec); + if (err < 0) + return err; + err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + err = alc880_auto_create_extra_out(spec, + spec->autocfg.speaker_pins[0], + "Speaker"); + if (err < 0) + return err; + err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0], + "Headphone"); + if (err < 0) + return err; + err = alc880_auto_create_input_ctls(codec, &spec->autocfg); + if (err < 0) + return err; + + spec->multiout.max_channels = spec->multiout.num_dacs * 2; + + alc_auto_parse_digital(codec); + + if (spec->kctls.list) + add_mixer(spec, spec->kctls.list); + + add_verb(spec, alc880_volume_init_verbs); + + spec->num_mux_defs = 1; + spec->input_mux = &spec->private_imux[0]; + + alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0); + + return 1; +} + +/* additional initialization for auto-configuration model */ +static void alc880_auto_init(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + alc880_auto_init_multi_out(codec); + alc880_auto_init_extra_out(codec); + alc880_auto_init_analog_input(codec); + alc880_auto_init_input_src(codec); + alc_auto_init_digital(codec); + if (spec->unsol_event) + alc_inithook(codec); +} + +/* check the ADC/MUX contains all input pins; some ADC/MUX contains only + * one of two digital mic pins, e.g. on ALC272 + */ +static void fixup_automic_adc(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int i; + + for (i = 0; i < spec->num_adc_nids; i++) { + hda_nid_t cap = spec->capsrc_nids ? + spec->capsrc_nids[i] : spec->adc_nids[i]; + int iidx, eidx; + + iidx = get_connection_index(codec, cap, spec->int_mic.pin); + if (iidx < 0) + continue; + eidx = get_connection_index(codec, cap, spec->ext_mic.pin); + if (eidx < 0) + continue; + spec->int_mic.mux_idx = iidx; + spec->ext_mic.mux_idx = eidx; + if (spec->capsrc_nids) + spec->capsrc_nids += i; + spec->adc_nids += i; + spec->num_adc_nids = 1; + /* optional dock-mic */ + eidx = get_connection_index(codec, cap, spec->dock_mic.pin); + if (eidx < 0) + spec->dock_mic.pin = 0; + else + spec->dock_mic.mux_idx = eidx; + return; + } + snd_printd(KERN_INFO "hda_codec: %s: " + "No ADC/MUX containing both 0x%x and 0x%x pins\n", + codec->chip_name, spec->int_mic.pin, spec->ext_mic.pin); + spec->auto_mic = 0; /* disable auto-mic to be sure */ +} + +/* select or unmute the given capsrc route */ +static void select_or_unmute_capsrc(struct hda_codec *codec, hda_nid_t cap, + int idx) +{ + if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) { + snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx, + HDA_AMP_MUTE, 0); + } else { + snd_hda_codec_write_cache(codec, cap, 0, + AC_VERB_SET_CONNECT_SEL, idx); + } +} + +/* set the default connection to that pin */ +static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin) +{ + struct alc_spec *spec = codec->spec; + int i; + + if (!pin) + return 0; + for (i = 0; i < spec->num_adc_nids; i++) { + hda_nid_t cap = spec->capsrc_nids ? + spec->capsrc_nids[i] : spec->adc_nids[i]; + int idx; + + idx = get_connection_index(codec, cap, pin); + if (idx < 0) + continue; + select_or_unmute_capsrc(codec, cap, idx); + return i; /* return the found index */ + } + return -1; /* not found */ +} + +/* choose the ADC/MUX containing the input pin and initialize the setup */ +static void fixup_single_adc(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i; + + /* search for the input pin; there must be only one */ + if (cfg->num_inputs != 1) + return; + i = init_capsrc_for_pin(codec, cfg->inputs[0].pin); + if (i >= 0) { + /* use only this ADC */ + if (spec->capsrc_nids) + spec->capsrc_nids += i; + spec->adc_nids += i; + spec->num_adc_nids = 1; + spec->single_input_src = 1; + } +} + +/* initialize dual adcs */ +static void fixup_dual_adc_switch(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + init_capsrc_for_pin(codec, spec->ext_mic.pin); + init_capsrc_for_pin(codec, spec->dock_mic.pin); + init_capsrc_for_pin(codec, spec->int_mic.pin); +} + +/* initialize some special cases for input sources */ +static void alc_init_special_input_src(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + if (spec->dual_adc_switch) + fixup_dual_adc_switch(codec); + else if (spec->single_input_src) + init_capsrc_for_pin(codec, spec->autocfg.inputs[0].pin); +} + +static void set_capture_mixer(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + static const struct snd_kcontrol_new *caps[2][3] = { + { alc_capture_mixer_nosrc1, + alc_capture_mixer_nosrc2, + alc_capture_mixer_nosrc3 }, + { alc_capture_mixer1, + alc_capture_mixer2, + alc_capture_mixer3 }, + }; + if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) { + int mux = 0; + int num_adcs = spec->num_adc_nids; + if (spec->dual_adc_switch) + num_adcs = 1; + else if (spec->auto_mic) + fixup_automic_adc(codec); + else if (spec->input_mux) { + if (spec->input_mux->num_items > 1) + mux = 1; + else if (spec->input_mux->num_items == 1) + fixup_single_adc(codec); + } + spec->cap_mixer = caps[mux][num_adcs - 1]; + } +} + +/* fill adc_nids (and capsrc_nids) containing all active input pins */ +static void fillup_priv_adc_nids(struct hda_codec *codec, const hda_nid_t *nids, + int num_nids) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int n; + hda_nid_t fallback_adc = 0, fallback_cap = 0; + + for (n = 0; n < num_nids; n++) { + hda_nid_t adc, cap; + hda_nid_t conn[HDA_MAX_NUM_INPUTS]; + int nconns, i, j; + + adc = nids[n]; + if (get_wcaps_type(get_wcaps(codec, adc)) != AC_WID_AUD_IN) + continue; + cap = adc; + nconns = snd_hda_get_connections(codec, cap, conn, + ARRAY_SIZE(conn)); + if (nconns == 1) { + cap = conn[0]; + nconns = snd_hda_get_connections(codec, cap, conn, + ARRAY_SIZE(conn)); + } + if (nconns <= 0) + continue; + if (!fallback_adc) { + fallback_adc = adc; + fallback_cap = cap; + } + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; + for (j = 0; j < nconns; j++) { + if (conn[j] == nid) + break; + } + if (j >= nconns) + break; + } + if (i >= cfg->num_inputs) { + int num_adcs = spec->num_adc_nids; + spec->private_adc_nids[num_adcs] = adc; + spec->private_capsrc_nids[num_adcs] = cap; + spec->num_adc_nids++; + spec->adc_nids = spec->private_adc_nids; + if (adc != cap) + spec->capsrc_nids = spec->private_capsrc_nids; + } + } + if (!spec->num_adc_nids) { + printk(KERN_WARNING "hda_codec: %s: no valid ADC found;" + " using fallback 0x%x\n", + codec->chip_name, fallback_adc); + spec->private_adc_nids[0] = fallback_adc; + spec->adc_nids = spec->private_adc_nids; + if (fallback_adc != fallback_cap) { + spec->private_capsrc_nids[0] = fallback_cap; + spec->capsrc_nids = spec->private_adc_nids; + } + } +} + +#ifdef CONFIG_SND_HDA_INPUT_BEEP +#define set_beep_amp(spec, nid, idx, dir) \ + ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir)) + +static const struct snd_pci_quirk beep_white_list[] = { + SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1), + SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1), + SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1), + SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1), + SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1), + {} +}; + +static inline int has_cdefine_beep(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + const struct snd_pci_quirk *q; + q = snd_pci_quirk_lookup(codec->bus->pci, beep_white_list); + if (q) + return q->value; + return spec->cdefine.enable_pcbeep; +} +#else +#define set_beep_amp(spec, nid, idx, dir) /* NOP */ +#define has_cdefine_beep(codec) 0 +#endif + +/* + * OK, here we have finally the patch for ALC880 + */ + +static int patch_alc880(struct hda_codec *codec) +{ + struct alc_spec *spec; + int board_config; + int err; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; + + board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST, + alc880_models, + alc880_cfg_tbl); + if (board_config < 0) { + printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); + board_config = ALC880_AUTO; + } + + if (board_config == ALC880_AUTO) { + /* automatic parse from the BIOS config */ + err = alc880_parse_auto_config(codec); + if (err < 0) { + alc_free(codec); + return err; + } else if (!err) { + printk(KERN_INFO + "hda_codec: Cannot set up configuration " + "from BIOS. Using 3-stack mode...\n"); + board_config = ALC880_3ST; + } + } + + err = snd_hda_attach_beep_device(codec, 0x1); + if (err < 0) { + alc_free(codec); + return err; + } + + if (board_config != ALC880_AUTO) + setup_preset(codec, &alc880_presets[board_config]); + + spec->stream_analog_playback = &alc880_pcm_analog_playback; + spec->stream_analog_capture = &alc880_pcm_analog_capture; + spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture; + + spec->stream_digital_playback = &alc880_pcm_digital_playback; + spec->stream_digital_capture = &alc880_pcm_digital_capture; + + if (!spec->adc_nids && spec->input_mux) { + /* check whether NID 0x07 is valid */ + unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]); + /* get type */ + wcap = get_wcaps_type(wcap); + if (wcap != AC_WID_AUD_IN) { + spec->adc_nids = alc880_adc_nids_alt; + spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt); + } else { + spec->adc_nids = alc880_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids); + } + } + set_capture_mixer(codec); + set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); + + spec->vmaster_nid = 0x0c; + + codec->patch_ops = alc_patch_ops; + if (board_config == ALC880_AUTO) + spec->init_hook = alc880_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc880_loopbacks; +#endif + + return 0; +} + + +/* + * ALC260 support + */ + +static const hda_nid_t alc260_dac_nids[1] = { + /* front */ + 0x02, +}; + +static const hda_nid_t alc260_adc_nids[1] = { + /* ADC0 */ + 0x04, +}; + +static const hda_nid_t alc260_adc_nids_alt[1] = { + /* ADC1 */ + 0x05, +}; + +/* NIDs used when simultaneous access to both ADCs makes sense. Note that + * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC. + */ +static const hda_nid_t alc260_dual_adc_nids[2] = { + /* ADC0, ADC1 */ + 0x04, 0x05 +}; + +#define ALC260_DIGOUT_NID 0x03 +#define ALC260_DIGIN_NID 0x06 + +static const struct hda_input_mux alc260_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x1 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + }, +}; + +/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack, + * headphone jack and the internal CD lines since these are the only pins at + * which audio can appear. For flexibility, also allow the option of + * recording the mixer output on the second ADC (ADC0 doesn't have a + * connection to the mixer output). + */ +static const struct hda_input_mux alc260_fujitsu_capture_sources[2] = { + { + .num_items = 3, + .items = { + { "Mic/Line", 0x0 }, + { "CD", 0x4 }, + { "Headphone", 0x2 }, + }, + }, + { + .num_items = 4, + .items = { + { "Mic/Line", 0x0 }, + { "CD", 0x4 }, + { "Headphone", 0x2 }, + { "Mixer", 0x5 }, + }, + }, + +}; + +/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to + * the Fujitsu S702x, but jacks are marked differently. + */ +static const struct hda_input_mux alc260_acer_capture_sources[2] = { + { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + { "Headphone", 0x5 }, + }, + }, + { + .num_items = 5, + .items = { + { "Mic", 0x0 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + { "Headphone", 0x6 }, + { "Mixer", 0x5 }, + }, + }, +}; + +/* Maxdata Favorit 100XS */ +static const struct hda_input_mux alc260_favorit100_capture_sources[2] = { + { + .num_items = 2, + .items = { + { "Line/Mic", 0x0 }, + { "CD", 0x4 }, + }, + }, + { + .num_items = 3, + .items = { + { "Line/Mic", 0x0 }, + { "CD", 0x4 }, + { "Mixer", 0x5 }, + }, + }, +}; + +/* + * This is just place-holder, so there's something for alc_build_pcms to look + * at when it calculates the maximum number of channels. ALC260 has no mixer + * element which allows changing the channel mode, so the verb list is + * never used. + */ +static const struct hda_channel_mode alc260_modes[1] = { + { 2, NULL }, +}; + + +/* Mixer combinations + * + * basic: base_output + input + pc_beep + capture + * HP: base_output + input + capture_alt + * HP_3013: hp_3013 + input + capture + * fujitsu: fujitsu + capture + * acer: acer + capture + */ + +static const struct snd_kcontrol_new alc260_base_output_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc260_input_mixer[] = { + HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT), + { } /* end */ +}; + +/* update HP, line and mono out pins according to the master switch */ +static void alc260_hp_master_update(struct hda_codec *codec) +{ + update_speakers(codec); +} + +static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + *ucontrol->value.integer.value = !spec->master_mute; + return 0; +} + +static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + int val = !*ucontrol->value.integer.value; + + if (val == spec->master_mute) + return 0; + spec->master_mute = val; + alc260_hp_master_update(codec); + return 1; +} + +static const struct snd_kcontrol_new alc260_hp_output_mixer[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .subdevice = HDA_SUBDEV_NID_FLAG | 0x11, + .info = snd_ctl_boolean_mono_info, + .get = alc260_hp_master_sw_get, + .put = alc260_hp_master_sw_put, + }, + HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, + HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT), + { } /* end */ +}; + +static const struct hda_verb alc260_hp_unsol_verbs[] = { + {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {}, +}; + +static void alc260_hp_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x0f; + spec->autocfg.speaker_pins[0] = 0x10; + spec->autocfg.speaker_pins[1] = 0x11; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; +} + +static const struct snd_kcontrol_new alc260_hp_3013_mixer[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .subdevice = HDA_SUBDEV_NID_FLAG | 0x11, + .info = snd_ctl_boolean_mono_info, + .get = alc260_hp_master_sw_get, + .put = alc260_hp_master_sw_put, + }, + HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT), + HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT), + { } /* end */ +}; + +static void alc260_hp_3013_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x10; + spec->autocfg.speaker_pins[1] = 0x11; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; +} + +static const struct hda_bind_ctls alc260_dc7600_bind_master_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT), + 0 + }, +}; + +static const struct hda_bind_ctls alc260_dc7600_bind_switch = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), + 0 + }, +}; + +static const struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = { + HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol), + HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT), + { } /* end */ +}; + +static const struct hda_verb alc260_hp_3013_unsol_verbs[] = { + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {}, +}; + +static void alc260_hp_3012_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x10; + spec->autocfg.speaker_pins[0] = 0x0f; + spec->autocfg.speaker_pins[1] = 0x11; + spec->autocfg.speaker_pins[2] = 0x15; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; +} + +/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12, + * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10. + */ +static const struct snd_kcontrol_new alc260_fujitsu_mixer[] = { + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT), + ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT), + ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT), + { } /* end */ +}; + +/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current + * versions of the ALC260 don't act on requests to enable mic bias from NID + * 0x0f (used to drive the headphone jack in these laptops). The ALC260 + * datasheet doesn't mention this restriction. At this stage it's not clear + * whether this behaviour is intentional or is a hardware bug in chip + * revisions available in early 2006. Therefore for now allow the + * "Headphone Jack Mode" control to span all choices, but if it turns out + * that the lack of mic bias for this NID is intentional we could change the + * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS. + * + * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006 + * don't appear to make the mic bias available from the "line" jack, even + * though the NID used for this jack (0x14) can supply it. The theory is + * that perhaps Acer have included blocking capacitors between the ALC260 + * and the output jack. If this turns out to be the case for all such + * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT + * to ALC_PIN_DIR_INOUT_NOMICBIAS. + * + * The C20x Tablet series have a mono internal speaker which is controlled + * via the chip's Mono sum widget and pin complex, so include the necessary + * controls for such models. On models without a "mono speaker" the control + * won't do anything. + */ +static const struct snd_kcontrol_new alc260_acer_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT), + ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT), + HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, + HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, + HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), + ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN), + HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), + ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT), + { } /* end */ +}; + +/* Maxdata Favorit 100XS: one output and one input (0x12) jack + */ +static const struct snd_kcontrol_new alc260_favorit100_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT), + ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT), + HDA_CODEC_VOLUME("Line/Mic Playback Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Line/Mic Playback Switch", 0x07, 0x0, HDA_INPUT), + ALC_PIN_MODE("Line/Mic Jack Mode", 0x12, ALC_PIN_DIR_IN), + { } /* end */ +}; + +/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12, + * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17. + */ +static const struct snd_kcontrol_new alc260_will_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), + ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN), + HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), + ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), + { } /* end */ +}; + +/* Replacer 672V ALC260 pin usage: Mic jack = 0x12, + * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f. + */ +static const struct snd_kcontrol_new alc260_replacer_672v_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), + ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN), + HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), + ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT), + { } /* end */ +}; + +/* + * initialization verbs + */ +static const struct hda_verb alc260_init_verbs[] = { + /* Line In pin widget for input */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + /* CD pin widget for input */ + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + /* Mic1 (rear panel) pin widget for input and vref at 80% */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + /* Mic2 (front panel) pin widget for input and vref at 80% */ + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + /* LINE-2 is used for line-out in rear */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + /* select line-out */ + {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* LINE-OUT pin */ + {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + /* enable HP */ + {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + /* enable Mono */ + {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + /* mute capture amp left and right */ + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* set connection select to line in (default select for this ADC) */ + {0x04, AC_VERB_SET_CONNECT_SEL, 0x02}, + /* mute capture amp left and right */ + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* set connection select to line in (default select for this ADC) */ + {0x05, AC_VERB_SET_CONNECT_SEL, 0x02}, + /* set vol=0 Line-Out mixer amp left and right */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* unmute pin widget amp left and right (no gain on this amp) */ + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* set vol=0 HP mixer amp left and right */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* unmute pin widget amp left and right (no gain on this amp) */ + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* set vol=0 Mono mixer amp left and right */ + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* unmute pin widget amp left and right (no gain on this amp) */ + {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* unmute LINE-2 out pin */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & + * Line In 2 = 0x03 + */ + /* mute analog inputs */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ + /* mute Front out path */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* mute Headphone out path */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* mute Mono out path */ + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + { } +}; + +#if 0 /* should be identical with alc260_init_verbs? */ +static const struct hda_verb alc260_hp_init_verbs[] = { + /* Headphone and output */ + {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, + /* mono output */ + {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + /* Mic1 (rear panel) pin widget for input and vref at 80% */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + /* Mic2 (front panel) pin widget for input and vref at 80% */ + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + /* Line In pin widget for input */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + /* Line-2 pin widget for output */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + /* CD pin widget for input */ + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + /* unmute amp left and right */ + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + /* set connection select to line in (default select for this ADC) */ + {0x04, AC_VERB_SET_CONNECT_SEL, 0x02}, + /* unmute Line-Out mixer amp left and right (volume = 0) */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + /* mute pin widget amp left and right (no gain on this amp) */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + /* unmute HP mixer amp left and right (volume = 0) */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + /* mute pin widget amp left and right (no gain on this amp) */ + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & + * Line In 2 = 0x03 + */ + /* mute analog inputs */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ + /* Unmute Front out path */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + /* Unmute Headphone out path */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + /* Unmute Mono out path */ + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + { } +}; +#endif + +static const struct hda_verb alc260_hp_3013_init_verbs[] = { + /* Line out and output */ + {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + /* mono output */ + {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + /* Mic1 (rear panel) pin widget for input and vref at 80% */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + /* Mic2 (front panel) pin widget for input and vref at 80% */ + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + /* Line In pin widget for input */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + /* Headphone pin widget for output */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, + /* CD pin widget for input */ + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + /* unmute amp left and right */ + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + /* set connection select to line in (default select for this ADC) */ + {0x04, AC_VERB_SET_CONNECT_SEL, 0x02}, + /* unmute Line-Out mixer amp left and right (volume = 0) */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + /* mute pin widget amp left and right (no gain on this amp) */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + /* unmute HP mixer amp left and right (volume = 0) */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + /* mute pin widget amp left and right (no gain on this amp) */ + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & + * Line In 2 = 0x03 + */ + /* mute analog inputs */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ + /* Unmute Front out path */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + /* Unmute Headphone out path */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + /* Unmute Mono out path */ + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + { } +}; + +/* Initialisation sequence for ALC260 as configured in Fujitsu S702x + * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD + * audio = 0x16, internal speaker = 0x10. + */ +static const struct hda_verb alc260_fujitsu_init_verbs[] = { + /* Disable all GPIOs */ + {0x01, AC_VERB_SET_GPIO_MASK, 0}, + /* Internal speaker is connected to headphone pin */ + {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + /* Headphone/Line-out jack connects to Line1 pin; make it an output */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + /* Mic/Line-in jack is connected to mic1 pin, so make it an input */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + /* Ensure all other unused pins are disabled and muted. */ + {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + + /* Disable digital (SPDIF) pins */ + {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, + {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, + + /* Ensure Line1 pin widget takes its input from the OUT1 sum bus + * when acting as an output. + */ + {0x0d, AC_VERB_SET_CONNECT_SEL, 0}, + + /* Start with output sum widgets muted and their output gains at min */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */ + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Unmute Line1 pin widget output buffer since it starts as an output. + * If the pin mode is changed by the user the pin mode control will + * take care of enabling the pin's input/output buffers as needed. + * Therefore there's no need to enable the input buffer at this + * stage. + */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Unmute input buffer of pin widget used for Line-in (no equiv + * mixer ctrl) + */ + {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Mute capture amp left and right */ + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + /* Set ADC connection select to match default mixer setting - line + * in (on mic1 pin) + */ + {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Do the same for the second ADC: mute capture input amp and + * set ADC connection to line in (on mic1 pin) + */ + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x05, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Mute all inputs to mixer widget (even unconnected ones) */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ + + { } +}; + +/* Initialisation sequence for ALC260 as configured in Acer TravelMate and + * similar laptops (adapted from Fujitsu init verbs). + */ +static const struct hda_verb alc260_acer_init_verbs[] = { + /* On TravelMate laptops, GPIO 0 enables the internal speaker and + * the headphone jack. Turn this on and rely on the standard mute + * methods whenever the user wants to turn these outputs off. + */ + {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, + {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, + {0x01, AC_VERB_SET_GPIO_DATA, 0x01}, + /* Internal speaker/Headphone jack is connected to Line-out pin */ + {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + /* Internal microphone/Mic jack is connected to Mic1 pin */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, + /* Line In jack is connected to Line1 pin */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */ + {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + /* Ensure all other unused pins are disabled and muted. */ + {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + /* Disable digital (SPDIF) pins */ + {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, + {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, + + /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum + * bus when acting as outputs. + */ + {0x0b, AC_VERB_SET_CONNECT_SEL, 0}, + {0x0d, AC_VERB_SET_CONNECT_SEL, 0}, + + /* Start with output sum widgets muted and their output gains at min */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* Unmute Line-out pin widget amp left and right + * (no equiv mixer ctrl) + */ + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Unmute mono pin widget amp output (no equiv mixer ctrl) */ + {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Unmute Mic1 and Line1 pin widget input buffers since they start as + * inputs. If the pin mode is changed by the user the pin mode control + * will take care of enabling the pin's input/output buffers as needed. + * Therefore there's no need to enable the input buffer at this + * stage. + */ + {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Mute capture amp left and right */ + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + /* Set ADC connection select to match default mixer setting - mic + * (on mic1 pin) + */ + {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Do similar with the second ADC: mute capture input amp and + * set ADC connection to mic to match ALSA's default state. + */ + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x05, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Mute all inputs to mixer widget (even unconnected ones) */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ + + { } +}; + +/* Initialisation sequence for Maxdata Favorit 100XS + * (adapted from Acer init verbs). + */ +static const struct hda_verb alc260_favorit100_init_verbs[] = { + /* GPIO 0 enables the output jack. + * Turn this on and rely on the standard mute + * methods whenever the user wants to turn these outputs off. + */ + {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, + {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, + {0x01, AC_VERB_SET_GPIO_DATA, 0x01}, + /* Line/Mic input jack is connected to Mic1 pin */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, + /* Ensure all other unused pins are disabled and muted. */ + {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + /* Disable digital (SPDIF) pins */ + {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, + {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, + + /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum + * bus when acting as outputs. + */ + {0x0b, AC_VERB_SET_CONNECT_SEL, 0}, + {0x0d, AC_VERB_SET_CONNECT_SEL, 0}, + + /* Start with output sum widgets muted and their output gains at min */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* Unmute Line-out pin widget amp left and right + * (no equiv mixer ctrl) + */ + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Unmute Mic1 and Line1 pin widget input buffers since they start as + * inputs. If the pin mode is changed by the user the pin mode control + * will take care of enabling the pin's input/output buffers as needed. + * Therefore there's no need to enable the input buffer at this + * stage. + */ + {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Mute capture amp left and right */ + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + /* Set ADC connection select to match default mixer setting - mic + * (on mic1 pin) + */ + {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Do similar with the second ADC: mute capture input amp and + * set ADC connection to mic to match ALSA's default state. + */ + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x05, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Mute all inputs to mixer widget (even unconnected ones) */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ + + { } +}; + +static const struct hda_verb alc260_will_verbs[] = { + {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, + {0x1a, AC_VERB_SET_COEF_INDEX, 0x07}, + {0x1a, AC_VERB_SET_PROC_COEF, 0x3040}, + {} +}; + +static const struct hda_verb alc260_replacer_672v_verbs[] = { + {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, + {0x1a, AC_VERB_SET_COEF_INDEX, 0x07}, + {0x1a, AC_VERB_SET_PROC_COEF, 0x3050}, + + {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, + {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, + {0x01, AC_VERB_SET_GPIO_DATA, 0x00}, + + {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; + +/* toggle speaker-output according to the hp-jack state */ +static void alc260_replacer_672v_automute(struct hda_codec *codec) +{ + unsigned int present; + + /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */ + present = snd_hda_jack_detect(codec, 0x0f); + if (present) { + snd_hda_codec_write_cache(codec, 0x01, 0, + AC_VERB_SET_GPIO_DATA, 1); + snd_hda_codec_write_cache(codec, 0x0f, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + PIN_HP); + } else { + snd_hda_codec_write_cache(codec, 0x01, 0, + AC_VERB_SET_GPIO_DATA, 0); + snd_hda_codec_write_cache(codec, 0x0f, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + PIN_OUT); + } +} + +static void alc260_replacer_672v_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc260_replacer_672v_automute(codec); +} + +static const struct hda_verb alc260_hp_dc7600_verbs[] = { + {0x05, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; + +/* Test configuration for debugging, modelled after the ALC880 test + * configuration. + */ +#ifdef CONFIG_SND_DEBUG +static const hda_nid_t alc260_test_dac_nids[1] = { + 0x02, +}; +static const hda_nid_t alc260_test_adc_nids[2] = { + 0x04, 0x05, +}; +/* For testing the ALC260, each input MUX needs its own definition since + * the signal assignments are different. This assumes that the first ADC + * is NID 0x04. + */ +static const struct hda_input_mux alc260_test_capture_sources[2] = { + { + .num_items = 7, + .items = { + { "MIC1 pin", 0x0 }, + { "MIC2 pin", 0x1 }, + { "LINE1 pin", 0x2 }, + { "LINE2 pin", 0x3 }, + { "CD pin", 0x4 }, + { "LINE-OUT pin", 0x5 }, + { "HP-OUT pin", 0x6 }, + }, + }, + { + .num_items = 8, + .items = { + { "MIC1 pin", 0x0 }, + { "MIC2 pin", 0x1 }, + { "LINE1 pin", 0x2 }, + { "LINE2 pin", 0x3 }, + { "CD pin", 0x4 }, + { "Mixer", 0x5 }, + { "LINE-OUT pin", 0x6 }, + { "HP-OUT pin", 0x7 }, + }, + }, +}; +static const struct snd_kcontrol_new alc260_test_mixer[] = { + /* Output driver widgets */ + HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT), + HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT), + HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT), + + /* Modes for retasking pin widgets + * Note: the ALC260 doesn't seem to act on requests to enable mic + * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't + * mention this restriction. At this stage it's not clear whether + * this behaviour is intentional or is a hardware bug in chip + * revisions available at least up until early 2006. Therefore for + * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all + * choices, but if it turns out that the lack of mic bias for these + * NIDs is intentional we could change their modes from + * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS. + */ + ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT), + ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT), + ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT), + ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT), + ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT), + ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT), + + /* Loopback mixer controls */ + HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT), + HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT), + HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT), + HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT), + HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT), + HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT), + + /* Controls for GPIO pins, assuming they are configured as outputs */ + ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01), + ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02), + ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04), + ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08), + + /* Switches to allow the digital IO pins to be enabled. The datasheet + * is ambigious as to which NID is which; testing on laptops which + * make this output available should provide clarification. + */ + ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01), + ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01), + + /* A switch allowing EAPD to be enabled. Some laptops seem to use + * this output to turn on an external amplifier. + */ + ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02), + ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02), + + { } /* end */ +}; +static const struct hda_verb alc260_test_init_verbs[] = { + /* Enable all GPIOs as outputs with an initial value of 0 */ + {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f}, + {0x01, AC_VERB_SET_GPIO_DATA, 0x00}, + {0x01, AC_VERB_SET_GPIO_MASK, 0x0f}, + + /* Enable retasking pins as output, initially without power amp */ + {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + + /* Disable digital (SPDIF) pins initially, but users can enable + * them via a mixer switch. In the case of SPDIF-out, this initverb + * payload also sets the generation to 0, output to be in "consumer" + * PCM format, copyright asserted, no pre-emphasis and no validity + * control. + */ + {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, + {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, + + /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the + * OUT1 sum bus when acting as an output. + */ + {0x0b, AC_VERB_SET_CONNECT_SEL, 0}, + {0x0c, AC_VERB_SET_CONNECT_SEL, 0}, + {0x0d, AC_VERB_SET_CONNECT_SEL, 0}, + {0x0e, AC_VERB_SET_CONNECT_SEL, 0}, + + /* Start with output sum widgets muted and their output gains at min */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* Unmute retasking pin widget output buffers since the default + * state appears to be output. As the pin mode is changed by the + * user the pin mode control will take care of enabling the pin's + * input/output buffers as needed. + */ + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Also unmute the mono-out pin widget */ + {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Mute capture amp left and right */ + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + /* Set ADC connection select to match default mixer setting (mic1 + * pin) + */ + {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Do the same for the second ADC: mute capture input amp and + * set ADC connection to mic1 pin + */ + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x05, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Mute all inputs to mixer widget (even unconnected ones) */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ + + { } +}; +#endif + +#define alc260_pcm_analog_playback alc880_pcm_analog_alt_playback +#define alc260_pcm_analog_capture alc880_pcm_analog_capture + +#define alc260_pcm_digital_playback alc880_pcm_digital_playback +#define alc260_pcm_digital_capture alc880_pcm_digital_capture + +/* + * for BIOS auto-configuration + */ + +static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid, + const char *pfx, int *vol_bits) +{ + hda_nid_t nid_vol; + unsigned long vol_val, sw_val; + int err; + + if (nid >= 0x0f && nid < 0x11) { + nid_vol = nid - 0x7; + vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT); + sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); + } else if (nid == 0x11) { + nid_vol = nid - 0x7; + vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT); + sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT); + } else if (nid >= 0x12 && nid <= 0x15) { + nid_vol = 0x08; + vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT); + sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); + } else + return 0; /* N/A */ + + if (!(*vol_bits & (1 << nid_vol))) { + /* first control for the volume widget */ + err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, vol_val); + if (err < 0) + return err; + *vol_bits |= (1 << nid_vol); + } + err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, sw_val); + if (err < 0) + return err; + return 1; +} + +/* add playback controls from the parsed DAC table */ +static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec, + const struct auto_pin_cfg *cfg) +{ + hda_nid_t nid; + int err; + int vols = 0; + + spec->multiout.num_dacs = 1; + spec->multiout.dac_nids = spec->private_dac_nids; + spec->private_dac_nids[0] = 0x02; + + nid = cfg->line_out_pins[0]; + if (nid) { + const char *pfx; + if (!cfg->speaker_pins[0] && !cfg->hp_pins[0]) + pfx = "Master"; + else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) + pfx = "Speaker"; + else + pfx = "Front"; + err = alc260_add_playback_controls(spec, nid, pfx, &vols); + if (err < 0) + return err; + } + + nid = cfg->speaker_pins[0]; + if (nid) { + err = alc260_add_playback_controls(spec, nid, "Speaker", &vols); + if (err < 0) + return err; + } + + nid = cfg->hp_pins[0]; + if (nid) { + err = alc260_add_playback_controls(spec, nid, "Headphone", + &vols); + if (err < 0) + return err; + } + return 0; +} + +/* create playback/capture controls for input pins */ +static int alc260_auto_create_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) +{ + return alc_auto_create_input_ctls(codec, cfg, 0x07, 0x04, 0x05); +} + +static void alc260_auto_set_output_and_unmute(struct hda_codec *codec, + hda_nid_t nid, int pin_type, + int sel_idx) +{ + alc_set_pin_output(codec, nid, pin_type); + /* need the manual connection? */ + if (nid >= 0x12) { + int idx = nid - 0x12; + snd_hda_codec_write(codec, idx + 0x0b, 0, + AC_VERB_SET_CONNECT_SEL, sel_idx); + } +} + +static void alc260_auto_init_multi_out(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t nid; + + nid = spec->autocfg.line_out_pins[0]; + if (nid) { + int pin_type = get_pin_type(spec->autocfg.line_out_type); + alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0); + } + + nid = spec->autocfg.speaker_pins[0]; + if (nid) + alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0); + + nid = spec->autocfg.hp_pins[0]; + if (nid) + alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0); +} + +#define ALC260_PIN_CD_NID 0x16 +static void alc260_auto_init_analog_input(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i; + + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; + if (nid >= 0x12) { + alc_set_input_pin(codec, nid, cfg->inputs[i].type); + if (nid != ALC260_PIN_CD_NID && + (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)) + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_OUT_MUTE); + } + } +} + +#define alc260_auto_init_input_src alc880_auto_init_input_src + +/* + * generic initialization of ADC, input mixers and output mixers + */ +static const struct hda_verb alc260_volume_init_verbs[] = { + /* + * Unmute ADC0-1 and set the default input to mic-in + */ + {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x05, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + * Note: PASD motherboards uses the Line In 2 as the input for + * front panel mic (mic 2) + */ + /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ + /* mute analog inputs */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + + /* + * Set up output mixers (0x08 - 0x0a) + */ + /* set vol=0 to output mixers */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* set up input amps for analog loopback */ + /* Amp Indices: DAC = 0, mixer = 1 */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + { } +}; + +static int alc260_parse_auto_config(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int err; + static const hda_nid_t alc260_ignore[] = { 0x17, 0 }; + + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, + alc260_ignore); + if (err < 0) + return err; + err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + if (!spec->kctls.list) + return 0; /* can't find valid BIOS pin config */ + err = alc260_auto_create_input_ctls(codec, &spec->autocfg); + if (err < 0) + return err; + + spec->multiout.max_channels = 2; + + if (spec->autocfg.dig_outs) + spec->multiout.dig_out_nid = ALC260_DIGOUT_NID; + if (spec->kctls.list) + add_mixer(spec, spec->kctls.list); + + add_verb(spec, alc260_volume_init_verbs); + + spec->num_mux_defs = 1; + spec->input_mux = &spec->private_imux[0]; + + alc_ssid_check(codec, 0x10, 0x15, 0x0f, 0); + + return 1; +} + +/* additional initialization for auto-configuration model */ +static void alc260_auto_init(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + alc260_auto_init_multi_out(codec); + alc260_auto_init_analog_input(codec); + alc260_auto_init_input_src(codec); + alc_auto_init_digital(codec); + if (spec->unsol_event) + alc_inithook(codec); +} + +#ifdef CONFIG_SND_HDA_POWER_SAVE +static const struct hda_amp_list alc260_loopbacks[] = { + { 0x07, HDA_INPUT, 0 }, + { 0x07, HDA_INPUT, 1 }, + { 0x07, HDA_INPUT, 2 }, + { 0x07, HDA_INPUT, 3 }, + { 0x07, HDA_INPUT, 4 }, + { } /* end */ +}; +#endif + +/* + * Pin config fixes + */ +enum { + PINFIX_HP_DC5750, +}; + +static const struct alc_fixup alc260_fixups[] = { + [PINFIX_HP_DC5750] = { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { + { 0x11, 0x90130110 }, /* speaker */ + { } + } + }, +}; + +static const struct snd_pci_quirk alc260_fixup_tbl[] = { + SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", PINFIX_HP_DC5750), + {} +}; + +/* + * ALC260 configurations + */ +static const char * const alc260_models[ALC260_MODEL_LAST] = { + [ALC260_BASIC] = "basic", + [ALC260_HP] = "hp", + [ALC260_HP_3013] = "hp-3013", + [ALC260_HP_DC7600] = "hp-dc7600", + [ALC260_FUJITSU_S702X] = "fujitsu", + [ALC260_ACER] = "acer", + [ALC260_WILL] = "will", + [ALC260_REPLACER_672V] = "replacer", + [ALC260_FAVORIT100] = "favorit100", +#ifdef CONFIG_SND_DEBUG + [ALC260_TEST] = "test", +#endif + [ALC260_AUTO] = "auto", +}; + +static const struct snd_pci_quirk alc260_cfg_tbl[] = { + SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER), + SND_PCI_QUIRK(0x1025, 0x007f, "Acer", ALC260_WILL), + SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER), + SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100), + SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013), + SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_AUTO), /* no quirk */ + SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013), + SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013), + SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600), + SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013), + SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP), + SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP), + SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP), + SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC), + SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC), + SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC), + SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X), + SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC), + SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V), + SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL), + {} +}; + +static const struct alc_config_preset alc260_presets[] = { + [ALC260_BASIC] = { + .mixers = { alc260_base_output_mixer, + alc260_input_mixer }, + .init_verbs = { alc260_init_verbs }, + .num_dacs = ARRAY_SIZE(alc260_dac_nids), + .dac_nids = alc260_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), + .adc_nids = alc260_dual_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc260_modes), + .channel_mode = alc260_modes, + .input_mux = &alc260_capture_source, + }, + [ALC260_HP] = { + .mixers = { alc260_hp_output_mixer, + alc260_input_mixer }, + .init_verbs = { alc260_init_verbs, + alc260_hp_unsol_verbs }, + .num_dacs = ARRAY_SIZE(alc260_dac_nids), + .dac_nids = alc260_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt), + .adc_nids = alc260_adc_nids_alt, + .num_channel_mode = ARRAY_SIZE(alc260_modes), + .channel_mode = alc260_modes, + .input_mux = &alc260_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc260_hp_setup, + .init_hook = alc_inithook, + }, + [ALC260_HP_DC7600] = { + .mixers = { alc260_hp_dc7600_mixer, + alc260_input_mixer }, + .init_verbs = { alc260_init_verbs, + alc260_hp_dc7600_verbs }, + .num_dacs = ARRAY_SIZE(alc260_dac_nids), + .dac_nids = alc260_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt), + .adc_nids = alc260_adc_nids_alt, + .num_channel_mode = ARRAY_SIZE(alc260_modes), + .channel_mode = alc260_modes, + .input_mux = &alc260_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc260_hp_3012_setup, + .init_hook = alc_inithook, + }, + [ALC260_HP_3013] = { + .mixers = { alc260_hp_3013_mixer, + alc260_input_mixer }, + .init_verbs = { alc260_hp_3013_init_verbs, + alc260_hp_3013_unsol_verbs }, + .num_dacs = ARRAY_SIZE(alc260_dac_nids), + .dac_nids = alc260_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt), + .adc_nids = alc260_adc_nids_alt, + .num_channel_mode = ARRAY_SIZE(alc260_modes), + .channel_mode = alc260_modes, + .input_mux = &alc260_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc260_hp_3013_setup, + .init_hook = alc_inithook, + }, + [ALC260_FUJITSU_S702X] = { + .mixers = { alc260_fujitsu_mixer }, + .init_verbs = { alc260_fujitsu_init_verbs }, + .num_dacs = ARRAY_SIZE(alc260_dac_nids), + .dac_nids = alc260_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), + .adc_nids = alc260_dual_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc260_modes), + .channel_mode = alc260_modes, + .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources), + .input_mux = alc260_fujitsu_capture_sources, + }, + [ALC260_ACER] = { + .mixers = { alc260_acer_mixer }, + .init_verbs = { alc260_acer_init_verbs }, + .num_dacs = ARRAY_SIZE(alc260_dac_nids), + .dac_nids = alc260_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), + .adc_nids = alc260_dual_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc260_modes), + .channel_mode = alc260_modes, + .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources), + .input_mux = alc260_acer_capture_sources, + }, + [ALC260_FAVORIT100] = { + .mixers = { alc260_favorit100_mixer }, + .init_verbs = { alc260_favorit100_init_verbs }, + .num_dacs = ARRAY_SIZE(alc260_dac_nids), + .dac_nids = alc260_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), + .adc_nids = alc260_dual_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc260_modes), + .channel_mode = alc260_modes, + .num_mux_defs = ARRAY_SIZE(alc260_favorit100_capture_sources), + .input_mux = alc260_favorit100_capture_sources, + }, + [ALC260_WILL] = { + .mixers = { alc260_will_mixer }, + .init_verbs = { alc260_init_verbs, alc260_will_verbs }, + .num_dacs = ARRAY_SIZE(alc260_dac_nids), + .dac_nids = alc260_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc260_adc_nids), + .adc_nids = alc260_adc_nids, + .dig_out_nid = ALC260_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc260_modes), + .channel_mode = alc260_modes, + .input_mux = &alc260_capture_source, + }, + [ALC260_REPLACER_672V] = { + .mixers = { alc260_replacer_672v_mixer }, + .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs }, + .num_dacs = ARRAY_SIZE(alc260_dac_nids), + .dac_nids = alc260_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc260_adc_nids), + .adc_nids = alc260_adc_nids, + .dig_out_nid = ALC260_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc260_modes), + .channel_mode = alc260_modes, + .input_mux = &alc260_capture_source, + .unsol_event = alc260_replacer_672v_unsol_event, + .init_hook = alc260_replacer_672v_automute, + }, +#ifdef CONFIG_SND_DEBUG + [ALC260_TEST] = { + .mixers = { alc260_test_mixer }, + .init_verbs = { alc260_test_init_verbs }, + .num_dacs = ARRAY_SIZE(alc260_test_dac_nids), + .dac_nids = alc260_test_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids), + .adc_nids = alc260_test_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc260_modes), + .channel_mode = alc260_modes, + .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources), + .input_mux = alc260_test_capture_sources, + }, +#endif +}; + +static int patch_alc260(struct hda_codec *codec) +{ + struct alc_spec *spec; + int err, board_config; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; + + board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST, + alc260_models, + alc260_cfg_tbl); + if (board_config < 0) { + snd_printd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); + board_config = ALC260_AUTO; + } + + if (board_config == ALC260_AUTO) { + alc_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups); + alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + } + + if (board_config == ALC260_AUTO) { + /* automatic parse from the BIOS config */ + err = alc260_parse_auto_config(codec); + if (err < 0) { + alc_free(codec); + return err; + } else if (!err) { + printk(KERN_INFO + "hda_codec: Cannot set up configuration " + "from BIOS. Using base mode...\n"); + board_config = ALC260_BASIC; + } + } + + err = snd_hda_attach_beep_device(codec, 0x1); + if (err < 0) { + alc_free(codec); + return err; + } + + if (board_config != ALC260_AUTO) + setup_preset(codec, &alc260_presets[board_config]); + + spec->stream_analog_playback = &alc260_pcm_analog_playback; + spec->stream_analog_capture = &alc260_pcm_analog_capture; + spec->stream_analog_alt_capture = &alc260_pcm_analog_capture; + + spec->stream_digital_playback = &alc260_pcm_digital_playback; + spec->stream_digital_capture = &alc260_pcm_digital_capture; + + if (!spec->adc_nids && spec->input_mux) { + /* check whether NID 0x04 is valid */ + unsigned int wcap = get_wcaps(codec, 0x04); + wcap = get_wcaps_type(wcap); + /* get type */ + if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) { + spec->adc_nids = alc260_adc_nids_alt; + spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt); + } else { + spec->adc_nids = alc260_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids); + } + } + set_capture_mixer(codec); + set_beep_amp(spec, 0x07, 0x05, HDA_INPUT); + + alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + + spec->vmaster_nid = 0x08; + + codec->patch_ops = alc_patch_ops; + if (board_config == ALC260_AUTO) + spec->init_hook = alc260_auto_init; + spec->shutup = alc_eapd_shutup; +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc260_loopbacks; +#endif + + return 0; +} + + +/* + * ALC882/883/885/888/889 support + * + * ALC882 is almost identical with ALC880 but has cleaner and more flexible + * configuration. Each pin widget can choose any input DACs and a mixer. + * Each ADC is connected from a mixer of all inputs. This makes possible + * 6-channel independent captures. + * + * In addition, an independent DAC for the multi-playback (not used in this + * driver yet). + */ +#define ALC882_DIGOUT_NID 0x06 +#define ALC882_DIGIN_NID 0x0a +#define ALC883_DIGOUT_NID ALC882_DIGOUT_NID +#define ALC883_DIGIN_NID ALC882_DIGIN_NID +#define ALC1200_DIGOUT_NID 0x10 + + +static const struct hda_channel_mode alc882_ch_modes[1] = { + { 8, NULL } +}; + +/* DACs */ +static const hda_nid_t alc882_dac_nids[4] = { + /* front, rear, clfe, rear_surr */ + 0x02, 0x03, 0x04, 0x05 +}; +#define alc883_dac_nids alc882_dac_nids + +/* ADCs */ +#define alc882_adc_nids alc880_adc_nids +#define alc882_adc_nids_alt alc880_adc_nids_alt +#define alc883_adc_nids alc882_adc_nids_alt +static const hda_nid_t alc883_adc_nids_alt[1] = { 0x08 }; +static const hda_nid_t alc883_adc_nids_rev[2] = { 0x09, 0x08 }; +#define alc889_adc_nids alc880_adc_nids + +static const hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 }; +static const hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 }; +#define alc883_capsrc_nids alc882_capsrc_nids_alt +static const hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 }; +#define alc889_capsrc_nids alc882_capsrc_nids + +/* input MUX */ +/* FIXME: should be a matrix-type input source selection */ + +static const struct hda_input_mux alc882_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x1 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + }, +}; + +#define alc883_capture_source alc882_capture_source + +static const struct hda_input_mux alc889_capture_source = { + .num_items = 3, + .items = { + { "Front Mic", 0x0 }, + { "Mic", 0x3 }, + { "Line", 0x2 }, + }, +}; + +static const struct hda_input_mux mb5_capture_source = { + .num_items = 3, + .items = { + { "Mic", 0x1 }, + { "Line", 0x7 }, + { "CD", 0x4 }, + }, +}; + +static const struct hda_input_mux macmini3_capture_source = { + .num_items = 2, + .items = { + { "Line", 0x2 }, + { "CD", 0x4 }, + }, +}; + +static const struct hda_input_mux alc883_3stack_6ch_intel = { + .num_items = 4, + .items = { + { "Mic", 0x1 }, + { "Front Mic", 0x0 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + }, +}; + +static const struct hda_input_mux alc883_lenovo_101e_capture_source = { + .num_items = 2, + .items = { + { "Mic", 0x1 }, + { "Line", 0x2 }, + }, +}; + +static const struct hda_input_mux alc883_lenovo_nb0763_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Internal Mic", 0x1 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + }, +}; + +static const struct hda_input_mux alc883_fujitsu_pi2515_capture_source = { + .num_items = 2, + .items = { + { "Mic", 0x0 }, + { "Internal Mic", 0x1 }, + }, +}; + +static const struct hda_input_mux alc883_lenovo_sky_capture_source = { + .num_items = 3, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x1 }, + { "Line", 0x4 }, + }, +}; + +static const struct hda_input_mux alc883_asus_eee1601_capture_source = { + .num_items = 2, + .items = { + { "Mic", 0x0 }, + { "Line", 0x2 }, + }, +}; + +static const struct hda_input_mux alc889A_mb31_capture_source = { + .num_items = 2, + .items = { + { "Mic", 0x0 }, + /* Front Mic (0x01) unused */ + { "Line", 0x2 }, + /* Line 2 (0x03) unused */ + /* CD (0x04) unused? */ + }, +}; + +static const struct hda_input_mux alc889A_imac91_capture_source = { + .num_items = 2, + .items = { + { "Mic", 0x01 }, + { "Line", 0x2 }, /* Not sure! */ + }, +}; + +/* + * 2ch mode + */ +static const struct hda_channel_mode alc883_3ST_2ch_modes[1] = { + { 2, NULL } +}; + +/* + * 2ch mode + */ +static const struct hda_verb alc882_3ST_ch2_init[] = { + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { } /* end */ +}; + +/* + * 4ch mode + */ +static const struct hda_verb alc882_3ST_ch4_init[] = { + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; + +/* + * 6ch mode + */ +static const struct hda_verb alc882_3ST_ch6_init[] = { + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; + +static const struct hda_channel_mode alc882_3ST_6ch_modes[3] = { + { 2, alc882_3ST_ch2_init }, + { 4, alc882_3ST_ch4_init }, + { 6, alc882_3ST_ch6_init }, +}; + +#define alc883_3ST_6ch_modes alc882_3ST_6ch_modes + +/* + * 2ch mode + */ +static const struct hda_verb alc883_3ST_ch2_clevo_init[] = { + { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { } /* end */ +}; + +/* + * 4ch mode + */ +static const struct hda_verb alc883_3ST_ch4_clevo_init[] = { + { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; + +/* + * 6ch mode + */ +static const struct hda_verb alc883_3ST_ch6_clevo_init[] = { + { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; + +static const struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = { + { 2, alc883_3ST_ch2_clevo_init }, + { 4, alc883_3ST_ch4_clevo_init }, + { 6, alc883_3ST_ch6_clevo_init }, +}; + + +/* + * 6ch mode + */ +static const struct hda_verb alc882_sixstack_ch6_init[] = { + { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, + { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { } /* end */ +}; + +/* + * 8ch mode + */ +static const struct hda_verb alc882_sixstack_ch8_init[] = { + { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { } /* end */ +}; + +static const struct hda_channel_mode alc882_sixstack_modes[2] = { + { 6, alc882_sixstack_ch6_init }, + { 8, alc882_sixstack_ch8_init }, +}; + + +/* Macbook Air 2,1 */ + +static const struct hda_channel_mode alc885_mba21_ch_modes[1] = { + { 2, NULL }, +}; + +/* + * macbook pro ALC885 can switch LineIn to LineOut without losing Mic + */ + +/* + * 2ch mode + */ +static const struct hda_verb alc885_mbp_ch2_init[] = { + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + { } /* end */ +}; + +/* + * 4ch mode + */ +static const struct hda_verb alc885_mbp_ch4_init[] = { + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + { } /* end */ +}; + +static const struct hda_channel_mode alc885_mbp_4ch_modes[2] = { + { 2, alc885_mbp_ch2_init }, + { 4, alc885_mbp_ch4_init }, +}; + +/* + * 2ch + * Speakers/Woofer/HP = Front + * LineIn = Input + */ +static const struct hda_verb alc885_mb5_ch2_init[] = { + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + { } /* end */ +}; + +/* + * 6ch mode + * Speakers/HP = Front + * Woofer = LFE + * LineIn = Surround + */ +static const struct hda_verb alc885_mb5_ch6_init[] = { + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + { } /* end */ +}; + +static const struct hda_channel_mode alc885_mb5_6ch_modes[2] = { + { 2, alc885_mb5_ch2_init }, + { 6, alc885_mb5_ch6_init }, +}; + +#define alc885_macmini3_6ch_modes alc885_mb5_6ch_modes + +/* + * 2ch mode + */ +static const struct hda_verb alc883_4ST_ch2_init[] = { + { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { } /* end */ +}; + +/* + * 4ch mode + */ +static const struct hda_verb alc883_4ST_ch4_init[] = { + { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; + +/* + * 6ch mode + */ +static const struct hda_verb alc883_4ST_ch6_init[] = { + { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; + +/* + * 8ch mode + */ +static const struct hda_verb alc883_4ST_ch8_init[] = { + { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 }, + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; + +static const struct hda_channel_mode alc883_4ST_8ch_modes[4] = { + { 2, alc883_4ST_ch2_init }, + { 4, alc883_4ST_ch4_init }, + { 6, alc883_4ST_ch6_init }, + { 8, alc883_4ST_ch8_init }, +}; + + +/* + * 2ch mode + */ +static const struct hda_verb alc883_3ST_ch2_intel_init[] = { + { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { } /* end */ +}; + +/* + * 4ch mode + */ +static const struct hda_verb alc883_3ST_ch4_intel_init[] = { + { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; + +/* + * 6ch mode + */ +static const struct hda_verb alc883_3ST_ch6_intel_init[] = { + { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; + +static const struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = { + { 2, alc883_3ST_ch2_intel_init }, + { 4, alc883_3ST_ch4_intel_init }, + { 6, alc883_3ST_ch6_intel_init }, +}; + +/* + * 2ch mode + */ +static const struct hda_verb alc889_ch2_intel_init[] = { + { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 }, + { 0x19, AC_VERB_SET_CONNECT_SEL, 0x00 }, + { 0x16, AC_VERB_SET_CONNECT_SEL, 0x00 }, + { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00 }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { } /* end */ +}; + +/* + * 6ch mode + */ +static const struct hda_verb alc889_ch6_intel_init[] = { + { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 }, + { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 }, + { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { } /* end */ +}; + +/* + * 8ch mode + */ +static const struct hda_verb alc889_ch8_intel_init[] = { + { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 }, + { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 }, + { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 }, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x03 }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { } /* end */ +}; + +static const struct hda_channel_mode alc889_8ch_intel_modes[3] = { + { 2, alc889_ch2_intel_init }, + { 6, alc889_ch6_intel_init }, + { 8, alc889_ch8_intel_init }, +}; + +/* + * 6ch mode + */ +static const struct hda_verb alc883_sixstack_ch6_init[] = { + { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, + { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { } /* end */ +}; + +/* + * 8ch mode + */ +static const struct hda_verb alc883_sixstack_ch8_init[] = { + { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { } /* end */ +}; + +static const struct hda_channel_mode alc883_sixstack_modes[2] = { + { 6, alc883_sixstack_ch6_init }, + { 8, alc883_sixstack_ch8_init }, +}; + + +/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 + * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b + */ +static const struct snd_kcontrol_new alc882_base_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +/* Macbook Air 2,1 same control for HP and internal Speaker */ + +static const struct snd_kcontrol_new alc885_mba21_mixer[] = { + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_OUTPUT), + { } +}; + + +static const struct snd_kcontrol_new alc885_mbp3_mixer[] = { + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0e, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("Headphone Playback Switch", 0x0e, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT), + HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc885_mb5_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT), + HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0x00, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc885_macmini3_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT), + HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT), + HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc885_imac91_mixer[] = { + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT), + { } /* end */ +}; + + +static const struct snd_kcontrol_new alc882_w2jc_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc882_targa_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + { } /* end */ +}; + +/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ??? + * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c + */ +static const struct snd_kcontrol_new alc882_asus_a7j_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT), + HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc882_asus_a7m_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc882_chmode_mixer[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + }, + { } /* end */ +}; + +static const struct hda_verb alc882_base_init_verbs[] = { + /* Front mixer: unmute input/output amp left and right (volume = 0) */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Rear mixer */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* CLFE mixer */ + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Side mixer */ + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + + /* Front Pin: output 0 (0x0c) */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* Rear Pin: output 1 (0x0d) */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + /* CLFE Pin: output 2 (0x0e) */ + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, + /* Side Pin: output 3 (0x0f) */ + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, + /* Mic (rear) pin: input vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Front Mic pin: input vref at 80% */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line In pin: input */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line-2 In: Headphone output (output 0 - 0x0c) */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* CD pin widget for input */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + /* FIXME: use matrix-type input source selection */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ + /* Input mixer2 */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* Input mixer3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* ADC2: mute amp left and right */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* ADC3: mute amp left and right */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + + { } +}; + +static const struct hda_verb alc882_adc1_init_verbs[] = { + /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* ADC1: mute amp left and right */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + { } +}; + +static const struct hda_verb alc882_eapd_verbs[] = { + /* change to EAPD mode */ + {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, + {0x20, AC_VERB_SET_PROC_COEF, 0x3060}, + { } +}; + +static const struct hda_verb alc889_eapd_verbs[] = { + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, + {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, + { } +}; + +static const struct hda_verb alc_hp15_unsol_verbs[] = { + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {} +}; + +static const struct hda_verb alc885_init_verbs[] = { + /* Front mixer: unmute input/output amp left and right (volume = 0) */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + /* Rear mixer */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + /* CLFE mixer */ + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + /* Side mixer */ + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* Front HP Pin: output 0 (0x0c) */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* Front Pin: output 0 (0x0c) */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* Rear Pin: output 1 (0x0d) */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x19, AC_VERB_SET_CONNECT_SEL, 0x01}, + /* CLFE Pin: output 2 (0x0e) */ + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, + /* Side Pin: output 3 (0x0f) */ + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, + /* Mic (rear) pin: input vref at 80% */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Front Mic pin: input vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line In pin: input */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + + /* Mixer elements: 0x18, , 0x1a, 0x1b */ + /* Input mixer1 */ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* Input mixer2 */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* Input mixer3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* ADC2: mute amp left and right */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + /* ADC3: mute amp left and right */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + + { } +}; + +static const struct hda_verb alc885_init_input_verbs[] = { + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + { } +}; + + +/* Unmute Selector 24h and set the default input to front mic */ +static const struct hda_verb alc889_init_input_verbs[] = { + {0x24, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + { } +}; + + +#define alc883_init_verbs alc882_base_init_verbs + +/* Mac Pro test */ +static const struct snd_kcontrol_new alc882_macpro_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT), + /* FIXME: this looks suspicious... + HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x02, HDA_INPUT), + */ + { } /* end */ +}; + +static const struct hda_verb alc882_macpro_init_verbs[] = { + /* Front mixer: unmute input/output amp left and right (volume = 0) */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Front Pin: output 0 (0x0c) */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* Front Mic pin: input vref at 80% */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Speaker: output */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04}, + /* Headphone output (output 0 - 0x0c) */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x18, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* FIXME: use matrix-type input source selection */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ + /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* Input mixer2 */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* Input mixer3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* ADC1: mute amp left and right */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* ADC2: mute amp left and right */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* ADC3: mute amp left and right */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + + { } +}; + +/* Macbook 5,1 */ +static const struct hda_verb alc885_mb5_init_verbs[] = { + /* DACs */ + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Front mixer */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Surround mixer */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* LFE mixer */ + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* HP mixer */ + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Front Pin (0x0c) */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x18, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* LFE Pin (0x0e) */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, + /* HP Pin (0x0f) */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x03}, + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + /* Front Mic pin: input vref at 80% */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line In pin */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0x1)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x7)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x4)}, + { } +}; + +/* Macmini 3,1 */ +static const struct hda_verb alc885_macmini3_init_verbs[] = { + /* DACs */ + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Front mixer */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Surround mixer */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* LFE mixer */ + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* HP mixer */ + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Front Pin (0x0c) */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x18, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* LFE Pin (0x0e) */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, + /* HP Pin (0x0f) */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x03}, + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + /* Line In pin */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + { } +}; + + +static const struct hda_verb alc885_mba21_init_verbs[] = { + /*Internal and HP Speaker Mixer*/ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + /*Internal Speaker Pin (0x0c)*/ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) }, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x18, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* HP Pin: output 0 (0x0e) */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)}, + /* Line in (is hp when jack connected)*/ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + + { } + }; + + +/* Macbook Pro rev3 */ +static const struct hda_verb alc885_mbp3_init_verbs[] = { + /* Front mixer: unmute input/output amp left and right (volume = 0) */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Rear mixer */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* HP mixer */ + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Front Pin: output 0 (0x0c) */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* HP Pin: output 0 (0x0e) */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x02}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + /* Mic (rear) pin: input vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Front Mic pin: input vref at 80% */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line In pin: use output 1 when in LineOut mode */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, + + /* FIXME: use matrix-type input source selection */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ + /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* Input mixer2 */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* Input mixer3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* ADC1: mute amp left and right */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* ADC2: mute amp left and right */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* ADC3: mute amp left and right */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + + { } +}; + +/* iMac 9,1 */ +static const struct hda_verb alc885_imac91_init_verbs[] = { + /* Internal Speaker Pin (0x0c) */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) }, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x18, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) }, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* HP Pin: Rear */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)}, + /* Line in Rear */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Front Mic pin: input vref at 80% */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Rear mixer */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Line-Out mixer: unmute input/output amp left and right (volume = 0) */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* 0x24 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* 0x23 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* 0x22 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* 0x07 [Audio Input] wcaps 0x10011b: Stereo Amp-In */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* 0x08 [Audio Input] wcaps 0x10011b: Stereo Amp-In */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* 0x09 [Audio Input] wcaps 0x10011b: Stereo Amp-In */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + { } +}; + +/* iMac 24 mixer. */ +static const struct snd_kcontrol_new alc885_imac24_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT), + HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT), + { } /* end */ +}; + +/* iMac 24 init verbs. */ +static const struct hda_verb alc885_imac24_init_verbs[] = { + /* Internal speakers: output 0 (0x0c) */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x18, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* Internal speakers: output 0 (0x0c) */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* Headphone: output 0 (0x0c) */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + /* Front Mic: input vref at 80% */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + { } +}; + +/* Toggle speaker-output according to the hp-jack state */ +static void alc885_imac24_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x18; + spec->autocfg.speaker_pins[1] = 0x1a; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +#define alc885_mb5_setup alc885_imac24_setup +#define alc885_macmini3_setup alc885_imac24_setup + +/* Macbook Air 2,1 */ +static void alc885_mba21_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x18; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + + + +static void alc885_mbp3_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static void alc885_imac91_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x18; + spec->autocfg.speaker_pins[1] = 0x1a; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static const struct hda_verb alc882_targa_verbs[] = { + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + + {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */ + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + { } /* end */ +}; + +/* toggle speaker-output according to the hp-jack state */ +static void alc882_targa_automute(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + alc_hp_automute(codec); + snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA, + spec->jack_present ? 1 : 3); +} + +static void alc882_targa_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x1b; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc882_targa_automute(codec); +} + +static const struct hda_verb alc882_asus_a7j_verbs[] = { + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */ + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */ + + {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */ + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + { } /* end */ +}; + +static const struct hda_verb alc882_asus_a7m_verbs[] = { + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */ + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */ + + {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */ + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + { } /* end */ +}; + +static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted) +{ + unsigned int gpiostate, gpiomask, gpiodir; + + gpiostate = snd_hda_codec_read(codec, codec->afg, 0, + AC_VERB_GET_GPIO_DATA, 0); + + if (!muted) + gpiostate |= (1 << pin); + else + gpiostate &= ~(1 << pin); + + gpiomask = snd_hda_codec_read(codec, codec->afg, 0, + AC_VERB_GET_GPIO_MASK, 0); + gpiomask |= (1 << pin); + + gpiodir = snd_hda_codec_read(codec, codec->afg, 0, + AC_VERB_GET_GPIO_DIRECTION, 0); + gpiodir |= (1 << pin); + + + snd_hda_codec_write(codec, codec->afg, 0, + AC_VERB_SET_GPIO_MASK, gpiomask); + snd_hda_codec_write(codec, codec->afg, 0, + AC_VERB_SET_GPIO_DIRECTION, gpiodir); + + msleep(1); + + snd_hda_codec_write(codec, codec->afg, 0, + AC_VERB_SET_GPIO_DATA, gpiostate); +} + +/* set up GPIO at initialization */ +static void alc885_macpro_init_hook(struct hda_codec *codec) +{ + alc882_gpio_mute(codec, 0, 0); + alc882_gpio_mute(codec, 1, 0); +} + +/* set up GPIO and update auto-muting at initialization */ +static void alc885_imac24_init_hook(struct hda_codec *codec) +{ + alc885_macpro_init_hook(codec); + alc_hp_automute(codec); +} + +/* + * generic initialization of ADC, input mixers and output mixers + */ +static const struct hda_verb alc883_auto_init_verbs[] = { + /* + * Unmute ADC0-2 and set the default input to mic-in + */ + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* + * Set up output mixers (0x0c - 0x0f) + */ + /* set vol=0 to output mixers */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* set up input amps for analog loopback */ + /* Amp Indices: DAC = 0, mixer = 1 */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* FIXME: use matrix-type input source selection */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ + /* Input mixer2 */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* Input mixer3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + { } +}; + +/* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */ +static const struct hda_verb alc889A_mb31_ch2_init[] = { + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */ + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */ + { } /* end */ +}; + +/* 4ch mode (Speaker:front, Subwoofer:CLFE, Line:CLFE, Headphones:front) */ +static const struct hda_verb alc889A_mb31_ch4_init[] = { + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */ + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */ + { } /* end */ +}; + +/* 5ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:rear) */ +static const struct hda_verb alc889A_mb31_ch5_init[] = { + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as rear */ + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */ + { } /* end */ +}; + +/* 6ch mode (Speaker:front, Subwoofer:off, Line:CLFE, Headphones:Rear) */ +static const struct hda_verb alc889A_mb31_ch6_init[] = { + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as front */ + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Subwoofer off */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */ + { } /* end */ +}; + +static const struct hda_channel_mode alc889A_mb31_6ch_modes[4] = { + { 2, alc889A_mb31_ch2_init }, + { 4, alc889A_mb31_ch4_init }, + { 5, alc889A_mb31_ch5_init }, + { 6, alc889A_mb31_ch6_init }, +}; + +static const struct hda_verb alc883_medion_eapd_verbs[] = { + /* eanable EAPD on medion laptop */ + {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, + {0x20, AC_VERB_SET_PROC_COEF, 0x3070}, + { } +}; + +#define alc883_base_mixer alc882_base_mixer + +static const struct snd_kcontrol_new alc883_mitac_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc883_clevo_m720_mixer[] = { + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = { + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, + HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc885_8ch_intel_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, + HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x0f, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x3, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x1b, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x3, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc883_fivestack_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc883_targa_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc883_targa_2ch_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc883_targa_8ch_mixer[] = { + HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = { + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc883_medion_wim2160_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x08, 0x0, HDA_INPUT), + { } /* end */ +}; + +static const struct hda_verb alc883_medion_wim2160_verbs[] = { + /* Unmute front mixer */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* Set speaker pin to front mixer */ + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Init headphone pin */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + + { } /* end */ +}; + +/* toggle speaker-output according to the hp-jack state */ +static void alc883_medion_wim2160_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x1a; + spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static const struct snd_kcontrol_new alc883_acer_aspire_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("LFE Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", + 0x0d, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc889A_mb31_mixer[] = { + /* Output mixers */ + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x00, + HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x02, HDA_INPUT), + /* Output switches */ + HDA_CODEC_MUTE("Enable Speaker", 0x14, 0x00, HDA_OUTPUT), + HDA_CODEC_MUTE("Enable Headphones", 0x15, 0x00, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Enable LFE", 0x16, 2, 0x00, HDA_OUTPUT), + /* Boost mixers */ + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT), + /* Input mixers */ + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc883_vaiott_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct hda_bind_ctls alc883_bind_cap_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT), + HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT), + 0 + }, +}; + +static const struct hda_bind_ctls alc883_bind_cap_switch = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT), + HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT), + 0 + }, +}; + +static const struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = { + HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol), + HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 1, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, + }, + { } /* end */ +}; + +static const struct snd_kcontrol_new alc883_chmode_mixer[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + }, + { } /* end */ +}; + +/* toggle speaker-output according to the hp-jack state */ +static void alc883_mitac_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x17; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static const struct hda_verb alc883_mitac_verbs[] = { + /* HP */ + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + /* Subwoofer */ + {0x17, AC_VERB_SET_CONNECT_SEL, 0x02}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + + /* enable unsolicited event */ + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */ + + { } /* end */ +}; + +static const struct hda_verb alc883_clevo_m540r_verbs[] = { + /* HP */ + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + /* Int speaker */ + /*{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},*/ + + /* enable unsolicited event */ + /* + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, + */ + + { } /* end */ +}; + +static const struct hda_verb alc883_clevo_m720_verbs[] = { + /* HP */ + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + /* Int speaker */ + {0x14, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + + /* enable unsolicited event */ + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, + + { } /* end */ +}; + +static const struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = { + /* HP */ + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + /* Subwoofer */ + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + + /* enable unsolicited event */ + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + + { } /* end */ +}; + +static const struct hda_verb alc883_targa_verbs[] = { + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + +/* Connect Line-Out side jack (SPDIF) to Side */ + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, +/* Connect Mic jack to CLFE */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, +/* Connect Line-in jack to Surround */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, +/* Connect HP out jack to Front */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + + { } /* end */ +}; + +static const struct hda_verb alc883_lenovo_101e_verbs[] = { + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN}, + { } /* end */ +}; + +static const struct hda_verb alc883_lenovo_nb0763_verbs[] = { + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + { } /* end */ +}; + +static const struct hda_verb alc888_lenovo_ms7195_verbs[] = { + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + { } /* end */ +}; + +static const struct hda_verb alc883_haier_w66_verbs[] = { + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + { } /* end */ +}; + +static const struct hda_verb alc888_lenovo_sky_verbs[] = { + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + { } /* end */ +}; + +static const struct hda_verb alc888_6st_dell_verbs[] = { + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + { } +}; + +static const struct hda_verb alc883_vaiott_verbs[] = { + /* HP */ + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + + /* enable unsolicited event */ + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + + { } /* end */ +}; + +static void alc888_3st_hp_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x16; + spec->autocfg.speaker_pins[2] = 0x18; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static const struct hda_verb alc888_3st_hp_verbs[] = { + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */ + {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */ + {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */ + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + { } /* end */ +}; + +/* + * 2ch mode + */ +static const struct hda_verb alc888_3st_hp_2ch_init[] = { + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { } /* end */ +}; + +/* + * 4ch mode + */ +static const struct hda_verb alc888_3st_hp_4ch_init[] = { + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; + +/* + * 6ch mode + */ +static const struct hda_verb alc888_3st_hp_6ch_init[] = { + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, + { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; + +static const struct hda_channel_mode alc888_3st_hp_modes[3] = { + { 2, alc888_3st_hp_2ch_init }, + { 4, alc888_3st_hp_4ch_init }, + { 6, alc888_3st_hp_6ch_init }, +}; + +static void alc888_lenovo_ms7195_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.line_out_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +/* toggle speaker-output according to the hp-jack state */ +static void alc883_lenovo_nb0763_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +/* toggle speaker-output according to the hp-jack state */ +#define alc883_targa_init_hook alc882_targa_init_hook +#define alc883_targa_unsol_event alc882_targa_unsol_event + +static void alc883_clevo_m720_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static void alc883_clevo_m720_init_hook(struct hda_codec *codec) +{ + alc_hp_automute(codec); + alc88x_simple_mic_automute(codec); +} + +static void alc883_clevo_m720_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + switch (res >> 26) { + case ALC880_MIC_EVENT: + alc88x_simple_mic_automute(codec); + break; + default: + alc_sku_unsol_event(codec, res); + break; + } +} + +/* toggle speaker-output according to the hp-jack state */ +static void alc883_2ch_fujitsu_pi2515_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static void alc883_haier_w66_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static void alc883_lenovo_101e_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.line_out_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->detect_line = 1; + spec->automute_lines = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +/* toggle speaker-output according to the hp-jack state */ +static void alc883_acer_aspire_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x15; + spec->autocfg.speaker_pins[1] = 0x16; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static const struct hda_verb alc883_acer_eapd_verbs[] = { + /* HP Pin: output 0 (0x0c) */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* Front Pin: output 0 (0x0c) */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* eanable EAPD on medion laptop */ + {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, + {0x20, AC_VERB_SET_PROC_COEF, 0x3050}, + /* enable unsolicited event */ + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + { } +}; + +static void alc888_6st_dell_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x15; + spec->autocfg.speaker_pins[2] = 0x16; + spec->autocfg.speaker_pins[3] = 0x17; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static void alc888_lenovo_sky_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x15; + spec->autocfg.speaker_pins[2] = 0x16; + spec->autocfg.speaker_pins[3] = 0x17; + spec->autocfg.speaker_pins[4] = 0x1a; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static void alc883_vaiott_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x17; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static const struct hda_verb alc888_asus_m90v_verbs[] = { + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + /* enable unsolicited event */ + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, + { } /* end */ +}; + +static void alc883_mode2_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x15; + spec->autocfg.speaker_pins[2] = 0x16; + spec->ext_mic.pin = 0x18; + spec->int_mic.pin = 0x19; + spec->ext_mic.mux_idx = 0; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static const struct hda_verb alc888_asus_eee1601_verbs[] = { + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x20, AC_VERB_SET_COEF_INDEX, 0x0b}, + {0x20, AC_VERB_SET_PROC_COEF, 0x0838}, + /* enable unsolicited event */ + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + { } /* end */ +}; + +static void alc883_eee1601_inithook(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x1b; + alc_hp_automute(codec); +} + +static const struct hda_verb alc889A_mb31_verbs[] = { + /* Init rear pin (used as headphone output) */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, /* Apple Headphones */ + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Connect to front */ + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + /* Init line pin (used as output in 4ch and 6ch mode) */ + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Connect to CLFE */ + /* Init line 2 pin (used as headphone out by default) */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Use as input */ + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Mute output */ + { } /* end */ +}; + +/* Mute speakers according to the headphone jack state */ +static void alc889A_mb31_automute(struct hda_codec *codec) +{ + unsigned int present; + + /* Mute only in 2ch or 4ch mode */ + if (snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_CONNECT_SEL, 0) + == 0x00) { + present = snd_hda_jack_detect(codec, 0x15); + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + } +} + +static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc889A_mb31_automute(codec); +} + + +#ifdef CONFIG_SND_HDA_POWER_SAVE +#define alc882_loopbacks alc880_loopbacks +#endif + +/* pcm configuration: identical with ALC880 */ +#define alc882_pcm_analog_playback alc880_pcm_analog_playback +#define alc882_pcm_analog_capture alc880_pcm_analog_capture +#define alc882_pcm_digital_playback alc880_pcm_digital_playback +#define alc882_pcm_digital_capture alc880_pcm_digital_capture + +static const hda_nid_t alc883_slave_dig_outs[] = { + ALC1200_DIGOUT_NID, 0, +}; + +static const hda_nid_t alc1200_slave_dig_outs[] = { + ALC883_DIGOUT_NID, 0, +}; + +/* + * configuration and preset + */ +static const char * const alc882_models[ALC882_MODEL_LAST] = { + [ALC882_3ST_DIG] = "3stack-dig", + [ALC882_6ST_DIG] = "6stack-dig", + [ALC882_ARIMA] = "arima", + [ALC882_W2JC] = "w2jc", + [ALC882_TARGA] = "targa", + [ALC882_ASUS_A7J] = "asus-a7j", + [ALC882_ASUS_A7M] = "asus-a7m", + [ALC885_MACPRO] = "macpro", + [ALC885_MB5] = "mb5", + [ALC885_MACMINI3] = "macmini3", + [ALC885_MBA21] = "mba21", + [ALC885_MBP3] = "mbp3", + [ALC885_IMAC24] = "imac24", + [ALC885_IMAC91] = "imac91", + [ALC883_3ST_2ch_DIG] = "3stack-2ch-dig", + [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig", + [ALC883_3ST_6ch] = "3stack-6ch", + [ALC883_6ST_DIG] = "alc883-6stack-dig", + [ALC883_TARGA_DIG] = "targa-dig", + [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig", + [ALC883_TARGA_8ch_DIG] = "targa-8ch-dig", + [ALC883_ACER] = "acer", + [ALC883_ACER_ASPIRE] = "acer-aspire", + [ALC888_ACER_ASPIRE_4930G] = "acer-aspire-4930g", + [ALC888_ACER_ASPIRE_6530G] = "acer-aspire-6530g", + [ALC888_ACER_ASPIRE_8930G] = "acer-aspire-8930g", + [ALC888_ACER_ASPIRE_7730G] = "acer-aspire-7730g", + [ALC883_MEDION] = "medion", + [ALC883_MEDION_WIM2160] = "medion-wim2160", + [ALC883_LAPTOP_EAPD] = "laptop-eapd", + [ALC883_LENOVO_101E_2ch] = "lenovo-101e", + [ALC883_LENOVO_NB0763] = "lenovo-nb0763", + [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig", + [ALC888_LENOVO_SKY] = "lenovo-sky", + [ALC883_HAIER_W66] = "haier-w66", + [ALC888_3ST_HP] = "3stack-hp", + [ALC888_6ST_DELL] = "6stack-dell", + [ALC883_MITAC] = "mitac", + [ALC883_CLEVO_M540R] = "clevo-m540r", + [ALC883_CLEVO_M720] = "clevo-m720", + [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515", + [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530", + [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel", + [ALC889A_INTEL] = "intel-alc889a", + [ALC889_INTEL] = "intel-x58", + [ALC1200_ASUS_P5Q] = "asus-p5q", + [ALC889A_MB31] = "mb31", + [ALC883_SONY_VAIO_TT] = "sony-vaio-tt", + [ALC882_AUTO] = "auto", +}; + +static const struct snd_pci_quirk alc882_cfg_tbl[] = { + SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG), + + SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE), + SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE), + SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_ACER_ASPIRE), + SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE), + SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE), + SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE), + SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G", + ALC888_ACER_ASPIRE_4930G), + SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G", + ALC888_ACER_ASPIRE_4930G), + SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G", + ALC888_ACER_ASPIRE_8930G), + SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G", + ALC888_ACER_ASPIRE_8930G), + SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC882_AUTO), + SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC882_AUTO), + SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G", + ALC888_ACER_ASPIRE_6530G), + SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G", + ALC888_ACER_ASPIRE_6530G), + SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G", + ALC888_ACER_ASPIRE_7730G), + /* default Acer -- disabled as it causes more problems. + * model=auto should work fine now + */ + /* SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), */ + + SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL), + + SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavilion", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP), + SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP), + SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP), + SND_PCI_QUIRK(0x103c, 0x2a72, "HP Educ.ar", ALC888_3ST_HP), + + SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J), + SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J), + SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M), + SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V), + SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC), + SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG), + SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG), + SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG), + SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q), + SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601), + + SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC883_SONY_VAIO_TT), + SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG), + SND_PCI_QUIRK(0x1071, 0x8227, "Mitac 82801H", ALC883_MITAC), + SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC), + SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD), + SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL), + SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch), + SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG), + + SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG), + SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG), + SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG), + SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */ + SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC882_AUTO), + SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG), + SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG), + SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0x42cd, "MSI", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0x4570, "MSI Wind Top AE2220", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0x6510, "MSI GX620", ALC883_TARGA_8ch_DIG), + SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x1462, 0x7260, "MSI 7260", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG), + SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x1462, 0x7350, "MSI", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x1462, 0x7437, "MSI NetOn AP1900", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG), + SND_PCI_QUIRK(0x1462, 0xaa08, "MSI", ALC883_TARGA_2ch_DIG), + + SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x1558, 0x0571, "Clevo laptop M570U", ALC883_3ST_6ch_DIG), + SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720), + SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720), + SND_PCI_QUIRK(0x1558, 0x5409, "Clevo laptop M540R", ALC883_CLEVO_M540R), + SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD), + SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch), + /* SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), */ + SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION), + SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1100, "FSC AMILO Xi/Pi25xx", + ALC883_FUJITSU_PI2515), + SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1130, "Fujitsu AMILO Xa35xx", + ALC888_FUJITSU_XA3530), + SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch), + SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763), + SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763), + SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763), + SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY), + SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG), + SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66), + + SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL), + SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL), + SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC), + SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_INTEL), + SND_PCI_QUIRK(0x8086, 0x0021, "Intel IbexPeak", ALC889A_INTEL), + SND_PCI_QUIRK(0x8086, 0x3b56, "Intel IbexPeak", ALC889A_INTEL), + SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC882_6ST_DIG), + + {} +}; + +/* codec SSID table for Intel Mac */ +static const struct snd_pci_quirk alc882_ssid_cfg_tbl[] = { + SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC885_MBP3), + SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC885_MBP3), + SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC885_MBP3), + SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_MACPRO), + SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24), + SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24), + SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3), + SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889A_MB31), + SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_ASUS_A7M), + SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC885_MBP3), + SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC885_MBA21), + SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31), + SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3), + SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24), + SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC885_IMAC91), + SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5), + SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC885_MB5), + /* FIXME: HP jack sense seems not working for MBP 5,1 or 5,2, + * so apparently no perfect solution yet + */ + SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC885_MB5), + SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC885_MB5), + SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC885_MACMINI3), + {} /* terminator */ +}; + +static const struct alc_config_preset alc882_presets[] = { + [ALC882_3ST_DIG] = { + .mixers = { alc882_base_mixer }, + .init_verbs = { alc882_base_init_verbs, + alc882_adc1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .dig_out_nid = ALC882_DIGOUT_NID, + .dig_in_nid = ALC882_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), + .channel_mode = alc882_ch_modes, + .need_dac_fix = 1, + .input_mux = &alc882_capture_source, + }, + [ALC882_6ST_DIG] = { + .mixers = { alc882_base_mixer, alc882_chmode_mixer }, + .init_verbs = { alc882_base_init_verbs, + alc882_adc1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .dig_out_nid = ALC882_DIGOUT_NID, + .dig_in_nid = ALC882_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes), + .channel_mode = alc882_sixstack_modes, + .input_mux = &alc882_capture_source, + }, + [ALC882_ARIMA] = { + .mixers = { alc882_base_mixer, alc882_chmode_mixer }, + .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs, + alc882_eapd_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes), + .channel_mode = alc882_sixstack_modes, + .input_mux = &alc882_capture_source, + }, + [ALC882_W2JC] = { + .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer }, + .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs, + alc882_eapd_verbs, alc880_gpio1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), + .channel_mode = alc880_threestack_modes, + .need_dac_fix = 1, + .input_mux = &alc882_capture_source, + .dig_out_nid = ALC882_DIGOUT_NID, + }, + [ALC885_MBA21] = { + .mixers = { alc885_mba21_mixer }, + .init_verbs = { alc885_mba21_init_verbs, alc880_gpio1_init_verbs }, + .num_dacs = 2, + .dac_nids = alc882_dac_nids, + .channel_mode = alc885_mba21_ch_modes, + .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes), + .input_mux = &alc882_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc885_mba21_setup, + .init_hook = alc_hp_automute, + }, + [ALC885_MBP3] = { + .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer }, + .init_verbs = { alc885_mbp3_init_verbs, + alc880_gpio1_init_verbs }, + .num_dacs = 2, + .dac_nids = alc882_dac_nids, + .hp_nid = 0x04, + .channel_mode = alc885_mbp_4ch_modes, + .num_channel_mode = ARRAY_SIZE(alc885_mbp_4ch_modes), + .input_mux = &alc882_capture_source, + .dig_out_nid = ALC882_DIGOUT_NID, + .dig_in_nid = ALC882_DIGIN_NID, + .unsol_event = alc_sku_unsol_event, + .setup = alc885_mbp3_setup, + .init_hook = alc_hp_automute, + }, + [ALC885_MB5] = { + .mixers = { alc885_mb5_mixer, alc882_chmode_mixer }, + .init_verbs = { alc885_mb5_init_verbs, + alc880_gpio1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .channel_mode = alc885_mb5_6ch_modes, + .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes), + .input_mux = &mb5_capture_source, + .dig_out_nid = ALC882_DIGOUT_NID, + .dig_in_nid = ALC882_DIGIN_NID, + .unsol_event = alc_sku_unsol_event, + .setup = alc885_mb5_setup, + .init_hook = alc_hp_automute, + }, + [ALC885_MACMINI3] = { + .mixers = { alc885_macmini3_mixer, alc882_chmode_mixer }, + .init_verbs = { alc885_macmini3_init_verbs, + alc880_gpio1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .channel_mode = alc885_macmini3_6ch_modes, + .num_channel_mode = ARRAY_SIZE(alc885_macmini3_6ch_modes), + .input_mux = &macmini3_capture_source, + .dig_out_nid = ALC882_DIGOUT_NID, + .dig_in_nid = ALC882_DIGIN_NID, + .unsol_event = alc_sku_unsol_event, + .setup = alc885_macmini3_setup, + .init_hook = alc_hp_automute, + }, + [ALC885_MACPRO] = { + .mixers = { alc882_macpro_mixer }, + .init_verbs = { alc882_macpro_init_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .dig_out_nid = ALC882_DIGOUT_NID, + .dig_in_nid = ALC882_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), + .channel_mode = alc882_ch_modes, + .input_mux = &alc882_capture_source, + .init_hook = alc885_macpro_init_hook, + }, + [ALC885_IMAC24] = { + .mixers = { alc885_imac24_mixer }, + .init_verbs = { alc885_imac24_init_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .dig_out_nid = ALC882_DIGOUT_NID, + .dig_in_nid = ALC882_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), + .channel_mode = alc882_ch_modes, + .input_mux = &alc882_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc885_imac24_setup, + .init_hook = alc885_imac24_init_hook, + }, + [ALC885_IMAC91] = { + .mixers = {alc885_imac91_mixer}, + .init_verbs = { alc885_imac91_init_verbs, + alc880_gpio1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .channel_mode = alc885_mba21_ch_modes, + .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes), + .input_mux = &alc889A_imac91_capture_source, + .dig_out_nid = ALC882_DIGOUT_NID, + .dig_in_nid = ALC882_DIGIN_NID, + .unsol_event = alc_sku_unsol_event, + .setup = alc885_imac91_setup, + .init_hook = alc_hp_automute, + }, + [ALC882_TARGA] = { + .mixers = { alc882_targa_mixer, alc882_chmode_mixer }, + .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs, + alc880_gpio3_init_verbs, alc882_targa_verbs}, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .dig_out_nid = ALC882_DIGOUT_NID, + .num_adc_nids = ARRAY_SIZE(alc882_adc_nids), + .adc_nids = alc882_adc_nids, + .capsrc_nids = alc882_capsrc_nids, + .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes), + .channel_mode = alc882_3ST_6ch_modes, + .need_dac_fix = 1, + .input_mux = &alc882_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc882_targa_setup, + .init_hook = alc882_targa_automute, + }, + [ALC882_ASUS_A7J] = { + .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer }, + .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs, + alc882_asus_a7j_verbs}, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .dig_out_nid = ALC882_DIGOUT_NID, + .num_adc_nids = ARRAY_SIZE(alc882_adc_nids), + .adc_nids = alc882_adc_nids, + .capsrc_nids = alc882_capsrc_nids, + .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes), + .channel_mode = alc882_3ST_6ch_modes, + .need_dac_fix = 1, + .input_mux = &alc882_capture_source, + }, + [ALC882_ASUS_A7M] = { + .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer }, + .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs, + alc882_eapd_verbs, alc880_gpio1_init_verbs, + alc882_asus_a7m_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .dig_out_nid = ALC882_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), + .channel_mode = alc880_threestack_modes, + .need_dac_fix = 1, + .input_mux = &alc882_capture_source, + }, + [ALC883_3ST_2ch_DIG] = { + .mixers = { alc883_3ST_2ch_mixer }, + .init_verbs = { alc883_init_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .dig_in_nid = ALC883_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .input_mux = &alc883_capture_source, + }, + [ALC883_3ST_6ch_DIG] = { + .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .dig_in_nid = ALC883_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), + .channel_mode = alc883_3ST_6ch_modes, + .need_dac_fix = 1, + .input_mux = &alc883_capture_source, + }, + [ALC883_3ST_6ch] = { + .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), + .channel_mode = alc883_3ST_6ch_modes, + .need_dac_fix = 1, + .input_mux = &alc883_capture_source, + }, + [ALC883_3ST_6ch_INTEL] = { + .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .dig_in_nid = ALC883_DIGIN_NID, + .slave_dig_outs = alc883_slave_dig_outs, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes), + .channel_mode = alc883_3ST_6ch_intel_modes, + .need_dac_fix = 1, + .input_mux = &alc883_3stack_6ch_intel, + }, + [ALC889A_INTEL] = { + .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer }, + .init_verbs = { alc885_init_verbs, alc885_init_input_verbs, + alc_hp15_unsol_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc889_adc_nids), + .adc_nids = alc889_adc_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .dig_in_nid = ALC883_DIGIN_NID, + .slave_dig_outs = alc883_slave_dig_outs, + .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes), + .channel_mode = alc889_8ch_intel_modes, + .capsrc_nids = alc889_capsrc_nids, + .input_mux = &alc889_capture_source, + .setup = alc889_automute_setup, + .init_hook = alc_hp_automute, + .unsol_event = alc_sku_unsol_event, + .need_dac_fix = 1, + }, + [ALC889_INTEL] = { + .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer }, + .init_verbs = { alc885_init_verbs, alc889_init_input_verbs, + alc889_eapd_verbs, alc_hp15_unsol_verbs}, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc889_adc_nids), + .adc_nids = alc889_adc_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .dig_in_nid = ALC883_DIGIN_NID, + .slave_dig_outs = alc883_slave_dig_outs, + .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes), + .channel_mode = alc889_8ch_intel_modes, + .capsrc_nids = alc889_capsrc_nids, + .input_mux = &alc889_capture_source, + .setup = alc889_automute_setup, + .init_hook = alc889_intel_init_hook, + .unsol_event = alc_sku_unsol_event, + .need_dac_fix = 1, + }, + [ALC883_6ST_DIG] = { + .mixers = { alc883_base_mixer, alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .dig_in_nid = ALC883_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), + .channel_mode = alc883_sixstack_modes, + .input_mux = &alc883_capture_source, + }, + [ALC883_TARGA_DIG] = { + .mixers = { alc883_targa_mixer, alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs, + alc883_targa_verbs}, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), + .channel_mode = alc883_3ST_6ch_modes, + .need_dac_fix = 1, + .input_mux = &alc883_capture_source, + .unsol_event = alc883_targa_unsol_event, + .setup = alc882_targa_setup, + .init_hook = alc882_targa_automute, + }, + [ALC883_TARGA_2ch_DIG] = { + .mixers = { alc883_targa_2ch_mixer}, + .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs, + alc883_targa_verbs}, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .adc_nids = alc883_adc_nids_alt, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt), + .capsrc_nids = alc883_capsrc_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .input_mux = &alc883_capture_source, + .unsol_event = alc883_targa_unsol_event, + .setup = alc882_targa_setup, + .init_hook = alc882_targa_automute, + }, + [ALC883_TARGA_8ch_DIG] = { + .mixers = { alc883_targa_mixer, alc883_targa_8ch_mixer, + alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs, + alc883_targa_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev), + .adc_nids = alc883_adc_nids_rev, + .capsrc_nids = alc883_capsrc_nids_rev, + .dig_out_nid = ALC883_DIGOUT_NID, + .dig_in_nid = ALC883_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc883_4ST_8ch_modes), + .channel_mode = alc883_4ST_8ch_modes, + .need_dac_fix = 1, + .input_mux = &alc883_capture_source, + .unsol_event = alc883_targa_unsol_event, + .setup = alc882_targa_setup, + .init_hook = alc882_targa_automute, + }, + [ALC883_ACER] = { + .mixers = { alc883_base_mixer }, + /* On TravelMate laptops, GPIO 0 enables the internal speaker + * and the headphone jack. Turn this on and rely on the + * standard mute methods whenever the user wants to turn + * these outputs off. + */ + .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .input_mux = &alc883_capture_source, + }, + [ALC883_ACER_ASPIRE] = { + .mixers = { alc883_acer_aspire_mixer }, + .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .input_mux = &alc883_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc883_acer_aspire_setup, + .init_hook = alc_hp_automute, + }, + [ALC888_ACER_ASPIRE_4930G] = { + .mixers = { alc888_acer_aspire_4930g_mixer, + alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs, + alc888_acer_aspire_4930g_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev), + .adc_nids = alc883_adc_nids_rev, + .capsrc_nids = alc883_capsrc_nids_rev, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), + .channel_mode = alc883_3ST_6ch_modes, + .need_dac_fix = 1, + .const_channel_count = 6, + .num_mux_defs = + ARRAY_SIZE(alc888_2_capture_sources), + .input_mux = alc888_2_capture_sources, + .unsol_event = alc_sku_unsol_event, + .setup = alc888_acer_aspire_4930g_setup, + .init_hook = alc_hp_automute, + }, + [ALC888_ACER_ASPIRE_6530G] = { + .mixers = { alc888_acer_aspire_6530_mixer }, + .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs, + alc888_acer_aspire_6530g_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev), + .adc_nids = alc883_adc_nids_rev, + .capsrc_nids = alc883_capsrc_nids_rev, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .num_mux_defs = + ARRAY_SIZE(alc888_2_capture_sources), + .input_mux = alc888_acer_aspire_6530_sources, + .unsol_event = alc_sku_unsol_event, + .setup = alc888_acer_aspire_6530g_setup, + .init_hook = alc_hp_automute, + }, + [ALC888_ACER_ASPIRE_8930G] = { + .mixers = { alc889_acer_aspire_8930g_mixer, + alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs, + alc889_acer_aspire_8930g_verbs, + alc889_eapd_verbs}, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc889_adc_nids), + .adc_nids = alc889_adc_nids, + .capsrc_nids = alc889_capsrc_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), + .channel_mode = alc883_3ST_6ch_modes, + .need_dac_fix = 1, + .const_channel_count = 6, + .num_mux_defs = + ARRAY_SIZE(alc889_capture_sources), + .input_mux = alc889_capture_sources, + .unsol_event = alc_sku_unsol_event, + .setup = alc889_acer_aspire_8930g_setup, + .init_hook = alc_hp_automute, +#ifdef CONFIG_SND_HDA_POWER_SAVE + .power_hook = alc_power_eapd, +#endif + }, + [ALC888_ACER_ASPIRE_7730G] = { + .mixers = { alc883_3ST_6ch_mixer, + alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs, + alc888_acer_aspire_7730G_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev), + .adc_nids = alc883_adc_nids_rev, + .capsrc_nids = alc883_capsrc_nids_rev, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), + .channel_mode = alc883_3ST_6ch_modes, + .need_dac_fix = 1, + .const_channel_count = 6, + .input_mux = &alc883_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc888_acer_aspire_7730g_setup, + .init_hook = alc_hp_automute, + }, + [ALC883_MEDION] = { + .mixers = { alc883_fivestack_mixer, + alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, + alc883_medion_eapd_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .adc_nids = alc883_adc_nids_alt, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt), + .capsrc_nids = alc883_capsrc_nids, + .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), + .channel_mode = alc883_sixstack_modes, + .input_mux = &alc883_capture_source, + }, + [ALC883_MEDION_WIM2160] = { + .mixers = { alc883_medion_wim2160_mixer }, + .init_verbs = { alc883_init_verbs, alc883_medion_wim2160_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), + .adc_nids = alc883_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .input_mux = &alc883_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc883_medion_wim2160_setup, + .init_hook = alc_hp_automute, + }, + [ALC883_LAPTOP_EAPD] = { + .mixers = { alc883_base_mixer }, + .init_verbs = { alc883_init_verbs, alc882_eapd_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .input_mux = &alc883_capture_source, + }, + [ALC883_CLEVO_M540R] = { + .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, alc883_clevo_m540r_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .dig_in_nid = ALC883_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_clevo_modes), + .channel_mode = alc883_3ST_6ch_clevo_modes, + .need_dac_fix = 1, + .input_mux = &alc883_capture_source, + /* This machine has the hardware HP auto-muting, thus + * we need no software mute via unsol event + */ + }, + [ALC883_CLEVO_M720] = { + .mixers = { alc883_clevo_m720_mixer }, + .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .input_mux = &alc883_capture_source, + .unsol_event = alc883_clevo_m720_unsol_event, + .setup = alc883_clevo_m720_setup, + .init_hook = alc883_clevo_m720_init_hook, + }, + [ALC883_LENOVO_101E_2ch] = { + .mixers = { alc883_lenovo_101e_2ch_mixer}, + .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs}, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .adc_nids = alc883_adc_nids_alt, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt), + .capsrc_nids = alc883_capsrc_nids, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .input_mux = &alc883_lenovo_101e_capture_source, + .setup = alc883_lenovo_101e_setup, + .unsol_event = alc_sku_unsol_event, + .init_hook = alc_inithook, + }, + [ALC883_LENOVO_NB0763] = { + .mixers = { alc883_lenovo_nb0763_mixer }, + .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs}, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .need_dac_fix = 1, + .input_mux = &alc883_lenovo_nb0763_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc883_lenovo_nb0763_setup, + .init_hook = alc_hp_automute, + }, + [ALC888_LENOVO_MS7195_DIG] = { + .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs}, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), + .channel_mode = alc883_3ST_6ch_modes, + .need_dac_fix = 1, + .input_mux = &alc883_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc888_lenovo_ms7195_setup, + .init_hook = alc_inithook, + }, + [ALC883_HAIER_W66] = { + .mixers = { alc883_targa_2ch_mixer}, + .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs}, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .input_mux = &alc883_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc883_haier_w66_setup, + .init_hook = alc_hp_automute, + }, + [ALC888_3ST_HP] = { + .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes), + .channel_mode = alc888_3st_hp_modes, + .need_dac_fix = 1, + .input_mux = &alc883_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc888_3st_hp_setup, + .init_hook = alc_hp_automute, + }, + [ALC888_6ST_DELL] = { + .mixers = { alc883_base_mixer, alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .dig_in_nid = ALC883_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), + .channel_mode = alc883_sixstack_modes, + .input_mux = &alc883_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc888_6st_dell_setup, + .init_hook = alc_hp_automute, + }, + [ALC883_MITAC] = { + .mixers = { alc883_mitac_mixer }, + .init_verbs = { alc883_init_verbs, alc883_mitac_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .input_mux = &alc883_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc883_mitac_setup, + .init_hook = alc_hp_automute, + }, + [ALC883_FUJITSU_PI2515] = { + .mixers = { alc883_2ch_fujitsu_pi2515_mixer }, + .init_verbs = { alc883_init_verbs, + alc883_2ch_fujitsu_pi2515_verbs}, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .input_mux = &alc883_fujitsu_pi2515_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc883_2ch_fujitsu_pi2515_setup, + .init_hook = alc_hp_automute, + }, + [ALC888_FUJITSU_XA3530] = { + .mixers = { alc888_base_mixer, alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, + alc888_fujitsu_xa3530_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev), + .adc_nids = alc883_adc_nids_rev, + .capsrc_nids = alc883_capsrc_nids_rev, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc888_4ST_8ch_intel_modes), + .channel_mode = alc888_4ST_8ch_intel_modes, + .num_mux_defs = + ARRAY_SIZE(alc888_2_capture_sources), + .input_mux = alc888_2_capture_sources, + .unsol_event = alc_sku_unsol_event, + .setup = alc888_fujitsu_xa3530_setup, + .init_hook = alc_hp_automute, + }, + [ALC888_LENOVO_SKY] = { + .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs}, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), + .channel_mode = alc883_sixstack_modes, + .need_dac_fix = 1, + .input_mux = &alc883_lenovo_sky_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc888_lenovo_sky_setup, + .init_hook = alc_hp_automute, + }, + [ALC888_ASUS_M90V] = { + .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .dig_in_nid = ALC883_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), + .channel_mode = alc883_3ST_6ch_modes, + .need_dac_fix = 1, + .input_mux = &alc883_fujitsu_pi2515_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc883_mode2_setup, + .init_hook = alc_inithook, + }, + [ALC888_ASUS_EEE1601] = { + .mixers = { alc883_asus_eee1601_mixer }, + .cap_mixer = alc883_asus_eee1601_cap_mixer, + .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .dig_in_nid = ALC883_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .need_dac_fix = 1, + .input_mux = &alc883_asus_eee1601_capture_source, + .unsol_event = alc_sku_unsol_event, + .init_hook = alc883_eee1601_inithook, + }, + [ALC1200_ASUS_P5Q] = { + .mixers = { alc883_base_mixer, alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC1200_DIGOUT_NID, + .dig_in_nid = ALC883_DIGIN_NID, + .slave_dig_outs = alc1200_slave_dig_outs, + .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), + .channel_mode = alc883_sixstack_modes, + .input_mux = &alc883_capture_source, + }, + [ALC889A_MB31] = { + .mixers = { alc889A_mb31_mixer, alc883_chmode_mixer}, + .init_verbs = { alc883_init_verbs, alc889A_mb31_verbs, + alc880_gpio1_init_verbs }, + .adc_nids = alc883_adc_nids, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), + .capsrc_nids = alc883_capsrc_nids, + .dac_nids = alc883_dac_nids, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .channel_mode = alc889A_mb31_6ch_modes, + .num_channel_mode = ARRAY_SIZE(alc889A_mb31_6ch_modes), + .input_mux = &alc889A_mb31_capture_source, + .dig_out_nid = ALC883_DIGOUT_NID, + .unsol_event = alc889A_mb31_unsol_event, + .init_hook = alc889A_mb31_automute, + }, + [ALC883_SONY_VAIO_TT] = { + .mixers = { alc883_vaiott_mixer }, + .init_verbs = { alc883_init_verbs, alc883_vaiott_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .input_mux = &alc883_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc883_vaiott_setup, + .init_hook = alc_hp_automute, + }, +}; + + +/* + * Pin config fixes + */ +enum { + PINFIX_ABIT_AW9D_MAX, + PINFIX_LENOVO_Y530, + PINFIX_PB_M5210, + PINFIX_ACER_ASPIRE_7736, +}; + +static const struct alc_fixup alc882_fixups[] = { + [PINFIX_ABIT_AW9D_MAX] = { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { + { 0x15, 0x01080104 }, /* side */ + { 0x16, 0x01011012 }, /* rear */ + { 0x17, 0x01016011 }, /* clfe */ + { } + } + }, + [PINFIX_LENOVO_Y530] = { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { + { 0x15, 0x99130112 }, /* rear int speakers */ + { 0x16, 0x99130111 }, /* subwoofer */ + { } + } + }, + [PINFIX_PB_M5210] = { + .type = ALC_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 }, + {} + } + }, + [PINFIX_ACER_ASPIRE_7736] = { + .type = ALC_FIXUP_SKU, + .v.sku = ALC_FIXUP_SKU_IGNORE, + }, +}; + +static const struct snd_pci_quirk alc882_fixup_tbl[] = { + SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210), + SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", PINFIX_LENOVO_Y530), + SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX), + SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", PINFIX_ACER_ASPIRE_7736), + {} +}; + +/* + * BIOS auto configuration + */ +static int alc882_auto_create_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) +{ + return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x23, 0x22); +} + +static void alc882_auto_set_output_and_unmute(struct hda_codec *codec, + hda_nid_t nid, int pin_type, + hda_nid_t dac) +{ + int idx; + + /* set as output */ + alc_set_pin_output(codec, nid, pin_type); + + if (dac == 0x25) + idx = 4; + else if (dac >= 0x02 && dac <= 0x05) + idx = dac - 2; + else + return; + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx); +} + +static void alc882_auto_init_multi_out(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int i; + + for (i = 0; i <= HDA_SIDE; i++) { + hda_nid_t nid = spec->autocfg.line_out_pins[i]; + int pin_type = get_pin_type(spec->autocfg.line_out_type); + if (nid) + alc882_auto_set_output_and_unmute(codec, nid, pin_type, + spec->multiout.dac_nids[i]); + } +} + +static void alc882_auto_init_hp_out(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t pin, dac; + int i; + + if (spec->autocfg.line_out_type != AUTO_PIN_HP_OUT) { + for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) { + pin = spec->autocfg.hp_pins[i]; + if (!pin) + break; + dac = spec->multiout.hp_nid; + if (!dac) + dac = spec->multiout.dac_nids[0]; /* to front */ + alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, dac); + } + } + + if (spec->autocfg.line_out_type != AUTO_PIN_SPEAKER_OUT) { + for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) { + pin = spec->autocfg.speaker_pins[i]; + if (!pin) + break; + dac = spec->multiout.extra_out_nid[0]; + if (!dac) + dac = spec->multiout.dac_nids[0]; /* to front */ + alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac); + } + } +} + +static void alc882_auto_init_analog_input(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i; + + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; + alc_set_input_pin(codec, nid, cfg->inputs[i].type); + if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_OUT_MUTE); + } +} + +static void alc882_auto_init_input_src(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int c; + + for (c = 0; c < spec->num_adc_nids; c++) { + hda_nid_t conn_list[HDA_MAX_NUM_INPUTS]; + hda_nid_t nid = spec->capsrc_nids[c]; + unsigned int mux_idx; + const struct hda_input_mux *imux; + int conns, mute, idx, item; + + /* mute ADC */ + snd_hda_codec_write(codec, spec->adc_nids[c], 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_MUTE(0)); + + conns = snd_hda_get_connections(codec, nid, conn_list, + ARRAY_SIZE(conn_list)); + if (conns < 0) + continue; + mux_idx = c >= spec->num_mux_defs ? 0 : c; + imux = &spec->input_mux[mux_idx]; + if (!imux->num_items && mux_idx > 0) + imux = &spec->input_mux[0]; + for (idx = 0; idx < conns; idx++) { + /* if the current connection is the selected one, + * unmute it as default - otherwise mute it + */ + mute = AMP_IN_MUTE(idx); + for (item = 0; item < imux->num_items; item++) { + if (imux->items[item].index == idx) { + if (spec->cur_mux[c] == item) + mute = AMP_IN_UNMUTE(idx); + break; + } + } + /* check if we have a selector or mixer + * we could check for the widget type instead, but + * just check for Amp-In presence (in case of mixer + * without amp-in there is something wrong, this + * function shouldn't be used or capsrc nid is wrong) + */ + if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + mute); + else if (mute != AMP_IN_MUTE(idx)) + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_CONNECT_SEL, + idx); + } + } +} + +/* add mic boosts if needed */ +static int alc_auto_add_mic_boost(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i, err; + int type_idx = 0; + hda_nid_t nid; + const char *prev_label = NULL; + + for (i = 0; i < cfg->num_inputs; i++) { + if (cfg->inputs[i].type > AUTO_PIN_MIC) + break; + nid = cfg->inputs[i].pin; + if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) { + const char *label; + char boost_label[32]; + + label = hda_get_autocfg_input_label(codec, cfg, i); + if (prev_label && !strcmp(label, prev_label)) + type_idx++; + else + type_idx = 0; + prev_label = label; + + snprintf(boost_label, sizeof(boost_label), + "%s Boost Volume", label); + err = add_control(spec, ALC_CTL_WIDGET_VOL, + boost_label, type_idx, + HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); + if (err < 0) + return err; + } + } + return 0; +} + +/* almost identical with ALC880 parser... */ +static int alc882_parse_auto_config(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + static const hda_nid_t alc882_ignore[] = { 0x1d, 0 }; + int err; + + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, + alc882_ignore); + if (err < 0) + return err; + if (!spec->autocfg.line_outs) + return 0; /* can't find valid BIOS pin config */ + + err = alc880_auto_fill_dac_nids(spec, &spec->autocfg); + if (err < 0) + return err; + err = alc_auto_add_multi_channel_mode(codec); + if (err < 0) + return err; + err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0], + "Headphone"); + if (err < 0) + return err; + err = alc880_auto_create_extra_out(spec, + spec->autocfg.speaker_pins[0], + "Speaker"); + if (err < 0) + return err; + err = alc882_auto_create_input_ctls(codec, &spec->autocfg); + if (err < 0) + return err; + + spec->multiout.max_channels = spec->multiout.num_dacs * 2; + + alc_auto_parse_digital(codec); + + if (spec->kctls.list) + add_mixer(spec, spec->kctls.list); + + add_verb(spec, alc883_auto_init_verbs); + /* if ADC 0x07 is available, initialize it, too */ + if (get_wcaps_type(get_wcaps(codec, 0x07)) == AC_WID_AUD_IN) + add_verb(spec, alc882_adc1_init_verbs); + + spec->num_mux_defs = 1; + spec->input_mux = &spec->private_imux[0]; + + alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0); + + err = alc_auto_add_mic_boost(codec); + if (err < 0) + return err; + + return 1; /* config found */ +} + +/* additional initialization for auto-configuration model */ +static void alc882_auto_init(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + alc882_auto_init_multi_out(codec); + alc882_auto_init_hp_out(codec); + alc882_auto_init_analog_input(codec); + alc882_auto_init_input_src(codec); + alc_auto_init_digital(codec); + if (spec->unsol_event) + alc_inithook(codec); +} + +static int patch_alc882(struct hda_codec *codec) +{ + struct alc_spec *spec; + int err, board_config; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; + + switch (codec->vendor_id) { + case 0x10ec0882: + case 0x10ec0885: + break; + default: + /* ALC883 and variants */ + alc_fix_pll_init(codec, 0x20, 0x0a, 10); + break; + } + + board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST, + alc882_models, + alc882_cfg_tbl); + + if (board_config < 0 || board_config >= ALC882_MODEL_LAST) + board_config = snd_hda_check_board_codec_sid_config(codec, + ALC882_MODEL_LAST, alc882_models, alc882_ssid_cfg_tbl); + + if (board_config < 0 || board_config >= ALC882_MODEL_LAST) { + printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); + board_config = ALC882_AUTO; + } + + if (board_config == ALC882_AUTO) { + alc_pick_fixup(codec, NULL, alc882_fixup_tbl, alc882_fixups); + alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + } + + alc_auto_parse_customize_define(codec); + + if (board_config == ALC882_AUTO) { + /* automatic parse from the BIOS config */ + err = alc882_parse_auto_config(codec); + if (err < 0) { + alc_free(codec); + return err; + } else if (!err) { + printk(KERN_INFO + "hda_codec: Cannot set up configuration " + "from BIOS. Using base mode...\n"); + board_config = ALC882_3ST_DIG; + } + } + + if (has_cdefine_beep(codec)) { + err = snd_hda_attach_beep_device(codec, 0x1); + if (err < 0) { + alc_free(codec); + return err; + } + } + + if (board_config != ALC882_AUTO) + setup_preset(codec, &alc882_presets[board_config]); + + spec->stream_analog_playback = &alc882_pcm_analog_playback; + spec->stream_analog_capture = &alc882_pcm_analog_capture; + /* FIXME: setup DAC5 */ + /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/ + spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture; + + spec->stream_digital_playback = &alc882_pcm_digital_playback; + spec->stream_digital_capture = &alc882_pcm_digital_capture; + + if (!spec->adc_nids && spec->input_mux) { + int i, j; + spec->num_adc_nids = 0; + for (i = 0; i < ARRAY_SIZE(alc882_adc_nids); i++) { + const struct hda_input_mux *imux = spec->input_mux; + hda_nid_t cap; + hda_nid_t items[16]; + hda_nid_t nid = alc882_adc_nids[i]; + unsigned int wcap = get_wcaps(codec, nid); + /* get type */ + wcap = get_wcaps_type(wcap); + if (wcap != AC_WID_AUD_IN) + continue; + spec->private_adc_nids[spec->num_adc_nids] = nid; + err = snd_hda_get_connections(codec, nid, &cap, 1); + if (err < 0) + continue; + err = snd_hda_get_connections(codec, cap, items, + ARRAY_SIZE(items)); + if (err < 0) + continue; + for (j = 0; j < imux->num_items; j++) + if (imux->items[j].index >= err) + break; + if (j < imux->num_items) + continue; + spec->private_capsrc_nids[spec->num_adc_nids] = cap; + spec->num_adc_nids++; + } + spec->adc_nids = spec->private_adc_nids; + spec->capsrc_nids = spec->private_capsrc_nids; + } + + set_capture_mixer(codec); + + if (has_cdefine_beep(codec)) + set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); + + alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + + spec->vmaster_nid = 0x0c; + + codec->patch_ops = alc_patch_ops; + if (board_config == ALC882_AUTO) + spec->init_hook = alc882_auto_init; + + alc_init_jacks(codec); +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc882_loopbacks; +#endif + + return 0; +} + + +/* + * ALC262 support + */ + +#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID +#define ALC262_DIGIN_NID ALC880_DIGIN_NID + +#define alc262_dac_nids alc260_dac_nids +#define alc262_adc_nids alc882_adc_nids +#define alc262_adc_nids_alt alc882_adc_nids_alt +#define alc262_capsrc_nids alc882_capsrc_nids +#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt + +#define alc262_modes alc260_modes +#define alc262_capture_source alc882_capture_source + +static const hda_nid_t alc262_dmic_adc_nids[1] = { + /* ADC0 */ + 0x09 +}; + +static const hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 }; + +static const struct snd_kcontrol_new alc262_base_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), + { } /* end */ +}; + +/* update HP, line and mono-out pins according to the master switch */ +#define alc262_hp_master_update alc260_hp_master_update + +static void alc262_hp_bpc_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x16; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; +} + +static void alc262_hp_wildwest_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x16; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; +} + +#define alc262_hp_master_sw_get alc260_hp_master_sw_get +#define alc262_hp_master_sw_put alc260_hp_master_sw_put + +#define ALC262_HP_MASTER_SWITCH \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = "Master Playback Switch", \ + .info = snd_ctl_boolean_mono_info, \ + .get = alc262_hp_master_sw_get, \ + .put = alc262_hp_master_sw_put, \ + }, \ + { \ + .iface = NID_MAPPING, \ + .name = "Master Playback Switch", \ + .private_value = 0x15 | (0x16 << 8) | (0x1b << 16), \ + } + + +static const struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { + ALC262_HP_MASTER_SWITCH, + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0, + HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0, + HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT), + HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = { + ALC262_HP_MASTER_SWITCH, + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0, + HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0, + HDA_OUTPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x1a, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = { + HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Rear Mic Boost Volume", 0x18, 0, HDA_INPUT), + { } /* end */ +}; + +/* mute/unmute internal speaker according to the hp jack and mute state */ +static void alc262_hp_t5735_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; +} + +static const struct snd_kcontrol_new alc262_hp_t5735_mixer[] = { + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + { } /* end */ +}; + +static const struct hda_verb alc262_hp_t5735_verbs[] = { + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + { } +}; + +static const struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = { + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT), + { } /* end */ +}; + +static const struct hda_verb alc262_hp_rp5700_verbs[] = { + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))}, + {} +}; + +static const struct hda_input_mux alc262_hp_rp5700_capture_source = { + .num_items = 1, + .items = { + { "Line", 0x1 }, + }, +}; + +/* bind hp and internal speaker mute (with plug check) as master switch */ +#define alc262_hippo_master_update alc262_hp_master_update +#define alc262_hippo_master_sw_get alc262_hp_master_sw_get +#define alc262_hippo_master_sw_put alc262_hp_master_sw_put + +#define ALC262_HIPPO_MASTER_SWITCH \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = "Master Playback Switch", \ + .info = snd_ctl_boolean_mono_info, \ + .get = alc262_hippo_master_sw_get, \ + .put = alc262_hippo_master_sw_put, \ + }, \ + { \ + .iface = NID_MAPPING, \ + .name = "Master Playback Switch", \ + .subdevice = SUBDEV_HP(0) | (SUBDEV_LINE(0) << 8) | \ + (SUBDEV_SPEAKER(0) << 16), \ + } + +static const struct snd_kcontrol_new alc262_hippo_mixer[] = { + ALC262_HIPPO_MASTER_SWITCH, + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc262_hippo1_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + ALC262_HIPPO_MASTER_SWITCH, + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + { } /* end */ +}; + +/* mute/unmute internal speaker according to the hp jack and mute state */ +static void alc262_hippo_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static void alc262_hippo1_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + + +static const struct snd_kcontrol_new alc262_sony_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + ALC262_HIPPO_MASTER_SWITCH, + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc262_benq_t31_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + ALC262_HIPPO_MASTER_SWITCH, + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc262_tyan_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT), + HDA_CODEC_MUTE("Aux Playback Switch", 0x0b, 0x06, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + { } /* end */ +}; + +static const struct hda_verb alc262_tyan_verbs[] = { + /* Headphone automute */ + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* P11 AUX_IN, white 4-pin connector */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0xe1}, + {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x93}, + {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x19}, + + {} +}; + +/* unsolicited event for HP jack sensing */ +static void alc262_tyan_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + + +#define alc262_capture_mixer alc882_capture_mixer +#define alc262_capture_alt_mixer alc882_capture_alt_mixer + +/* + * generic initialization of ADC, input mixers and output mixers + */ +static const struct hda_verb alc262_init_verbs[] = { + /* + * Unmute ADC0-2 and set the default input to mic-in + */ + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + * Note: PASD motherboards uses the Line In 2 as the input for + * front panel mic (mic 2) + */ + /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + + /* + * Set up output mixers (0x0c - 0x0e) + */ + /* set vol=0 to output mixers */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* set up input amps for analog loopback */ + /* Amp Indices: DAC = 0, mixer = 1 */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + + /* FIXME: use matrix-type input source selection */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ + /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, + /* Input mixer2 */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, + /* Input mixer3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, + + { } +}; + +static const struct hda_verb alc262_eapd_verbs[] = { + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, + {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, + { } +}; + +static const struct hda_verb alc262_hippo1_unsol_verbs[] = { + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {} +}; + +static const struct hda_verb alc262_sony_unsol_verbs[] = { + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic + + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {} +}; + +static const struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = { + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + +static const struct hda_verb alc262_toshiba_s06_verbs[] = { + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x22, AC_VERB_SET_CONNECT_SEL, 0x09}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; + +static void alc262_toshiba_s06_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x12; + spec->int_mic.mux_idx = 9; + spec->auto_mic = 1; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; +} + +/* + * nec model + * 0x15 = headphone + * 0x16 = internal speaker + * 0x18 = external mic + */ + +static const struct snd_kcontrol_new alc262_nec_mixer[] = { + HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + { } /* end */ +}; + +static const struct hda_verb alc262_nec_verbs[] = { + /* Unmute Speaker */ + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Headphone */ + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + + /* External mic to headphone */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + /* External mic to speaker */ + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {} +}; + +/* + * fujitsu model + * 0x14 = headphone/spdif-out, 0x15 = internal speaker, + * 0x1b = port replicator headphone out + */ + +#define ALC_HP_EVENT ALC880_HP_EVENT + +static const struct hda_verb alc262_fujitsu_unsol_verbs[] = { + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {} +}; + +static const struct hda_verb alc262_lenovo_3000_unsol_verbs[] = { + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {} +}; + +static const struct hda_verb alc262_lenovo_3000_init_verbs[] = { + /* Front Mic pin: input vref at 50% */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {} +}; + +static const struct hda_input_mux alc262_fujitsu_capture_source = { + .num_items = 3, + .items = { + { "Mic", 0x0 }, + { "Internal Mic", 0x1 }, + { "CD", 0x4 }, + }, +}; + +static const struct hda_input_mux alc262_HP_capture_source = { + .num_items = 5, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x1 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + { "AUX IN", 0x6 }, + }, +}; + +static const struct hda_input_mux alc262_HP_D7000_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x2 }, + { "Line", 0x1 }, + { "CD", 0x4 }, + }, +}; + +static void alc262_fujitsu_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.hp_pins[1] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +/* bind volumes of both NID 0x0c and 0x0d */ +static const struct hda_bind_ctls alc262_fujitsu_bind_master_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT), + 0 + }, +}; + +static const struct snd_kcontrol_new alc262_fujitsu_mixer[] = { + HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .subdevice = HDA_SUBDEV_NID_FLAG | 0x14, + .info = snd_ctl_boolean_mono_info, + .get = alc262_hp_master_sw_get, + .put = alc262_hp_master_sw_put, + }, + { + .iface = NID_MAPPING, + .name = "Master Playback Switch", + .private_value = 0x1b, + }, + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static void alc262_lenovo_3000_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x16; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static const struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = { + HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b, + .info = snd_ctl_boolean_mono_info, + .get = alc262_hp_master_sw_get, + .put = alc262_hp_master_sw_put, + }, + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = { + HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol), + ALC262_HIPPO_MASTER_SWITCH, + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + { } /* end */ +}; + +/* additional init verbs for Benq laptops */ +static const struct hda_verb alc262_EAPD_verbs[] = { + {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, + {0x20, AC_VERB_SET_PROC_COEF, 0x3070}, + {} +}; + +static const struct hda_verb alc262_benq_t31_EAPD_verbs[] = { + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + + {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, + {0x20, AC_VERB_SET_PROC_COEF, 0x3050}, + {} +}; + +/* Samsung Q1 Ultra Vista model setup */ +static const struct snd_kcontrol_new alc262_ultra_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Mic Boost Volume", 0x15, 0, HDA_INPUT), + { } /* end */ +}; + +static const struct hda_verb alc262_ultra_verbs[] = { + /* output mixer */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* speaker */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* HP */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + /* internal mic */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* ADC, choose mic */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)}, + {} +}; + +/* mute/unmute internal speaker according to the hp jack and mute state */ +static void alc262_ultra_automute(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + unsigned int mute; + + mute = 0; + /* auto-mute only when HP is used as HP */ + if (!spec->cur_mux[0]) { + spec->jack_present = snd_hda_jack_detect(codec, 0x15); + if (spec->jack_present) + mute = HDA_AMP_MUTE; + } + /* mute/unmute internal speaker */ + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); + /* mute/unmute HP */ + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE); +} + +/* unsolicited event for HP jack sensing */ +static void alc262_ultra_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) != ALC880_HP_EVENT) + return; + alc262_ultra_automute(codec); +} + +static const struct hda_input_mux alc262_ultra_capture_source = { + .num_items = 2, + .items = { + { "Mic", 0x1 }, + { "Headphone", 0x7 }, + }, +}; + +static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + int ret; + + ret = alc_mux_enum_put(kcontrol, ucontrol); + if (!ret) + return 0; + /* reprogram the HP pin as mic or HP according to the input source */ + snd_hda_codec_write_cache(codec, 0x15, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + spec->cur_mux[0] ? PIN_VREF80 : PIN_HP); + alc262_ultra_automute(codec); /* mute/unmute HP */ + return ret; +} + +static const struct snd_kcontrol_new alc262_ultra_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc262_ultra_mux_enum_put, + }, + { + .iface = NID_MAPPING, + .name = "Capture Source", + .private_value = 0x15, + }, + { } /* end */ +}; + +/* We use two mixers depending on the output pin; 0x16 is a mono output + * and thus it's bound with a different mixer. + * This function returns which mixer amp should be used. + */ +static int alc262_check_volbit(hda_nid_t nid) +{ + if (!nid) + return 0; + else if (nid == 0x16) + return 2; + else + return 1; +} + +static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid, + const char *pfx, int *vbits, int idx) +{ + unsigned long val; + int vbit; + + vbit = alc262_check_volbit(nid); + if (!vbit) + return 0; + if (*vbits & vbit) /* a volume control for this mixer already there */ + return 0; + *vbits |= vbit; + if (vbit == 2) + val = HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT); + else + val = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT); + return __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, idx, val); +} + +static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid, + const char *pfx, int idx) +{ + unsigned long val; + + if (!nid) + return 0; + if (nid == 0x16) + val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT); + else + val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); + return __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, idx, val); +} + +/* add playback controls from the parsed DAC table */ +static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, + const struct auto_pin_cfg *cfg) +{ + const char *pfx; + int vbits; + int i, err; + + spec->multiout.num_dacs = 1; /* only use one dac */ + spec->multiout.dac_nids = spec->private_dac_nids; + spec->private_dac_nids[0] = 2; + + pfx = alc_get_line_out_pfx(spec, true); + if (!pfx) + pfx = "Front"; + for (i = 0; i < 2; i++) { + err = alc262_add_out_sw_ctl(spec, cfg->line_out_pins[i], pfx, i); + if (err < 0) + return err; + if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { + err = alc262_add_out_sw_ctl(spec, cfg->speaker_pins[i], + "Speaker", i); + if (err < 0) + return err; + } + if (cfg->line_out_type != AUTO_PIN_HP_OUT) { + err = alc262_add_out_sw_ctl(spec, cfg->hp_pins[i], + "Headphone", i); + if (err < 0) + return err; + } + } + + vbits = alc262_check_volbit(cfg->line_out_pins[0]) | + alc262_check_volbit(cfg->speaker_pins[0]) | + alc262_check_volbit(cfg->hp_pins[0]); + if (vbits == 1 || vbits == 2) + pfx = "Master"; /* only one mixer is used */ + vbits = 0; + for (i = 0; i < 2; i++) { + err = alc262_add_out_vol_ctl(spec, cfg->line_out_pins[i], pfx, + &vbits, i); + if (err < 0) + return err; + if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { + err = alc262_add_out_vol_ctl(spec, cfg->speaker_pins[i], + "Speaker", &vbits, i); + if (err < 0) + return err; + } + if (cfg->line_out_type != AUTO_PIN_HP_OUT) { + err = alc262_add_out_vol_ctl(spec, cfg->hp_pins[i], + "Headphone", &vbits, i); + if (err < 0) + return err; + } + } + return 0; +} + +#define alc262_auto_create_input_ctls \ + alc882_auto_create_input_ctls + +/* + * generic initialization of ADC, input mixers and output mixers + */ +static const struct hda_verb alc262_volume_init_verbs[] = { + /* + * Unmute ADC0-2 and set the default input to mic-in + */ + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + * Note: PASD motherboards uses the Line In 2 as the input for + * front panel mic (mic 2) + */ + /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + + /* + * Set up output mixers (0x0c - 0x0f) + */ + /* set vol=0 to output mixers */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* set up input amps for analog loopback */ + /* Amp Indices: DAC = 0, mixer = 1 */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* FIXME: use matrix-type input source selection */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ + /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, + /* Input mixer2 */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, + /* Input mixer3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, + + { } +}; + +static const struct hda_verb alc262_HP_BPC_init_verbs[] = { + /* + * Unmute ADC0-2 and set the default input to mic-in + */ + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + * Note: PASD motherboards uses the Line In 2 as the input for + * front panel mic (mic 2) + */ + /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, + + /* + * Set up output mixers (0x0c - 0x0e) + */ + /* set vol=0 to output mixers */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* set up input amps for analog loopback */ + /* Amp Indices: DAC = 0, mixer = 1 */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, + {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, + + + /* FIXME: use matrix-type input source selection */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 0b, 12 */ + /* Input mixer1: only unmute Mic */ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))}, + /* Input mixer2 */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))}, + /* Input mixer3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))}, + + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + + { } +}; + +static const struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = { + /* + * Unmute ADC0-2 and set the default input to mic-in + */ + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + * Note: PASD motherboards uses the Line In 2 as the input for front + * panel mic (mic 2) + */ + /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, + /* + * Set up output mixers (0x0c - 0x0e) + */ + /* set vol=0 to output mixers */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* set up input amps for analog loopback */ + /* Amp Indices: DAC = 0, mixer = 1 */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */ + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */ + + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + + /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */ + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, + {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, + + /* FIXME: use matrix-type input source selection */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ + /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/ + /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/ + /* Input mixer2 */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, + /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, + /* Input mixer3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, + /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, + + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + + { } +}; + +static const struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = { + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Front Speaker */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x01}, + + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* MIC jack */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */ + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) }, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) }, + + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP jack */ + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; + +/* + * Pin config fixes + */ +enum { + PINFIX_FSC_H270, + PINFIX_HP_Z200, +}; + +static const struct alc_fixup alc262_fixups[] = { + [PINFIX_FSC_H270] = { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { + { 0x14, 0x99130110 }, /* speaker */ + { 0x15, 0x0221142f }, /* front HP */ + { 0x1b, 0x0121141f }, /* rear HP */ + { } + } + }, + [PINFIX_HP_Z200] = { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { + { 0x16, 0x99130120 }, /* internal speaker */ + { } + } + }, +}; + +static const struct snd_pci_quirk alc262_fixup_tbl[] = { + SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", PINFIX_HP_Z200), + SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", PINFIX_FSC_H270), + {} +}; + + +#ifdef CONFIG_SND_HDA_POWER_SAVE +#define alc262_loopbacks alc880_loopbacks +#endif + +/* pcm configuration: identical with ALC880 */ +#define alc262_pcm_analog_playback alc880_pcm_analog_playback +#define alc262_pcm_analog_capture alc880_pcm_analog_capture +#define alc262_pcm_digital_playback alc880_pcm_digital_playback +#define alc262_pcm_digital_capture alc880_pcm_digital_capture + +/* + * BIOS auto configuration + */ +static int alc262_parse_auto_config(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int err; + static const hda_nid_t alc262_ignore[] = { 0x1d, 0 }; + + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, + alc262_ignore); + if (err < 0) + return err; + if (!spec->autocfg.line_outs) { + if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) { + spec->multiout.max_channels = 2; + spec->no_analog = 1; + goto dig_only; + } + return 0; /* can't find valid BIOS pin config */ + } + err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + err = alc262_auto_create_input_ctls(codec, &spec->autocfg); + if (err < 0) + return err; + + spec->multiout.max_channels = spec->multiout.num_dacs * 2; + + dig_only: + alc_auto_parse_digital(codec); + + if (spec->kctls.list) + add_mixer(spec, spec->kctls.list); + + add_verb(spec, alc262_volume_init_verbs); + spec->num_mux_defs = 1; + spec->input_mux = &spec->private_imux[0]; + + err = alc_auto_add_mic_boost(codec); + if (err < 0) + return err; + + alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0); + + return 1; +} + +#define alc262_auto_init_multi_out alc882_auto_init_multi_out +#define alc262_auto_init_hp_out alc882_auto_init_hp_out +#define alc262_auto_init_analog_input alc882_auto_init_analog_input +#define alc262_auto_init_input_src alc882_auto_init_input_src + + +/* init callback for auto-configuration model -- overriding the default init */ +static void alc262_auto_init(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + alc262_auto_init_multi_out(codec); + alc262_auto_init_hp_out(codec); + alc262_auto_init_analog_input(codec); + alc262_auto_init_input_src(codec); + alc_auto_init_digital(codec); + if (spec->unsol_event) + alc_inithook(codec); +} + +/* + * configuration and preset + */ +static const char * const alc262_models[ALC262_MODEL_LAST] = { + [ALC262_BASIC] = "basic", + [ALC262_HIPPO] = "hippo", + [ALC262_HIPPO_1] = "hippo_1", + [ALC262_FUJITSU] = "fujitsu", + [ALC262_HP_BPC] = "hp-bpc", + [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000", + [ALC262_HP_TC_T5735] = "hp-tc-t5735", + [ALC262_HP_RP5700] = "hp-rp5700", + [ALC262_BENQ_ED8] = "benq", + [ALC262_BENQ_T31] = "benq-t31", + [ALC262_SONY_ASSAMD] = "sony-assamd", + [ALC262_TOSHIBA_S06] = "toshiba-s06", + [ALC262_TOSHIBA_RX1] = "toshiba-rx1", + [ALC262_ULTRA] = "ultra", + [ALC262_LENOVO_3000] = "lenovo-3000", + [ALC262_NEC] = "nec", + [ALC262_TYAN] = "tyan", + [ALC262_AUTO] = "auto", +}; + +static const struct snd_pci_quirk alc262_cfg_tbl[] = { + SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO), + SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC), + SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1200, "HP xw series", + ALC262_HP_BPC), + SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1300, "HP xw series", + ALC262_HP_BPC), + SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1500, "HP z series", + ALC262_HP_BPC), + SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", + ALC262_AUTO), + SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1700, "HP xw series", + ALC262_HP_BPC), + SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL), + SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF), + SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL), + SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF), + SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL), + SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF), + SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL), + SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF), + SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC), + SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC), + SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC), + SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735", + ALC262_HP_TC_T5735), + SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700), + SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD), + SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO), + SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD), + SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */ + SND_PCI_QUIRK(0x104d, 0x9025, "Sony VAIO Z21MN", ALC262_TOSHIBA_S06), + SND_PCI_QUIRK(0x104d, 0x9035, "Sony VAIO VGN-FW170J", ALC262_AUTO), + SND_PCI_QUIRK(0x104d, 0x9047, "Sony VAIO Type G", ALC262_AUTO), +#if 0 /* disable the quirk since model=auto works better in recent versions */ + SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO", + ALC262_SONY_ASSAMD), +#endif + SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1", + ALC262_TOSHIBA_RX1), + SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06), + SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU), + SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU), + SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_TYAN), + SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc032, "Samsung Q1", + ALC262_ULTRA), + SND_PCI_QUIRK(0x144d, 0xc510, "Samsung Q45", ALC262_HIPPO), + SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000), + SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8), + SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31), + SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1), + {} +}; + +static const struct alc_config_preset alc262_presets[] = { + [ALC262_BASIC] = { + .mixers = { alc262_base_mixer }, + .init_verbs = { alc262_init_verbs }, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_capture_source, + }, + [ALC262_HIPPO] = { + .mixers = { alc262_hippo_mixer }, + .init_verbs = { alc262_init_verbs, alc_hp15_unsol_verbs}, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x03, + .dig_out_nid = ALC262_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_hippo_setup, + .init_hook = alc_inithook, + }, + [ALC262_HIPPO_1] = { + .mixers = { alc262_hippo1_mixer }, + .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs}, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x02, + .dig_out_nid = ALC262_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_hippo1_setup, + .init_hook = alc_inithook, + }, + [ALC262_FUJITSU] = { + .mixers = { alc262_fujitsu_mixer }, + .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs, + alc262_fujitsu_unsol_verbs }, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x03, + .dig_out_nid = ALC262_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_fujitsu_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_fujitsu_setup, + .init_hook = alc_inithook, + }, + [ALC262_HP_BPC] = { + .mixers = { alc262_HP_BPC_mixer }, + .init_verbs = { alc262_HP_BPC_init_verbs }, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_HP_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_hp_bpc_setup, + .init_hook = alc_inithook, + }, + [ALC262_HP_BPC_D7000_WF] = { + .mixers = { alc262_HP_BPC_WildWest_mixer }, + .init_verbs = { alc262_HP_BPC_WildWest_init_verbs }, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_HP_D7000_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_hp_wildwest_setup, + .init_hook = alc_inithook, + }, + [ALC262_HP_BPC_D7000_WL] = { + .mixers = { alc262_HP_BPC_WildWest_mixer, + alc262_HP_BPC_WildWest_option_mixer }, + .init_verbs = { alc262_HP_BPC_WildWest_init_verbs }, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_HP_D7000_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_hp_wildwest_setup, + .init_hook = alc_inithook, + }, + [ALC262_HP_TC_T5735] = { + .mixers = { alc262_hp_t5735_mixer }, + .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs }, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_hp_t5735_setup, + .init_hook = alc_inithook, + }, + [ALC262_HP_RP5700] = { + .mixers = { alc262_hp_rp5700_mixer }, + .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs }, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_hp_rp5700_capture_source, + }, + [ALC262_BENQ_ED8] = { + .mixers = { alc262_base_mixer }, + .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs }, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_capture_source, + }, + [ALC262_SONY_ASSAMD] = { + .mixers = { alc262_sony_mixer }, + .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs}, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x02, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_hippo_setup, + .init_hook = alc_inithook, + }, + [ALC262_BENQ_T31] = { + .mixers = { alc262_benq_t31_mixer }, + .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs, + alc_hp15_unsol_verbs }, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_hippo_setup, + .init_hook = alc_inithook, + }, + [ALC262_ULTRA] = { + .mixers = { alc262_ultra_mixer }, + .cap_mixer = alc262_ultra_capture_mixer, + .init_verbs = { alc262_ultra_verbs }, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_ultra_capture_source, + .adc_nids = alc262_adc_nids, /* ADC0 */ + .capsrc_nids = alc262_capsrc_nids, + .num_adc_nids = 1, /* single ADC */ + .unsol_event = alc262_ultra_unsol_event, + .init_hook = alc262_ultra_automute, + }, + [ALC262_LENOVO_3000] = { + .mixers = { alc262_lenovo_3000_mixer }, + .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs, + alc262_lenovo_3000_unsol_verbs, + alc262_lenovo_3000_init_verbs }, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x03, + .dig_out_nid = ALC262_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_fujitsu_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_lenovo_3000_setup, + .init_hook = alc_inithook, + }, + [ALC262_NEC] = { + .mixers = { alc262_nec_mixer }, + .init_verbs = { alc262_nec_verbs }, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_capture_source, + }, + [ALC262_TOSHIBA_S06] = { + .mixers = { alc262_toshiba_s06_mixer }, + .init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs, + alc262_eapd_verbs }, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .capsrc_nids = alc262_dmic_capsrc_nids, + .dac_nids = alc262_dac_nids, + .adc_nids = alc262_dmic_adc_nids, /* ADC0 */ + .num_adc_nids = 1, /* single ADC */ + .dig_out_nid = ALC262_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_toshiba_s06_setup, + .init_hook = alc_inithook, + }, + [ALC262_TOSHIBA_RX1] = { + .mixers = { alc262_toshiba_rx1_mixer }, + .init_verbs = { alc262_init_verbs, alc262_toshiba_rx1_unsol_verbs }, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_hippo_setup, + .init_hook = alc_inithook, + }, + [ALC262_TYAN] = { + .mixers = { alc262_tyan_mixer }, + .init_verbs = { alc262_init_verbs, alc262_tyan_verbs}, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x02, + .dig_out_nid = ALC262_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_tyan_setup, + .init_hook = alc_hp_automute, + }, +}; + +static int patch_alc262(struct hda_codec *codec) +{ + struct alc_spec *spec; + int board_config; + int err; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; +#if 0 + /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is + * under-run + */ + { + int tmp; + snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7); + tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0); + snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7); + snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80); + } +#endif + alc_auto_parse_customize_define(codec); + + alc_fix_pll_init(codec, 0x20, 0x0a, 10); + + board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST, + alc262_models, + alc262_cfg_tbl); + + if (board_config < 0) { + printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); + board_config = ALC262_AUTO; + } + + if (board_config == ALC262_AUTO) { + alc_pick_fixup(codec, NULL, alc262_fixup_tbl, alc262_fixups); + alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + } + + if (board_config == ALC262_AUTO) { + /* automatic parse from the BIOS config */ + err = alc262_parse_auto_config(codec); + if (err < 0) { + alc_free(codec); + return err; + } else if (!err) { + printk(KERN_INFO + "hda_codec: Cannot set up configuration " + "from BIOS. Using base mode...\n"); + board_config = ALC262_BASIC; + } + } + + if (!spec->no_analog && has_cdefine_beep(codec)) { + err = snd_hda_attach_beep_device(codec, 0x1); + if (err < 0) { + alc_free(codec); + return err; + } + } + + if (board_config != ALC262_AUTO) + setup_preset(codec, &alc262_presets[board_config]); + + spec->stream_analog_playback = &alc262_pcm_analog_playback; + spec->stream_analog_capture = &alc262_pcm_analog_capture; + + spec->stream_digital_playback = &alc262_pcm_digital_playback; + spec->stream_digital_capture = &alc262_pcm_digital_capture; + + if (!spec->adc_nids && spec->input_mux) { + int i; + /* check whether the digital-mic has to be supported */ + for (i = 0; i < spec->input_mux->num_items; i++) { + if (spec->input_mux->items[i].index >= 9) + break; + } + if (i < spec->input_mux->num_items) { + /* use only ADC0 */ + spec->adc_nids = alc262_dmic_adc_nids; + spec->num_adc_nids = 1; + spec->capsrc_nids = alc262_dmic_capsrc_nids; + } else { + /* all analog inputs */ + /* check whether NID 0x07 is valid */ + unsigned int wcap = get_wcaps(codec, 0x07); + + /* get type */ + wcap = get_wcaps_type(wcap); + if (wcap != AC_WID_AUD_IN) { + spec->adc_nids = alc262_adc_nids_alt; + spec->num_adc_nids = + ARRAY_SIZE(alc262_adc_nids_alt); + spec->capsrc_nids = alc262_capsrc_nids_alt; + } else { + spec->adc_nids = alc262_adc_nids; + spec->num_adc_nids = + ARRAY_SIZE(alc262_adc_nids); + spec->capsrc_nids = alc262_capsrc_nids; + } + } + } + if (!spec->cap_mixer && !spec->no_analog) + set_capture_mixer(codec); + if (!spec->no_analog && has_cdefine_beep(codec)) + set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); + + alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + + spec->vmaster_nid = 0x0c; + + codec->patch_ops = alc_patch_ops; + if (board_config == ALC262_AUTO) + spec->init_hook = alc262_auto_init; + spec->shutup = alc_eapd_shutup; + + alc_init_jacks(codec); +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc262_loopbacks; +#endif + + return 0; +} + +/* + * ALC268 channel source setting (2 channel) + */ +#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID +#define alc268_modes alc260_modes + +static const hda_nid_t alc268_dac_nids[2] = { + /* front, hp */ + 0x02, 0x03 +}; + +static const hda_nid_t alc268_adc_nids[2] = { + /* ADC0-1 */ + 0x08, 0x07 +}; + +static const hda_nid_t alc268_adc_nids_alt[1] = { + /* ADC0 */ + 0x08 +}; + +static const hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 }; + +static const struct snd_kcontrol_new alc268_base_mixer[] = { + /* output mixer control */ + HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT), + { } +}; + +static const struct snd_kcontrol_new alc268_toshiba_mixer[] = { + /* output mixer control */ + HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT), + ALC262_HIPPO_MASTER_SWITCH, + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT), + { } +}; + +/* bind Beep switches of both NID 0x0f and 0x10 */ +static const struct hda_bind_ctls alc268_bind_beep_sw = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT), + HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT), + 0 + }, +}; + +static const struct snd_kcontrol_new alc268_beep_mixer[] = { + HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT), + HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw), + { } +}; + +static const struct hda_verb alc268_eapd_verbs[] = { + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, + {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, + { } +}; + +/* Toshiba specific */ +static const struct hda_verb alc268_toshiba_verbs[] = { + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + { } /* end */ +}; + +/* Acer specific */ +/* bind volumes of both NID 0x02 and 0x03 */ +static const struct hda_bind_ctls alc268_acer_bind_master_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT), + 0 + }, +}; + +static void alc268_acer_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +#define alc268_acer_master_sw_get alc262_hp_master_sw_get +#define alc268_acer_master_sw_put alc262_hp_master_sw_put + +static const struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = { + /* output mixer control */ + HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .subdevice = HDA_SUBDEV_NID_FLAG | 0x15, + .info = snd_ctl_boolean_mono_info, + .get = alc268_acer_master_sw_get, + .put = alc268_acer_master_sw_put, + }, + HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT), + { } +}; + +static const struct snd_kcontrol_new alc268_acer_mixer[] = { + /* output mixer control */ + HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .subdevice = HDA_SUBDEV_NID_FLAG | 0x14, + .info = snd_ctl_boolean_mono_info, + .get = alc268_acer_master_sw_get, + .put = alc268_acer_master_sw_put, + }, + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT), + { } +}; + +static const struct snd_kcontrol_new alc268_acer_dmic_mixer[] = { + /* output mixer control */ + HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .subdevice = HDA_SUBDEV_NID_FLAG | 0x14, + .info = snd_ctl_boolean_mono_info, + .get = alc268_acer_master_sw_get, + .put = alc268_acer_master_sw_put, + }, + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT), + { } +}; + +static const struct hda_verb alc268_acer_aspire_one_verbs[] = { + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x23, AC_VERB_SET_CONNECT_SEL, 0x06}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017}, + { } +}; + +static const struct hda_verb alc268_acer_verbs[] = { + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */ + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + { } +}; + +/* unsolicited event for HP jack sensing */ +#define alc268_toshiba_setup alc262_hippo_setup + +static void alc268_acer_lc_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x12; + spec->int_mic.mux_idx = 6; + spec->auto_mic = 1; +} + +static const struct snd_kcontrol_new alc268_dell_mixer[] = { + /* output mixer control */ + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + { } +}; + +static const struct hda_verb alc268_dell_verbs[] = { + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, + { } +}; + +/* mute/unmute internal speaker according to the hp jack and mute state */ +static void alc268_dell_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; +} + +static const struct snd_kcontrol_new alc267_quanta_il1_mixer[] = { + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + { } +}; + +static const struct hda_verb alc267_quanta_il1_verbs[] = { + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, + { } +}; + +static void alc267_quanta_il1_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; +} + +/* + * generic initialization of ADC, input mixers and output mixers + */ +static const struct hda_verb alc268_base_init_verbs[] = { + /* Unmute DAC0-1 and set vol = 0 */ + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* + * Set up output mixers (0x0c - 0x0e) + */ + /* set vol=0 to output mixers */ + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00}, + + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + + /* set PCBEEP vol = 0, mute connections */ + {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + + /* Unmute Selector 23h,24h and set the default input to mic-in */ + + {0x23, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x24, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + { } +}; + +/* + * generic initialization of ADC, input mixers and output mixers + */ +static const struct hda_verb alc268_volume_init_verbs[] = { + /* set output DAC */ + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + + /* set PCBEEP vol = 0, mute connections */ + {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + + { } +}; + +static const struct snd_kcontrol_new alc268_capture_nosrc_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc268_capture_alt_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT), + _DEFINE_CAPSRC(1), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc268_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT), + _DEFINE_CAPSRC(2), + { } /* end */ +}; + +static const struct hda_input_mux alc268_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x1 }, + { "Line", 0x2 }, + { "CD", 0x3 }, + }, +}; + +static const struct hda_input_mux alc268_acer_capture_source = { + .num_items = 3, + .items = { + { "Mic", 0x0 }, + { "Internal Mic", 0x1 }, + { "Line", 0x2 }, + }, +}; + +static const struct hda_input_mux alc268_acer_dmic_capture_source = { + .num_items = 3, + .items = { + { "Mic", 0x0 }, + { "Internal Mic", 0x6 }, + { "Line", 0x2 }, + }, +}; + +#ifdef CONFIG_SND_DEBUG +static const struct snd_kcontrol_new alc268_test_mixer[] = { + /* Volume widgets */ + HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT), + HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT), + HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT), + HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT), + HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT), + HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT), + HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT), + HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT), + HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT), + /* The below appears problematic on some hardwares */ + /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/ + HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT), + HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT), + + /* Modes for retasking pin widgets */ + ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT), + ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT), + ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT), + ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT), + + /* Controls for GPIO pins, assuming they are configured as outputs */ + ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01), + ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02), + ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04), + ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08), + + /* Switches to allow the digital SPDIF output pin to be enabled. + * The ALC268 does not have an SPDIF input. + */ + ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01), + + /* A switch allowing EAPD to be enabled. Some laptops seem to use + * this output to turn on an external amplifier. + */ + ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02), + ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02), + + { } /* end */ +}; +#endif + +/* create input playback/capture controls for the given pin */ +static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid, + const char *ctlname, int idx) +{ + hda_nid_t dac; + int err; + + switch (nid) { + case 0x14: + case 0x16: + dac = 0x02; + break; + case 0x15: + case 0x1a: /* ALC259/269 only */ + case 0x1b: /* ALC259/269 only */ + case 0x21: /* ALC269vb has this pin, too */ + dac = 0x03; + break; + default: + snd_printd(KERN_WARNING "hda_codec: " + "ignoring pin 0x%x as unknown\n", nid); + return 0; + } + if (spec->multiout.dac_nids[0] != dac && + spec->multiout.dac_nids[1] != dac) { + err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, + HDA_COMPOSE_AMP_VAL(dac, 3, idx, + HDA_OUTPUT)); + if (err < 0) + return err; + spec->private_dac_nids[spec->multiout.num_dacs++] = dac; + } + + if (nid != 0x16) + err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, + HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT)); + else /* mono */ + err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, + HDA_COMPOSE_AMP_VAL(nid, 2, idx, HDA_OUTPUT)); + if (err < 0) + return err; + return 0; +} + +/* add playback controls from the parsed DAC table */ +static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec, + const struct auto_pin_cfg *cfg) +{ + hda_nid_t nid; + int err; + + spec->multiout.dac_nids = spec->private_dac_nids; + + nid = cfg->line_out_pins[0]; + if (nid) { + const char *name; + if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) + name = "Speaker"; + else + name = "Front"; + err = alc268_new_analog_output(spec, nid, name, 0); + if (err < 0) + return err; + } + + nid = cfg->speaker_pins[0]; + if (nid == 0x1d) { + err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, "Speaker", + HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); + if (err < 0) + return err; + } else if (nid) { + err = alc268_new_analog_output(spec, nid, "Speaker", 0); + if (err < 0) + return err; + } + nid = cfg->hp_pins[0]; + if (nid) { + err = alc268_new_analog_output(spec, nid, "Headphone", 0); + if (err < 0) + return err; + } + + nid = cfg->line_out_pins[1] | cfg->line_out_pins[2]; + if (nid == 0x16) { + err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, "Mono", + HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT)); + if (err < 0) + return err; + } + return 0; +} + +/* create playback/capture controls for input pins */ +static int alc268_auto_create_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) +{ + return alc_auto_create_input_ctls(codec, cfg, 0, 0x23, 0x24); +} + +static void alc268_auto_set_output_and_unmute(struct hda_codec *codec, + hda_nid_t nid, int pin_type) +{ + int idx; + + alc_set_pin_output(codec, nid, pin_type); + if (nid == 0x14 || nid == 0x16) + idx = 0; + else + idx = 1; + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx); +} + +static void alc268_auto_init_multi_out(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int i; + + for (i = 0; i < spec->autocfg.line_outs; i++) { + hda_nid_t nid = spec->autocfg.line_out_pins[i]; + int pin_type = get_pin_type(spec->autocfg.line_out_type); + alc268_auto_set_output_and_unmute(codec, nid, pin_type); + } +} + +static void alc268_auto_init_hp_out(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t pin; + int i; + + for (i = 0; i < spec->autocfg.hp_outs; i++) { + pin = spec->autocfg.hp_pins[i]; + alc268_auto_set_output_and_unmute(codec, pin, PIN_HP); + } + for (i = 0; i < spec->autocfg.speaker_outs; i++) { + pin = spec->autocfg.speaker_pins[i]; + alc268_auto_set_output_and_unmute(codec, pin, PIN_OUT); + } + if (spec->autocfg.mono_out_pin) + snd_hda_codec_write(codec, spec->autocfg.mono_out_pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); +} + +static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0]; + hda_nid_t hp_nid = spec->autocfg.hp_pins[0]; + hda_nid_t line_nid = spec->autocfg.line_out_pins[0]; + unsigned int dac_vol1, dac_vol2; + + if (line_nid == 0x1d || speaker_nid == 0x1d) { + snd_hda_codec_write(codec, speaker_nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + /* mute mixer inputs from 0x1d */ + snd_hda_codec_write(codec, 0x0f, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_UNMUTE(1)); + snd_hda_codec_write(codec, 0x10, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_UNMUTE(1)); + } else { + /* unmute mixer inputs from 0x1d */ + snd_hda_codec_write(codec, 0x0f, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)); + snd_hda_codec_write(codec, 0x10, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)); + } + + dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */ + if (line_nid == 0x14) + dac_vol2 = AMP_OUT_ZERO; + else if (line_nid == 0x15) + dac_vol1 = AMP_OUT_ZERO; + if (hp_nid == 0x14) + dac_vol2 = AMP_OUT_ZERO; + else if (hp_nid == 0x15) + dac_vol1 = AMP_OUT_ZERO; + if (line_nid != 0x16 || hp_nid != 0x16 || + spec->autocfg.line_out_pins[1] != 0x16 || + spec->autocfg.line_out_pins[2] != 0x16) + dac_vol1 = dac_vol2 = AMP_OUT_ZERO; + + snd_hda_codec_write(codec, 0x02, 0, + AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1); + snd_hda_codec_write(codec, 0x03, 0, + AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2); +} + +/* pcm configuration: identical with ALC880 */ +#define alc268_pcm_analog_playback alc880_pcm_analog_playback +#define alc268_pcm_analog_capture alc880_pcm_analog_capture +#define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture +#define alc268_pcm_digital_playback alc880_pcm_digital_playback + +/* + * BIOS auto configuration + */ +static int alc268_parse_auto_config(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int err; + static const hda_nid_t alc268_ignore[] = { 0 }; + + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, + alc268_ignore); + if (err < 0) + return err; + if (!spec->autocfg.line_outs) { + if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) { + spec->multiout.max_channels = 2; + spec->no_analog = 1; + goto dig_only; + } + return 0; /* can't find valid BIOS pin config */ + } + err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + err = alc268_auto_create_input_ctls(codec, &spec->autocfg); + if (err < 0) + return err; + + spec->multiout.max_channels = 2; + + dig_only: + /* digital only support output */ + alc_auto_parse_digital(codec); + if (spec->kctls.list) + add_mixer(spec, spec->kctls.list); + + if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d) + add_mixer(spec, alc268_beep_mixer); + + add_verb(spec, alc268_volume_init_verbs); + spec->num_mux_defs = 2; + spec->input_mux = &spec->private_imux[0]; + + err = alc_auto_add_mic_boost(codec); + if (err < 0) + return err; + + alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0); + + return 1; +} + +#define alc268_auto_init_analog_input alc882_auto_init_analog_input +#define alc268_auto_init_input_src alc882_auto_init_input_src + +/* init callback for auto-configuration model -- overriding the default init */ +static void alc268_auto_init(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + alc268_auto_init_multi_out(codec); + alc268_auto_init_hp_out(codec); + alc268_auto_init_mono_speaker_out(codec); + alc268_auto_init_analog_input(codec); + alc268_auto_init_input_src(codec); + alc_auto_init_digital(codec); + if (spec->unsol_event) + alc_inithook(codec); +} + +/* + * configuration and preset + */ +static const char * const alc268_models[ALC268_MODEL_LAST] = { + [ALC267_QUANTA_IL1] = "quanta-il1", + [ALC268_3ST] = "3stack", + [ALC268_TOSHIBA] = "toshiba", + [ALC268_ACER] = "acer", + [ALC268_ACER_DMIC] = "acer-dmic", + [ALC268_ACER_ASPIRE_ONE] = "acer-aspire", + [ALC268_DELL] = "dell", + [ALC268_ZEPTO] = "zepto", +#ifdef CONFIG_SND_DEBUG + [ALC268_TEST] = "test", +#endif + [ALC268_AUTO] = "auto", +}; + +static const struct snd_pci_quirk alc268_cfg_tbl[] = { + SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER), + SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER), + SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER), + SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER), + SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER), + SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One", + ALC268_ACER_ASPIRE_ONE), + SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL), + SND_PCI_QUIRK(0x1028, 0x02b0, "Dell Inspiron 910", ALC268_AUTO), + SND_PCI_QUIRK_MASK(0x1028, 0xfff0, 0x02b0, + "Dell Inspiron Mini9/Vostro A90", ALC268_DELL), + /* almost compatible with toshiba but with optional digital outs; + * auto-probing seems working fine + */ + SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP TX25xx series", + ALC268_AUTO), + SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST), + SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO), + SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA), + SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1), + {} +}; + +/* Toshiba laptops have no unique PCI SSID but only codec SSID */ +static const struct snd_pci_quirk alc268_ssid_cfg_tbl[] = { + SND_PCI_QUIRK(0x1179, 0xff0a, "TOSHIBA X-200", ALC268_AUTO), + SND_PCI_QUIRK(0x1179, 0xff0e, "TOSHIBA X-200 HDMI", ALC268_AUTO), + SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05", + ALC268_TOSHIBA), + {} +}; + +static const struct alc_config_preset alc268_presets[] = { + [ALC267_QUANTA_IL1] = { + .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer, + alc268_capture_nosrc_mixer }, + .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, + alc267_quanta_il1_verbs }, + .num_dacs = ARRAY_SIZE(alc268_dac_nids), + .dac_nids = alc268_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), + .adc_nids = alc268_adc_nids_alt, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc268_modes), + .channel_mode = alc268_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc267_quanta_il1_setup, + .init_hook = alc_inithook, + }, + [ALC268_3ST] = { + .mixers = { alc268_base_mixer, alc268_capture_alt_mixer, + alc268_beep_mixer }, + .init_verbs = { alc268_base_init_verbs }, + .num_dacs = ARRAY_SIZE(alc268_dac_nids), + .dac_nids = alc268_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), + .adc_nids = alc268_adc_nids_alt, + .capsrc_nids = alc268_capsrc_nids, + .hp_nid = 0x03, + .dig_out_nid = ALC268_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc268_modes), + .channel_mode = alc268_modes, + .input_mux = &alc268_capture_source, + }, + [ALC268_TOSHIBA] = { + .mixers = { alc268_toshiba_mixer, alc268_capture_alt_mixer, + alc268_beep_mixer }, + .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, + alc268_toshiba_verbs }, + .num_dacs = ARRAY_SIZE(alc268_dac_nids), + .dac_nids = alc268_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), + .adc_nids = alc268_adc_nids_alt, + .capsrc_nids = alc268_capsrc_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc268_modes), + .channel_mode = alc268_modes, + .input_mux = &alc268_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc268_toshiba_setup, + .init_hook = alc_inithook, + }, + [ALC268_ACER] = { + .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer, + alc268_beep_mixer }, + .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, + alc268_acer_verbs }, + .num_dacs = ARRAY_SIZE(alc268_dac_nids), + .dac_nids = alc268_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), + .adc_nids = alc268_adc_nids_alt, + .capsrc_nids = alc268_capsrc_nids, + .hp_nid = 0x02, + .num_channel_mode = ARRAY_SIZE(alc268_modes), + .channel_mode = alc268_modes, + .input_mux = &alc268_acer_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc268_acer_setup, + .init_hook = alc_inithook, + }, + [ALC268_ACER_DMIC] = { + .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer, + alc268_beep_mixer }, + .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, + alc268_acer_verbs }, + .num_dacs = ARRAY_SIZE(alc268_dac_nids), + .dac_nids = alc268_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), + .adc_nids = alc268_adc_nids_alt, + .capsrc_nids = alc268_capsrc_nids, + .hp_nid = 0x02, + .num_channel_mode = ARRAY_SIZE(alc268_modes), + .channel_mode = alc268_modes, + .input_mux = &alc268_acer_dmic_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc268_acer_setup, + .init_hook = alc_inithook, + }, + [ALC268_ACER_ASPIRE_ONE] = { + .mixers = { alc268_acer_aspire_one_mixer, + alc268_beep_mixer, + alc268_capture_nosrc_mixer }, + .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, + alc268_acer_aspire_one_verbs }, + .num_dacs = ARRAY_SIZE(alc268_dac_nids), + .dac_nids = alc268_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), + .adc_nids = alc268_adc_nids_alt, + .capsrc_nids = alc268_capsrc_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc268_modes), + .channel_mode = alc268_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc268_acer_lc_setup, + .init_hook = alc_inithook, + }, + [ALC268_DELL] = { + .mixers = { alc268_dell_mixer, alc268_beep_mixer, + alc268_capture_nosrc_mixer }, + .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, + alc268_dell_verbs }, + .num_dacs = ARRAY_SIZE(alc268_dac_nids), + .dac_nids = alc268_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), + .adc_nids = alc268_adc_nids_alt, + .capsrc_nids = alc268_capsrc_nids, + .hp_nid = 0x02, + .num_channel_mode = ARRAY_SIZE(alc268_modes), + .channel_mode = alc268_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc268_dell_setup, + .init_hook = alc_inithook, + }, + [ALC268_ZEPTO] = { + .mixers = { alc268_base_mixer, alc268_capture_alt_mixer, + alc268_beep_mixer }, + .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, + alc268_toshiba_verbs }, + .num_dacs = ARRAY_SIZE(alc268_dac_nids), + .dac_nids = alc268_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), + .adc_nids = alc268_adc_nids_alt, + .capsrc_nids = alc268_capsrc_nids, + .hp_nid = 0x03, + .dig_out_nid = ALC268_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc268_modes), + .channel_mode = alc268_modes, + .input_mux = &alc268_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc268_toshiba_setup, + .init_hook = alc_inithook, + }, +#ifdef CONFIG_SND_DEBUG + [ALC268_TEST] = { + .mixers = { alc268_test_mixer, alc268_capture_mixer }, + .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, + alc268_volume_init_verbs }, + .num_dacs = ARRAY_SIZE(alc268_dac_nids), + .dac_nids = alc268_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), + .adc_nids = alc268_adc_nids_alt, + .capsrc_nids = alc268_capsrc_nids, + .hp_nid = 0x03, + .dig_out_nid = ALC268_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc268_modes), + .channel_mode = alc268_modes, + .input_mux = &alc268_capture_source, + }, +#endif +}; + +static int patch_alc268(struct hda_codec *codec) +{ + struct alc_spec *spec; + int board_config; + int i, has_beep, err; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) return -ENOMEM; - knew->index = cidx; - if (get_amp_nid_(val)) - knew->subdevice = HDA_SUBDEV_AMP_FLAG; - knew->private_value = val; + + codec->spec = spec; + + board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST, + alc268_models, + alc268_cfg_tbl); + + if (board_config < 0 || board_config >= ALC268_MODEL_LAST) + board_config = snd_hda_check_board_codec_sid_config(codec, + ALC268_MODEL_LAST, alc268_models, alc268_ssid_cfg_tbl); + + if (board_config < 0 || board_config >= ALC268_MODEL_LAST) { + printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); + board_config = ALC268_AUTO; + } + + if (board_config == ALC268_AUTO) { + /* automatic parse from the BIOS config */ + err = alc268_parse_auto_config(codec); + if (err < 0) { + alc_free(codec); + return err; + } else if (!err) { + printk(KERN_INFO + "hda_codec: Cannot set up configuration " + "from BIOS. Using base mode...\n"); + board_config = ALC268_3ST; + } + } + + if (board_config != ALC268_AUTO) + setup_preset(codec, &alc268_presets[board_config]); + + spec->stream_analog_playback = &alc268_pcm_analog_playback; + spec->stream_analog_capture = &alc268_pcm_analog_capture; + spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture; + + spec->stream_digital_playback = &alc268_pcm_digital_playback; + + has_beep = 0; + for (i = 0; i < spec->num_mixers; i++) { + if (spec->mixers[i] == alc268_beep_mixer) { + has_beep = 1; + break; + } + } + + if (has_beep) { + err = snd_hda_attach_beep_device(codec, 0x1); + if (err < 0) { + alc_free(codec); + return err; + } + if (!query_amp_caps(codec, 0x1d, HDA_INPUT)) + /* override the amp caps for beep generator */ + snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT, + (0x0c << AC_AMPCAP_OFFSET_SHIFT) | + (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) | + (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) | + (0 << AC_AMPCAP_MUTE_SHIFT)); + } + + if (!spec->no_analog && !spec->adc_nids && spec->input_mux) { + /* check whether NID 0x07 is valid */ + unsigned int wcap = get_wcaps(codec, 0x07); + + spec->capsrc_nids = alc268_capsrc_nids; + /* get type */ + wcap = get_wcaps_type(wcap); + if (spec->auto_mic || + wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) { + spec->adc_nids = alc268_adc_nids_alt; + spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt); + if (spec->auto_mic) + fixup_automic_adc(codec); + if (spec->auto_mic || spec->input_mux->num_items == 1) + add_mixer(spec, alc268_capture_nosrc_mixer); + else + add_mixer(spec, alc268_capture_alt_mixer); + } else { + spec->adc_nids = alc268_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids); + add_mixer(spec, alc268_capture_mixer); + } + } + + spec->vmaster_nid = 0x02; + + codec->patch_ops = alc_patch_ops; + if (board_config == ALC268_AUTO) + spec->init_hook = alc268_auto_init; + spec->shutup = alc_eapd_shutup; + + alc_init_jacks(codec); + return 0; } -static int add_control_with_pfx(struct alc_spec *spec, int type, - const char *pfx, const char *dir, - const char *sfx, int cidx, unsigned long val) +/* + * ALC269 channel source setting (2 channel) + */ +#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID + +#define alc269_dac_nids alc260_dac_nids + +static const hda_nid_t alc269_adc_nids[1] = { + /* ADC1 */ + 0x08, +}; + +static const hda_nid_t alc269_capsrc_nids[1] = { + 0x23, +}; + +static const hda_nid_t alc269vb_adc_nids[1] = { + /* ADC1 */ + 0x09, +}; + +static const hda_nid_t alc269vb_capsrc_nids[1] = { + 0x22, +}; + +static const hda_nid_t alc269_adc_candidates[] = { + 0x08, 0x09, 0x07, 0x11, +}; + +#define alc269_modes alc260_modes +#define alc269_capture_source alc880_lg_lw_capture_source + +static const struct snd_kcontrol_new alc269_base_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = { + /* output mixer control */ + HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .subdevice = HDA_SUBDEV_AMP_FLAG, + .info = snd_hda_mixer_amp_switch_info, + .get = snd_hda_mixer_amp_switch_get, + .put = alc268_acer_master_sw_put, + .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), + }, + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + { } +}; + +static const struct snd_kcontrol_new alc269_lifebook_mixer[] = { + /* output mixer control */ + HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .subdevice = HDA_SUBDEV_AMP_FLAG, + .info = snd_hda_mixer_amp_switch_info, + .get = snd_hda_mixer_amp_switch_get, + .put = alc268_acer_master_sw_put, + .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), + }, + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT), + HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT), + HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x1b, 0, HDA_INPUT), + { } +}; + +static const struct snd_kcontrol_new alc269_laptop_mixer[] = { + HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc269vb_laptop_mixer[] = { + HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc269_asus_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x0, HDA_INPUT), + { } /* end */ +}; + +/* capture mixer elements */ +static const struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + { } /* end */ +}; + +/* FSC amilo */ +#define alc269_fujitsu_mixer alc269_laptop_mixer + +static const struct hda_verb alc269_quanta_fl1_verbs[] = { + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + { } +}; + +static const struct hda_verb alc269_lifebook_verbs[] = { + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + { } +}; + +/* toggle speaker-output according to the hp-jack state */ +static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec) { - char name[32]; - snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx); - return add_control(spec, type, name, cidx, val); + alc_hp_automute(codec); + + snd_hda_codec_write(codec, 0x20, 0, + AC_VERB_SET_COEF_INDEX, 0x0c); + snd_hda_codec_write(codec, 0x20, 0, + AC_VERB_SET_PROC_COEF, 0x680); + + snd_hda_codec_write(codec, 0x20, 0, + AC_VERB_SET_COEF_INDEX, 0x0c); + snd_hda_codec_write(codec, 0x20, 0, + AC_VERB_SET_PROC_COEF, 0x480); } -#define add_pb_vol_ctrl(spec, type, pfx, val) \ - add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val) -#define add_pb_sw_ctrl(spec, type, pfx, val) \ - add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val) -#define __add_pb_vol_ctrl(spec, type, pfx, cidx, val) \ - add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val) -#define __add_pb_sw_ctrl(spec, type, pfx, cidx, val) \ - add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val) +#define alc269_lifebook_speaker_automute \ + alc269_quanta_fl1_speaker_automute -static const char *alc_get_line_out_pfx(struct alc_spec *spec, int ch, - bool can_be_master, int *index) +static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec) { - struct auto_pin_cfg *cfg = &spec->autocfg; - static const char * const chname[4] = { - "Front", "Surround", NULL /*CLFE*/, "Side" - }; - - *index = 0; - if (cfg->line_outs == 1 && !spec->multi_ios && - !cfg->hp_outs && !cfg->speaker_outs && can_be_master) - return "Master"; + unsigned int present_laptop; + unsigned int present_dock; + + present_laptop = snd_hda_jack_detect(codec, 0x18); + present_dock = snd_hda_jack_detect(codec, 0x1b); + + /* Laptop mic port overrides dock mic port, design decision */ + if (present_dock) + snd_hda_codec_write(codec, 0x23, 0, + AC_VERB_SET_CONNECT_SEL, 0x3); + if (present_laptop) + snd_hda_codec_write(codec, 0x23, 0, + AC_VERB_SET_CONNECT_SEL, 0x0); + if (!present_dock && !present_laptop) + snd_hda_codec_write(codec, 0x23, 0, + AC_VERB_SET_CONNECT_SEL, 0x1); +} - switch (cfg->line_out_type) { - case AUTO_PIN_SPEAKER_OUT: - if (cfg->line_outs == 1) - return "Speaker"; +static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + switch (res >> 26) { + case ALC880_HP_EVENT: + alc269_quanta_fl1_speaker_automute(codec); break; - case AUTO_PIN_HP_OUT: - /* for multi-io case, only the primary out */ - if (ch && spec->multi_ios) - break; - *index = ch; - return "Headphone"; - default: - if (cfg->line_outs == 1 && !spec->multi_ios) - return "PCM"; + case ALC880_MIC_EVENT: + alc_mic_automute(codec); break; } - return chname[ch]; } -/* create input playback/capture controls for the given pin */ -static int new_analog_input(struct alc_spec *spec, hda_nid_t pin, - const char *ctlname, int ctlidx, - int idx, hda_nid_t mix_nid) +static void alc269_lifebook_unsol_event(struct hda_codec *codec, + unsigned int res) { - int err; + if ((res >> 26) == ALC880_HP_EVENT) + alc269_lifebook_speaker_automute(codec); + if ((res >> 26) == ALC880_MIC_EVENT) + alc269_lifebook_mic_autoswitch(codec); +} - err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, ctlidx, - HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); - if (err < 0) - return err; - err = __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, ctlidx, - HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); - if (err < 0) - return err; +static void alc269_quanta_fl1_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; +} + +static void alc269_quanta_fl1_init_hook(struct hda_codec *codec) +{ + alc269_quanta_fl1_speaker_automute(codec); + alc_mic_automute(codec); +} + +static void alc269_lifebook_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.hp_pins[1] = 0x1a; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; +} + +static void alc269_lifebook_init_hook(struct hda_codec *codec) +{ + alc269_lifebook_speaker_automute(codec); + alc269_lifebook_mic_autoswitch(codec); +} + +static const struct hda_verb alc269_laptop_dmic_init_verbs[] = { + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x23, AC_VERB_SET_CONNECT_SEL, 0x05}, + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))}, + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; + +static const struct hda_verb alc269_laptop_amic_init_verbs[] = { + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x23, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; + +static const struct hda_verb alc269vb_laptop_dmic_init_verbs[] = { + {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x22, AC_VERB_SET_CONNECT_SEL, 0x06}, + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))}, + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; + +static const struct hda_verb alc269vb_laptop_amic_init_verbs[] = { + {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x22, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))}, + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; + +static const struct hda_verb alc271_acer_dmic_verbs[] = { + {0x20, AC_VERB_SET_COEF_INDEX, 0x0d}, + {0x20, AC_VERB_SET_PROC_COEF, 0x4000}, + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x22, AC_VERB_SET_CONNECT_SEL, 6}, + { } +}; + +static void alc269_laptop_amic_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; +} + +static void alc269_laptop_dmic_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x12; + spec->int_mic.mux_idx = 5; + spec->auto_mic = 1; +} + +static void alc269vb_laptop_amic_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; +} + +static void alc269vb_laptop_dmic_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x12; + spec->int_mic.mux_idx = 6; + spec->auto_mic = 1; +} + +/* + * generic initialization of ADC, input mixers and output mixers + */ +static const struct hda_verb alc269_init_verbs[] = { + /* + * Unmute ADC0 and set the default input to mic-in + */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* + * Set up output mixers (0x02 - 0x03) + */ + /* set vol=0 to output mixers */ + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* set up input amps for analog loopback */ + /* Amp Indices: DAC = 0, mixer = 1 */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* FIXME: use Mux-type input source selection */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */ + /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ + {0x23, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* set EAPD */ + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, + { } +}; + +static const struct hda_verb alc269vb_init_verbs[] = { + /* + * Unmute ADC0 and set the default input to mic-in + */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* + * Set up output mixers (0x02 - 0x03) + */ + /* set vol=0 to output mixers */ + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* set up input amps for analog loopback */ + /* Amp Indices: DAC = 0, mixer = 1 */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* FIXME: use Mux-type input source selection */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */ + /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ + {0x22, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* set EAPD */ + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, + { } +}; + +#define alc269_auto_create_multi_out_ctls \ + alc268_auto_create_multi_out_ctls +#define alc269_auto_create_input_ctls \ + alc268_auto_create_input_ctls + +#ifdef CONFIG_SND_HDA_POWER_SAVE +#define alc269_loopbacks alc880_loopbacks +#endif + +/* pcm configuration: identical with ALC880 */ +#define alc269_pcm_analog_playback alc880_pcm_analog_playback +#define alc269_pcm_analog_capture alc880_pcm_analog_capture +#define alc269_pcm_digital_playback alc880_pcm_digital_playback +#define alc269_pcm_digital_capture alc880_pcm_digital_capture + +static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_44100, /* fixed rate */ + /* NID is set in alc_build_pcms */ + .ops = { + .open = alc880_playback_pcm_open, + .prepare = alc880_playback_pcm_prepare, + .cleanup = alc880_playback_pcm_cleanup + }, +}; + +static const struct hda_pcm_stream alc269_44k_pcm_analog_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_44100, /* fixed rate */ + /* NID is set in alc_build_pcms */ +}; + +#ifdef CONFIG_SND_HDA_POWER_SAVE +static int alc269_mic2_for_mute_led(struct hda_codec *codec) +{ + switch (codec->subsystem_id) { + case 0x103c1586: + return 1; + } return 0; } -static int alc_is_input_pin(struct hda_codec *codec, hda_nid_t nid) +static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid) { - unsigned int pincap = snd_hda_query_pin_caps(codec, nid); - return (pincap & AC_PINCAP_IN) != 0; + /* update mute-LED according to the speaker mute state */ + if (nid == 0x01 || nid == 0x14) { + int pinval; + if (snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0) & + HDA_AMP_MUTE) + pinval = 0x24; + else + pinval = 0x20; + /* mic2 vref pin is used for mute LED control */ + snd_hda_codec_update_cache(codec, 0x19, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + pinval); + } + return alc_check_power_status(codec, nid); } +#endif /* CONFIG_SND_HDA_POWER_SAVE */ -/* Parse the codec tree and retrieve ADCs and corresponding capsrc MUXs */ -static int alc_auto_fill_adc_caps(struct hda_codec *codec) +static int alc275_setup_dual_adc(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - hda_nid_t nid; - hda_nid_t *adc_nids = spec->private_adc_nids; - hda_nid_t *cap_nids = spec->private_capsrc_nids; - int max_nums = ARRAY_SIZE(spec->private_adc_nids); - bool indep_capsrc = false; - int i, nums = 0; - - nid = codec->start_nid; - for (i = 0; i < codec->num_nodes; i++, nid++) { - hda_nid_t src; - const hda_nid_t *list; - unsigned int caps = get_wcaps(codec, nid); - int type = get_wcaps_type(caps); - - if (type != AC_WID_AUD_IN || (caps & AC_WCAP_DIGITAL)) - continue; - adc_nids[nums] = nid; - cap_nids[nums] = nid; - src = nid; - for (;;) { - int n; - type = get_wcaps_type(get_wcaps(codec, src)); - if (type == AC_WID_PIN) - break; - if (type == AC_WID_AUD_SEL) { - cap_nids[nums] = src; - indep_capsrc = true; - break; - } - n = snd_hda_get_conn_list(codec, src, &list); - if (n > 1) { - cap_nids[nums] = src; - indep_capsrc = true; - break; - } else if (n != 1) - break; - src = *list; + + if (codec->vendor_id != 0x10ec0275 || !spec->auto_mic) + return 0; + if ((spec->ext_mic.pin >= 0x18 && spec->int_mic.pin <= 0x13) || + (spec->ext_mic.pin <= 0x12 && spec->int_mic.pin >= 0x18)) { + if (spec->ext_mic.pin <= 0x12) { + spec->private_adc_nids[0] = 0x08; + spec->private_adc_nids[1] = 0x11; + spec->private_capsrc_nids[0] = 0x23; + spec->private_capsrc_nids[1] = 0x22; + } else { + spec->private_adc_nids[0] = 0x11; + spec->private_adc_nids[1] = 0x08; + spec->private_capsrc_nids[0] = 0x22; + spec->private_capsrc_nids[1] = 0x23; } - if (++nums >= max_nums) - break; + spec->adc_nids = spec->private_adc_nids; + spec->capsrc_nids = spec->private_capsrc_nids; + spec->num_adc_nids = 2; + spec->dual_adc_switch = 1; + snd_printdd("realtek: enabling dual ADC switchg (%02x:%02x)\n", + spec->adc_nids[0], spec->adc_nids[1]); + return 1; } - spec->adc_nids = spec->private_adc_nids; - spec->capsrc_nids = spec->private_capsrc_nids; - spec->num_adc_nids = nums; - return nums; + return 0; } -/* create playback/capture controls for input pins */ -static int alc_auto_create_input_ctls(struct hda_codec *codec) +/* different alc269-variants */ +enum { + ALC269_TYPE_NORMAL, + ALC269_TYPE_ALC258, + ALC269_TYPE_ALC259, + ALC269_TYPE_ALC269VB, + ALC269_TYPE_ALC270, + ALC269_TYPE_ALC271X, +}; + +/* + * BIOS auto configuration + */ +static int alc269_parse_auto_config(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - const struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t mixer = spec->mixer_nid; - struct hda_input_mux *imux = &spec->private_imux[0]; - int num_adcs; - int i, c, err, idx, type_idx = 0; - const char *prev_label = NULL; + int err; + static const hda_nid_t alc269_ignore[] = { 0x1d, 0 }; - num_adcs = alc_auto_fill_adc_caps(codec); - if (num_adcs < 0) - return 0; + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, + alc269_ignore); + if (err < 0) + return err; - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t pin; - const char *label; + err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + if (spec->codec_variant == ALC269_TYPE_NORMAL) + err = alc269_auto_create_input_ctls(codec, &spec->autocfg); + else + err = alc_auto_create_input_ctls(codec, &spec->autocfg, 0, + 0x22, 0); + if (err < 0) + return err; - pin = cfg->inputs[i].pin; - if (!alc_is_input_pin(codec, pin)) - continue; + spec->multiout.max_channels = spec->multiout.num_dacs * 2; - label = hda_get_autocfg_input_label(codec, cfg, i); - if (prev_label && !strcmp(label, prev_label)) - type_idx++; - else - type_idx = 0; - prev_label = label; + alc_auto_parse_digital(codec); - if (mixer) { - idx = get_connection_index(codec, mixer, pin); - if (idx >= 0) { - err = new_analog_input(spec, pin, - label, type_idx, - idx, mixer); - if (err < 0) - return err; - } - } + if (spec->kctls.list) + add_mixer(spec, spec->kctls.list); - for (c = 0; c < num_adcs; c++) { - hda_nid_t cap = spec->capsrc_nids ? - spec->capsrc_nids[c] : spec->adc_nids[c]; - idx = get_connection_index(codec, cap, pin); - if (idx >= 0) { - spec->imux_pins[imux->num_items] = pin; - snd_hda_add_imux_item(imux, label, idx, NULL); - break; - } - } + if (spec->codec_variant != ALC269_TYPE_NORMAL) { + add_verb(spec, alc269vb_init_verbs); + alc_ssid_check(codec, 0, 0x1b, 0x14, 0x21); + } else { + add_verb(spec, alc269_init_verbs); + alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0); } spec->num_mux_defs = 1; - spec->input_mux = imux; + spec->input_mux = &spec->private_imux[0]; - return 0; + if (!alc275_setup_dual_adc(codec)) + fillup_priv_adc_nids(codec, alc269_adc_candidates, + sizeof(alc269_adc_candidates)); + + err = alc_auto_add_mic_boost(codec); + if (err < 0) + return err; + + if (!spec->cap_mixer && !spec->no_analog) + set_capture_mixer(codec); + + return 1; } -static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid, - unsigned int pin_type) +#define alc269_auto_init_multi_out alc268_auto_init_multi_out +#define alc269_auto_init_hp_out alc268_auto_init_hp_out +#define alc269_auto_init_analog_input alc882_auto_init_analog_input +#define alc269_auto_init_input_src alc882_auto_init_input_src + + +/* init callback for auto-configuration model -- overriding the default init */ +static void alc269_auto_init(struct hda_codec *codec) { - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, - pin_type); - /* unmute pin */ - if (nid_has_mute(codec, nid, HDA_OUTPUT)) - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_UNMUTE); + struct alc_spec *spec = codec->spec; + alc269_auto_init_multi_out(codec); + alc269_auto_init_hp_out(codec); + alc269_auto_init_analog_input(codec); + if (!spec->dual_adc_switch) + alc269_auto_init_input_src(codec); + alc_auto_init_digital(codec); + if (spec->unsol_event) + alc_inithook(codec); } -static int get_pin_type(int line_out_type) +static void alc269_toggle_power_output(struct hda_codec *codec, int power_up) { - if (line_out_type == AUTO_PIN_HP_OUT) - return PIN_HP; + int val = alc_read_coef_idx(codec, 0x04); + if (power_up) + val |= 1 << 11; else - return PIN_OUT; + val &= ~(1 << 11); + alc_write_coef_idx(codec, 0x04, val); } -static void alc_auto_init_analog_input(struct hda_codec *codec) +static void alc269_shutup(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i; + if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) + alc269_toggle_power_output(codec, 0); + if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) { + alc269_toggle_power_output(codec, 0); + msleep(150); + } +} - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t nid = cfg->inputs[i].pin; - if (alc_is_input_pin(codec, nid)) { - alc_set_input_pin(codec, nid, cfg->inputs[i].type); - if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_MUTE); - } +#ifdef SND_HDA_NEEDS_RESUME +static int alc269_resume(struct hda_codec *codec) +{ + if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) { + alc269_toggle_power_output(codec, 0); + msleep(150); } - /* mute all loopback inputs */ - if (spec->mixer_nid) { - int nums = snd_hda_get_conn_list(codec, spec->mixer_nid, NULL); - for (i = 0; i < nums; i++) - snd_hda_codec_write(codec, spec->mixer_nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_MUTE(i)); + codec->patch_ops.init(codec); + + if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) { + alc269_toggle_power_output(codec, 1); + msleep(200); } + + if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) + alc269_toggle_power_output(codec, 1); + + snd_hda_codec_resume_amp(codec); + snd_hda_codec_resume_cache(codec); + hda_call_check_power_status(codec, 0x01); + return 0; } +#endif /* SND_HDA_NEEDS_RESUME */ -/* convert from MIX nid to DAC */ -static hda_nid_t alc_auto_mix_to_dac(struct hda_codec *codec, hda_nid_t nid) +static void alc269_fixup_hweq(struct hda_codec *codec, + const struct alc_fixup *fix, int action) { - hda_nid_t list[5]; - int i, num; + int coef; - if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_AUD_OUT) - return nid; - num = snd_hda_get_connections(codec, nid, list, ARRAY_SIZE(list)); - for (i = 0; i < num; i++) { - if (get_wcaps_type(get_wcaps(codec, list[i])) == AC_WID_AUD_OUT) - return list[i]; - } - return 0; + if (action != ALC_FIXUP_ACT_INIT) + return; + coef = alc_read_coef_idx(codec, 0x1e); + alc_write_coef_idx(codec, 0x1e, coef | 0x80); +} + +static void alc271_fixup_dmic(struct hda_codec *codec, + const struct alc_fixup *fix, int action) +{ + static const struct hda_verb verbs[] = { + {0x20, AC_VERB_SET_COEF_INDEX, 0x0d}, + {0x20, AC_VERB_SET_PROC_COEF, 0x4000}, + {} + }; + unsigned int cfg; + + if (strcmp(codec->chip_name, "ALC271X")) + return; + cfg = snd_hda_codec_get_pincfg(codec, 0x12); + if (get_defcfg_connect(cfg) == AC_JACK_PORT_FIXED) + snd_hda_sequence_write(codec, verbs); } -/* go down to the selector widget before the mixer */ -static hda_nid_t alc_go_down_to_selector(struct hda_codec *codec, hda_nid_t pin) +enum { + ALC269_FIXUP_SONY_VAIO, + ALC275_FIXUP_SONY_VAIO_GPIO2, + ALC269_FIXUP_DELL_M101Z, + ALC269_FIXUP_SKU_IGNORE, + ALC269_FIXUP_ASUS_G73JW, + ALC269_FIXUP_LENOVO_EAPD, + ALC275_FIXUP_SONY_HWEQ, + ALC271_FIXUP_DMIC, +}; + +static const struct alc_fixup alc269_fixups[] = { + [ALC269_FIXUP_SONY_VAIO] = { + .type = ALC_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD}, + {} + } + }, + [ALC275_FIXUP_SONY_VAIO_GPIO2] = { + .type = ALC_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + {0x01, AC_VERB_SET_GPIO_MASK, 0x04}, + {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04}, + {0x01, AC_VERB_SET_GPIO_DATA, 0x00}, + { } + }, + .chained = true, + .chain_id = ALC269_FIXUP_SONY_VAIO + }, + [ALC269_FIXUP_DELL_M101Z] = { + .type = ALC_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + /* Enables internal speaker */ + {0x20, AC_VERB_SET_COEF_INDEX, 13}, + {0x20, AC_VERB_SET_PROC_COEF, 0x4040}, + {} + } + }, + [ALC269_FIXUP_SKU_IGNORE] = { + .type = ALC_FIXUP_SKU, + .v.sku = ALC_FIXUP_SKU_IGNORE, + }, + [ALC269_FIXUP_ASUS_G73JW] = { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { + { 0x17, 0x99130111 }, /* subwoofer */ + { } + } + }, + [ALC269_FIXUP_LENOVO_EAPD] = { + .type = ALC_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0}, + {} + } + }, + [ALC275_FIXUP_SONY_HWEQ] = { + .type = ALC_FIXUP_FUNC, + .v.func = alc269_fixup_hweq, + .chained = true, + .chain_id = ALC275_FIXUP_SONY_VAIO_GPIO2 + }, + [ALC271_FIXUP_DMIC] = { + .type = ALC_FIXUP_FUNC, + .v.func = alc271_fixup_dmic, + }, +}; + +static const struct snd_pci_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2), + SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), + SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), + SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), + SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), + SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC), + SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE), + SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE), + SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE), + SND_PCI_QUIRK(0x17aa, 0x21ca, "Thinkpad L412", ALC269_FIXUP_SKU_IGNORE), + SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE), + SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW), + SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD), + {} +}; + + +/* + * configuration and preset + */ +static const char * const alc269_models[ALC269_MODEL_LAST] = { + [ALC269_BASIC] = "basic", + [ALC269_QUANTA_FL1] = "quanta", + [ALC269_AMIC] = "laptop-amic", + [ALC269_DMIC] = "laptop-dmic", + [ALC269_FUJITSU] = "fujitsu", + [ALC269_LIFEBOOK] = "lifebook", + [ALC269_AUTO] = "auto", +}; + +static const struct snd_pci_quirk alc269_cfg_tbl[] = { + SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1), + SND_PCI_QUIRK(0x1025, 0x047c, "ACER ZGA", ALC271_ACER), + SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A", + ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269VB_AMIC), + SND_PCI_QUIRK(0x1043, 0x1113, "ASUS N63Jn", ALC269VB_AMIC), + SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269VB_AMIC), + SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269VB_AMIC), + SND_PCI_QUIRK(0x1043, 0x11b3, "ASUS K52DR", ALC269VB_AMIC), + SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269VB_AMIC), + SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269VB_AMIC), + SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82JV", ALC269VB_AMIC), + SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1593, "ASUS N51Vn", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_DMIC), + SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901", + ALC269_DMIC), + SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101", + ALC269_DMIC), + SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005HA", ALC269_DMIC), + SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005HA", ALC269_DMIC), + SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_AUTO), + SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK), + SND_PCI_QUIRK(0x152d, 0x1778, "Quanta ON1", ALC269_DMIC), + SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU), + SND_PCI_QUIRK(0x17aa, 0x3be9, "Quanta Wistron", ALC269_AMIC), + SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_AMIC), + SND_PCI_QUIRK(0x17ff, 0x059a, "Quanta EL3", ALC269_DMIC), + SND_PCI_QUIRK(0x17ff, 0x059b, "Quanta JR1", ALC269_DMIC), + {} +}; + +static const struct alc_config_preset alc269_presets[] = { + [ALC269_BASIC] = { + .mixers = { alc269_base_mixer }, + .init_verbs = { alc269_init_verbs }, + .num_dacs = ARRAY_SIZE(alc269_dac_nids), + .dac_nids = alc269_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc269_modes), + .channel_mode = alc269_modes, + .input_mux = &alc269_capture_source, + }, + [ALC269_QUANTA_FL1] = { + .mixers = { alc269_quanta_fl1_mixer }, + .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs }, + .num_dacs = ARRAY_SIZE(alc269_dac_nids), + .dac_nids = alc269_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc269_modes), + .channel_mode = alc269_modes, + .input_mux = &alc269_capture_source, + .unsol_event = alc269_quanta_fl1_unsol_event, + .setup = alc269_quanta_fl1_setup, + .init_hook = alc269_quanta_fl1_init_hook, + }, + [ALC269_AMIC] = { + .mixers = { alc269_laptop_mixer }, + .cap_mixer = alc269_laptop_analog_capture_mixer, + .init_verbs = { alc269_init_verbs, + alc269_laptop_amic_init_verbs }, + .num_dacs = ARRAY_SIZE(alc269_dac_nids), + .dac_nids = alc269_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc269_modes), + .channel_mode = alc269_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc269_laptop_amic_setup, + .init_hook = alc_inithook, + }, + [ALC269_DMIC] = { + .mixers = { alc269_laptop_mixer }, + .cap_mixer = alc269_laptop_digital_capture_mixer, + .init_verbs = { alc269_init_verbs, + alc269_laptop_dmic_init_verbs }, + .num_dacs = ARRAY_SIZE(alc269_dac_nids), + .dac_nids = alc269_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc269_modes), + .channel_mode = alc269_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc269_laptop_dmic_setup, + .init_hook = alc_inithook, + }, + [ALC269VB_AMIC] = { + .mixers = { alc269vb_laptop_mixer }, + .cap_mixer = alc269vb_laptop_analog_capture_mixer, + .init_verbs = { alc269vb_init_verbs, + alc269vb_laptop_amic_init_verbs }, + .num_dacs = ARRAY_SIZE(alc269_dac_nids), + .dac_nids = alc269_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc269_modes), + .channel_mode = alc269_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc269vb_laptop_amic_setup, + .init_hook = alc_inithook, + }, + [ALC269VB_DMIC] = { + .mixers = { alc269vb_laptop_mixer }, + .cap_mixer = alc269vb_laptop_digital_capture_mixer, + .init_verbs = { alc269vb_init_verbs, + alc269vb_laptop_dmic_init_verbs }, + .num_dacs = ARRAY_SIZE(alc269_dac_nids), + .dac_nids = alc269_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc269_modes), + .channel_mode = alc269_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc269vb_laptop_dmic_setup, + .init_hook = alc_inithook, + }, + [ALC269_FUJITSU] = { + .mixers = { alc269_fujitsu_mixer }, + .cap_mixer = alc269_laptop_digital_capture_mixer, + .init_verbs = { alc269_init_verbs, + alc269_laptop_dmic_init_verbs }, + .num_dacs = ARRAY_SIZE(alc269_dac_nids), + .dac_nids = alc269_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc269_modes), + .channel_mode = alc269_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc269_laptop_dmic_setup, + .init_hook = alc_inithook, + }, + [ALC269_LIFEBOOK] = { + .mixers = { alc269_lifebook_mixer }, + .init_verbs = { alc269_init_verbs, alc269_lifebook_verbs }, + .num_dacs = ARRAY_SIZE(alc269_dac_nids), + .dac_nids = alc269_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc269_modes), + .channel_mode = alc269_modes, + .input_mux = &alc269_capture_source, + .unsol_event = alc269_lifebook_unsol_event, + .setup = alc269_lifebook_setup, + .init_hook = alc269_lifebook_init_hook, + }, + [ALC271_ACER] = { + .mixers = { alc269_asus_mixer }, + .cap_mixer = alc269vb_laptop_digital_capture_mixer, + .init_verbs = { alc269_init_verbs, alc271_acer_dmic_verbs }, + .num_dacs = ARRAY_SIZE(alc269_dac_nids), + .dac_nids = alc269_dac_nids, + .adc_nids = alc262_dmic_adc_nids, + .num_adc_nids = ARRAY_SIZE(alc262_dmic_adc_nids), + .capsrc_nids = alc262_dmic_capsrc_nids, + .num_channel_mode = ARRAY_SIZE(alc269_modes), + .channel_mode = alc269_modes, + .input_mux = &alc269_capture_source, + .dig_out_nid = ALC880_DIGOUT_NID, + .unsol_event = alc_sku_unsol_event, + .setup = alc269vb_laptop_dmic_setup, + .init_hook = alc_inithook, + }, +}; + +static int alc269_fill_coef(struct hda_codec *codec) { - hda_nid_t srcs[5]; - int num = snd_hda_get_connections(codec, pin, srcs, - ARRAY_SIZE(srcs)); - if (num != 1 || - get_wcaps_type(get_wcaps(codec, srcs[0])) != AC_WID_AUD_SEL) - return pin; - return srcs[0]; -} + int val; -/* get MIX nid connected to the given pin targeted to DAC */ -static hda_nid_t alc_auto_dac_to_mix(struct hda_codec *codec, hda_nid_t pin, - hda_nid_t dac) -{ - hda_nid_t mix[5]; - int i, num; + if ((alc_read_coef_idx(codec, 0) & 0x00ff) < 0x015) { + alc_write_coef_idx(codec, 0xf, 0x960b); + alc_write_coef_idx(codec, 0xe, 0x8817); + } - pin = alc_go_down_to_selector(codec, pin); - num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix)); - for (i = 0; i < num; i++) { - if (alc_auto_mix_to_dac(codec, mix[i]) == dac) - return mix[i]; + if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x016) { + alc_write_coef_idx(codec, 0xf, 0x960b); + alc_write_coef_idx(codec, 0xe, 0x8814); } - return 0; -} -/* select the connection from pin to DAC if needed */ -static int alc_auto_select_dac(struct hda_codec *codec, hda_nid_t pin, - hda_nid_t dac) -{ - hda_nid_t mix[5]; - int i, num; + if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) { + val = alc_read_coef_idx(codec, 0x04); + /* Power up output pin */ + alc_write_coef_idx(codec, 0x04, val | (1<<11)); + } - pin = alc_go_down_to_selector(codec, pin); - num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix)); - if (num < 2) - return 0; - for (i = 0; i < num; i++) { - if (alc_auto_mix_to_dac(codec, mix[i]) == dac) { - snd_hda_codec_update_cache(codec, pin, 0, - AC_VERB_SET_CONNECT_SEL, i); - return 0; + if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) { + val = alc_read_coef_idx(codec, 0xd); + if ((val & 0x0c00) >> 10 != 0x1) { + /* Capless ramp up clock control */ + alc_write_coef_idx(codec, 0xd, val | (1<<10)); + } + val = alc_read_coef_idx(codec, 0x17); + if ((val & 0x01c0) >> 6 != 0x4) { + /* Class D power on reset */ + alc_write_coef_idx(codec, 0x17, val | (1<<7)); } } - return 0; -} -/* look for an empty DAC slot */ -static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t srcs[5]; - int i, num; + val = alc_read_coef_idx(codec, 0xd); /* Class D */ + alc_write_coef_idx(codec, 0xd, val | (1<<14)); - pin = alc_go_down_to_selector(codec, pin); - num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs)); - for (i = 0; i < num; i++) { - hda_nid_t nid = alc_auto_mix_to_dac(codec, srcs[i]); - if (!nid) - continue; - if (found_in_nid_list(nid, spec->multiout.dac_nids, - spec->multiout.num_dacs)) - continue; - if (spec->multiout.hp_nid == nid) - continue; - if (found_in_nid_list(nid, spec->multiout.extra_out_nid, - ARRAY_SIZE(spec->multiout.extra_out_nid))) - continue; - return nid; - } - return 0; -} + val = alc_read_coef_idx(codec, 0x4); /* HP */ + alc_write_coef_idx(codec, 0x4, val | (1<<11)); -static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin) -{ - hda_nid_t sel = alc_go_down_to_selector(codec, pin); - if (snd_hda_get_conn_list(codec, sel, NULL) == 1) - return alc_auto_look_for_dac(codec, pin); return 0; } -/* fill in the dac_nids table from the parsed pin configuration */ -static int alc_auto_fill_dac_nids(struct hda_codec *codec) +static int patch_alc269(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; - const struct auto_pin_cfg *cfg = &spec->autocfg; - bool redone = false; - int i; + struct alc_spec *spec; + int board_config, coef; + int err; - again: - spec->multiout.num_dacs = 0; - spec->multiout.hp_nid = 0; - spec->multiout.extra_out_nid[0] = 0; - memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids)); - spec->multiout.dac_nids = spec->private_dac_nids; + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; - /* fill hard-wired DACs first */ - if (!redone) { - for (i = 0; i < cfg->line_outs; i++) - spec->private_dac_nids[i] = - get_dac_if_single(codec, cfg->line_out_pins[i]); - if (cfg->hp_outs) - spec->multiout.hp_nid = - get_dac_if_single(codec, cfg->hp_pins[0]); - if (cfg->speaker_outs) - spec->multiout.extra_out_nid[0] = - get_dac_if_single(codec, cfg->speaker_pins[0]); - } + codec->spec = spec; - for (i = 0; i < cfg->line_outs; i++) { - hda_nid_t pin = cfg->line_out_pins[i]; - if (spec->private_dac_nids[i]) - continue; - spec->private_dac_nids[i] = alc_auto_look_for_dac(codec, pin); - if (!spec->private_dac_nids[i] && !redone) { - /* if we can't find primary DACs, re-probe without - * checking the hard-wired DACs - */ - redone = true; - goto again; - } + alc_auto_parse_customize_define(codec); + + if (codec->vendor_id == 0x10ec0269) { + coef = alc_read_coef_idx(codec, 0); + if ((coef & 0x00f0) == 0x0010) { + if (codec->bus->pci->subsystem_vendor == 0x1025 && + spec->cdefine.platform_type == 1) { + alc_codec_rename(codec, "ALC271X"); + spec->codec_variant = ALC269_TYPE_ALC271X; + } else if ((coef & 0xf000) == 0x1000) { + spec->codec_variant = ALC269_TYPE_ALC270; + } else if ((coef & 0xf000) == 0x2000) { + alc_codec_rename(codec, "ALC259"); + spec->codec_variant = ALC269_TYPE_ALC259; + } else if ((coef & 0xf000) == 0x3000) { + alc_codec_rename(codec, "ALC258"); + spec->codec_variant = ALC269_TYPE_ALC258; + } else { + alc_codec_rename(codec, "ALC269VB"); + spec->codec_variant = ALC269_TYPE_ALC269VB; + } + } else + alc_fix_pll_init(codec, 0x20, 0x04, 15); + alc269_fill_coef(codec); } - for (i = 0; i < cfg->line_outs; i++) { - if (spec->private_dac_nids[i]) - spec->multiout.num_dacs++; - else - memmove(spec->private_dac_nids + i, - spec->private_dac_nids + i + 1, - sizeof(hda_nid_t) * (cfg->line_outs - i - 1)); + board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST, + alc269_models, + alc269_cfg_tbl); + + if (board_config < 0) { + printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); + board_config = ALC269_AUTO; } - if (cfg->hp_outs && !spec->multiout.hp_nid) - spec->multiout.hp_nid = - alc_auto_look_for_dac(codec, cfg->hp_pins[0]); - if (cfg->speaker_outs && !spec->multiout.extra_out_nid[0]) - spec->multiout.extra_out_nid[0] = - alc_auto_look_for_dac(codec, cfg->speaker_pins[0]); + if (board_config == ALC269_AUTO) { + alc_pick_fixup(codec, NULL, alc269_fixup_tbl, alc269_fixups); + alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + } - return 0; -} + if (board_config == ALC269_AUTO) { + /* automatic parse from the BIOS config */ + err = alc269_parse_auto_config(codec); + if (err < 0) { + alc_free(codec); + return err; + } else if (!err) { + printk(KERN_INFO + "hda_codec: Cannot set up configuration " + "from BIOS. Using base mode...\n"); + board_config = ALC269_BASIC; + } + } -static int alc_auto_add_vol_ctl(struct hda_codec *codec, - const char *pfx, int cidx, - hda_nid_t nid, unsigned int chs) -{ - if (!nid) - return 0; - return __add_pb_vol_ctrl(codec->spec, ALC_CTL_WIDGET_VOL, pfx, cidx, - HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); -} + if (has_cdefine_beep(codec)) { + err = snd_hda_attach_beep_device(codec, 0x1); + if (err < 0) { + alc_free(codec); + return err; + } + } -#define alc_auto_add_stereo_vol(codec, pfx, cidx, nid) \ - alc_auto_add_vol_ctl(codec, pfx, cidx, nid, 3) + if (board_config != ALC269_AUTO) + setup_preset(codec, &alc269_presets[board_config]); -/* create a mute-switch for the given mixer widget; - * if it has multiple sources (e.g. DAC and loopback), create a bind-mute - */ -static int alc_auto_add_sw_ctl(struct hda_codec *codec, - const char *pfx, int cidx, - hda_nid_t nid, unsigned int chs) -{ - int wid_type; - int type; - unsigned long val; - if (!nid) - return 0; - wid_type = get_wcaps_type(get_wcaps(codec, nid)); - if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT) { - type = ALC_CTL_WIDGET_MUTE; - val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT); - } else if (snd_hda_get_conn_list(codec, nid, NULL) == 1) { - type = ALC_CTL_WIDGET_MUTE; - val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT); + if (board_config == ALC269_QUANTA_FL1) { + /* Due to a hardware problem on Lenovo Ideadpad, we need to + * fix the sample rate of analog I/O to 44.1kHz + */ + spec->stream_analog_playback = &alc269_44k_pcm_analog_playback; + spec->stream_analog_capture = &alc269_44k_pcm_analog_capture; + } else if (spec->dual_adc_switch) { + spec->stream_analog_playback = &alc269_pcm_analog_playback; + /* switch ADC dynamically */ + spec->stream_analog_capture = &dualmic_pcm_analog_capture; } else { - type = ALC_CTL_BIND_MUTE; - val = HDA_COMPOSE_AMP_VAL(nid, chs, 2, HDA_INPUT); + spec->stream_analog_playback = &alc269_pcm_analog_playback; + spec->stream_analog_capture = &alc269_pcm_analog_capture; + } + spec->stream_digital_playback = &alc269_pcm_digital_playback; + spec->stream_digital_capture = &alc269_pcm_digital_capture; + + if (!spec->adc_nids) { /* wasn't filled automatically? use default */ + if (spec->codec_variant == ALC269_TYPE_NORMAL) { + spec->adc_nids = alc269_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids); + spec->capsrc_nids = alc269_capsrc_nids; + } else { + spec->adc_nids = alc269vb_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(alc269vb_adc_nids); + spec->capsrc_nids = alc269vb_capsrc_nids; + } } - return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val); -} -#define alc_auto_add_stereo_sw(codec, pfx, cidx, nid) \ - alc_auto_add_sw_ctl(codec, pfx, cidx, nid, 3) + if (!spec->cap_mixer) + set_capture_mixer(codec); + if (has_cdefine_beep(codec)) + set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); -static hda_nid_t alc_look_for_out_mute_nid(struct hda_codec *codec, - hda_nid_t pin, hda_nid_t dac) -{ - hda_nid_t mix = alc_auto_dac_to_mix(codec, pin, dac); - if (nid_has_mute(codec, pin, HDA_OUTPUT)) - return pin; - else if (mix && nid_has_mute(codec, mix, HDA_INPUT)) - return mix; - else if (nid_has_mute(codec, dac, HDA_OUTPUT)) - return dac; - return 0; -} + alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + + spec->vmaster_nid = 0x02; + + codec->patch_ops = alc_patch_ops; +#ifdef SND_HDA_NEEDS_RESUME + codec->patch_ops.resume = alc269_resume; +#endif + if (board_config == ALC269_AUTO) + spec->init_hook = alc269_auto_init; + spec->shutup = alc269_shutup; + + alc_init_jacks(codec); +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc269_loopbacks; + if (alc269_mic2_for_mute_led(codec)) + codec->patch_ops.check_power_status = alc269_mic2_mute_check_ps; +#endif -static hda_nid_t alc_look_for_out_vol_nid(struct hda_codec *codec, - hda_nid_t pin, hda_nid_t dac) -{ - hda_nid_t mix = alc_auto_dac_to_mix(codec, pin, dac); - if (nid_has_volume(codec, dac, HDA_OUTPUT)) - return dac; - else if (nid_has_volume(codec, mix, HDA_OUTPUT)) - return mix; - else if (nid_has_volume(codec, pin, HDA_OUTPUT)) - return pin; return 0; } -/* add playback controls from the parsed DAC table */ -static int alc_auto_create_multi_out_ctls(struct hda_codec *codec, - const struct auto_pin_cfg *cfg) -{ - struct alc_spec *spec = codec->spec; - int i, err, noutputs; +/* + * ALC861 channel source setting (2/6 channel selection for 3-stack) + */ - noutputs = cfg->line_outs; - if (spec->multi_ios > 0) - noutputs += spec->multi_ios; +/* + * set the path ways for 2 channel output + * need to set the codec line out and mic 1 pin widgets to inputs + */ +static const struct hda_verb alc861_threestack_ch2_init[] = { + /* set pin widget 1Ah (line in) for input */ + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* set pin widget 18h (mic1/2) for input, for mic also enable + * the vref + */ + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - for (i = 0; i < noutputs; i++) { - const char *name; - int index; - hda_nid_t dac, pin; - hda_nid_t sw, vol; + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c }, +#if 0 + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/ + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/ +#endif + { } /* end */ +}; +/* + * 6ch mode + * need to set the codec line out and mic 1 pin widgets to outputs + */ +static const struct hda_verb alc861_threestack_ch6_init[] = { + /* set pin widget 1Ah (line in) for output (Back Surround)*/ + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + /* set pin widget 18h (mic1) for output (CLFE)*/ + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - dac = spec->multiout.dac_nids[i]; - if (!dac) - continue; - if (i >= cfg->line_outs) - pin = spec->multi_io[i - 1].pin; - else - pin = cfg->line_out_pins[i]; + { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 }, + { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 }, - sw = alc_look_for_out_mute_nid(codec, pin, dac); - vol = alc_look_for_out_vol_nid(codec, pin, dac); - name = alc_get_line_out_pfx(spec, i, true, &index); - if (!name) { - /* Center/LFE */ - err = alc_auto_add_vol_ctl(codec, "Center", 0, vol, 1); - if (err < 0) - return err; - err = alc_auto_add_vol_ctl(codec, "LFE", 0, vol, 2); - if (err < 0) - return err; - err = alc_auto_add_sw_ctl(codec, "Center", 0, sw, 1); - if (err < 0) - return err; - err = alc_auto_add_sw_ctl(codec, "LFE", 0, sw, 2); - if (err < 0) - return err; - } else { - err = alc_auto_add_stereo_vol(codec, name, index, vol); - if (err < 0) - return err; - err = alc_auto_add_stereo_sw(codec, name, index, sw); - if (err < 0) - return err; - } - } - return 0; -} + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, +#if 0 + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/ + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/ +#endif + { } /* end */ +}; + +static const struct hda_channel_mode alc861_threestack_modes[2] = { + { 2, alc861_threestack_ch2_init }, + { 6, alc861_threestack_ch6_init }, +}; +/* Set mic1 as input and unmute the mixer */ +static const struct hda_verb alc861_uniwill_m31_ch2_init[] = { + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/ + { } /* end */ +}; +/* Set mic1 as output and mute mixer */ +static const struct hda_verb alc861_uniwill_m31_ch4_init[] = { + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/ + { } /* end */ +}; + +static const struct hda_channel_mode alc861_uniwill_m31_modes[2] = { + { 2, alc861_uniwill_m31_ch2_init }, + { 4, alc861_uniwill_m31_ch4_init }, +}; + +/* Set mic1 and line-in as input and unmute the mixer */ +static const struct hda_verb alc861_asus_ch2_init[] = { + /* set pin widget 1Ah (line in) for input */ + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* set pin widget 18h (mic1/2) for input, for mic also enable + * the vref + */ + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c }, +#if 0 + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/ + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/ +#endif + { } /* end */ +}; +/* Set mic1 nad line-in as output and mute mixer */ +static const struct hda_verb alc861_asus_ch6_init[] = { + /* set pin widget 1Ah (line in) for output (Back Surround)*/ + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */ + /* set pin widget 18h (mic1) for output (CLFE)*/ + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */ + { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 }, + { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 }, + + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, +#if 0 + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/ + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/ +#endif + { } /* end */ +}; -/* add playback controls for speaker and HP outputs */ -static int alc_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, - hda_nid_t dac, const char *pfx) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t sw, vol; - int err; +static const struct hda_channel_mode alc861_asus_modes[2] = { + { 2, alc861_asus_ch2_init }, + { 6, alc861_asus_ch6_init }, +}; - if (!pin) - return 0; - if (!dac) { - /* the corresponding DAC is already occupied */ - if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)) - return 0; /* no way */ - /* create a switch only */ - return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, - HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); - } +/* patch-ALC861 */ + +static const struct snd_kcontrol_new alc861_base_mixer[] = { + /* output mixer control */ + HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), + + /*Input mixer control */ + /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */ + HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT), - sw = alc_look_for_out_mute_nid(codec, pin, dac); - vol = alc_look_for_out_vol_nid(codec, pin, dac); - err = alc_auto_add_stereo_vol(codec, pfx, 0, vol); - if (err < 0) - return err; - err = alc_auto_add_stereo_sw(codec, pfx, 0, sw); - if (err < 0) - return err; - return 0; -} + { } /* end */ +}; -static int alc_auto_create_hp_out(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - return alc_auto_create_extra_out(codec, spec->autocfg.hp_pins[0], - spec->multiout.hp_nid, - "Headphone"); -} +static const struct snd_kcontrol_new alc861_3ST_mixer[] = { + /* output mixer control */ + HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), + /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */ + + /* Input mixer control */ + /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */ + HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT), -static int alc_auto_create_speaker_out(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - return alc_auto_create_extra_out(codec, spec->autocfg.speaker_pins[0], - spec->multiout.extra_out_nid[0], - "Speaker"); -} + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + .private_value = ARRAY_SIZE(alc861_threestack_modes), + }, + { } /* end */ +}; -static void alc_auto_set_output_and_unmute(struct hda_codec *codec, - hda_nid_t pin, int pin_type, - hda_nid_t dac) -{ - int i, num; - hda_nid_t nid, mix = 0; - hda_nid_t srcs[HDA_MAX_CONNECTIONS]; +static const struct snd_kcontrol_new alc861_toshiba_mixer[] = { + /* output mixer control */ + HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), - alc_set_pin_output(codec, pin, pin_type); - nid = alc_go_down_to_selector(codec, pin); - num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs)); - for (i = 0; i < num; i++) { - if (alc_auto_mix_to_dac(codec, srcs[i]) != dac) - continue; - mix = srcs[i]; - break; - } - if (!mix) - return; + { } /* end */ +}; - /* need the manual connection? */ - if (num > 1) - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i); - /* unmute mixer widget inputs */ - if (nid_has_mute(codec, mix, HDA_INPUT)) { - snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_UNMUTE(0)); - snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_UNMUTE(1)); - } - /* initialize volume */ - nid = alc_look_for_out_vol_nid(codec, pin, dac); - if (nid) - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_ZERO); -} +static const struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = { + /* output mixer control */ + HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), + /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */ + + /* Input mixer control */ + /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */ + HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT), -static void alc_auto_init_multi_out(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int pin_type = get_pin_type(spec->autocfg.line_out_type); - int i; + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes), + }, + { } /* end */ +}; - for (i = 0; i <= HDA_SIDE; i++) { - hda_nid_t nid = spec->autocfg.line_out_pins[i]; - if (nid) - alc_auto_set_output_and_unmute(codec, nid, pin_type, - spec->multiout.dac_nids[i]); - } -} +static const struct snd_kcontrol_new alc861_asus_mixer[] = { + /* output mixer control */ + HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), + + /* Input mixer control */ + HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT), -static void alc_auto_init_extra_out(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t pin; + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + .private_value = ARRAY_SIZE(alc861_asus_modes), + }, + { } +}; - pin = spec->autocfg.hp_pins[0]; - if (pin) - alc_auto_set_output_and_unmute(codec, pin, PIN_HP, - spec->multiout.hp_nid); - pin = spec->autocfg.speaker_pins[0]; - if (pin) - alc_auto_set_output_and_unmute(codec, pin, PIN_OUT, - spec->multiout.extra_out_nid[0]); -} +/* additional mixer */ +static const struct snd_kcontrol_new alc861_asus_laptop_mixer[] = { + HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), + { } +}; /* - * multi-io helper + * generic initialization of ADC, input mixers and output mixers */ -static int alc_auto_fill_multi_ios(struct hda_codec *codec, - unsigned int location) -{ - struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int type, i, num_pins = 0; +static const struct hda_verb alc861_base_init_verbs[] = { + /* + * Unmute ADC0 and set the default input to mic-in + */ + /* port-A for surround (rear panel) */ + { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 }, + /* port-B for mic-in (rear panel) with vref */ + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* port-C for line-in (rear panel) */ + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* port-D for Front */ + { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 }, + /* port-E for HP out (front panel) */ + { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + /* route front PCM to HP */ + { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, + /* port-F for mic-in (front panel) with vref */ + { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* port-G for CLFE (rear panel) */ + { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 }, + /* port-H for side (rear panel) */ + { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 }, + /* CD-in */ + { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* route front mic to ADC1*/ + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Unmute DAC0~3 & spdif out*/ + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Unmute Mixer 14 (mic) 1c (Line in)*/ + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* Unmute Stereo Mixer 15 */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */ + + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + /* hp used DAC 3 (Front) */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) { - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t nid = cfg->inputs[i].pin; - hda_nid_t dac; - unsigned int defcfg, caps; - if (cfg->inputs[i].type != type) - continue; - defcfg = snd_hda_codec_get_pincfg(codec, nid); - if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX) - continue; - if (location && get_defcfg_location(defcfg) != location) - continue; - caps = snd_hda_query_pin_caps(codec, nid); - if (!(caps & AC_PINCAP_OUT)) - continue; - dac = alc_auto_look_for_dac(codec, nid); - if (!dac) - continue; - spec->multi_io[num_pins].pin = nid; - spec->multi_io[num_pins].dac = dac; - num_pins++; - spec->private_dac_nids[spec->multiout.num_dacs++] = dac; - } - } - spec->multiout.num_dacs = 1; - if (num_pins < 2) - return 0; - return num_pins; -} + { } +}; -static int alc_auto_ch_mode_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; +static const struct hda_verb alc861_threestack_init_verbs[] = { + /* + * Unmute ADC0 and set the default input to mic-in + */ + /* port-A for surround (rear panel) */ + { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, + /* port-B for mic-in (rear panel) with vref */ + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* port-C for line-in (rear panel) */ + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* port-D for Front */ + { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 }, + /* port-E for HP out (front panel) */ + { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + /* route front PCM to HP */ + { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, + /* port-F for mic-in (front panel) with vref */ + { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* port-G for CLFE (rear panel) */ + { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, + /* port-H for side (rear panel) */ + { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, + /* CD-in */ + { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* route front mic to ADC1*/ + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* Unmute DAC0~3 & spdif out*/ + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Unmute Mixer 14 (mic) 1c (Line in)*/ + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* Unmute Stereo Mixer 15 */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */ + + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + /* hp used DAC 3 (Front) */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + { } +}; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = spec->multi_ios + 1; - if (uinfo->value.enumerated.item > spec->multi_ios) - uinfo->value.enumerated.item = spec->multi_ios; - sprintf(uinfo->value.enumerated.name, "%dch", - (uinfo->value.enumerated.item + 1) * 2); - return 0; -} +static const struct hda_verb alc861_uniwill_m31_init_verbs[] = { + /* + * Unmute ADC0 and set the default input to mic-in + */ + /* port-A for surround (rear panel) */ + { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, + /* port-B for mic-in (rear panel) with vref */ + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* port-C for line-in (rear panel) */ + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* port-D for Front */ + { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 }, + /* port-E for HP out (front panel) */ + /* this has to be set to VREF80 */ + { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* route front PCM to HP */ + { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, + /* port-F for mic-in (front panel) with vref */ + { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* port-G for CLFE (rear panel) */ + { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, + /* port-H for side (rear panel) */ + { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, + /* CD-in */ + { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* route front mic to ADC1*/ + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* Unmute DAC0~3 & spdif out*/ + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Unmute Mixer 14 (mic) 1c (Line in)*/ + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* Unmute Stereo Mixer 15 */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */ + + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + /* hp used DAC 3 (Front) */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + { } +}; -static int alc_auto_ch_mode_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - ucontrol->value.enumerated.item[0] = (spec->ext_channel_count - 1) / 2; - return 0; -} +static const struct hda_verb alc861_asus_init_verbs[] = { + /* + * Unmute ADC0 and set the default input to mic-in + */ + /* port-A for surround (rear panel) + * according to codec#0 this is the HP jack + */ + { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */ + /* route front PCM to HP */ + { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 }, + /* port-B for mic-in (rear panel) with vref */ + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* port-C for line-in (rear panel) */ + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* port-D for Front */ + { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 }, + /* port-E for HP out (front panel) */ + /* this has to be set to VREF80 */ + { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* route front PCM to HP */ + { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, + /* port-F for mic-in (front panel) with vref */ + { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* port-G for CLFE (rear panel) */ + { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + /* port-H for side (rear panel) */ + { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + /* CD-in */ + { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* route front mic to ADC1*/ + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* Unmute DAC0~3 & spdif out*/ + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Unmute Mixer 14 (mic) 1c (Line in)*/ + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* Unmute Stereo Mixer 15 */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */ + + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + /* hp used DAC 3 (Front) */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + { } +}; -static int alc_set_multi_io(struct hda_codec *codec, int idx, bool output) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t nid = spec->multi_io[idx].pin; +/* additional init verbs for ASUS laptops */ +static const struct hda_verb alc861_asus_laptop_init_verbs[] = { + { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */ + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */ + { } +}; - if (!spec->multi_io[idx].ctl_in) - spec->multi_io[idx].ctl_in = - snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - if (output) { - snd_hda_codec_update_cache(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - PIN_OUT); - if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) - snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, 0); - alc_auto_select_dac(codec, nid, spec->multi_io[idx].dac); - } else { - if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) - snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, HDA_AMP_MUTE); - snd_hda_codec_update_cache(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - spec->multi_io[idx].ctl_in); - } - return 0; -} +/* + * generic initialization of ADC, input mixers and output mixers + */ +static const struct hda_verb alc861_auto_init_verbs[] = { + /* + * Unmute ADC0 and set the default input to mic-in + */ + /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Unmute DAC0~3 & spdif out*/ + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Unmute Mixer 14 (mic) 1c (Line in)*/ + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* Unmute Stereo Mixer 15 */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, + + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */ -static int alc_auto_ch_mode_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - int i, ch; + { } +}; - ch = ucontrol->value.enumerated.item[0]; - if (ch < 0 || ch > spec->multi_ios) - return -EINVAL; - if (ch == (spec->ext_channel_count - 1) / 2) - return 0; - spec->ext_channel_count = (ch + 1) * 2; - for (i = 0; i < spec->multi_ios; i++) - alc_set_multi_io(codec, i, i < ch); - spec->multiout.max_channels = spec->ext_channel_count; - if (spec->need_dac_fix && !spec->const_channel_count) - spec->multiout.num_dacs = spec->multiout.max_channels / 2; - return 1; -} +static const struct hda_verb alc861_toshiba_init_verbs[] = { + {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, -static const struct snd_kcontrol_new alc_auto_channel_mode_enum = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_auto_ch_mode_info, - .get = alc_auto_ch_mode_get, - .put = alc_auto_ch_mode_put, + { } }; -static int alc_auto_add_multi_channel_mode(struct hda_codec *codec, - int (*fill_dac)(struct hda_codec *)) +/* toggle speaker-output according to the hp-jack state */ +static void alc861_toshiba_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - unsigned int location, defcfg; - int num_pins; + unsigned int present = snd_hda_jack_detect(codec, 0x0f); - if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && cfg->hp_outs == 1) { - /* use HP as primary out */ - cfg->speaker_outs = cfg->line_outs; - memcpy(cfg->speaker_pins, cfg->line_out_pins, - sizeof(cfg->speaker_pins)); - cfg->line_outs = cfg->hp_outs; - memcpy(cfg->line_out_pins, cfg->hp_pins, sizeof(cfg->hp_pins)); - cfg->hp_outs = 0; - memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); - cfg->line_out_type = AUTO_PIN_HP_OUT; - if (fill_dac) - fill_dac(codec); - } - if (cfg->line_outs != 1 || - cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) - return 0; + snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3, + HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE); +} - defcfg = snd_hda_codec_get_pincfg(codec, cfg->line_out_pins[0]); - location = get_defcfg_location(defcfg); +static void alc861_toshiba_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc861_toshiba_automute(codec); +} - num_pins = alc_auto_fill_multi_ios(codec, location); - if (num_pins > 0) { - struct snd_kcontrol_new *knew; +/* pcm configuration: identical with ALC880 */ +#define alc861_pcm_analog_playback alc880_pcm_analog_playback +#define alc861_pcm_analog_capture alc880_pcm_analog_capture +#define alc861_pcm_digital_playback alc880_pcm_digital_playback +#define alc861_pcm_digital_capture alc880_pcm_digital_capture - knew = alc_kcontrol_new(spec); - if (!knew) - return -ENOMEM; - *knew = alc_auto_channel_mode_enum; - knew->name = kstrdup("Channel Mode", GFP_KERNEL); - if (!knew->name) - return -ENOMEM; - spec->multi_ios = num_pins; - spec->ext_channel_count = 2; - spec->multiout.num_dacs = num_pins + 1; - } - return 0; -} +#define ALC861_DIGOUT_NID 0x07 + +static const struct hda_channel_mode alc861_8ch_modes[1] = { + { 8, NULL } +}; + +static const hda_nid_t alc861_dac_nids[4] = { + /* front, surround, clfe, side */ + 0x03, 0x06, 0x05, 0x04 +}; + +static const hda_nid_t alc660_dac_nids[3] = { + /* front, clfe, surround */ + 0x03, 0x05, 0x06 +}; -/* filter out invalid adc_nids (and capsrc_nids) that don't give all - * active input pins - */ -static void alc_remove_invalid_adc_nids(struct hda_codec *codec) +static const hda_nid_t alc861_adc_nids[1] = { + /* ADC0-2 */ + 0x08, +}; + +static const struct hda_input_mux alc861_capture_source = { + .num_items = 5, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x3 }, + { "Line", 0x1 }, + { "CD", 0x4 }, + { "Mixer", 0x5 }, + }, +}; + +static hda_nid_t alc861_look_for_dac(struct hda_codec *codec, hda_nid_t pin) { struct alc_spec *spec = codec->spec; - const struct hda_input_mux *imux; - hda_nid_t adc_nids[ARRAY_SIZE(spec->private_adc_nids)]; - hda_nid_t capsrc_nids[ARRAY_SIZE(spec->private_adc_nids)]; - int i, n, nums; - - imux = spec->input_mux; - if (!imux) - return; - if (spec->dyn_adc_switch) - return; + hda_nid_t mix, srcs[5]; + int i, j, num; - nums = 0; - for (n = 0; n < spec->num_adc_nids; n++) { - hda_nid_t cap = spec->private_capsrc_nids[n]; - int num_conns = snd_hda_get_conn_list(codec, cap, NULL); - for (i = 0; i < imux->num_items; i++) { - hda_nid_t pin = spec->imux_pins[i]; - if (pin) { - if (get_connection_index(codec, cap, pin) < 0) - break; - } else if (num_conns <= imux->items[i].index) + if (snd_hda_get_connections(codec, pin, &mix, 1) != 1) + return 0; + num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs)); + if (num < 0) + return 0; + for (i = 0; i < num; i++) { + unsigned int type; + type = get_wcaps_type(get_wcaps(codec, srcs[i])); + if (type != AC_WID_AUD_OUT) + continue; + for (j = 0; j < spec->multiout.num_dacs; j++) + if (spec->multiout.dac_nids[j] == srcs[i]) break; - } - if (i >= imux->num_items) { - adc_nids[nums] = spec->private_adc_nids[n]; - capsrc_nids[nums++] = cap; - } - } - if (!nums) { - /* check whether ADC-switch is possible */ - if (!alc_check_dyn_adc_switch(codec)) { - printk(KERN_WARNING "hda_codec: %s: no valid ADC found;" - " using fallback 0x%x\n", - codec->chip_name, spec->private_adc_nids[0]); - spec->num_adc_nids = 1; - spec->auto_mic = 0; - return; - } - } else if (nums != spec->num_adc_nids) { - memcpy(spec->private_adc_nids, adc_nids, - nums * sizeof(hda_nid_t)); - memcpy(spec->private_capsrc_nids, capsrc_nids, - nums * sizeof(hda_nid_t)); - spec->num_adc_nids = nums; + if (j >= spec->multiout.num_dacs) + return srcs[i]; } - - if (spec->auto_mic) - alc_auto_mic_check_imux(codec); /* check auto-mic setups */ - else if (spec->input_mux->num_items == 1) - spec->num_adc_nids = 1; /* reduce to a single ADC */ + return 0; } -/* - * initialize ADC paths - */ -static void alc_auto_init_adc(struct hda_codec *codec, int adc_idx) +/* fill in the dac_nids table from the parsed pin configuration */ +static int alc861_auto_fill_dac_nids(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) { struct alc_spec *spec = codec->spec; - hda_nid_t nid; + int i; + hda_nid_t nid, dac; - nid = spec->adc_nids[adc_idx]; - /* mute ADC */ - if (nid_has_mute(codec, nid, HDA_INPUT)) { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_MUTE(0)); - return; + spec->multiout.dac_nids = spec->private_dac_nids; + for (i = 0; i < cfg->line_outs; i++) { + nid = cfg->line_out_pins[i]; + dac = alc861_look_for_dac(codec, nid); + if (!dac) + continue; + spec->private_dac_nids[spec->multiout.num_dacs++] = dac; } - if (!spec->capsrc_nids) - return; - nid = spec->capsrc_nids[adc_idx]; - if (nid_has_mute(codec, nid, HDA_OUTPUT)) - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_MUTE); + return 0; } -static void alc_auto_init_input_src(struct hda_codec *codec) +static int __alc861_create_out_sw(struct hda_codec *codec, const char *pfx, + hda_nid_t nid, int idx, unsigned int chs) { - struct alc_spec *spec = codec->spec; - int c, nums; - - for (c = 0; c < spec->num_adc_nids; c++) - alc_auto_init_adc(codec, c); - if (spec->dyn_adc_switch) - nums = 1; - else - nums = spec->num_adc_nids; - for (c = 0; c < nums; c++) - alc_mux_select(codec, 0, spec->cur_mux[c], true); + return __add_pb_sw_ctrl(codec->spec, ALC_CTL_WIDGET_MUTE, pfx, idx, + HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); } -/* add mic boosts if needed */ -static int alc_auto_add_mic_boost(struct hda_codec *codec) +#define alc861_create_out_sw(codec, pfx, nid, chs) \ + __alc861_create_out_sw(codec, pfx, nid, 0, chs) + +/* add playback controls from the parsed DAC table */ +static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) { struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i, err; - int type_idx = 0; + static const char * const chname[4] = { + "Front", "Surround", NULL /*CLFE*/, "Side" + }; + const char *pfx = alc_get_line_out_pfx(spec, true); hda_nid_t nid; - const char *prev_label = NULL; - - for (i = 0; i < cfg->num_inputs; i++) { - if (cfg->inputs[i].type > AUTO_PIN_MIC) - break; - nid = cfg->inputs[i].pin; - if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) { - const char *label; - char boost_label[32]; + int i, err, noutputs; - label = hda_get_autocfg_input_label(codec, cfg, i); - if (prev_label && !strcmp(label, prev_label)) - type_idx++; - else - type_idx = 0; - prev_label = label; + noutputs = cfg->line_outs; + if (spec->multi_ios > 0) + noutputs += spec->multi_ios; - snprintf(boost_label, sizeof(boost_label), - "%s Boost Volume", label); - err = add_control(spec, ALC_CTL_WIDGET_VOL, - boost_label, type_idx, - HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); + for (i = 0; i < noutputs; i++) { + nid = spec->multiout.dac_nids[i]; + if (!nid) + continue; + if (!pfx && i == 2) { + /* Center/LFE */ + err = alc861_create_out_sw(codec, "Center", nid, 1); + if (err < 0) + return err; + err = alc861_create_out_sw(codec, "LFE", nid, 2); + if (err < 0) + return err; + } else { + const char *name = pfx; + int index = i; + if (!name) { + name = chname[i]; + index = 0; + } + err = __alc861_create_out_sw(codec, name, nid, index, 3); if (err < 0) return err; } @@ -3391,247 +16085,349 @@ static int alc_auto_add_mic_boost(struct hda_codec *codec) return 0; } -/* select or unmute the given capsrc route */ -static void select_or_unmute_capsrc(struct hda_codec *codec, hda_nid_t cap, - int idx) -{ - if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) { - snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx, - HDA_AMP_MUTE, 0); - } else if (snd_hda_get_conn_list(codec, cap, NULL) > 1) { - snd_hda_codec_write_cache(codec, cap, 0, - AC_VERB_SET_CONNECT_SEL, idx); - } -} - -/* set the default connection to that pin */ -static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin) +static int alc861_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin) { struct alc_spec *spec = codec->spec; - int i; + int err; + hda_nid_t nid; if (!pin) return 0; - for (i = 0; i < spec->num_adc_nids; i++) { - hda_nid_t cap = spec->capsrc_nids ? - spec->capsrc_nids[i] : spec->adc_nids[i]; - int idx; - idx = get_connection_index(codec, cap, pin); - if (idx < 0) - continue; - select_or_unmute_capsrc(codec, cap, idx); - return i; /* return the found index */ + if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) { + nid = alc861_look_for_dac(codec, pin); + if (nid) { + err = alc861_create_out_sw(codec, "Headphone", nid, 3); + if (err < 0) + return err; + spec->multiout.hp_nid = nid; + } } - return -1; /* not found */ + return 0; } -/* initialize some special cases for input sources */ -static void alc_init_special_input_src(struct hda_codec *codec) +/* create playback/capture controls for input pins */ +static int alc861_auto_create_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) { - struct alc_spec *spec = codec->spec; - int i; - - for (i = 0; i < spec->autocfg.num_inputs; i++) - init_capsrc_for_pin(codec, spec->autocfg.inputs[i].pin); + return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x08, 0); } -/* assign appropriate capture mixers */ -static void set_capture_mixer(struct hda_codec *codec) +static void alc861_auto_set_output_and_unmute(struct hda_codec *codec, + hda_nid_t nid, + int pin_type, hda_nid_t dac) { - struct alc_spec *spec = codec->spec; - static const struct snd_kcontrol_new *caps[2][3] = { - { alc_capture_mixer_nosrc1, - alc_capture_mixer_nosrc2, - alc_capture_mixer_nosrc3 }, - { alc_capture_mixer1, - alc_capture_mixer2, - alc_capture_mixer3 }, - }; + hda_nid_t mix, srcs[5]; + int i, num; - /* check whether either of ADC or MUX has a volume control */ - if (!nid_has_volume(codec, spec->adc_nids[0], HDA_INPUT)) { - if (!spec->capsrc_nids) - return; /* no volume */ - if (!nid_has_volume(codec, spec->capsrc_nids[0], HDA_OUTPUT)) - return; /* no volume in capsrc, too */ - spec->vol_in_capsrc = 1; + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + pin_type); + snd_hda_codec_write(codec, dac, 0, AC_VERB_SET_AMP_GAIN_MUTE, + AMP_OUT_UNMUTE); + if (snd_hda_get_connections(codec, nid, &mix, 1) != 1) + return; + num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs)); + if (num < 0) + return; + for (i = 0; i < num; i++) { + unsigned int mute; + if (srcs[i] == dac || srcs[i] == 0x15) + mute = AMP_IN_UNMUTE(i); + else + mute = AMP_IN_MUTE(i); + snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE, + mute); } +} - if (spec->num_adc_nids > 0) { - int mux = 0; - int num_adcs = 0; +static void alc861_auto_init_multi_out(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int i; - if (spec->input_mux && spec->input_mux->num_items > 1) - mux = 1; - if (spec->auto_mic) { - num_adcs = 1; - mux = 0; - } else if (spec->dyn_adc_switch) - num_adcs = 1; - if (!num_adcs) { - if (spec->num_adc_nids > 3) - spec->num_adc_nids = 3; - else if (!spec->num_adc_nids) - return; - num_adcs = spec->num_adc_nids; - } - spec->cap_mixer = caps[mux][num_adcs - 1]; + for (i = 0; i < spec->autocfg.line_outs; i++) { + hda_nid_t nid = spec->autocfg.line_out_pins[i]; + int pin_type = get_pin_type(spec->autocfg.line_out_type); + if (nid) + alc861_auto_set_output_and_unmute(codec, nid, pin_type, + spec->multiout.dac_nids[i]); } } -/* - * standard auto-parser initializations - */ -static void alc_auto_init_std(struct hda_codec *codec) +static void alc861_auto_init_hp_out(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - alc_auto_init_multi_out(codec); - alc_auto_init_extra_out(codec); - alc_auto_init_analog_input(codec); - alc_auto_init_input_src(codec); - alc_auto_init_digital(codec); - if (spec->unsol_event) - alc_inithook(codec); -} -/* - * Digital-beep handlers - */ -#ifdef CONFIG_SND_HDA_INPUT_BEEP -#define set_beep_amp(spec, nid, idx, dir) \ - ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir)) - -static const struct snd_pci_quirk beep_white_list[] = { - SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1), - SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1), - SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1), - SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1), - SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1), - {} -}; + if (spec->autocfg.hp_outs) + alc861_auto_set_output_and_unmute(codec, + spec->autocfg.hp_pins[0], + PIN_HP, + spec->multiout.hp_nid); + if (spec->autocfg.speaker_outs) + alc861_auto_set_output_and_unmute(codec, + spec->autocfg.speaker_pins[0], + PIN_OUT, + spec->multiout.dac_nids[0]); +} -static inline int has_cdefine_beep(struct hda_codec *codec) +static void alc861_auto_init_analog_input(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - const struct snd_pci_quirk *q; - q = snd_pci_quirk_lookup(codec->bus->pci, beep_white_list); - if (q) - return q->value; - return spec->cdefine.enable_pcbeep; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i; + + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; + if (nid >= 0x0c && nid <= 0x11) + alc_set_input_pin(codec, nid, cfg->inputs[i].type); + } } -#else -#define set_beep_amp(spec, nid, idx, dir) /* NOP */ -#define has_cdefine_beep(codec) 0 -#endif /* parse the BIOS configuration and set up the alc_spec */ /* return 1 if successful, 0 if the proper config is not found, * or a negative error code */ -static int alc_parse_auto_config(struct hda_codec *codec, - const hda_nid_t *ignore_nids, - const hda_nid_t *ssid_nids) +static int alc861_parse_auto_config(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; int err; + static const hda_nid_t alc861_ignore[] = { 0x1d, 0 }; err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, - ignore_nids); + alc861_ignore); if (err < 0) return err; - if (!spec->autocfg.line_outs) { - if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) { - spec->multiout.max_channels = 2; - spec->no_analog = 1; - goto dig_only; - } + if (!spec->autocfg.line_outs) return 0; /* can't find valid BIOS pin config */ - } - err = alc_auto_fill_dac_nids(codec); - if (err < 0) - return err; - err = alc_auto_add_multi_channel_mode(codec, alc_auto_fill_dac_nids); + + err = alc861_auto_fill_dac_nids(codec, &spec->autocfg); if (err < 0) return err; - err = alc_auto_create_multi_out_ctls(codec, &spec->autocfg); + err = alc_auto_add_multi_channel_mode(codec); if (err < 0) return err; - err = alc_auto_create_hp_out(codec); + err = alc861_auto_create_multi_out_ctls(codec, &spec->autocfg); if (err < 0) return err; - err = alc_auto_create_speaker_out(codec); + err = alc861_auto_create_hp_ctls(codec, spec->autocfg.hp_pins[0]); if (err < 0) return err; - err = alc_auto_create_input_ctls(codec); + err = alc861_auto_create_input_ctls(codec, &spec->autocfg); if (err < 0) return err; spec->multiout.max_channels = spec->multiout.num_dacs * 2; - dig_only: alc_auto_parse_digital(codec); - if (!spec->no_analog) - alc_remove_invalid_adc_nids(codec); + if (spec->kctls.list) + add_mixer(spec, spec->kctls.list); + + add_verb(spec, alc861_auto_init_verbs); - if (ssid_nids) - alc_ssid_check(codec, ssid_nids); + spec->num_mux_defs = 1; + spec->input_mux = &spec->private_imux[0]; - if (!spec->no_analog) { - alc_auto_check_switches(codec); - err = alc_auto_add_mic_boost(codec); - if (err < 0) - return err; - } + spec->adc_nids = alc861_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids); + set_capture_mixer(codec); - if (spec->kctls.list) - add_mixer(spec, spec->kctls.list); + alc_ssid_check(codec, 0x0e, 0x0f, 0x0b, 0); return 1; } -static int alc880_parse_auto_config(struct hda_codec *codec) +/* additional initialization for auto-configuration model */ +static void alc861_auto_init(struct hda_codec *codec) { - static const hda_nid_t alc880_ignore[] = { 0x1d, 0 }; - static const hda_nid_t alc880_ssids[] = { 0x15, 0x1b, 0x14, 0 }; - return alc_parse_auto_config(codec, alc880_ignore, alc880_ssids); + struct alc_spec *spec = codec->spec; + alc861_auto_init_multi_out(codec); + alc861_auto_init_hp_out(codec); + alc861_auto_init_analog_input(codec); + alc_auto_init_digital(codec); + if (spec->unsol_event) + alc_inithook(codec); } #ifdef CONFIG_SND_HDA_POWER_SAVE -static const struct hda_amp_list alc880_loopbacks[] = { - { 0x0b, HDA_INPUT, 0 }, - { 0x0b, HDA_INPUT, 1 }, - { 0x0b, HDA_INPUT, 2 }, - { 0x0b, HDA_INPUT, 3 }, - { 0x0b, HDA_INPUT, 4 }, +static const struct hda_amp_list alc861_loopbacks[] = { + { 0x15, HDA_INPUT, 0 }, + { 0x15, HDA_INPUT, 1 }, + { 0x15, HDA_INPUT, 2 }, + { 0x15, HDA_INPUT, 3 }, { } /* end */ }; -#endif +#endif + + +/* + * configuration and preset + */ +static const char * const alc861_models[ALC861_MODEL_LAST] = { + [ALC861_3ST] = "3stack", + [ALC660_3ST] = "3stack-660", + [ALC861_3ST_DIG] = "3stack-dig", + [ALC861_6ST_DIG] = "6stack-dig", + [ALC861_UNIWILL_M31] = "uniwill-m31", + [ALC861_TOSHIBA] = "toshiba", + [ALC861_ASUS] = "asus", + [ALC861_ASUS_LAPTOP] = "asus-laptop", + [ALC861_AUTO] = "auto", +}; + +static const struct snd_pci_quirk alc861_cfg_tbl[] = { + SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST), + SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP), + SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP), + SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS), + SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP), + SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG), + SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA), + /* FIXME: the entry below breaks Toshiba A100 (model=auto works!) + * Any other models that need this preset? + */ + /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */ + SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST), + SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST), + SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31), + SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31), + SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP), + /* FIXME: the below seems conflict */ + /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */ + SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST), + SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST), + {} +}; + +static const struct alc_config_preset alc861_presets[] = { + [ALC861_3ST] = { + .mixers = { alc861_3ST_mixer }, + .init_verbs = { alc861_threestack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc861_dac_nids), + .dac_nids = alc861_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), + .channel_mode = alc861_threestack_modes, + .need_dac_fix = 1, + .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), + .adc_nids = alc861_adc_nids, + .input_mux = &alc861_capture_source, + }, + [ALC861_3ST_DIG] = { + .mixers = { alc861_base_mixer }, + .init_verbs = { alc861_threestack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc861_dac_nids), + .dac_nids = alc861_dac_nids, + .dig_out_nid = ALC861_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), + .channel_mode = alc861_threestack_modes, + .need_dac_fix = 1, + .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), + .adc_nids = alc861_adc_nids, + .input_mux = &alc861_capture_source, + }, + [ALC861_6ST_DIG] = { + .mixers = { alc861_base_mixer }, + .init_verbs = { alc861_base_init_verbs }, + .num_dacs = ARRAY_SIZE(alc861_dac_nids), + .dac_nids = alc861_dac_nids, + .dig_out_nid = ALC861_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes), + .channel_mode = alc861_8ch_modes, + .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), + .adc_nids = alc861_adc_nids, + .input_mux = &alc861_capture_source, + }, + [ALC660_3ST] = { + .mixers = { alc861_3ST_mixer }, + .init_verbs = { alc861_threestack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc660_dac_nids), + .dac_nids = alc660_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), + .channel_mode = alc861_threestack_modes, + .need_dac_fix = 1, + .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), + .adc_nids = alc861_adc_nids, + .input_mux = &alc861_capture_source, + }, + [ALC861_UNIWILL_M31] = { + .mixers = { alc861_uniwill_m31_mixer }, + .init_verbs = { alc861_uniwill_m31_init_verbs }, + .num_dacs = ARRAY_SIZE(alc861_dac_nids), + .dac_nids = alc861_dac_nids, + .dig_out_nid = ALC861_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes), + .channel_mode = alc861_uniwill_m31_modes, + .need_dac_fix = 1, + .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), + .adc_nids = alc861_adc_nids, + .input_mux = &alc861_capture_source, + }, + [ALC861_TOSHIBA] = { + .mixers = { alc861_toshiba_mixer }, + .init_verbs = { alc861_base_init_verbs, + alc861_toshiba_init_verbs }, + .num_dacs = ARRAY_SIZE(alc861_dac_nids), + .dac_nids = alc861_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), + .adc_nids = alc861_adc_nids, + .input_mux = &alc861_capture_source, + .unsol_event = alc861_toshiba_unsol_event, + .init_hook = alc861_toshiba_automute, + }, + [ALC861_ASUS] = { + .mixers = { alc861_asus_mixer }, + .init_verbs = { alc861_asus_init_verbs }, + .num_dacs = ARRAY_SIZE(alc861_dac_nids), + .dac_nids = alc861_dac_nids, + .dig_out_nid = ALC861_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc861_asus_modes), + .channel_mode = alc861_asus_modes, + .need_dac_fix = 1, + .hp_nid = 0x06, + .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), + .adc_nids = alc861_adc_nids, + .input_mux = &alc861_capture_source, + }, + [ALC861_ASUS_LAPTOP] = { + .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer }, + .init_verbs = { alc861_asus_init_verbs, + alc861_asus_laptop_init_verbs }, + .num_dacs = ARRAY_SIZE(alc861_dac_nids), + .dac_nids = alc861_dac_nids, + .dig_out_nid = ALC861_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .need_dac_fix = 1, + .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), + .adc_nids = alc861_adc_nids, + .input_mux = &alc861_capture_source, + }, +}; + +/* Pin config fixes */ +enum { + PINFIX_FSC_AMILO_PI1505, +}; -/* - * board setups - */ -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS -#define alc_board_config \ - snd_hda_check_board_config -#define alc_board_codec_sid_config \ - snd_hda_check_board_codec_sid_config -#include "alc_quirks.c" -#else -#define alc_board_config(codec, nums, models, tbl) -1 -#define alc_board_codec_sid_config(codec, nums, models, tbl) -1 -#define setup_preset(codec, x) /* NOP */ -#endif +static const struct alc_fixup alc861_fixups[] = { + [PINFIX_FSC_AMILO_PI1505] = { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { + { 0x0b, 0x0221101f }, /* HP */ + { 0x0f, 0x90170310 }, /* speaker */ + { } + } + }, +}; -/* - * OK, here we have finally the patch for ALC880 - */ -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS -#include "alc880_quirks.c" -#endif +static const struct snd_pci_quirk alc861_fixup_tbl[] = { + SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505), + {} +}; -static int patch_alc880(struct hda_codec *codec) +static int patch_alc861(struct hda_codec *codec) { struct alc_spec *spec; int board_config; @@ -3643,281 +16439,970 @@ static int patch_alc880(struct hda_codec *codec) codec->spec = spec; - spec->mixer_nid = 0x0b; - spec->need_dac_fix = 1; + board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST, + alc861_models, + alc861_cfg_tbl); - board_config = alc_board_config(codec, ALC880_MODEL_LAST, - alc880_models, alc880_cfg_tbl); if (board_config < 0) { printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", codec->chip_name); - board_config = ALC_MODEL_AUTO; + board_config = ALC861_AUTO; + } + + if (board_config == ALC861_AUTO) { + alc_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups); + alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); } - if (board_config == ALC_MODEL_AUTO) { + if (board_config == ALC861_AUTO) { /* automatic parse from the BIOS config */ - err = alc880_parse_auto_config(codec); + err = alc861_parse_auto_config(codec); if (err < 0) { alc_free(codec); return err; - } -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS - else if (!err) { + } else if (!err) { printk(KERN_INFO "hda_codec: Cannot set up configuration " - "from BIOS. Using 3-stack mode...\n"); - board_config = ALC880_3ST; + "from BIOS. Using base mode...\n"); + board_config = ALC861_3ST_DIG; } -#endif } - if (board_config != ALC_MODEL_AUTO) - setup_preset(codec, &alc880_presets[board_config]); - - if (!spec->no_analog && !spec->adc_nids && spec->input_mux) { - alc_auto_fill_adc_caps(codec); - alc_rebuild_imux_for_auto_mic(codec); - alc_remove_invalid_adc_nids(codec); + err = snd_hda_attach_beep_device(codec, 0x23); + if (err < 0) { + alc_free(codec); + return err; } - if (!spec->no_analog && !spec->cap_mixer) + if (board_config != ALC861_AUTO) + setup_preset(codec, &alc861_presets[board_config]); + + spec->stream_analog_playback = &alc861_pcm_analog_playback; + spec->stream_analog_capture = &alc861_pcm_analog_capture; + + spec->stream_digital_playback = &alc861_pcm_digital_playback; + spec->stream_digital_capture = &alc861_pcm_digital_capture; + + if (!spec->cap_mixer) set_capture_mixer(codec); + set_beep_amp(spec, 0x23, 0, HDA_OUTPUT); - if (!spec->no_analog) { - err = snd_hda_attach_beep_device(codec, 0x1); - if (err < 0) { - alc_free(codec); - return err; - } - set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); - } + spec->vmaster_nid = 0x03; - spec->vmaster_nid = 0x0c; + alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); codec->patch_ops = alc_patch_ops; - if (board_config == ALC_MODEL_AUTO) - spec->init_hook = alc_auto_init_std; + if (board_config == ALC861_AUTO) { + spec->init_hook = alc861_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->power_hook = alc_power_eapd; +#endif + } #ifdef CONFIG_SND_HDA_POWER_SAVE if (!spec->loopback.amplist) - spec->loopback.amplist = alc880_loopbacks; + spec->loopback.amplist = alc861_loopbacks; #endif return 0; } +/* + * ALC861-VD support + * + * Based on ALC882 + * + * In addition, an independent DAC + */ +#define ALC861VD_DIGOUT_NID 0x06 + +static const hda_nid_t alc861vd_dac_nids[4] = { + /* front, surr, clfe, side surr */ + 0x02, 0x03, 0x04, 0x05 +}; + +/* dac_nids for ALC660vd are in a different order - according to + * Realtek's driver. + * This should probably result in a different mixer for 6stack models + * of ALC660vd codecs, but for now there is only 3stack mixer + * - and it is the same as in 861vd. + * adc_nids in ALC660vd are (is) the same as in 861vd + */ +static const hda_nid_t alc660vd_dac_nids[3] = { + /* front, rear, clfe, rear_surr */ + 0x02, 0x04, 0x03 +}; + +static const hda_nid_t alc861vd_adc_nids[1] = { + /* ADC0 */ + 0x09, +}; + +static const hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 }; + +/* input MUX */ +/* FIXME: should be a matrix-type input source selection */ +static const struct hda_input_mux alc861vd_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x1 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + }, +}; + +static const struct hda_input_mux alc861vd_dallas_capture_source = { + .num_items = 2, + .items = { + { "Mic", 0x0 }, + { "Internal Mic", 0x1 }, + }, +}; + +static const struct hda_input_mux alc861vd_hp_capture_source = { + .num_items = 2, + .items = { + { "Front Mic", 0x0 }, + { "ATAPI Mic", 0x1 }, + }, +}; /* - * ALC260 support + * 2ch mode */ -static int alc260_parse_auto_config(struct hda_codec *codec) +static const struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = { + { 2, NULL } +}; + +/* + * 6ch mode + */ +static const struct hda_verb alc861vd_6stack_ch6_init[] = { + { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, + { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { } /* end */ +}; + +/* + * 8ch mode + */ +static const struct hda_verb alc861vd_6stack_ch8_init[] = { + { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { } /* end */ +}; + +static const struct hda_channel_mode alc861vd_6stack_modes[2] = { + { 6, alc861vd_6stack_ch6_init }, + { 8, alc861vd_6stack_ch8_init }, +}; + +static const struct snd_kcontrol_new alc861vd_chmode_mixer[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + }, + { } /* end */ +}; + +/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 + * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b + */ +static const struct snd_kcontrol_new alc861vd_6st_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + + HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, + HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, + HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + + HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), + + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + + { } /* end */ +}; + +static const struct snd_kcontrol_new alc861vd_3st_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + + { } /* end */ +}; + +static const struct snd_kcontrol_new alc861vd_lenovo_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), + /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/ + HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), + + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + + { } /* end */ +}; + +/* Pin assignment: Speaker=0x14, HP = 0x15, + * Mic=0x18, Internal Mic = 0x19, CD = 0x1c, PC Beep = 0x1d + */ +static const struct snd_kcontrol_new alc861vd_dallas_mixer[] = { + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +/* Pin assignment: Speaker=0x14, Line-out = 0x15, + * Front Mic=0x18, ATAPI Mic = 0x19, + */ +static const struct snd_kcontrol_new alc861vd_hp_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + + { } /* end */ +}; + +/* + * generic initialization of ADC, input mixers and output mixers + */ +static const struct hda_verb alc861vd_volume_init_verbs[] = { + /* + * Unmute ADC0 and set the default input to mic-in + */ + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of + * the analog-loopback mixer widget + */ + /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + + /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + + /* + * Set up output mixers (0x02 - 0x05) + */ + /* set vol=0 to output mixers */ + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* set up input amps for analog loopback */ + /* Amp Indices: DAC = 0, mixer = 1 */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + + { } +}; + +/* + * 3-stack pin configuration: + * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b + */ +static const struct hda_verb alc861vd_3stack_init_verbs[] = { + /* + * Set pin mode and muting + */ + /* set front pin widgets 0x14 for output */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Mic (rear) pin: input vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Front Mic pin: input vref at 80% */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line In pin: input */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line-2 In: Headphone output (output 0 - 0x0c) */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* CD pin widget for input */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + { } +}; + +/* + * 6-stack pin configuration: + */ +static const struct hda_verb alc861vd_6stack_init_verbs[] = { + /* + * Set pin mode and muting + */ + /* set front pin widgets 0x14 for output */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Rear Pin: output 1 (0x0d) */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + /* CLFE Pin: output 2 (0x0e) */ + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, + /* Side Pin: output 3 (0x0f) */ + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, + + /* Mic (rear) pin: input vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Front Mic pin: input vref at 80% */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line In pin: input */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line-2 In: Headphone output (output 0 - 0x0c) */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* CD pin widget for input */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + { } +}; + +static const struct hda_verb alc861vd_eapd_verbs[] = { + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, + { } +}; + +static const struct hda_verb alc660vd_eapd_verbs[] = { + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, + {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, + { } +}; + +static const struct hda_verb alc861vd_lenovo_unsol_verbs[] = { + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {} +}; + +static void alc861vd_lenovo_setup(struct hda_codec *codec) { - static const hda_nid_t alc260_ignore[] = { 0x17, 0 }; - static const hda_nid_t alc260_ssids[] = { 0x10, 0x15, 0x0f, 0 }; - return alc_parse_auto_config(codec, alc260_ignore, alc260_ssids); + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } -#ifdef CONFIG_SND_HDA_POWER_SAVE -static const struct hda_amp_list alc260_loopbacks[] = { - { 0x07, HDA_INPUT, 0 }, - { 0x07, HDA_INPUT, 1 }, - { 0x07, HDA_INPUT, 2 }, - { 0x07, HDA_INPUT, 3 }, - { 0x07, HDA_INPUT, 4 }, +static void alc861vd_lenovo_init_hook(struct hda_codec *codec) +{ + alc_hp_automute(codec); + alc88x_simple_mic_automute(codec); +} + +static void alc861vd_lenovo_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + switch (res >> 26) { + case ALC880_MIC_EVENT: + alc88x_simple_mic_automute(codec); + break; + default: + alc_sku_unsol_event(codec, res); + break; + } +} + +static const struct hda_verb alc861vd_dallas_verbs[] = { + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + { } /* end */ }; + +/* toggle speaker-output according to the hp-jack state */ +static void alc861vd_dallas_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +#ifdef CONFIG_SND_HDA_POWER_SAVE +#define alc861vd_loopbacks alc880_loopbacks #endif +/* pcm configuration: identical with ALC880 */ +#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback +#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture +#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback +#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture + /* - * Pin config fixes + * configuration and preset */ -enum { - PINFIX_HP_DC5750, +static const char * const alc861vd_models[ALC861VD_MODEL_LAST] = { + [ALC660VD_3ST] = "3stack-660", + [ALC660VD_3ST_DIG] = "3stack-660-digout", + [ALC660VD_ASUS_V1S] = "asus-v1s", + [ALC861VD_3ST] = "3stack", + [ALC861VD_3ST_DIG] = "3stack-digout", + [ALC861VD_6ST_DIG] = "6stack-digout", + [ALC861VD_LENOVO] = "lenovo", + [ALC861VD_DALLAS] = "dallas", + [ALC861VD_HP] = "hp", + [ALC861VD_AUTO] = "auto", }; -static const struct alc_fixup alc260_fixups[] = { - [PINFIX_HP_DC5750] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x11, 0x90130110 }, /* speaker */ - { } - } +static const struct snd_pci_quirk alc861vd_cfg_tbl[] = { + SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST), + SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP), + SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST), + /*SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),*/ /* auto */ + SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S), + SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG), + SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST), + SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO), + /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/ + SND_PCI_QUIRK(0x1179, 0xff01, "Toshiba A135", ALC861VD_LENOVO), + SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO), + SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS), + SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG), + SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", ALC861VD_LENOVO), + SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG), + {} +}; + +static const struct alc_config_preset alc861vd_presets[] = { + [ALC660VD_3ST] = { + .mixers = { alc861vd_3st_mixer }, + .init_verbs = { alc861vd_volume_init_verbs, + alc861vd_3stack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc660vd_dac_nids), + .dac_nids = alc660vd_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), + .channel_mode = alc861vd_3stack_2ch_modes, + .input_mux = &alc861vd_capture_source, + }, + [ALC660VD_3ST_DIG] = { + .mixers = { alc861vd_3st_mixer }, + .init_verbs = { alc861vd_volume_init_verbs, + alc861vd_3stack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc660vd_dac_nids), + .dac_nids = alc660vd_dac_nids, + .dig_out_nid = ALC861VD_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), + .channel_mode = alc861vd_3stack_2ch_modes, + .input_mux = &alc861vd_capture_source, + }, + [ALC861VD_3ST] = { + .mixers = { alc861vd_3st_mixer }, + .init_verbs = { alc861vd_volume_init_verbs, + alc861vd_3stack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), + .dac_nids = alc861vd_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), + .channel_mode = alc861vd_3stack_2ch_modes, + .input_mux = &alc861vd_capture_source, + }, + [ALC861VD_3ST_DIG] = { + .mixers = { alc861vd_3st_mixer }, + .init_verbs = { alc861vd_volume_init_verbs, + alc861vd_3stack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), + .dac_nids = alc861vd_dac_nids, + .dig_out_nid = ALC861VD_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), + .channel_mode = alc861vd_3stack_2ch_modes, + .input_mux = &alc861vd_capture_source, + }, + [ALC861VD_6ST_DIG] = { + .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer }, + .init_verbs = { alc861vd_volume_init_verbs, + alc861vd_6stack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), + .dac_nids = alc861vd_dac_nids, + .dig_out_nid = ALC861VD_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes), + .channel_mode = alc861vd_6stack_modes, + .input_mux = &alc861vd_capture_source, + }, + [ALC861VD_LENOVO] = { + .mixers = { alc861vd_lenovo_mixer }, + .init_verbs = { alc861vd_volume_init_verbs, + alc861vd_3stack_init_verbs, + alc861vd_eapd_verbs, + alc861vd_lenovo_unsol_verbs }, + .num_dacs = ARRAY_SIZE(alc660vd_dac_nids), + .dac_nids = alc660vd_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), + .channel_mode = alc861vd_3stack_2ch_modes, + .input_mux = &alc861vd_capture_source, + .unsol_event = alc861vd_lenovo_unsol_event, + .setup = alc861vd_lenovo_setup, + .init_hook = alc861vd_lenovo_init_hook, + }, + [ALC861VD_DALLAS] = { + .mixers = { alc861vd_dallas_mixer }, + .init_verbs = { alc861vd_dallas_verbs }, + .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), + .dac_nids = alc861vd_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), + .channel_mode = alc861vd_3stack_2ch_modes, + .input_mux = &alc861vd_dallas_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc861vd_dallas_setup, + .init_hook = alc_hp_automute, + }, + [ALC861VD_HP] = { + .mixers = { alc861vd_hp_mixer }, + .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs }, + .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), + .dac_nids = alc861vd_dac_nids, + .dig_out_nid = ALC861VD_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), + .channel_mode = alc861vd_3stack_2ch_modes, + .input_mux = &alc861vd_hp_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc861vd_dallas_setup, + .init_hook = alc_hp_automute, + }, + [ALC660VD_ASUS_V1S] = { + .mixers = { alc861vd_lenovo_mixer }, + .init_verbs = { alc861vd_volume_init_verbs, + alc861vd_3stack_init_verbs, + alc861vd_eapd_verbs, + alc861vd_lenovo_unsol_verbs }, + .num_dacs = ARRAY_SIZE(alc660vd_dac_nids), + .dac_nids = alc660vd_dac_nids, + .dig_out_nid = ALC861VD_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), + .channel_mode = alc861vd_3stack_2ch_modes, + .input_mux = &alc861vd_capture_source, + .unsol_event = alc861vd_lenovo_unsol_event, + .setup = alc861vd_lenovo_setup, + .init_hook = alc861vd_lenovo_init_hook, }, }; -static const struct snd_pci_quirk alc260_fixup_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", PINFIX_HP_DC5750), - {} -}; +/* + * BIOS auto configuration + */ +static int alc861vd_auto_create_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) +{ + return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x22, 0); +} + + +static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec, + hda_nid_t nid, int pin_type, int dac_idx) +{ + alc_set_pin_output(codec, nid, pin_type); +} + +static void alc861vd_auto_init_multi_out(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int i; + + for (i = 0; i <= HDA_SIDE; i++) { + hda_nid_t nid = spec->autocfg.line_out_pins[i]; + int pin_type = get_pin_type(spec->autocfg.line_out_type); + if (nid) + alc861vd_auto_set_output_and_unmute(codec, nid, + pin_type, i); + } +} -/* - */ -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS -#include "alc260_quirks.c" -#endif -static int patch_alc260(struct hda_codec *codec) +static void alc861vd_auto_init_hp_out(struct hda_codec *codec) { - struct alc_spec *spec; - int err, board_config; + struct alc_spec *spec = codec->spec; + hda_nid_t pin; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; + pin = spec->autocfg.hp_pins[0]; + if (pin) /* connect to front and use dac 0 */ + alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); + pin = spec->autocfg.speaker_pins[0]; + if (pin) + alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0); +} - codec->spec = spec; +#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID - spec->mixer_nid = 0x07; +static void alc861vd_auto_init_analog_input(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i; - board_config = alc_board_config(codec, ALC260_MODEL_LAST, - alc260_models, alc260_cfg_tbl); - if (board_config < 0) { - snd_printd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - board_config = ALC_MODEL_AUTO; + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; + if (alc_is_input_pin(codec, nid)) { + alc_set_input_pin(codec, nid, cfg->inputs[i].type); + if (nid != ALC861VD_PIN_CD_NID && + (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)) + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_OUT_MUTE); + } } +} - if (board_config == ALC_MODEL_AUTO) { - alc_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); - } +#define alc861vd_auto_init_input_src alc882_auto_init_input_src - if (board_config == ALC_MODEL_AUTO) { - /* automatic parse from the BIOS config */ - err = alc260_parse_auto_config(codec); - if (err < 0) { - alc_free(codec); - return err; - } -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS - else if (!err) { - printk(KERN_INFO - "hda_codec: Cannot set up configuration " - "from BIOS. Using base mode...\n"); - board_config = ALC260_BASIC; - } -#endif - } +#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02) +#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c) - if (board_config != ALC_MODEL_AUTO) - setup_preset(codec, &alc260_presets[board_config]); +/* add playback controls from the parsed DAC table */ +/* Based on ALC880 version. But ALC861VD has separate, + * different NIDs for mute/unmute switch and volume control */ +static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec, + const struct auto_pin_cfg *cfg) +{ + static const char * const chname[4] = { + "Front", "Surround", "CLFE", "Side" + }; + const char *pfx = alc_get_line_out_pfx(spec, true); + hda_nid_t nid_v, nid_s; + int i, err, noutputs; - if (!spec->no_analog && !spec->adc_nids && spec->input_mux) { - alc_auto_fill_adc_caps(codec); - alc_rebuild_imux_for_auto_mic(codec); - alc_remove_invalid_adc_nids(codec); + noutputs = cfg->line_outs; + if (spec->multi_ios > 0) + noutputs += spec->multi_ios; + + for (i = 0; i < noutputs; i++) { + if (!spec->multiout.dac_nids[i]) + continue; + nid_v = alc861vd_idx_to_mixer_vol( + alc880_dac_to_idx( + spec->multiout.dac_nids[i])); + nid_s = alc861vd_idx_to_mixer_switch( + alc880_dac_to_idx( + spec->multiout.dac_nids[i])); + + if (!pfx && i == 2) { + /* Center/LFE */ + err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, + "Center", + HDA_COMPOSE_AMP_VAL(nid_v, 1, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, + "LFE", + HDA_COMPOSE_AMP_VAL(nid_v, 2, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, + "Center", + HDA_COMPOSE_AMP_VAL(nid_s, 1, 2, + HDA_INPUT)); + if (err < 0) + return err; + err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, + "LFE", + HDA_COMPOSE_AMP_VAL(nid_s, 2, 2, + HDA_INPUT)); + if (err < 0) + return err; + } else { + const char *name = pfx; + int index = i; + if (!name) { + name = chname[i]; + index = 0; + } + err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, + name, index, + HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = __add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, + name, index, + HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, + HDA_INPUT)); + if (err < 0) + return err; + } } + return 0; +} - if (!spec->no_analog && !spec->cap_mixer) - set_capture_mixer(codec); +/* add playback controls for speaker and HP outputs */ +/* Based on ALC880 version. But ALC861VD has separate, + * different NIDs for mute/unmute switch and volume control */ +static int alc861vd_auto_create_extra_out(struct alc_spec *spec, + hda_nid_t pin, const char *pfx) +{ + hda_nid_t nid_v, nid_s; + int err; - if (!spec->no_analog) { - err = snd_hda_attach_beep_device(codec, 0x1); - if (err < 0) { - alc_free(codec); + if (!pin) + return 0; + + if (alc880_is_fixed_pin(pin)) { + nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin)); + /* specify the DAC as the extra output */ + if (!spec->multiout.hp_nid) + spec->multiout.hp_nid = nid_v; + else + spec->multiout.extra_out_nid[0] = nid_v; + /* control HP volume/switch on the output mixer amp */ + nid_v = alc861vd_idx_to_mixer_vol( + alc880_fixed_pin_idx(pin)); + nid_s = alc861vd_idx_to_mixer_switch( + alc880_fixed_pin_idx(pin)); + + err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, + HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx, + HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT)); + if (err < 0) + return err; + } else if (alc880_is_multi_pin(pin)) { + /* set manual connection */ + /* we have only a switch on HP-out PIN */ + err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); + if (err < 0) return err; - } - set_beep_amp(spec, 0x07, 0x05, HDA_INPUT); } + return 0; +} - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); +/* parse the BIOS configuration and set up the alc_spec + * return 1 if successful, 0 if the proper config is not found, + * or a negative error code + * Based on ALC880 version - had to change it to override + * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */ +static int alc861vd_parse_auto_config(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int err; + static const hda_nid_t alc861vd_ignore[] = { 0x1d, 0 }; - spec->vmaster_nid = 0x08; + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, + alc861vd_ignore); + if (err < 0) + return err; + if (!spec->autocfg.line_outs) + return 0; /* can't find valid BIOS pin config */ - codec->patch_ops = alc_patch_ops; - if (board_config == ALC_MODEL_AUTO) - spec->init_hook = alc_auto_init_std; - spec->shutup = alc_eapd_shutup; -#ifdef CONFIG_SND_HDA_POWER_SAVE - if (!spec->loopback.amplist) - spec->loopback.amplist = alc260_loopbacks; -#endif + err = alc880_auto_fill_dac_nids(spec, &spec->autocfg); + if (err < 0) + return err; + err = alc_auto_add_multi_channel_mode(codec); + if (err < 0) + return err; + err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + err = alc861vd_auto_create_extra_out(spec, + spec->autocfg.speaker_pins[0], + "Speaker"); + if (err < 0) + return err; + err = alc861vd_auto_create_extra_out(spec, + spec->autocfg.hp_pins[0], + "Headphone"); + if (err < 0) + return err; + err = alc861vd_auto_create_input_ctls(codec, &spec->autocfg); + if (err < 0) + return err; - return 0; -} + spec->multiout.max_channels = spec->multiout.num_dacs * 2; + alc_auto_parse_digital(codec); -/* - * ALC882/883/885/888/889 support - * - * ALC882 is almost identical with ALC880 but has cleaner and more flexible - * configuration. Each pin widget can choose any input DACs and a mixer. - * Each ADC is connected from a mixer of all inputs. This makes possible - * 6-channel independent captures. - * - * In addition, an independent DAC for the multi-playback (not used in this - * driver yet). - */ -#ifdef CONFIG_SND_HDA_POWER_SAVE -#define alc882_loopbacks alc880_loopbacks -#endif + if (spec->kctls.list) + add_mixer(spec, spec->kctls.list); + + add_verb(spec, alc861vd_volume_init_verbs); + + spec->num_mux_defs = 1; + spec->input_mux = &spec->private_imux[0]; + + err = alc_auto_add_mic_boost(codec); + if (err < 0) + return err; + + alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0); + + return 1; +} + +/* additional initialization for auto-configuration model */ +static void alc861vd_auto_init(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + alc861vd_auto_init_multi_out(codec); + alc861vd_auto_init_hp_out(codec); + alc861vd_auto_init_analog_input(codec); + alc861vd_auto_init_input_src(codec); + alc_auto_init_digital(codec); + if (spec->unsol_event) + alc_inithook(codec); +} -/* - * Pin config fixes - */ enum { - PINFIX_ABIT_AW9D_MAX, - PINFIX_LENOVO_Y530, - PINFIX_PB_M5210, - PINFIX_ACER_ASPIRE_7736, + ALC660VD_FIX_ASUS_GPIO1 }; -static const struct alc_fixup alc882_fixups[] = { - [PINFIX_ABIT_AW9D_MAX] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x15, 0x01080104 }, /* side */ - { 0x16, 0x01011012 }, /* rear */ - { 0x17, 0x01016011 }, /* clfe */ - { } - } - }, - [PINFIX_LENOVO_Y530] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x15, 0x99130112 }, /* rear int speakers */ - { 0x16, 0x99130111 }, /* subwoofer */ - { } - } - }, - [PINFIX_PB_M5210] = { +/* reset GPIO1 */ +static const struct alc_fixup alc861vd_fixups[] = { + [ALC660VD_FIX_ASUS_GPIO1] = { .type = ALC_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { - { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 }, - {} + {0x01, AC_VERB_SET_GPIO_MASK, 0x03}, + {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, + {0x01, AC_VERB_SET_GPIO_DATA, 0x01}, + { } } }, - [PINFIX_ACER_ASPIRE_7736] = { - .type = ALC_FIXUP_SKU, - .v.sku = ALC_FIXUP_SKU_IGNORE, - }, }; -static const struct snd_pci_quirk alc882_fixup_tbl[] = { - SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210), - SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", PINFIX_LENOVO_Y530), - SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX), - SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", PINFIX_ACER_ASPIRE_7736), +static const struct snd_pci_quirk alc861vd_fixup_tbl[] = { + SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1), {} }; -/* - * BIOS auto configuration - */ -/* almost identical with ALC880 parser... */ -static int alc882_parse_auto_config(struct hda_codec *codec) -{ - static const hda_nid_t alc882_ignore[] = { 0x1d, 0 }; - static const hda_nid_t alc882_ssids[] = { 0x15, 0x1b, 0x14, 0 }; - return alc_parse_auto_config(codec, alc882_ignore, alc882_ssids); -} - -/* - */ -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS -#include "alc882_quirks.c" -#endif - -static int patch_alc882(struct hda_codec *codec) +static int patch_alc861vd(struct hda_codec *codec) { struct alc_spec *spec; int err, board_config; @@ -3928,1126 +17413,2030 @@ static int patch_alc882(struct hda_codec *codec) codec->spec = spec; - spec->mixer_nid = 0x0b; - - switch (codec->vendor_id) { - case 0x10ec0882: - case 0x10ec0885: - break; - default: - /* ALC883 and variants */ - alc_fix_pll_init(codec, 0x20, 0x0a, 10); - break; - } - - board_config = alc_board_config(codec, ALC882_MODEL_LAST, - alc882_models, alc882_cfg_tbl); - - if (board_config < 0) - board_config = alc_board_codec_sid_config(codec, - ALC882_MODEL_LAST, alc882_models, alc882_ssid_cfg_tbl); + board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST, + alc861vd_models, + alc861vd_cfg_tbl); - if (board_config < 0) { + if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) { printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", codec->chip_name); - board_config = ALC_MODEL_AUTO; + board_config = ALC861VD_AUTO; } - if (board_config == ALC_MODEL_AUTO) { - alc_pick_fixup(codec, NULL, alc882_fixup_tbl, alc882_fixups); + if (board_config == ALC861VD_AUTO) { + alc_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups); alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); } - alc_auto_parse_customize_define(codec); - - if (board_config == ALC_MODEL_AUTO) { + if (board_config == ALC861VD_AUTO) { /* automatic parse from the BIOS config */ - err = alc882_parse_auto_config(codec); + err = alc861vd_parse_auto_config(codec); if (err < 0) { alc_free(codec); return err; - } -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS - else if (!err) { + } else if (!err) { printk(KERN_INFO "hda_codec: Cannot set up configuration " "from BIOS. Using base mode...\n"); - board_config = ALC882_3ST_DIG; + board_config = ALC861VD_3ST; } -#endif } - if (board_config != ALC_MODEL_AUTO) - setup_preset(codec, &alc882_presets[board_config]); + err = snd_hda_attach_beep_device(codec, 0x23); + if (err < 0) { + alc_free(codec); + return err; + } - if (!spec->no_analog && !spec->adc_nids && spec->input_mux) { - alc_auto_fill_adc_caps(codec); - alc_rebuild_imux_for_auto_mic(codec); - alc_remove_invalid_adc_nids(codec); + if (board_config != ALC861VD_AUTO) + setup_preset(codec, &alc861vd_presets[board_config]); + + if (codec->vendor_id == 0x10ec0660) { + /* always turn on EAPD */ + add_verb(spec, alc660vd_eapd_verbs); } - if (!spec->no_analog && !spec->cap_mixer) - set_capture_mixer(codec); + spec->stream_analog_playback = &alc861vd_pcm_analog_playback; + spec->stream_analog_capture = &alc861vd_pcm_analog_capture; - if (!spec->no_analog && has_cdefine_beep(codec)) { - err = snd_hda_attach_beep_device(codec, 0x1); - if (err < 0) { - alc_free(codec); - return err; - } - set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); + spec->stream_digital_playback = &alc861vd_pcm_digital_playback; + spec->stream_digital_capture = &alc861vd_pcm_digital_capture; + + if (!spec->adc_nids) { + spec->adc_nids = alc861vd_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids); } + if (!spec->capsrc_nids) + spec->capsrc_nids = alc861vd_capsrc_nids; - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + set_capture_mixer(codec); + set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); - spec->vmaster_nid = 0x0c; + spec->vmaster_nid = 0x02; + + alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); codec->patch_ops = alc_patch_ops; - if (board_config == ALC_MODEL_AUTO) - spec->init_hook = alc_auto_init_std; - alc_init_jacks(codec); + if (board_config == ALC861VD_AUTO) + spec->init_hook = alc861vd_auto_init; + spec->shutup = alc_eapd_shutup; #ifdef CONFIG_SND_HDA_POWER_SAVE if (!spec->loopback.amplist) - spec->loopback.amplist = alc882_loopbacks; + spec->loopback.amplist = alc861vd_loopbacks; #endif return 0; } - /* - * ALC262 support + * ALC662 support + * + * ALC662 is almost identical with ALC880 but has cleaner and more flexible + * configuration. Each pin widget can choose any input DACs and a mixer. + * Each ADC is connected from a mixer of all inputs. This makes possible + * 6-channel independent captures. + * + * In addition, an independent DAC for the multi-playback (not used in this + * driver yet). */ -static int alc262_parse_auto_config(struct hda_codec *codec) -{ - static const hda_nid_t alc262_ignore[] = { 0x1d, 0 }; - static const hda_nid_t alc262_ssids[] = { 0x15, 0x1b, 0x14, 0 }; - return alc_parse_auto_config(codec, alc262_ignore, alc262_ssids); -} +#define ALC662_DIGOUT_NID 0x06 +#define ALC662_DIGIN_NID 0x0a -/* - * Pin config fixes - */ -enum { - PINFIX_FSC_H270, - PINFIX_HP_Z200, +static const hda_nid_t alc662_dac_nids[3] = { + /* front, rear, clfe */ + 0x02, 0x03, 0x04 }; -static const struct alc_fixup alc262_fixups[] = { - [PINFIX_FSC_H270] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x14, 0x99130110 }, /* speaker */ - { 0x15, 0x0221142f }, /* front HP */ - { 0x1b, 0x0121141f }, /* rear HP */ - { } - } - }, - [PINFIX_HP_Z200] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x16, 0x99130120 }, /* internal speaker */ - { } - } +static const hda_nid_t alc272_dac_nids[2] = { + 0x02, 0x03 +}; + +static const hda_nid_t alc662_adc_nids[2] = { + /* ADC1-2 */ + 0x09, 0x08 +}; + +static const hda_nid_t alc272_adc_nids[1] = { + /* ADC1-2 */ + 0x08, +}; + +static const hda_nid_t alc662_capsrc_nids[2] = { 0x22, 0x23 }; +static const hda_nid_t alc272_capsrc_nids[1] = { 0x23 }; + + +/* input MUX */ +/* FIXME: should be a matrix-type input source selection */ +static const struct hda_input_mux alc662_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x1 }, + { "Line", 0x2 }, + { "CD", 0x4 }, }, }; -static const struct snd_pci_quirk alc262_fixup_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", PINFIX_HP_Z200), - SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", PINFIX_FSC_H270), - {} +static const struct hda_input_mux alc662_lenovo_101e_capture_source = { + .num_items = 2, + .items = { + { "Mic", 0x1 }, + { "Line", 0x2 }, + }, }; +static const struct hda_input_mux alc663_capture_source = { + .num_items = 3, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x1 }, + { "Line", 0x2 }, + }, +}; -#ifdef CONFIG_SND_HDA_POWER_SAVE -#define alc262_loopbacks alc880_loopbacks +#if 0 /* set to 1 for testing other input sources below */ +static const struct hda_input_mux alc272_nc10_capture_source = { + .num_items = 16, + .items = { + { "Autoselect Mic", 0x0 }, + { "Internal Mic", 0x1 }, + { "In-0x02", 0x2 }, + { "In-0x03", 0x3 }, + { "In-0x04", 0x4 }, + { "In-0x05", 0x5 }, + { "In-0x06", 0x6 }, + { "In-0x07", 0x7 }, + { "In-0x08", 0x8 }, + { "In-0x09", 0x9 }, + { "In-0x0a", 0x0a }, + { "In-0x0b", 0x0b }, + { "In-0x0c", 0x0c }, + { "In-0x0d", 0x0d }, + { "In-0x0e", 0x0e }, + { "In-0x0f", 0x0f }, + }, +}; #endif /* + * 2ch mode */ -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS -#include "alc262_quirks.c" -#endif +static const struct hda_channel_mode alc662_3ST_2ch_modes[1] = { + { 2, NULL } +}; -static int patch_alc262(struct hda_codec *codec) -{ - struct alc_spec *spec; - int board_config; - int err; +/* + * 2ch mode + */ +static const struct hda_verb alc662_3ST_ch2_init[] = { + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { } /* end */ +}; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; +/* + * 6ch mode + */ +static const struct hda_verb alc662_3ST_ch6_init[] = { + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; - codec->spec = spec; +static const struct hda_channel_mode alc662_3ST_6ch_modes[2] = { + { 2, alc662_3ST_ch2_init }, + { 6, alc662_3ST_ch6_init }, +}; - spec->mixer_nid = 0x0b; +/* + * 2ch mode + */ +static const struct hda_verb alc662_sixstack_ch6_init[] = { + { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, + { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { } /* end */ +}; -#if 0 - /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is - * under-run - */ - { - int tmp; - snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7); - tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0); - snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7); - snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80); - } -#endif - alc_auto_parse_customize_define(codec); +/* + * 6ch mode + */ +static const struct hda_verb alc662_sixstack_ch8_init[] = { + { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { } /* end */ +}; - alc_fix_pll_init(codec, 0x20, 0x0a, 10); +static const struct hda_channel_mode alc662_5stack_modes[2] = { + { 2, alc662_sixstack_ch6_init }, + { 6, alc662_sixstack_ch8_init }, +}; - board_config = alc_board_config(codec, ALC262_MODEL_LAST, - alc262_models, alc262_cfg_tbl); +/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 + * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b + */ - if (board_config < 0) { - printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - board_config = ALC_MODEL_AUTO; - } +static const struct snd_kcontrol_new alc662_base_mixer[] = { + /* output mixer control */ + HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + + /*Input mixer control */ + HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT), + { } /* end */ +}; - if (board_config == ALC_MODEL_AUTO) { - alc_pick_fixup(codec, NULL, alc262_fixup_tbl, alc262_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); - } +static const struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; - if (board_config == ALC_MODEL_AUTO) { - /* automatic parse from the BIOS config */ - err = alc262_parse_auto_config(codec); - if (err < 0) { - alc_free(codec); - return err; - } -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS - else if (!err) { - printk(KERN_INFO - "hda_codec: Cannot set up configuration " - "from BIOS. Using base mode...\n"); - board_config = ALC262_BASIC; - } -#endif - } +static const struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; - if (board_config != ALC_MODEL_AUTO) - setup_preset(codec, &alc262_presets[board_config]); +static const struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; - if (!spec->no_analog && !spec->adc_nids && spec->input_mux) { - alc_auto_fill_adc_caps(codec); - alc_rebuild_imux_for_auto_mic(codec); - alc_remove_invalid_adc_nids(codec); - } +static const struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT), + ALC262_HIPPO_MASTER_SWITCH, - if (!spec->no_analog && !spec->cap_mixer) - set_capture_mixer(codec); + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - if (!spec->no_analog && has_cdefine_beep(codec)) { - err = snd_hda_attach_beep_device(codec, 0x1); - if (err < 0) { - alc_free(codec); - return err; - } - set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); - } + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); +static const struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = { + ALC262_HIPPO_MASTER_SWITCH, + HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; - spec->vmaster_nid = 0x0c; +static const struct hda_bind_ctls alc663_asus_bind_master_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT), + 0 + }, +}; - codec->patch_ops = alc_patch_ops; - if (board_config == ALC_MODEL_AUTO) - spec->init_hook = alc_auto_init_std; - spec->shutup = alc_eapd_shutup; +static const struct hda_bind_ctls alc663_asus_one_bind_switch = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), + 0 + }, +}; - alc_init_jacks(codec); -#ifdef CONFIG_SND_HDA_POWER_SAVE - if (!spec->loopback.amplist) - spec->loopback.amplist = alc262_loopbacks; -#endif +static const struct snd_kcontrol_new alc663_m51va_mixer[] = { + HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol), + HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; - return 0; -} +static const struct hda_bind_ctls alc663_asus_tree_bind_switch = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), + 0 + }, +}; -/* - * ALC268 - */ -/* bind Beep switches of both NID 0x0f and 0x10 */ -static const struct hda_bind_ctls alc268_bind_beep_sw = { +static const struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = { + HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol), + HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + + { } /* end */ +}; + +static const struct hda_bind_ctls alc663_asus_four_bind_switch = { .ops = &snd_hda_bind_sw, .values = { - HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT), - HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT), + HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), + 0 + }, +}; + +static const struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = { + HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol), + HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc662_1bjd_mixer[] = { + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct hda_bind_ctls alc663_asus_two_bind_master_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT), 0 }, }; -static const struct snd_kcontrol_new alc268_beep_mixer[] = { - HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT), - HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw), +static const struct hda_bind_ctls alc663_asus_two_bind_switch = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT), + 0 + }, +}; + +static const struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = { + HDA_BIND_VOL("Master Playback Volume", + &alc663_asus_two_bind_master_vol), + HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = { + HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol), + HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc663_g71v_mixer[] = { + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc663_g50v_mixer[] = { + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + { } /* end */ +}; + +static const struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), + 0 + }, +}; + +static const struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT), + 0 + }, +}; + +static const struct snd_kcontrol_new alc663_mode7_mixer[] = { + HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch), + HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol), + HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch), + HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("IntMic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("IntMic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc663_mode8_mixer[] = { + HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch), + HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol), + HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch), + HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + + +static const struct snd_kcontrol_new alc662_chmode_mixer[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + }, + { } /* end */ +}; + +static const struct hda_verb alc662_init_verbs[] = { + /* ADC: mute amp left and right */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* Front Pin: output 0 (0x0c) */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Rear Pin: output 1 (0x0d) */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* CLFE Pin: output 2 (0x0e) */ + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Mic (rear) pin: input vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Front Mic pin: input vref at 80% */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line In pin: input */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line-2 In: Headphone output (output 0 - 0x0c) */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* CD pin widget for input */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + /* FIXME: use matrix-type input source selection */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ + /* Input mixer */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + { } }; -/* set PCBEEP vol = 0, mute connections */ -static const struct hda_verb alc268_beep_init_verbs[] = { - {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, +static const struct hda_verb alc662_eapd_init_verbs[] = { + /* always trun on EAPD */ + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, + {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, { } }; -/* - * BIOS auto configuration - */ -static int alc268_parse_auto_config(struct hda_codec *codec) -{ - static const hda_nid_t alc268_ssids[] = { 0x15, 0x1b, 0x14, 0 }; - struct alc_spec *spec = codec->spec; - int err = alc_parse_auto_config(codec, NULL, alc268_ssids); - if (err > 0) { - if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d) { - add_mixer(spec, alc268_beep_mixer); - add_verb(spec, alc268_beep_init_verbs); - } - } - return err; -} - -/* - */ -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS -#include "alc268_quirks.c" -#endif +static const struct hda_verb alc662_sue_init_verbs[] = { + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT}, + {} +}; -static int patch_alc268(struct hda_codec *codec) -{ - struct alc_spec *spec; - int board_config; - int i, has_beep, err; +static const struct hda_verb alc662_eeepc_sue_init_verbs[] = { + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; +/* Set Unsolicited Event*/ +static const struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = { + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; - codec->spec = spec; +static const struct hda_verb alc663_m51va_init_verbs[] = { + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; - /* ALC268 has no aa-loopback mixer */ +static const struct hda_verb alc663_21jd_amic_init_verbs[] = { + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; - board_config = alc_board_config(codec, ALC268_MODEL_LAST, - alc268_models, alc268_cfg_tbl); +static const struct hda_verb alc662_1bjd_amic_init_verbs[] = { + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; - if (board_config < 0) - board_config = alc_board_codec_sid_config(codec, - ALC268_MODEL_LAST, alc268_models, alc268_ssid_cfg_tbl); +static const struct hda_verb alc663_15jd_amic_init_verbs[] = { + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; - if (board_config < 0) { - printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - board_config = ALC_MODEL_AUTO; - } +static const struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = { + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x21, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; - if (board_config == ALC_MODEL_AUTO) { - /* automatic parse from the BIOS config */ - err = alc268_parse_auto_config(codec); - if (err < 0) { - alc_free(codec); - return err; - } -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS - else if (!err) { - printk(KERN_INFO - "hda_codec: Cannot set up configuration " - "from BIOS. Using base mode...\n"); - board_config = ALC268_3ST; - } -#endif - } +static const struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = { + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; - if (board_config != ALC_MODEL_AUTO) - setup_preset(codec, &alc268_presets[board_config]); +static const struct hda_verb alc663_g71v_init_verbs[] = { + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */ + /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */ - has_beep = 0; - for (i = 0; i < spec->num_mixers; i++) { - if (spec->mixers[i] == alc268_beep_mixer) { - has_beep = 1; - break; - } - } + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */ - if (has_beep) { - err = snd_hda_attach_beep_device(codec, 0x1); - if (err < 0) { - alc_free(codec); - return err; - } - if (!query_amp_caps(codec, 0x1d, HDA_INPUT)) - /* override the amp caps for beep generator */ - snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT, - (0x0c << AC_AMPCAP_OFFSET_SHIFT) | - (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) | - (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) | - (0 << AC_AMPCAP_MUTE_SHIFT)); - } + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_MIC_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT}, + {} +}; - if (!spec->no_analog && !spec->adc_nids && spec->input_mux) { - alc_auto_fill_adc_caps(codec); - alc_rebuild_imux_for_auto_mic(codec); - alc_remove_invalid_adc_nids(codec); - } +static const struct hda_verb alc663_g50v_init_verbs[] = { + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */ - if (!spec->no_analog && !spec->cap_mixer) - set_capture_mixer(codec); + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; - spec->vmaster_nid = 0x02; +static const struct hda_verb alc662_ecs_init_verbs[] = { + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; - codec->patch_ops = alc_patch_ops; - if (board_config == ALC_MODEL_AUTO) - spec->init_hook = alc_auto_init_std; - spec->shutup = alc_eapd_shutup; +static const struct hda_verb alc272_dell_zm1_init_verbs[] = { + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; - alc_init_jacks(codec); +static const struct hda_verb alc272_dell_init_verbs[] = { + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; - return 0; -} +static const struct hda_verb alc663_mode7_init_verbs[] = { + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)}, + {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; -/* - * ALC269 - */ -#ifdef CONFIG_SND_HDA_POWER_SAVE -#define alc269_loopbacks alc880_loopbacks -#endif +static const struct hda_verb alc663_mode8_init_verbs[] = { + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; -static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 8, - .rates = SNDRV_PCM_RATE_44100, /* fixed rate */ - /* NID is set in alc_build_pcms */ - .ops = { - .open = alc_playback_pcm_open, - .prepare = alc_playback_pcm_prepare, - .cleanup = alc_playback_pcm_cleanup - }, +static const struct snd_kcontrol_new alc662_auto_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), + { } /* end */ }; -static const struct hda_pcm_stream alc269_44k_pcm_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_44100, /* fixed rate */ - /* NID is set in alc_build_pcms */ +static const struct snd_kcontrol_new alc272_auto_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + { } /* end */ }; -#ifdef CONFIG_SND_HDA_POWER_SAVE -static int alc269_mic2_for_mute_led(struct hda_codec *codec) +static void alc662_lenovo_101e_setup(struct hda_codec *codec) { - switch (codec->subsystem_id) { - case 0x103c1586: - return 1; - } - return 0; + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.line_out_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->detect_line = 1; + spec->automute_lines = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } -static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid) +static void alc662_eeepc_setup(struct hda_codec *codec) { - /* update mute-LED according to the speaker mute state */ - if (nid == 0x01 || nid == 0x14) { - int pinval; - if (snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0) & - HDA_AMP_MUTE) - pinval = 0x24; - else - pinval = 0x20; - /* mic2 vref pin is used for mute LED control */ - snd_hda_codec_update_cache(codec, 0x19, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - pinval); - } - return alc_check_power_status(codec, nid); -} -#endif /* CONFIG_SND_HDA_POWER_SAVE */ + struct alc_spec *spec = codec->spec; -/* different alc269-variants */ -enum { - ALC269_TYPE_ALC269VA, - ALC269_TYPE_ALC269VB, - ALC269_TYPE_ALC269VC, -}; + alc262_hippo1_setup(codec); + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; +} -/* - * BIOS auto configuration - */ -static int alc269_parse_auto_config(struct hda_codec *codec) +static void alc662_eeepc_ep20_setup(struct hda_codec *codec) { - static const hda_nid_t alc269_ignore[] = { 0x1d, 0 }; - static const hda_nid_t alc269_ssids[] = { 0, 0x1b, 0x14, 0x21 }; - static const hda_nid_t alc269va_ssids[] = { 0x15, 0x1b, 0x14, 0 }; struct alc_spec *spec = codec->spec; - const hda_nid_t *ssids = spec->codec_variant == ALC269_TYPE_ALC269VA ? - alc269va_ssids : alc269_ssids; - return alc_parse_auto_config(codec, alc269_ignore, ssids); + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x1b; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } -static void alc269_toggle_power_output(struct hda_codec *codec, int power_up) +static void alc663_m51va_setup(struct hda_codec *codec) { - int val = alc_read_coef_idx(codec, 0x04); - if (power_up) - val |= 1 << 11; - else - val &= ~(1 << 11); - alc_write_coef_idx(codec, 0x04, val); + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x12; + spec->int_mic.mux_idx = 9; + spec->auto_mic = 1; } -static void alc269_shutup(struct hda_codec *codec) +/* ***************** Mode1 ******************************/ +static void alc663_mode1_setup(struct hda_codec *codec) { - if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) - alc269_toggle_power_output(codec, 0); - if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) { - alc269_toggle_power_output(codec, 0); - msleep(150); - } + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; } -#ifdef SND_HDA_NEEDS_RESUME -static int alc269_resume(struct hda_codec *codec) +/* ***************** Mode2 ******************************/ +static void alc662_mode2_setup(struct hda_codec *codec) { - if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) { - alc269_toggle_power_output(codec, 0); - msleep(150); - } - - codec->patch_ops.init(codec); - - if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) { - alc269_toggle_power_output(codec, 1); - msleep(200); - } - - if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) - alc269_toggle_power_output(codec, 1); - - snd_hda_codec_resume_amp(codec); - snd_hda_codec_resume_cache(codec); - hda_call_check_power_status(codec, 0x01); - return 0; + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; } -#endif /* SND_HDA_NEEDS_RESUME */ -static void alc269_fixup_hweq(struct hda_codec *codec, - const struct alc_fixup *fix, int action) +/* ***************** Mode3 ******************************/ +static void alc663_mode3_setup(struct hda_codec *codec) { - int coef; + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; +} - if (action != ALC_FIXUP_ACT_INIT) - return; - coef = alc_read_coef_idx(codec, 0x1e); - alc_write_coef_idx(codec, 0x1e, coef | 0x80); +/* ***************** Mode4 ******************************/ +static void alc663_mode4_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x16; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute_mixer_nid[1] = 0x0e; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; } -static void alc271_fixup_dmic(struct hda_codec *codec, - const struct alc_fixup *fix, int action) +/* ***************** Mode5 ******************************/ +static void alc663_mode5_setup(struct hda_codec *codec) { - static const struct hda_verb verbs[] = { - {0x20, AC_VERB_SET_COEF_INDEX, 0x0d}, - {0x20, AC_VERB_SET_PROC_COEF, 0x4000}, - {} - }; - unsigned int cfg; + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x16; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute_mixer_nid[1] = 0x0e; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; +} - if (strcmp(codec->chip_name, "ALC271X")) - return; - cfg = snd_hda_codec_get_pincfg(codec, 0x12); - if (get_defcfg_connect(cfg) == AC_JACK_PORT_FIXED) - snd_hda_sequence_write(codec, verbs); +/* ***************** Mode6 ******************************/ +static void alc663_mode6_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; } -static void alc269_fixup_pcm_44k(struct hda_codec *codec, - const struct alc_fixup *fix, int action) +/* ***************** Mode7 ******************************/ +static void alc663_mode7_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x17; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; +} - if (action != ALC_FIXUP_ACT_PROBE) - return; +/* ***************** Mode8 ******************************/ +static void alc663_mode8_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.hp_pins[1] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x17; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x12; + spec->int_mic.mux_idx = 9; + spec->auto_mic = 1; +} - /* Due to a hardware problem on Lenovo Ideadpad, we need to - * fix the sample rate of analog I/O to 44.1kHz - */ - spec->stream_analog_playback = &alc269_44k_pcm_analog_playback; - spec->stream_analog_capture = &alc269_44k_pcm_analog_capture; +static void alc663_g71v_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.line_out_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; + spec->detect_line = 1; + spec->automute_lines = 1; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x12; + spec->int_mic.mux_idx = 9; + spec->auto_mic = 1; } -enum { - ALC269_FIXUP_SONY_VAIO, - ALC275_FIXUP_SONY_VAIO_GPIO2, - ALC269_FIXUP_DELL_M101Z, - ALC269_FIXUP_SKU_IGNORE, - ALC269_FIXUP_ASUS_G73JW, - ALC269_FIXUP_LENOVO_EAPD, - ALC275_FIXUP_SONY_HWEQ, - ALC271_FIXUP_DMIC, - ALC269_FIXUP_PCM_44K, +#define alc663_g50v_setup alc663_m51va_setup + +static const struct snd_kcontrol_new alc662_ecs_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT), + ALC262_HIPPO_MASTER_SWITCH, + + HDA_CODEC_VOLUME("Mic/LineIn Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT), + + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ }; -static const struct alc_fixup alc269_fixups[] = { - [ALC269_FIXUP_SONY_VAIO] = { - .type = ALC_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD}, - {} - } +static const struct snd_kcontrol_new alc272_nc10_mixer[] = { + /* Master Playback automatically created from Speaker and Headphone */ + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + { } /* end */ +}; + +#ifdef CONFIG_SND_HDA_POWER_SAVE +#define alc662_loopbacks alc880_loopbacks +#endif + + +/* pcm configuration: identical with ALC880 */ +#define alc662_pcm_analog_playback alc880_pcm_analog_playback +#define alc662_pcm_analog_capture alc880_pcm_analog_capture +#define alc662_pcm_digital_playback alc880_pcm_digital_playback +#define alc662_pcm_digital_capture alc880_pcm_digital_capture + +/* + * configuration and preset + */ +static const char * const alc662_models[ALC662_MODEL_LAST] = { + [ALC662_3ST_2ch_DIG] = "3stack-dig", + [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig", + [ALC662_3ST_6ch] = "3stack-6ch", + [ALC662_5ST_DIG] = "5stack-dig", + [ALC662_LENOVO_101E] = "lenovo-101e", + [ALC662_ASUS_EEEPC_P701] = "eeepc-p701", + [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20", + [ALC662_ECS] = "ecs", + [ALC663_ASUS_M51VA] = "m51va", + [ALC663_ASUS_G71V] = "g71v", + [ALC663_ASUS_H13] = "h13", + [ALC663_ASUS_G50V] = "g50v", + [ALC663_ASUS_MODE1] = "asus-mode1", + [ALC662_ASUS_MODE2] = "asus-mode2", + [ALC663_ASUS_MODE3] = "asus-mode3", + [ALC663_ASUS_MODE4] = "asus-mode4", + [ALC663_ASUS_MODE5] = "asus-mode5", + [ALC663_ASUS_MODE6] = "asus-mode6", + [ALC663_ASUS_MODE7] = "asus-mode7", + [ALC663_ASUS_MODE8] = "asus-mode8", + [ALC272_DELL] = "dell", + [ALC272_DELL_ZM1] = "dell-zm1", + [ALC272_SAMSUNG_NC10] = "samsung-nc10", + [ALC662_AUTO] = "auto", +}; + +static const struct snd_pci_quirk alc662_cfg_tbl[] = { + SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS), + SND_PCI_QUIRK(0x1028, 0x02d6, "DELL", ALC272_DELL), + SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1), + SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3), + SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3), + SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC663_ASUS_MODE7), + SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC663_ASUS_MODE7), + SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC663_ASUS_MODE8), + SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC663_ASUS_MODE3), + SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6), + SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6), + SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC663_ASUS_MODE3), + SND_PCI_QUIRK(0x1043, 0x17c3, "ASUS UX20", ALC663_ASUS_M51VA), + SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5), + SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6), + SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA), + /*SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),*/ + SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3), + SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3), + SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3), + SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V), + /*SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),*/ + SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x19d3, "ASUS NB", ALC663_ASUS_M51VA), + SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4), + SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG), + SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701), + SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20), + SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS), + SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K", + ALC662_3ST_6ch_DIG), + SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB20x", ALC662_AUTO), + SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10), + SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L", + ALC662_3ST_6ch_DIG), + SND_PCI_QUIRK(0x152d, 0x2304, "Quanta WH1", ALC663_ASUS_H13), + SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG), + SND_PCI_QUIRK(0x1631, 0xc10c, "PB RS65", ALC663_ASUS_M51VA), + SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E), + SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0", + ALC662_3ST_6ch_DIG), + SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x", + ALC663_ASUS_H13), + SND_PCI_QUIRK(0x1991, 0x5628, "Ordissimo EVE", ALC662_LENOVO_101E), + {} +}; + +static const struct alc_config_preset alc662_presets[] = { + [ALC662_3ST_2ch_DIG] = { + .mixers = { alc662_3ST_2ch_mixer }, + .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .dig_in_nid = ALC662_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .input_mux = &alc662_capture_source, }, - [ALC275_FIXUP_SONY_VAIO_GPIO2] = { - .type = ALC_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - {0x01, AC_VERB_SET_GPIO_MASK, 0x04}, - {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04}, - {0x01, AC_VERB_SET_GPIO_DATA, 0x00}, - { } - }, - .chained = true, - .chain_id = ALC269_FIXUP_SONY_VAIO + [ALC662_3ST_6ch_DIG] = { + .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer }, + .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .dig_in_nid = ALC662_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), + .channel_mode = alc662_3ST_6ch_modes, + .need_dac_fix = 1, + .input_mux = &alc662_capture_source, }, - [ALC269_FIXUP_DELL_M101Z] = { - .type = ALC_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - /* Enables internal speaker */ - {0x20, AC_VERB_SET_COEF_INDEX, 13}, - {0x20, AC_VERB_SET_PROC_COEF, 0x4040}, - {} - } + [ALC662_3ST_6ch] = { + .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer }, + .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), + .channel_mode = alc662_3ST_6ch_modes, + .need_dac_fix = 1, + .input_mux = &alc662_capture_source, }, - [ALC269_FIXUP_SKU_IGNORE] = { - .type = ALC_FIXUP_SKU, - .v.sku = ALC_FIXUP_SKU_IGNORE, + [ALC662_5ST_DIG] = { + .mixers = { alc662_base_mixer, alc662_chmode_mixer }, + .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .dig_in_nid = ALC662_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes), + .channel_mode = alc662_5stack_modes, + .input_mux = &alc662_capture_source, }, - [ALC269_FIXUP_ASUS_G73JW] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x17, 0x99130111 }, /* subwoofer */ - { } - } + [ALC662_LENOVO_101E] = { + .mixers = { alc662_lenovo_101e_mixer }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc662_sue_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .input_mux = &alc662_lenovo_101e_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc662_lenovo_101e_setup, + .init_hook = alc_inithook, }, - [ALC269_FIXUP_LENOVO_EAPD] = { - .type = ALC_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0}, - {} - } + [ALC662_ASUS_EEEPC_P701] = { + .mixers = { alc662_eeepc_p701_mixer }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc662_eeepc_sue_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc662_eeepc_setup, + .init_hook = alc_inithook, }, - [ALC275_FIXUP_SONY_HWEQ] = { - .type = ALC_FIXUP_FUNC, - .v.func = alc269_fixup_hweq, - .chained = true, - .chain_id = ALC275_FIXUP_SONY_VAIO_GPIO2 + [ALC662_ASUS_EEEPC_EP20] = { + .mixers = { alc662_eeepc_ep20_mixer, + alc662_chmode_mixer }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc662_eeepc_ep20_sue_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), + .channel_mode = alc662_3ST_6ch_modes, + .input_mux = &alc662_lenovo_101e_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc662_eeepc_ep20_setup, + .init_hook = alc_inithook, }, - [ALC271_FIXUP_DMIC] = { - .type = ALC_FIXUP_FUNC, - .v.func = alc271_fixup_dmic, + [ALC662_ECS] = { + .mixers = { alc662_ecs_mixer }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc662_ecs_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc662_eeepc_setup, + .init_hook = alc_inithook, }, - [ALC269_FIXUP_PCM_44K] = { - .type = ALC_FIXUP_FUNC, - .v.func = alc269_fixup_pcm_44k, + [ALC663_ASUS_M51VA] = { + .mixers = { alc663_m51va_mixer }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_m51va_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc663_m51va_setup, + .init_hook = alc_inithook, + }, + [ALC663_ASUS_G71V] = { + .mixers = { alc663_g71v_mixer }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_g71v_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc663_g71v_setup, + .init_hook = alc_inithook, + }, + [ALC663_ASUS_H13] = { + .mixers = { alc663_m51va_mixer }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_m51va_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .setup = alc663_m51va_setup, + .unsol_event = alc_sku_unsol_event, + .init_hook = alc_inithook, + }, + [ALC663_ASUS_G50V] = { + .mixers = { alc663_g50v_mixer }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_g50v_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), + .channel_mode = alc662_3ST_6ch_modes, + .input_mux = &alc663_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc663_g50v_setup, + .init_hook = alc_inithook, + }, + [ALC663_ASUS_MODE1] = { + .mixers = { alc663_m51va_mixer }, + .cap_mixer = alc662_auto_capture_mixer, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_21jd_amic_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .hp_nid = 0x03, + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc663_mode1_setup, + .init_hook = alc_inithook, + }, + [ALC662_ASUS_MODE2] = { + .mixers = { alc662_1bjd_mixer }, + .cap_mixer = alc662_auto_capture_mixer, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc662_1bjd_amic_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc662_mode2_setup, + .init_hook = alc_inithook, + }, + [ALC663_ASUS_MODE3] = { + .mixers = { alc663_two_hp_m1_mixer }, + .cap_mixer = alc662_auto_capture_mixer, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_two_hp_amic_m1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .hp_nid = 0x03, + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc663_mode3_setup, + .init_hook = alc_inithook, + }, + [ALC663_ASUS_MODE4] = { + .mixers = { alc663_asus_21jd_clfe_mixer }, + .cap_mixer = alc662_auto_capture_mixer, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_21jd_amic_init_verbs}, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .hp_nid = 0x03, + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc663_mode4_setup, + .init_hook = alc_inithook, + }, + [ALC663_ASUS_MODE5] = { + .mixers = { alc663_asus_15jd_clfe_mixer }, + .cap_mixer = alc662_auto_capture_mixer, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_15jd_amic_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .hp_nid = 0x03, + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc663_mode5_setup, + .init_hook = alc_inithook, + }, + [ALC663_ASUS_MODE6] = { + .mixers = { alc663_two_hp_m2_mixer }, + .cap_mixer = alc662_auto_capture_mixer, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_two_hp_amic_m2_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .hp_nid = 0x03, + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc663_mode6_setup, + .init_hook = alc_inithook, + }, + [ALC663_ASUS_MODE7] = { + .mixers = { alc663_mode7_mixer }, + .cap_mixer = alc662_auto_capture_mixer, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_mode7_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .hp_nid = 0x03, + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc663_mode7_setup, + .init_hook = alc_inithook, + }, + [ALC663_ASUS_MODE8] = { + .mixers = { alc663_mode8_mixer }, + .cap_mixer = alc662_auto_capture_mixer, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_mode8_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .hp_nid = 0x03, + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc663_mode8_setup, + .init_hook = alc_inithook, + }, + [ALC272_DELL] = { + .mixers = { alc663_m51va_mixer }, + .cap_mixer = alc272_auto_capture_mixer, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc272_dell_init_verbs }, + .num_dacs = ARRAY_SIZE(alc272_dac_nids), + .dac_nids = alc272_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .adc_nids = alc272_adc_nids, + .num_adc_nids = ARRAY_SIZE(alc272_adc_nids), + .capsrc_nids = alc272_capsrc_nids, + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc663_m51va_setup, + .init_hook = alc_inithook, + }, + [ALC272_DELL_ZM1] = { + .mixers = { alc663_m51va_mixer }, + .cap_mixer = alc662_auto_capture_mixer, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc272_dell_zm1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc272_dac_nids), + .dac_nids = alc272_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .adc_nids = alc662_adc_nids, + .num_adc_nids = 1, + .capsrc_nids = alc662_capsrc_nids, + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc663_m51va_setup, + .init_hook = alc_inithook, + }, + [ALC272_SAMSUNG_NC10] = { + .mixers = { alc272_nc10_mixer }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_21jd_amic_init_verbs }, + .num_dacs = ARRAY_SIZE(alc272_dac_nids), + .dac_nids = alc272_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + /*.input_mux = &alc272_nc10_capture_source,*/ + .unsol_event = alc_sku_unsol_event, + .setup = alc663_mode4_setup, + .init_hook = alc_inithook, }, }; -static const struct snd_pci_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW), - SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2), - SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), - SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), - SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), - SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), - SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC), - SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE), - SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE), - SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE), - SND_PCI_QUIRK(0x17aa, 0x21ca, "Thinkpad L412", ALC269_FIXUP_SKU_IGNORE), - SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE), - SND_PCI_QUIRK(0x17aa, 0x3bf8, "Lenovo Ideapd", ALC269_FIXUP_PCM_44K), - SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD), - {} -}; +/* + * BIOS auto configuration + */ -static int alc269_fill_coef(struct hda_codec *codec) +/* convert from MIX nid to DAC */ +static hda_nid_t alc_auto_mix_to_dac(struct hda_codec *codec, hda_nid_t nid) { - int val; - - if ((alc_read_coef_idx(codec, 0) & 0x00ff) < 0x015) { - alc_write_coef_idx(codec, 0xf, 0x960b); - alc_write_coef_idx(codec, 0xe, 0x8817); - } - - if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x016) { - alc_write_coef_idx(codec, 0xf, 0x960b); - alc_write_coef_idx(codec, 0xe, 0x8814); - } - - if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) { - val = alc_read_coef_idx(codec, 0x04); - /* Power up output pin */ - alc_write_coef_idx(codec, 0x04, val | (1<<11)); - } + hda_nid_t list[5]; + int i, num; - if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) { - val = alc_read_coef_idx(codec, 0xd); - if ((val & 0x0c00) >> 10 != 0x1) { - /* Capless ramp up clock control */ - alc_write_coef_idx(codec, 0xd, val | (1<<10)); - } - val = alc_read_coef_idx(codec, 0x17); - if ((val & 0x01c0) >> 6 != 0x4) { - /* Class D power on reset */ - alc_write_coef_idx(codec, 0x17, val | (1<<7)); - } + num = snd_hda_get_connections(codec, nid, list, ARRAY_SIZE(list)); + for (i = 0; i < num; i++) { + if (get_wcaps_type(get_wcaps(codec, list[i])) == AC_WID_AUD_OUT) + return list[i]; } - - val = alc_read_coef_idx(codec, 0xd); /* Class D */ - alc_write_coef_idx(codec, 0xd, val | (1<<14)); - - val = alc_read_coef_idx(codec, 0x4); /* HP */ - alc_write_coef_idx(codec, 0x4, val | (1<<11)); - return 0; } -/* - */ -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS -#include "alc269_quirks.c" -#endif - -static int patch_alc269(struct hda_codec *codec) +/* go down to the selector widget before the mixer */ +static hda_nid_t alc_go_down_to_selector(struct hda_codec *codec, hda_nid_t pin) { - struct alc_spec *spec; - int board_config, coef; - int err; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; - - spec->mixer_nid = 0x0b; - - alc_auto_parse_customize_define(codec); - - if (codec->vendor_id == 0x10ec0269) { - spec->codec_variant = ALC269_TYPE_ALC269VA; - coef = alc_read_coef_idx(codec, 0); - if ((coef & 0x00f0) == 0x0010) { - if (codec->bus->pci->subsystem_vendor == 0x1025 && - spec->cdefine.platform_type == 1) { - alc_codec_rename(codec, "ALC271X"); - } else if ((coef & 0xf000) == 0x2000) { - alc_codec_rename(codec, "ALC259"); - } else if ((coef & 0xf000) == 0x3000) { - alc_codec_rename(codec, "ALC258"); - } else if ((coef & 0xfff0) == 0x3010) { - alc_codec_rename(codec, "ALC277"); - } else { - alc_codec_rename(codec, "ALC269VB"); - } - spec->codec_variant = ALC269_TYPE_ALC269VB; - } else if ((coef & 0x00f0) == 0x0020) { - if (coef == 0xa023) - alc_codec_rename(codec, "ALC259"); - else if (coef == 0x6023) - alc_codec_rename(codec, "ALC281X"); - else if (codec->bus->pci->subsystem_vendor == 0x17aa && - codec->bus->pci->subsystem_device == 0x21f3) - alc_codec_rename(codec, "ALC3202"); - else - alc_codec_rename(codec, "ALC269VC"); - spec->codec_variant = ALC269_TYPE_ALC269VC; - } else - alc_fix_pll_init(codec, 0x20, 0x04, 15); - alc269_fill_coef(codec); - } + hda_nid_t srcs[5]; + int num = snd_hda_get_connections(codec, pin, srcs, + ARRAY_SIZE(srcs)); + if (num != 1 || + get_wcaps_type(get_wcaps(codec, srcs[0])) != AC_WID_AUD_SEL) + return pin; + return srcs[0]; +} - board_config = alc_board_config(codec, ALC269_MODEL_LAST, - alc269_models, alc269_cfg_tbl); +/* get MIX nid connected to the given pin targeted to DAC */ +static hda_nid_t alc_auto_dac_to_mix(struct hda_codec *codec, hda_nid_t pin, + hda_nid_t dac) +{ + hda_nid_t mix[5]; + int i, num; - if (board_config < 0) { - printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - board_config = ALC_MODEL_AUTO; + pin = alc_go_down_to_selector(codec, pin); + num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix)); + for (i = 0; i < num; i++) { + if (alc_auto_mix_to_dac(codec, mix[i]) == dac) + return mix[i]; } + return 0; +} - if (board_config == ALC_MODEL_AUTO) { - alc_pick_fixup(codec, NULL, alc269_fixup_tbl, alc269_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); - } +/* select the connection from pin to DAC if needed */ +static int alc_auto_select_dac(struct hda_codec *codec, hda_nid_t pin, + hda_nid_t dac) +{ + hda_nid_t mix[5]; + int i, num; - if (board_config == ALC_MODEL_AUTO) { - /* automatic parse from the BIOS config */ - err = alc269_parse_auto_config(codec); - if (err < 0) { - alc_free(codec); - return err; - } -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS - else if (!err) { - printk(KERN_INFO - "hda_codec: Cannot set up configuration " - "from BIOS. Using base mode...\n"); - board_config = ALC269_BASIC; + pin = alc_go_down_to_selector(codec, pin); + num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix)); + if (num < 2) + return 0; + for (i = 0; i < num; i++) { + if (alc_auto_mix_to_dac(codec, mix[i]) == dac) { + snd_hda_codec_update_cache(codec, pin, 0, + AC_VERB_SET_CONNECT_SEL, i); + return 0; } -#endif } + return 0; +} - if (board_config != ALC_MODEL_AUTO) - setup_preset(codec, &alc269_presets[board_config]); +/* look for an empty DAC slot */ +static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t srcs[5]; + int i, j, num; - if (!spec->no_analog && !spec->adc_nids && spec->input_mux) { - alc_auto_fill_adc_caps(codec); - alc_rebuild_imux_for_auto_mic(codec); - alc_remove_invalid_adc_nids(codec); + pin = alc_go_down_to_selector(codec, pin); + num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs)); + for (i = 0; i < num; i++) { + hda_nid_t nid = alc_auto_mix_to_dac(codec, srcs[i]); + if (!nid) + continue; + for (j = 0; j < spec->multiout.num_dacs; j++) + if (spec->multiout.dac_nids[j] == nid) + break; + if (j >= spec->multiout.num_dacs) + return nid; } + return 0; +} - if (!spec->no_analog && !spec->cap_mixer) - set_capture_mixer(codec); +/* fill in the dac_nids table from the parsed pin configuration */ +static int alc662_auto_fill_dac_nids(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) +{ + struct alc_spec *spec = codec->spec; + int i; + hda_nid_t dac; - if (!spec->no_analog && has_cdefine_beep(codec)) { - err = snd_hda_attach_beep_device(codec, 0x1); - if (err < 0) { - alc_free(codec); - return err; - } - set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); + spec->multiout.dac_nids = spec->private_dac_nids; + for (i = 0; i < cfg->line_outs; i++) { + dac = alc_auto_look_for_dac(codec, cfg->line_out_pins[i]); + if (!dac) + continue; + spec->private_dac_nids[spec->multiout.num_dacs++] = dac; } - - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); - - spec->vmaster_nid = 0x02; - - codec->patch_ops = alc_patch_ops; -#ifdef SND_HDA_NEEDS_RESUME - codec->patch_ops.resume = alc269_resume; -#endif - if (board_config == ALC_MODEL_AUTO) - spec->init_hook = alc_auto_init_std; - spec->shutup = alc269_shutup; - - alc_init_jacks(codec); -#ifdef CONFIG_SND_HDA_POWER_SAVE - if (!spec->loopback.amplist) - spec->loopback.amplist = alc269_loopbacks; - if (alc269_mic2_for_mute_led(codec)) - codec->patch_ops.check_power_status = alc269_mic2_mute_check_ps; -#endif - return 0; } -/* - * ALC861 - */ +static inline int __alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx, + hda_nid_t nid, int idx, unsigned int chs) +{ + return __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, idx, + HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); +} -static int alc861_parse_auto_config(struct hda_codec *codec) +static inline int __alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx, + hda_nid_t nid, int idx, unsigned int chs) { - static const hda_nid_t alc861_ignore[] = { 0x1d, 0 }; - static const hda_nid_t alc861_ssids[] = { 0x0e, 0x0f, 0x0b, 0 }; - return alc_parse_auto_config(codec, alc861_ignore, alc861_ssids); + return __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, idx, + HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT)); } -#ifdef CONFIG_SND_HDA_POWER_SAVE -static const struct hda_amp_list alc861_loopbacks[] = { - { 0x15, HDA_INPUT, 0 }, - { 0x15, HDA_INPUT, 1 }, - { 0x15, HDA_INPUT, 2 }, - { 0x15, HDA_INPUT, 3 }, - { } /* end */ -}; -#endif +#define alc662_add_vol_ctl(spec, pfx, nid, chs) \ + __alc662_add_vol_ctl(spec, pfx, nid, 0, chs) +#define alc662_add_sw_ctl(spec, pfx, nid, chs) \ + __alc662_add_sw_ctl(spec, pfx, nid, 0, chs) +#define alc662_add_stereo_vol(spec, pfx, nid) \ + alc662_add_vol_ctl(spec, pfx, nid, 3) +#define alc662_add_stereo_sw(spec, pfx, nid) \ + alc662_add_sw_ctl(spec, pfx, nid, 3) +/* add playback controls from the parsed DAC table */ +static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) +{ + struct alc_spec *spec = codec->spec; + static const char * const chname[4] = { + "Front", "Surround", NULL /*CLFE*/, "Side" + }; + const char *pfx = alc_get_line_out_pfx(spec, true); + hda_nid_t nid, mix, pin; + int i, err, noutputs; -/* Pin config fixes */ -enum { - PINFIX_FSC_AMILO_PI1505, -}; + noutputs = cfg->line_outs; + if (spec->multi_ios > 0) + noutputs += spec->multi_ios; -static const struct alc_fixup alc861_fixups[] = { - [PINFIX_FSC_AMILO_PI1505] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x0b, 0x0221101f }, /* HP */ - { 0x0f, 0x90170310 }, /* speaker */ - { } + for (i = 0; i < noutputs; i++) { + nid = spec->multiout.dac_nids[i]; + if (!nid) + continue; + if (i >= cfg->line_outs) + pin = spec->multi_io[i - 1].pin; + else + pin = cfg->line_out_pins[i]; + mix = alc_auto_dac_to_mix(codec, pin, nid); + if (!mix) + continue; + if (!pfx && i == 2) { + /* Center/LFE */ + err = alc662_add_vol_ctl(spec, "Center", nid, 1); + if (err < 0) + return err; + err = alc662_add_vol_ctl(spec, "LFE", nid, 2); + if (err < 0) + return err; + err = alc662_add_sw_ctl(spec, "Center", mix, 1); + if (err < 0) + return err; + err = alc662_add_sw_ctl(spec, "LFE", mix, 2); + if (err < 0) + return err; + } else { + const char *name = pfx; + int index = i; + if (!name) { + name = chname[i]; + index = 0; + } + err = __alc662_add_vol_ctl(spec, name, nid, index, 3); + if (err < 0) + return err; + err = __alc662_add_sw_ctl(spec, name, mix, index, 3); + if (err < 0) + return err; } - }, -}; - -static const struct snd_pci_quirk alc861_fixup_tbl[] = { - SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505), - {} -}; - -/* - */ -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS -#include "alc861_quirks.c" -#endif + } + return 0; +} -static int patch_alc861(struct hda_codec *codec) +/* add playback controls for speaker and HP outputs */ +/* return DAC nid if any new DAC is assigned */ +static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, + const char *pfx) { - struct alc_spec *spec; - int board_config; + struct alc_spec *spec = codec->spec; + hda_nid_t nid, mix; int err; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; + if (!pin) + return 0; + nid = alc_auto_look_for_dac(codec, pin); + if (!nid) { + /* the corresponding DAC is already occupied */ + if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)) + return 0; /* no way */ + /* create a switch only */ + return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); + } - codec->spec = spec; + mix = alc_auto_dac_to_mix(codec, pin, nid); + if (!mix) + return 0; + err = alc662_add_vol_ctl(spec, pfx, nid, 3); + if (err < 0) + return err; + err = alc662_add_sw_ctl(spec, pfx, mix, 3); + if (err < 0) + return err; + return nid; +} - spec->mixer_nid = 0x15; +/* create playback/capture controls for input pins */ +#define alc662_auto_create_input_ctls \ + alc882_auto_create_input_ctls - board_config = alc_board_config(codec, ALC861_MODEL_LAST, - alc861_models, alc861_cfg_tbl); +static void alc662_auto_set_output_and_unmute(struct hda_codec *codec, + hda_nid_t nid, int pin_type, + hda_nid_t dac) +{ + int i, num; + hda_nid_t srcs[HDA_MAX_CONNECTIONS]; - if (board_config < 0) { - printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - board_config = ALC_MODEL_AUTO; + alc_set_pin_output(codec, nid, pin_type); + num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs)); + for (i = 0; i < num; i++) { + if (alc_auto_mix_to_dac(codec, srcs[i]) != dac) + continue; + /* need the manual connection? */ + if (num > 1) + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_CONNECT_SEL, i); + /* unmute mixer widget inputs */ + snd_hda_codec_write(codec, srcs[i], 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_UNMUTE(0)); + snd_hda_codec_write(codec, srcs[i], 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_UNMUTE(1)); + return; } +} - if (board_config == ALC_MODEL_AUTO) { - alc_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); +static void alc662_auto_init_multi_out(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int pin_type = get_pin_type(spec->autocfg.line_out_type); + int i; + + for (i = 0; i <= HDA_SIDE; i++) { + hda_nid_t nid = spec->autocfg.line_out_pins[i]; + if (nid) + alc662_auto_set_output_and_unmute(codec, nid, pin_type, + spec->multiout.dac_nids[i]); } +} - if (board_config == ALC_MODEL_AUTO) { - /* automatic parse from the BIOS config */ - err = alc861_parse_auto_config(codec); - if (err < 0) { - alc_free(codec); - return err; +static void alc662_auto_init_hp_out(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t pin; + + pin = spec->autocfg.hp_pins[0]; + if (pin) + alc662_auto_set_output_and_unmute(codec, pin, PIN_HP, + spec->multiout.hp_nid); + pin = spec->autocfg.speaker_pins[0]; + if (pin) + alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT, + spec->multiout.extra_out_nid[0]); +} + +#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID + +static void alc662_auto_init_analog_input(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i; + + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; + if (alc_is_input_pin(codec, nid)) { + alc_set_input_pin(codec, nid, cfg->inputs[i].type); + if (nid != ALC662_PIN_CD_NID && + (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)) + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_OUT_MUTE); } -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS - else if (!err) { - printk(KERN_INFO - "hda_codec: Cannot set up configuration " - "from BIOS. Using base mode...\n"); - board_config = ALC861_3ST_DIG; + } +} + +#define alc662_auto_init_input_src alc882_auto_init_input_src + +/* + * multi-io helper + */ +static int alc_auto_fill_multi_ios(struct hda_codec *codec, + unsigned int location) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int type, i, num_pins = 0; + + for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) { + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; + hda_nid_t dac; + unsigned int defcfg, caps; + if (cfg->inputs[i].type != type) + continue; + defcfg = snd_hda_codec_get_pincfg(codec, nid); + if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX) + continue; + if (location && get_defcfg_location(defcfg) != location) + continue; + caps = snd_hda_query_pin_caps(codec, nid); + if (!(caps & AC_PINCAP_OUT)) + continue; + dac = alc_auto_look_for_dac(codec, nid); + if (!dac) + continue; + spec->multi_io[num_pins].pin = nid; + spec->multi_io[num_pins].dac = dac; + num_pins++; + spec->private_dac_nids[spec->multiout.num_dacs++] = dac; } -#endif - } - - if (board_config != ALC_MODEL_AUTO) - setup_preset(codec, &alc861_presets[board_config]); - - if (!spec->no_analog && !spec->adc_nids && spec->input_mux) { - alc_auto_fill_adc_caps(codec); - alc_rebuild_imux_for_auto_mic(codec); - alc_remove_invalid_adc_nids(codec); } + spec->multiout.num_dacs = 1; + if (num_pins < 2) + return 0; + return num_pins; +} - if (!spec->no_analog && !spec->cap_mixer) - set_capture_mixer(codec); +static int alc_auto_ch_mode_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; - if (!spec->no_analog) { - err = snd_hda_attach_beep_device(codec, 0x23); - if (err < 0) { - alc_free(codec); - return err; - } - set_beep_amp(spec, 0x23, 0, HDA_OUTPUT); - } + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = spec->multi_ios + 1; + if (uinfo->value.enumerated.item > spec->multi_ios) + uinfo->value.enumerated.item = spec->multi_ios; + sprintf(uinfo->value.enumerated.name, "%dch", + (uinfo->value.enumerated.item + 1) * 2); + return 0; +} - spec->vmaster_nid = 0x03; +static int alc_auto_ch_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + ucontrol->value.enumerated.item[0] = (spec->ext_channel_count - 1) / 2; + return 0; +} - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); +static int alc_set_multi_io(struct hda_codec *codec, int idx, bool output) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t nid = spec->multi_io[idx].pin; - codec->patch_ops = alc_patch_ops; - if (board_config == ALC_MODEL_AUTO) { - spec->init_hook = alc_auto_init_std; -#ifdef CONFIG_SND_HDA_POWER_SAVE - spec->power_hook = alc_power_eapd; -#endif + if (!spec->multi_io[idx].ctl_in) + spec->multi_io[idx].ctl_in = + snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + if (output) { + snd_hda_codec_update_cache(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + PIN_OUT); + if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) + snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, 0); + alc_auto_select_dac(codec, nid, spec->multi_io[idx].dac); + } else { + if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) + snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); + snd_hda_codec_update_cache(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + spec->multi_io[idx].ctl_in); } -#ifdef CONFIG_SND_HDA_POWER_SAVE - if (!spec->loopback.amplist) - spec->loopback.amplist = alc861_loopbacks; -#endif - return 0; } -/* - * ALC861-VD support - * - * Based on ALC882 - * - * In addition, an independent DAC - */ -#ifdef CONFIG_SND_HDA_POWER_SAVE -#define alc861vd_loopbacks alc880_loopbacks -#endif - -static int alc861vd_parse_auto_config(struct hda_codec *codec) +static int alc_auto_ch_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - static const hda_nid_t alc861vd_ignore[] = { 0x1d, 0 }; - static const hda_nid_t alc861vd_ssids[] = { 0x15, 0x1b, 0x14, 0 }; - return alc_parse_auto_config(codec, alc861vd_ignore, alc861vd_ssids); -} - -enum { - ALC660VD_FIX_ASUS_GPIO1 -}; - -/* reset GPIO1 */ -static const struct alc_fixup alc861vd_fixups[] = { - [ALC660VD_FIX_ASUS_GPIO1] = { - .type = ALC_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - {0x01, AC_VERB_SET_GPIO_MASK, 0x03}, - {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, - {0x01, AC_VERB_SET_GPIO_DATA, 0x01}, - { } - } - }, -}; + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + int i, ch; -static const struct snd_pci_quirk alc861vd_fixup_tbl[] = { - SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1), - {} -}; + ch = ucontrol->value.enumerated.item[0]; + if (ch < 0 || ch > spec->multi_ios) + return -EINVAL; + if (ch == (spec->ext_channel_count - 1) / 2) + return 0; + spec->ext_channel_count = (ch + 1) * 2; + for (i = 0; i < spec->multi_ios; i++) + alc_set_multi_io(codec, i, i < ch); + spec->multiout.max_channels = spec->ext_channel_count; + return 1; +} -static const struct hda_verb alc660vd_eapd_verbs[] = { - {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, - {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, - { } +static const struct snd_kcontrol_new alc_auto_channel_mode_enum = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_auto_ch_mode_info, + .get = alc_auto_ch_mode_get, + .put = alc_auto_ch_mode_put, }; -/* - */ -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS -#include "alc861vd_quirks.c" -#endif - -static int patch_alc861vd(struct hda_codec *codec) +static int alc_auto_add_multi_channel_mode(struct hda_codec *codec) { - struct alc_spec *spec; - int err, board_config; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; - - spec->mixer_nid = 0x0b; - - board_config = alc_board_config(codec, ALC861VD_MODEL_LAST, - alc861vd_models, alc861vd_cfg_tbl); - - if (board_config < 0) { - printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - board_config = ALC_MODEL_AUTO; - } - - if (board_config == ALC_MODEL_AUTO) { - alc_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); - } - - if (board_config == ALC_MODEL_AUTO) { - /* automatic parse from the BIOS config */ - err = alc861vd_parse_auto_config(codec); - if (err < 0) { - alc_free(codec); - return err; - } -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS - else if (!err) { - printk(KERN_INFO - "hda_codec: Cannot set up configuration " - "from BIOS. Using base mode...\n"); - board_config = ALC861VD_3ST; - } -#endif - } + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + unsigned int location, defcfg; + int num_pins; - if (board_config != ALC_MODEL_AUTO) - setup_preset(codec, &alc861vd_presets[board_config]); + if (cfg->line_outs != 1 || + cfg->line_out_type != AUTO_PIN_LINE_OUT) + return 0; - if (codec->vendor_id == 0x10ec0660) { - /* always turn on EAPD */ - add_verb(spec, alc660vd_eapd_verbs); - } + defcfg = snd_hda_codec_get_pincfg(codec, cfg->line_out_pins[0]); + location = get_defcfg_location(defcfg); - if (!spec->no_analog && !spec->adc_nids && spec->input_mux) { - alc_auto_fill_adc_caps(codec); - alc_rebuild_imux_for_auto_mic(codec); - alc_remove_invalid_adc_nids(codec); - } + num_pins = alc_auto_fill_multi_ios(codec, location); + if (num_pins > 0) { + struct snd_kcontrol_new *knew; - if (!spec->no_analog && !spec->cap_mixer) - set_capture_mixer(codec); + knew = alc_kcontrol_new(spec); + if (!knew) + return -ENOMEM; + *knew = alc_auto_channel_mode_enum; + knew->name = kstrdup("Channel Mode", GFP_KERNEL); + if (!knew->name) + return -ENOMEM; - if (!spec->no_analog) { - err = snd_hda_attach_beep_device(codec, 0x23); - if (err < 0) { - alc_free(codec); - return err; - } - set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); + spec->multi_ios = num_pins; + spec->ext_channel_count = 2; + spec->multiout.num_dacs = num_pins + 1; } + return 0; +} - spec->vmaster_nid = 0x02; +static int alc662_parse_auto_config(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int err; + static const hda_nid_t alc662_ignore[] = { 0x1d, 0 }; - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, + alc662_ignore); + if (err < 0) + return err; + if (!spec->autocfg.line_outs) + return 0; /* can't find valid BIOS pin config */ - codec->patch_ops = alc_patch_ops; + err = alc662_auto_fill_dac_nids(codec, &spec->autocfg); + if (err < 0) + return err; + err = alc_auto_add_multi_channel_mode(codec); + if (err < 0) + return err; + err = alc662_auto_create_multi_out_ctls(codec, &spec->autocfg); + if (err < 0) + return err; + err = alc662_auto_create_extra_out(codec, + spec->autocfg.speaker_pins[0], + "Speaker"); + if (err < 0) + return err; + if (err) + spec->multiout.extra_out_nid[0] = err; + err = alc662_auto_create_extra_out(codec, spec->autocfg.hp_pins[0], + "Headphone"); + if (err < 0) + return err; + if (err) + spec->multiout.hp_nid = err; + err = alc662_auto_create_input_ctls(codec, &spec->autocfg); + if (err < 0) + return err; - if (board_config == ALC_MODEL_AUTO) - spec->init_hook = alc_auto_init_std; - spec->shutup = alc_eapd_shutup; -#ifdef CONFIG_SND_HDA_POWER_SAVE - if (!spec->loopback.amplist) - spec->loopback.amplist = alc861vd_loopbacks; -#endif + spec->multiout.max_channels = spec->multiout.num_dacs * 2; - return 0; -} + alc_auto_parse_digital(codec); -/* - * ALC662 support - * - * ALC662 is almost identical with ALC880 but has cleaner and more flexible - * configuration. Each pin widget can choose any input DACs and a mixer. - * Each ADC is connected from a mixer of all inputs. This makes possible - * 6-channel independent captures. - * - * In addition, an independent DAC for the multi-playback (not used in this - * driver yet). - */ -#ifdef CONFIG_SND_HDA_POWER_SAVE -#define alc662_loopbacks alc880_loopbacks -#endif + if (spec->kctls.list) + add_mixer(spec, spec->kctls.list); -/* - * BIOS auto configuration - */ + spec->num_mux_defs = 1; + spec->input_mux = &spec->private_imux[0]; -static int alc662_parse_auto_config(struct hda_codec *codec) -{ - static const hda_nid_t alc662_ignore[] = { 0x1d, 0 }; - static const hda_nid_t alc663_ssids[] = { 0x15, 0x1b, 0x14, 0x21 }; - static const hda_nid_t alc662_ssids[] = { 0x15, 0x1b, 0x14, 0 }; - const hda_nid_t *ssids; + err = alc_auto_add_mic_boost(codec); + if (err < 0) + return err; if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 || codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670) - ssids = alc663_ssids; + alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0x21); else - ssids = alc662_ssids; - return alc_parse_auto_config(codec, alc662_ignore, ssids); + alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0); + + return 1; +} + +/* additional initialization for auto-configuration model */ +static void alc662_auto_init(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + alc662_auto_init_multi_out(codec); + alc662_auto_init_hp_out(codec); + alc662_auto_init_analog_input(codec); + alc662_auto_init_input_src(codec); + alc_auto_init_digital(codec); + if (spec->unsol_event) + alc_inithook(codec); } static void alc272_fixup_mario(struct hda_codec *codec, @@ -5070,7 +19459,6 @@ enum { ALC272_FIXUP_MARIO, ALC662_FIXUP_CZC_P10T, ALC662_FIXUP_SKU_IGNORE, - ALC662_FIXUP_HP_RP5800, }; static const struct alc_fixup alc662_fixups[] = { @@ -5103,22 +19491,12 @@ static const struct alc_fixup alc662_fixups[] = { .type = ALC_FIXUP_SKU, .v.sku = ALC_FIXUP_SKU_IGNORE, }, - [ALC662_FIXUP_HP_RP5800] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x14, 0x0221201f }, /* HP out */ - { } - }, - .chained = true, - .chain_id = ALC662_FIXUP_SKU_IGNORE - }, }; static const struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE), SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE), - SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800), SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD), @@ -5132,12 +19510,6 @@ static const struct alc_model_fixup alc662_fixup_models[] = { }; -/* - */ -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS -#include "alc662_quirks.c" -#endif - static int patch_alc662(struct hda_codec *codec) { struct alc_spec *spec; @@ -5150,8 +19522,6 @@ static int patch_alc662(struct hda_codec *codec) codec->spec = spec; - spec->mixer_nid = 0x0b; - alc_auto_parse_customize_define(codec); alc_fix_pll_init(codec, 0x20, 0x04, 15); @@ -5166,15 +19536,16 @@ static int patch_alc662(struct hda_codec *codec) else if (coef == 0x4011) alc_codec_rename(codec, "ALC656"); - board_config = alc_board_config(codec, ALC662_MODEL_LAST, - alc662_models, alc662_cfg_tbl); + board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST, + alc662_models, + alc662_cfg_tbl); if (board_config < 0) { printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", codec->chip_name); - board_config = ALC_MODEL_AUTO; + board_config = ALC662_AUTO; } - if (board_config == ALC_MODEL_AUTO) { + if (board_config == ALC662_AUTO) { alc_pick_fixup(codec, alc662_fixup_models, alc662_fixup_tbl, alc662_fixups); alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); @@ -5183,35 +19554,42 @@ static int patch_alc662(struct hda_codec *codec) if (err < 0) { alc_free(codec); return err; - } -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS - else if (!err) { + } else if (!err) { printk(KERN_INFO "hda_codec: Cannot set up configuration " "from BIOS. Using base mode...\n"); board_config = ALC662_3ST_2ch_DIG; } -#endif } - if (board_config != ALC_MODEL_AUTO) + if (has_cdefine_beep(codec)) { + err = snd_hda_attach_beep_device(codec, 0x1); + if (err < 0) { + alc_free(codec); + return err; + } + } + + if (board_config != ALC662_AUTO) setup_preset(codec, &alc662_presets[board_config]); - if (!spec->no_analog && !spec->adc_nids && spec->input_mux) { - alc_auto_fill_adc_caps(codec); - alc_rebuild_imux_for_auto_mic(codec); - alc_remove_invalid_adc_nids(codec); + spec->stream_analog_playback = &alc662_pcm_analog_playback; + spec->stream_analog_capture = &alc662_pcm_analog_capture; + + spec->stream_digital_playback = &alc662_pcm_digital_playback; + spec->stream_digital_capture = &alc662_pcm_digital_capture; + + if (!spec->adc_nids) { + spec->adc_nids = alc662_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids); } + if (!spec->capsrc_nids) + spec->capsrc_nids = alc662_capsrc_nids; - if (!spec->no_analog && !spec->cap_mixer) + if (!spec->cap_mixer) set_capture_mixer(codec); - if (!spec->no_analog && has_cdefine_beep(codec)) { - err = snd_hda_attach_beep_device(codec, 0x1); - if (err < 0) { - alc_free(codec); - return err; - } + if (has_cdefine_beep(codec)) { switch (codec->vendor_id) { case 0x10ec0662: set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); @@ -5231,8 +19609,8 @@ static int patch_alc662(struct hda_codec *codec) alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); codec->patch_ops = alc_patch_ops; - if (board_config == ALC_MODEL_AUTO) - spec->init_hook = alc_auto_init_std; + if (board_config == ALC662_AUTO) + spec->init_hook = alc662_auto_init; spec->shutup = alc_eapd_shutup; alc_init_jacks(codec); @@ -5274,17 +19652,389 @@ static int patch_alc899(struct hda_codec *codec) /* * ALC680 support */ +#define ALC680_DIGIN_NID ALC880_DIGIN_NID +#define ALC680_DIGOUT_NID ALC880_DIGOUT_NID +#define alc680_modes alc260_modes + +static const hda_nid_t alc680_dac_nids[3] = { + /* Lout1, Lout2, hp */ + 0x02, 0x03, 0x04 +}; + +static const hda_nid_t alc680_adc_nids[3] = { + /* ADC0-2 */ + /* DMIC, MIC, Line-in*/ + 0x07, 0x08, 0x09 +}; + +/* + * Analog capture ADC cgange + */ +static void alc680_rec_autoswitch(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int pin_found = 0; + int type_found = AUTO_PIN_LAST; + hda_nid_t nid; + int i; + + for (i = 0; i < cfg->num_inputs; i++) { + nid = cfg->inputs[i].pin; + if (!is_jack_detectable(codec, nid)) + continue; + if (snd_hda_jack_detect(codec, nid)) { + if (cfg->inputs[i].type < type_found) { + type_found = cfg->inputs[i].type; + pin_found = nid; + } + } + } + + nid = 0x07; + if (pin_found) + snd_hda_get_connections(codec, pin_found, &nid, 1); + + if (nid != spec->cur_adc) + __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); + spec->cur_adc = nid; + snd_hda_codec_setup_stream(codec, nid, spec->cur_adc_stream_tag, 0, + spec->cur_adc_format); +} + +static int alc680_capture_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + struct alc_spec *spec = codec->spec; + + spec->cur_adc = 0x07; + spec->cur_adc_stream_tag = stream_tag; + spec->cur_adc_format = format; + + alc680_rec_autoswitch(codec); + return 0; +} + +static int alc680_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + snd_hda_codec_cleanup_stream(codec, 0x07); + snd_hda_codec_cleanup_stream(codec, 0x08); + snd_hda_codec_cleanup_stream(codec, 0x09); + return 0; +} + +static const struct hda_pcm_stream alc680_pcm_analog_auto_capture = { + .substreams = 1, /* can be overridden */ + .channels_min = 2, + .channels_max = 2, + /* NID is set in alc_build_pcms */ + .ops = { + .prepare = alc680_capture_pcm_prepare, + .cleanup = alc680_capture_pcm_cleanup + }, +}; + +static const struct snd_kcontrol_new alc680_base_mixer[] = { + /* output mixer control */ + HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x4, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x16, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x12, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Line In Boost Volume", 0x19, 0, HDA_INPUT), + { } +}; + +static const struct hda_bind_ctls alc680_bind_cap_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT), + HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT), + HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT), + 0 + }, +}; + +static const struct hda_bind_ctls alc680_bind_cap_switch = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT), + HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT), + HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT), + 0 + }, +}; + +static const struct snd_kcontrol_new alc680_master_capture_mixer[] = { + HDA_BIND_VOL("Capture Volume", &alc680_bind_cap_vol), + HDA_BIND_SW("Capture Switch", &alc680_bind_cap_switch), + { } /* end */ +}; + +/* + * generic initialization of ADC, input mixers and output mixers + */ +static const struct hda_verb alc680_init_verbs[] = { + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + + {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, + {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, + + { } +}; + +/* toggle speaker-output according to the hp-jack state */ +static void alc680_base_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x16; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x15; + spec->autocfg.num_inputs = 2; + spec->autocfg.inputs[0].pin = 0x18; + spec->autocfg.inputs[0].type = AUTO_PIN_MIC; + spec->autocfg.inputs[1].pin = 0x19; + spec->autocfg.inputs[1].type = AUTO_PIN_LINE_IN; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static void alc680_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc_hp_automute(codec); + if ((res >> 26) == ALC880_MIC_EVENT) + alc680_rec_autoswitch(codec); +} + +static void alc680_inithook(struct hda_codec *codec) +{ + alc_hp_automute(codec); + alc680_rec_autoswitch(codec); +} + +/* create input playback/capture controls for the given pin */ +static int alc680_new_analog_output(struct alc_spec *spec, hda_nid_t nid, + const char *ctlname, int idx) +{ + hda_nid_t dac; + int err; + + switch (nid) { + case 0x14: + dac = 0x02; + break; + case 0x15: + dac = 0x03; + break; + case 0x16: + dac = 0x04; + break; + default: + return 0; + } + if (spec->multiout.dac_nids[0] != dac && + spec->multiout.dac_nids[1] != dac) { + err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, + HDA_COMPOSE_AMP_VAL(dac, 3, idx, + HDA_OUTPUT)); + if (err < 0) + return err; + + err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, + HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT)); + + if (err < 0) + return err; + spec->private_dac_nids[spec->multiout.num_dacs++] = dac; + } + + return 0; +} + +/* add playback controls from the parsed DAC table */ +static int alc680_auto_create_multi_out_ctls(struct alc_spec *spec, + const struct auto_pin_cfg *cfg) +{ + hda_nid_t nid; + int err; + + spec->multiout.dac_nids = spec->private_dac_nids; + + nid = cfg->line_out_pins[0]; + if (nid) { + const char *name; + if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) + name = "Speaker"; + else + name = "Front"; + err = alc680_new_analog_output(spec, nid, name, 0); + if (err < 0) + return err; + } + + nid = cfg->speaker_pins[0]; + if (nid) { + err = alc680_new_analog_output(spec, nid, "Speaker", 0); + if (err < 0) + return err; + } + nid = cfg->hp_pins[0]; + if (nid) { + err = alc680_new_analog_output(spec, nid, "Headphone", 0); + if (err < 0) + return err; + } + + return 0; +} + +static void alc680_auto_set_output_and_unmute(struct hda_codec *codec, + hda_nid_t nid, int pin_type) +{ + alc_set_pin_output(codec, nid, pin_type); +} + +static void alc680_auto_init_multi_out(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t nid = spec->autocfg.line_out_pins[0]; + if (nid) { + int pin_type = get_pin_type(spec->autocfg.line_out_type); + alc680_auto_set_output_and_unmute(codec, nid, pin_type); + } +} + +static void alc680_auto_init_hp_out(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t pin; + pin = spec->autocfg.hp_pins[0]; + if (pin) + alc680_auto_set_output_and_unmute(codec, pin, PIN_HP); + pin = spec->autocfg.speaker_pins[0]; + if (pin) + alc680_auto_set_output_and_unmute(codec, pin, PIN_OUT); +} + +/* pcm configuration: identical with ALC880 */ +#define alc680_pcm_analog_playback alc880_pcm_analog_playback +#define alc680_pcm_analog_capture alc880_pcm_analog_capture +#define alc680_pcm_analog_alt_capture alc880_pcm_analog_alt_capture +#define alc680_pcm_digital_playback alc880_pcm_digital_playback +#define alc680_pcm_digital_capture alc880_pcm_digital_capture + +/* + * BIOS auto configuration + */ static int alc680_parse_auto_config(struct hda_codec *codec) { - return alc_parse_auto_config(codec, NULL, NULL); + struct alc_spec *spec = codec->spec; + int err; + static const hda_nid_t alc680_ignore[] = { 0 }; + + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, + alc680_ignore); + if (err < 0) + return err; + + if (!spec->autocfg.line_outs) { + if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) { + spec->multiout.max_channels = 2; + spec->no_analog = 1; + goto dig_only; + } + return 0; /* can't find valid BIOS pin config */ + } + err = alc680_auto_create_multi_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + + spec->multiout.max_channels = 2; + + dig_only: + /* digital only support output */ + alc_auto_parse_digital(codec); + if (spec->kctls.list) + add_mixer(spec, spec->kctls.list); + + add_verb(spec, alc680_init_verbs); + + err = alc_auto_add_mic_boost(codec); + if (err < 0) + return err; + + return 1; +} + +#define alc680_auto_init_analog_input alc882_auto_init_analog_input + +/* init callback for auto-configuration model -- overriding the default init */ +static void alc680_auto_init(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + alc680_auto_init_multi_out(codec); + alc680_auto_init_hp_out(codec); + alc680_auto_init_analog_input(codec); + alc_auto_init_digital(codec); + if (spec->unsol_event) + alc_inithook(codec); } /* + * configuration and preset */ -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS -#include "alc680_quirks.c" -#endif +static const char * const alc680_models[ALC680_MODEL_LAST] = { + [ALC680_BASE] = "base", + [ALC680_AUTO] = "auto", +}; + +static const struct snd_pci_quirk alc680_cfg_tbl[] = { + SND_PCI_QUIRK(0x1043, 0x12f3, "ASUS NX90", ALC680_BASE), + {} +}; + +static const struct alc_config_preset alc680_presets[] = { + [ALC680_BASE] = { + .mixers = { alc680_base_mixer }, + .cap_mixer = alc680_master_capture_mixer, + .init_verbs = { alc680_init_verbs }, + .num_dacs = ARRAY_SIZE(alc680_dac_nids), + .dac_nids = alc680_dac_nids, + .dig_out_nid = ALC680_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc680_modes), + .channel_mode = alc680_modes, + .unsol_event = alc680_unsol_event, + .setup = alc680_base_setup, + .init_hook = alc680_inithook, + + }, +}; static int patch_alc680(struct hda_codec *codec) { @@ -5298,55 +20048,51 @@ static int patch_alc680(struct hda_codec *codec) codec->spec = spec; - /* ALC680 has no aa-loopback mixer */ + board_config = snd_hda_check_board_config(codec, ALC680_MODEL_LAST, + alc680_models, + alc680_cfg_tbl); - board_config = alc_board_config(codec, ALC680_MODEL_LAST, - alc680_models, alc680_cfg_tbl); - - if (board_config < 0) { + if (board_config < 0 || board_config >= ALC680_MODEL_LAST) { printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", codec->chip_name); - board_config = ALC_MODEL_AUTO; + board_config = ALC680_AUTO; } - if (board_config == ALC_MODEL_AUTO) { + if (board_config == ALC680_AUTO) { /* automatic parse from the BIOS config */ err = alc680_parse_auto_config(codec); if (err < 0) { alc_free(codec); return err; - } -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS - else if (!err) { + } else if (!err) { printk(KERN_INFO "hda_codec: Cannot set up configuration " "from BIOS. Using base mode...\n"); board_config = ALC680_BASE; } -#endif } - if (board_config != ALC_MODEL_AUTO) { + if (board_config != ALC680_AUTO) setup_preset(codec, &alc680_presets[board_config]); -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS - spec->stream_analog_capture = &alc680_pcm_analog_auto_capture; -#endif - } - if (!spec->no_analog && !spec->adc_nids && spec->input_mux) { - alc_auto_fill_adc_caps(codec); - alc_rebuild_imux_for_auto_mic(codec); - alc_remove_invalid_adc_nids(codec); + spec->stream_analog_playback = &alc680_pcm_analog_playback; + spec->stream_analog_capture = &alc680_pcm_analog_auto_capture; + spec->stream_digital_playback = &alc680_pcm_digital_playback; + spec->stream_digital_capture = &alc680_pcm_digital_capture; + + if (!spec->adc_nids) { + spec->adc_nids = alc680_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(alc680_adc_nids); } - if (!spec->no_analog && !spec->cap_mixer) + if (!spec->cap_mixer) set_capture_mixer(codec); spec->vmaster_nid = 0x02; codec->patch_ops = alc_patch_ops; - if (board_config == ALC_MODEL_AUTO) - spec->init_hook = alc_auto_init_std; + if (board_config == ALC680_AUTO) + spec->init_hook = alc680_auto_init; return 0; } diff --git a/trunk/sound/pci/hda/patch_sigmatel.c b/trunk/sound/pci/hda/patch_sigmatel.c index 56425a53cf1b..7f81cc2274f3 100644 --- a/trunk/sound/pci/hda/patch_sigmatel.c +++ b/trunk/sound/pci/hda/patch_sigmatel.c @@ -1112,9 +1112,7 @@ static int stac92xx_build_controls(struct hda_codec *codec) } if (spec->multiout.dig_out_nid) { - err = snd_hda_create_spdif_out_ctls(codec, - spec->multiout.dig_out_nid, - spec->multiout.dig_out_nid); + err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); if (err < 0) return err; err = snd_hda_create_spdif_share_sw(codec, @@ -3408,9 +3406,30 @@ static hda_nid_t get_connected_node(struct hda_codec *codec, hda_nid_t mux, return 0; } -/* look for NID recursively */ -#define get_connection_index(codec, mux, nid) \ - snd_hda_get_conn_index(codec, mux, nid, 1) +static int get_connection_index(struct hda_codec *codec, hda_nid_t mux, + hda_nid_t nid) +{ + hda_nid_t conn[HDA_MAX_NUM_INPUTS]; + int i, nums; + + if (!(get_wcaps(codec, mux) & AC_WCAP_CONN_LIST)) + return -1; + + nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn)); + for (i = 0; i < nums; i++) + if (conn[i] == nid) + return i; + + for (i = 0; i < nums; i++) { + unsigned int wid_caps = get_wcaps(codec, conn[i]); + unsigned int wid_type = get_wcaps_type(wid_caps); + + if (wid_type != AC_WID_PIN && wid_type != AC_WID_AUD_MIX) + if (get_connection_index(codec, conn[i], nid) >= 0) + return i; + } + return -1; +} /* create a volume assigned to the given pin (only if supported) */ /* return 1 if the volume control is created */ diff --git a/trunk/sound/pci/hda/patch_via.c b/trunk/sound/pci/hda/patch_via.c index f38160b00e16..f43bb0eaed8b 100644 --- a/trunk/sound/pci/hda/patch_via.c +++ b/trunk/sound/pci/hda/patch_via.c @@ -54,10 +54,36 @@ #include "hda_codec.h" #include "hda_local.h" +#define NID_MAPPING (-1) + +/* amp values */ +#define AMP_VAL_IDX_SHIFT 19 +#define AMP_VAL_IDX_MASK (0x0f<<19) + /* Pin Widget NID */ +#define VT1708_HP_NID 0x13 +#define VT1708_DIGOUT_NID 0x14 +#define VT1708_DIGIN_NID 0x16 +#define VT1708_DIGIN_PIN 0x26 #define VT1708_HP_PIN_NID 0x20 #define VT1708_CD_PIN_NID 0x24 +#define VT1709_HP_DAC_NID 0x28 +#define VT1709_DIGOUT_NID 0x13 +#define VT1709_DIGIN_NID 0x17 +#define VT1709_DIGIN_PIN 0x25 + +#define VT1708B_HP_NID 0x25 +#define VT1708B_DIGOUT_NID 0x12 +#define VT1708B_DIGIN_NID 0x15 +#define VT1708B_DIGIN_PIN 0x21 + +#define VT1708S_HP_NID 0x25 +#define VT1708S_DIGOUT_NID 0x12 + +#define VT1702_HP_NID 0x17 +#define VT1702_DIGOUT_NID 0x11 + enum VIA_HDA_CODEC { UNKNOWN = -1, VT1708, @@ -81,39 +107,6 @@ enum VIA_HDA_CODEC { (spec)->codec_type == VT1812 ||\ (spec)->codec_type == VT1802) -#define MAX_NID_PATH_DEPTH 5 - -/* output-path: DAC -> ... -> pin - * idx[] contains the source index number of the next widget; - * e.g. idx[0] is the index of the DAC selected by path[1] widget - * multi[] indicates whether it's a selector widget with multi-connectors - * (i.e. the connection selection is mandatory) - * vol_ctl and mute_ctl contains the NIDs for the assigned mixers - */ -struct nid_path { - int depth; - hda_nid_t path[MAX_NID_PATH_DEPTH]; - unsigned char idx[MAX_NID_PATH_DEPTH]; - unsigned char multi[MAX_NID_PATH_DEPTH]; - unsigned int vol_ctl; - unsigned int mute_ctl; -}; - -/* input-path */ -struct via_input { - hda_nid_t pin; /* input-pin or aa-mix */ - int adc_idx; /* ADC index to be used */ - int mux_idx; /* MUX index (if any) */ - const char *label; /* input-source label */ -}; - -#define VIA_MAX_ADCS 3 - -enum { - STREAM_MULTI_OUT = (1 << 0), - STREAM_INDEP_HP = (1 << 1), -}; - struct via_spec { /* codec parameterization */ const struct snd_kcontrol_new *mixers[6]; @@ -122,66 +115,28 @@ struct via_spec { const struct hda_verb *init_verbs[5]; unsigned int num_iverbs; - char stream_name_analog[32]; - char stream_name_hp[32]; + char *stream_name_analog; const struct hda_pcm_stream *stream_analog_playback; const struct hda_pcm_stream *stream_analog_capture; - char stream_name_digital[32]; + char *stream_name_digital; const struct hda_pcm_stream *stream_digital_playback; const struct hda_pcm_stream *stream_digital_capture; /* playback */ struct hda_multi_out multiout; hda_nid_t slave_dig_outs[2]; - hda_nid_t hp_dac_nid; - hda_nid_t speaker_dac_nid; - int hp_indep_shared; /* indep HP-DAC is shared with side ch */ - int opened_streams; /* STREAM_* bits */ - int active_streams; /* STREAM_* bits */ - int aamix_mode; /* loopback is enabled for output-path? */ - - /* Output-paths: - * There are different output-paths depending on the setup. - * out_path, hp_path and speaker_path are primary paths. If both - * direct DAC and aa-loopback routes are available, these contain - * the former paths. Meanwhile *_mix_path contain the paths with - * loopback mixer. (Since the loopback is only for front channel, - * no out_mix_path for surround channels.) - * The HP output has another path, hp_indep_path, which is used in - * the independent-HP mode. - */ - struct nid_path out_path[HDA_SIDE + 1]; - struct nid_path out_mix_path; - struct nid_path hp_path; - struct nid_path hp_mix_path; - struct nid_path hp_indep_path; - struct nid_path speaker_path; - struct nid_path speaker_mix_path; /* capture */ unsigned int num_adc_nids; - hda_nid_t adc_nids[VIA_MAX_ADCS]; - hda_nid_t mux_nids[VIA_MAX_ADCS]; - hda_nid_t aa_mix_nid; + const hda_nid_t *adc_nids; + hda_nid_t mux_nids[3]; hda_nid_t dig_in_nid; + hda_nid_t dig_in_pin; /* capture source */ - bool dyn_adc_switch; - int num_inputs; - struct via_input inputs[AUTO_CFG_MAX_INS + 1]; - unsigned int cur_mux[VIA_MAX_ADCS]; - - /* dynamic DAC switching */ - unsigned int cur_dac_stream_tag; - unsigned int cur_dac_format; - unsigned int cur_hp_stream_tag; - unsigned int cur_hp_format; - - /* dynamic ADC switching */ - hda_nid_t cur_adc; - unsigned int cur_adc_stream_tag; - unsigned int cur_adc_format; + const struct hda_input_mux *input_mux; + unsigned int cur_mux[3]; /* PCM information */ struct hda_pcm pcm_rec[3]; @@ -189,38 +144,28 @@ struct via_spec { /* dynamic controls, init_verbs and input_mux */ struct auto_pin_cfg autocfg; struct snd_array kctls; + struct hda_input_mux private_imux[2]; hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; /* HP mode source */ + const struct hda_input_mux *hp_mux; unsigned int hp_independent_mode; + unsigned int hp_independent_mode_index; + unsigned int smart51_enabled; unsigned int dmic_enabled; - unsigned int no_pin_power_ctl; enum VIA_HDA_CODEC codec_type; - /* smart51 setup */ - unsigned int smart51_nums; - hda_nid_t smart51_pins[2]; - int smart51_idxs[2]; - const char *smart51_labels[2]; - unsigned int smart51_enabled; - /* work to check hp jack state */ struct hda_codec *codec; struct delayed_work vt1708_hp_work; - int vt1708_jack_detect; + int vt1708_jack_detectect; int vt1708_hp_present; void (*set_widgets_power_state)(struct hda_codec *codec); +#ifdef CONFIG_SND_HDA_POWER_SAVE struct hda_loopback_check loopback; - int num_loopbacks; - struct hda_amp_list loopback_list[8]; - - /* bind capture-volume */ - struct hda_bind_ctls *bind_cap_vol; - struct hda_bind_ctls *bind_cap_sw; - - struct mutex config_mutex; +#endif }; static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec); @@ -232,7 +177,6 @@ static struct via_spec * via_new_spec(struct hda_codec *codec) if (spec == NULL) return NULL; - mutex_init(&spec->config_mutex); codec->spec = spec; spec->codec = codec; spec->codec_type = get_codec_type(codec); @@ -293,23 +237,33 @@ static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec) #define VIA_JACK_EVENT 0x20 #define VIA_HP_EVENT 0x01 #define VIA_GPIO_EVENT 0x02 -#define VIA_LINE_EVENT 0x03 +#define VIA_MONO_EVENT 0x03 +#define VIA_SPEAKER_EVENT 0x04 +#define VIA_BIND_HP_EVENT 0x05 enum { VIA_CTL_WIDGET_VOL, VIA_CTL_WIDGET_MUTE, VIA_CTL_WIDGET_ANALOG_MUTE, + VIA_CTL_WIDGET_BIND_PIN_MUTE, }; -static void analog_low_current_mode(struct hda_codec *codec); -static bool is_aa_path_mute(struct hda_codec *codec); +enum { + AUTO_SEQ_FRONT = 0, + AUTO_SEQ_SURROUND, + AUTO_SEQ_CENLFE, + AUTO_SEQ_SIDE +}; + +static void analog_low_current_mode(struct hda_codec *codec, int stream_idle); +static int is_aa_path_mute(struct hda_codec *codec); static void vt1708_start_hp_work(struct via_spec *spec) { if (spec->codec_type != VT1708 || spec->autocfg.hp_pins[0] == 0) return; snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81, - !spec->vt1708_jack_detect); + !spec->vt1708_jack_detectect); if (!delayed_work_pending(&spec->vt1708_hp_work)) schedule_delayed_work(&spec->vt1708_hp_work, msecs_to_jiffies(100)); @@ -323,7 +277,7 @@ static void vt1708_stop_hp_work(struct via_spec *spec) && !is_aa_path_mute(spec->codec)) return; snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81, - !spec->vt1708_jack_detect); + !spec->vt1708_jack_detectect); cancel_delayed_work_sync(&spec->vt1708_hp_work); } @@ -341,7 +295,7 @@ static int analog_input_switch_put(struct snd_kcontrol *kcontrol, struct hda_codec *codec = snd_kcontrol_chip(kcontrol); set_widgets_power_state(codec); - analog_low_current_mode(snd_kcontrol_chip(kcontrol)); + analog_low_current_mode(snd_kcontrol_chip(kcontrol), -1); if (snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") == 1) { if (is_aa_path_mute(codec)) vt1708_start_hp_work(codec->spec); @@ -361,44 +315,168 @@ static int analog_input_switch_put(struct snd_kcontrol *kcontrol, .put = analog_input_switch_put, \ .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0) } +static void via_hp_bind_automute(struct hda_codec *codec); + +static int bind_pin_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct via_spec *spec = codec->spec; + int i; + int change = 0; + + long *valp = ucontrol->value.integer.value; + int lmute, rmute; + if (strstr(kcontrol->id.name, "Switch") == NULL) { + snd_printd("Invalid control!\n"); + return change; + } + change = snd_hda_mixer_amp_switch_put(kcontrol, + ucontrol); + /* Get mute value */ + lmute = *valp ? 0 : HDA_AMP_MUTE; + valp++; + rmute = *valp ? 0 : HDA_AMP_MUTE; + + /* Set hp pins */ + if (!spec->hp_independent_mode) { + for (i = 0; i < spec->autocfg.hp_outs; i++) { + snd_hda_codec_amp_update( + codec, spec->autocfg.hp_pins[i], + 0, HDA_OUTPUT, 0, HDA_AMP_MUTE, + lmute); + snd_hda_codec_amp_update( + codec, spec->autocfg.hp_pins[i], + 1, HDA_OUTPUT, 0, HDA_AMP_MUTE, + rmute); + } + } + + if (!lmute && !rmute) { + /* Line Outs */ + for (i = 0; i < spec->autocfg.line_outs; i++) + snd_hda_codec_amp_stereo( + codec, spec->autocfg.line_out_pins[i], + HDA_OUTPUT, 0, HDA_AMP_MUTE, 0); + /* Speakers */ + for (i = 0; i < spec->autocfg.speaker_outs; i++) + snd_hda_codec_amp_stereo( + codec, spec->autocfg.speaker_pins[i], + HDA_OUTPUT, 0, HDA_AMP_MUTE, 0); + /* unmute */ + via_hp_bind_automute(codec); + + } else { + if (lmute) { + /* Mute all left channels */ + for (i = 1; i < spec->autocfg.line_outs; i++) + snd_hda_codec_amp_update( + codec, + spec->autocfg.line_out_pins[i], + 0, HDA_OUTPUT, 0, HDA_AMP_MUTE, + lmute); + for (i = 0; i < spec->autocfg.speaker_outs; i++) + snd_hda_codec_amp_update( + codec, + spec->autocfg.speaker_pins[i], + 0, HDA_OUTPUT, 0, HDA_AMP_MUTE, + lmute); + } + if (rmute) { + /* mute all right channels */ + for (i = 1; i < spec->autocfg.line_outs; i++) + snd_hda_codec_amp_update( + codec, + spec->autocfg.line_out_pins[i], + 1, HDA_OUTPUT, 0, HDA_AMP_MUTE, + rmute); + for (i = 0; i < spec->autocfg.speaker_outs; i++) + snd_hda_codec_amp_update( + codec, + spec->autocfg.speaker_pins[i], + 1, HDA_OUTPUT, 0, HDA_AMP_MUTE, + rmute); + } + } + return change; +} + +#define BIND_PIN_MUTE \ + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = NULL, \ + .index = 0, \ + .info = snd_hda_mixer_amp_switch_info, \ + .get = snd_hda_mixer_amp_switch_get, \ + .put = bind_pin_switch_put, \ + .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0) } + static const struct snd_kcontrol_new via_control_templates[] = { HDA_CODEC_VOLUME(NULL, 0, 0, 0), HDA_CODEC_MUTE(NULL, 0, 0, 0), ANALOG_INPUT_MUTE, + BIND_PIN_MUTE, }; +static const hda_nid_t vt1708_adc_nids[2] = { + /* ADC1-2 */ + 0x15, 0x27 +}; -/* add dynamic controls */ -static struct snd_kcontrol_new *__via_clone_ctl(struct via_spec *spec, - const struct snd_kcontrol_new *tmpl, - const char *name) -{ - struct snd_kcontrol_new *knew; +static const hda_nid_t vt1709_adc_nids[3] = { + /* ADC1-2 */ + 0x14, 0x15, 0x16 +}; + +static const hda_nid_t vt1708B_adc_nids[2] = { + /* ADC1-2 */ + 0x13, 0x14 +}; + +static const hda_nid_t vt1708S_adc_nids[2] = { + /* ADC1-2 */ + 0x13, 0x14 +}; + +static const hda_nid_t vt1702_adc_nids[3] = { + /* ADC1-2 */ + 0x12, 0x20, 0x1F +}; + +static const hda_nid_t vt1718S_adc_nids[2] = { + /* ADC1-2 */ + 0x10, 0x11 +}; + +static const hda_nid_t vt1716S_adc_nids[2] = { + /* ADC1-2 */ + 0x13, 0x14 +}; + +static const hda_nid_t vt2002P_adc_nids[2] = { + /* ADC1-2 */ + 0x10, 0x11 +}; + +static const hda_nid_t vt1812_adc_nids[2] = { + /* ADC1-2 */ + 0x10, 0x11 +}; - snd_array_init(&spec->kctls, sizeof(*knew), 32); - knew = snd_array_new(&spec->kctls); - if (!knew) - return NULL; - *knew = *tmpl; - if (!name) - name = tmpl->name; - if (name) { - knew->name = kstrdup(name, GFP_KERNEL); - if (!knew->name) - return NULL; - } - return knew; -} +/* add dynamic controls */ static int __via_add_control(struct via_spec *spec, int type, const char *name, int idx, unsigned long val) { struct snd_kcontrol_new *knew; - knew = __via_clone_ctl(spec, &via_control_templates[type], name); + snd_array_init(&spec->kctls, sizeof(*knew), 32); + knew = snd_array_new(&spec->kctls); if (!knew) return -ENOMEM; - knew->index = idx; + *knew = via_control_templates[type]; + knew->name = kstrdup(name, GFP_KERNEL); + if (!knew->name) + return -ENOMEM; if (get_amp_nid_(val)) knew->subdevice = HDA_SUBDEV_AMP_FLAG; knew->private_value = val; @@ -408,7 +486,21 @@ static int __via_add_control(struct via_spec *spec, int type, const char *name, #define via_add_control(spec, type, name, val) \ __via_add_control(spec, type, name, 0, val) -#define via_clone_control(spec, tmpl) __via_clone_ctl(spec, tmpl, NULL) +static struct snd_kcontrol_new *via_clone_control(struct via_spec *spec, + const struct snd_kcontrol_new *tmpl) +{ + struct snd_kcontrol_new *knew; + + snd_array_init(&spec->kctls, sizeof(*knew), 32); + knew = snd_array_new(&spec->kctls); + if (!knew) + return NULL; + *knew = *tmpl; + knew->name = kstrdup(tmpl->name, GFP_KERNEL); + if (!knew->name) + return NULL; + return knew; +} static void via_free_kctls(struct hda_codec *codec) { @@ -443,208 +535,58 @@ static int via_new_analog_input(struct via_spec *spec, const char *ctlname, return 0; } -#define get_connection_index(codec, mux, nid) \ - snd_hda_get_conn_index(codec, mux, nid, 0) - -static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, - unsigned int mask) -{ - unsigned int caps; - if (!nid) - return false; - caps = get_wcaps(codec, nid); - if (dir == HDA_INPUT) - caps &= AC_WCAP_IN_AMP; - else - caps &= AC_WCAP_OUT_AMP; - if (!caps) - return false; - if (query_amp_caps(codec, nid, dir) & mask) - return true; - return false; -} - -#define have_mute(codec, nid, dir) \ - check_amp_caps(codec, nid, dir, AC_AMPCAP_MUTE) - -/* enable/disable the output-route mixers */ -static void activate_output_mix(struct hda_codec *codec, struct nid_path *path, - hda_nid_t mix_nid, int idx, bool enable) -{ - int i, num, val; - - if (!path) - return; - num = snd_hda_get_conn_list(codec, mix_nid, NULL); - for (i = 0; i < num; i++) { - if (i == idx) - val = AMP_IN_UNMUTE(i); - else - val = AMP_IN_MUTE(i); - snd_hda_codec_write(codec, mix_nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, val); - } -} - -/* enable/disable the output-route */ -static void activate_output_path(struct hda_codec *codec, struct nid_path *path, - bool enable, bool force) -{ - struct via_spec *spec = codec->spec; - int i; - for (i = 0; i < path->depth; i++) { - hda_nid_t src, dst; - int idx = path->idx[i]; - src = path->path[i]; - if (i < path->depth - 1) - dst = path->path[i + 1]; - else - dst = 0; - if (enable && path->multi[i]) - snd_hda_codec_write(codec, dst, 0, - AC_VERB_SET_CONNECT_SEL, idx); - if (!force && (dst == spec->aa_mix_nid)) - continue; - if (have_mute(codec, dst, HDA_INPUT)) - activate_output_mix(codec, path, dst, idx, enable); - if (!force && (src == path->vol_ctl || src == path->mute_ctl)) - continue; - if (have_mute(codec, src, HDA_OUTPUT)) { - int val = enable ? AMP_OUT_UNMUTE : AMP_OUT_MUTE; - snd_hda_codec_write(codec, src, 0, - AC_VERB_SET_AMP_GAIN_MUTE, val); - } - } -} - -/* set the given pin as output */ -static void init_output_pin(struct hda_codec *codec, hda_nid_t pin, - int pin_type) +static void via_auto_set_output_and_unmute(struct hda_codec *codec, + hda_nid_t nid, int pin_type, + int dac_idx) { - if (!pin) - return; - snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + /* set as output */ + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); - if (snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_EAPD) - snd_hda_codec_write(codec, pin, 0, + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, + AMP_OUT_UNMUTE); + if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD) + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE, 0x02); } -static void via_auto_init_output(struct hda_codec *codec, - struct nid_path *path, int pin_type) -{ - unsigned int caps; - hda_nid_t pin; - - if (!path->depth) - return; - pin = path->path[path->depth - 1]; - - init_output_pin(codec, pin, pin_type); - caps = query_amp_caps(codec, pin, HDA_OUTPUT); - if (caps & AC_AMPCAP_MUTE) { - unsigned int val; - val = (caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; - snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_MUTE | val); - } - activate_output_path(codec, path, true, true); /* force on */ -} static void via_auto_init_multi_out(struct hda_codec *codec) { struct via_spec *spec = codec->spec; - struct nid_path *path; int i; - for (i = 0; i < spec->autocfg.line_outs + spec->smart51_nums; i++) { - path = &spec->out_path[i]; - if (!i && spec->aamix_mode && spec->out_mix_path.depth) - path = &spec->out_mix_path; - via_auto_init_output(codec, path, PIN_OUT); - } -} - -/* deactivate the inactive headphone-paths */ -static void deactivate_hp_paths(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int shared = spec->hp_indep_shared; - - if (spec->hp_independent_mode) { - activate_output_path(codec, &spec->hp_path, false, false); - activate_output_path(codec, &spec->hp_mix_path, false, false); - if (shared) - activate_output_path(codec, &spec->out_path[shared], - false, false); - } else if (spec->aamix_mode || !spec->hp_path.depth) { - activate_output_path(codec, &spec->hp_indep_path, false, false); - activate_output_path(codec, &spec->hp_path, false, false); - } else { - activate_output_path(codec, &spec->hp_indep_path, false, false); - activate_output_path(codec, &spec->hp_mix_path, false, false); + for (i = 0; i <= AUTO_SEQ_SIDE; i++) { + hda_nid_t nid = spec->autocfg.line_out_pins[i]; + if (nid) + via_auto_set_output_and_unmute(codec, nid, PIN_OUT, i); } } static void via_auto_init_hp_out(struct hda_codec *codec) { struct via_spec *spec = codec->spec; + hda_nid_t pin; + int i; - if (!spec->hp_path.depth) { - via_auto_init_output(codec, &spec->hp_mix_path, PIN_HP); - return; - } - deactivate_hp_paths(codec); - if (spec->hp_independent_mode) - via_auto_init_output(codec, &spec->hp_indep_path, PIN_HP); - else if (spec->aamix_mode) - via_auto_init_output(codec, &spec->hp_mix_path, PIN_HP); - else - via_auto_init_output(codec, &spec->hp_path, PIN_HP); -} - -static void via_auto_init_speaker_out(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - - if (!spec->autocfg.speaker_outs) - return; - if (!spec->speaker_path.depth) { - via_auto_init_output(codec, &spec->speaker_mix_path, PIN_OUT); - return; - } - if (!spec->aamix_mode) { - activate_output_path(codec, &spec->speaker_mix_path, - false, false); - via_auto_init_output(codec, &spec->speaker_path, PIN_OUT); - } else { - activate_output_path(codec, &spec->speaker_path, false, false); - via_auto_init_output(codec, &spec->speaker_mix_path, PIN_OUT); + for (i = 0; i < spec->autocfg.hp_outs; i++) { + pin = spec->autocfg.hp_pins[i]; + if (pin) /* connect to front */ + via_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); } } -static bool is_smart51_pins(struct hda_codec *codec, hda_nid_t pin); -static void via_hp_automute(struct hda_codec *codec); +static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin); static void via_auto_init_analog_input(struct hda_codec *codec) { struct via_spec *spec = codec->spec; const struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t conn[HDA_MAX_CONNECTIONS]; unsigned int ctl; - int i, num_conns; - - /* init ADCs */ - for (i = 0; i < spec->num_adc_nids; i++) { - snd_hda_codec_write(codec, spec->adc_nids[i], 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_UNMUTE(0)); - } + int i; - /* init pins */ for (i = 0; i < cfg->num_inputs; i++) { hda_nid_t nid = cfg->inputs[i].pin; - if (spec->smart51_enabled && is_smart51_pins(codec, nid)) + if (spec->smart51_enabled && is_smart51_pins(spec, nid)) ctl = PIN_OUT; else if (cfg->inputs[i].type == AUTO_PIN_MIC) ctl = PIN_VREF50; @@ -653,32 +595,6 @@ static void via_auto_init_analog_input(struct hda_codec *codec) snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, ctl); } - - /* init input-src */ - for (i = 0; i < spec->num_adc_nids; i++) { - int adc_idx = spec->inputs[spec->cur_mux[i]].adc_idx; - if (spec->mux_nids[adc_idx]) { - int mux_idx = spec->inputs[spec->cur_mux[i]].mux_idx; - snd_hda_codec_write(codec, spec->mux_nids[adc_idx], 0, - AC_VERB_SET_CONNECT_SEL, - mux_idx); - } - if (spec->dyn_adc_switch) - break; /* only one input-src */ - } - - /* init aa-mixer */ - if (!spec->aa_mix_nid) - return; - num_conns = snd_hda_get_connections(codec, spec->aa_mix_nid, conn, - ARRAY_SIZE(conn)); - for (i = 0; i < num_conns; i++) { - unsigned int caps = get_wcaps(codec, conn[i]); - if (get_wcaps_type(caps) == AC_WID_PIN) - snd_hda_codec_write(codec, spec->aa_mix_nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_MUTE(i)); - } } static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid, @@ -689,13 +605,9 @@ static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid, unsigned no_presence = (def_conf & AC_DEFCFG_MISC) >> AC_DEFCFG_MISC_SHIFT & AC_DEFCFG_MISC_NO_PRESENCE; /* do not support pin sense */ + unsigned present = snd_hda_jack_detect(codec, nid); struct via_spec *spec = codec->spec; - unsigned present = 0; - - no_presence |= spec->no_pin_power_ctl; - if (!no_presence) - present = snd_hda_jack_detect(codec, nid); - if ((spec->smart51_enabled && is_smart51_pins(codec, nid)) + if ((spec->smart51_enabled && is_smart51_pins(spec, nid)) || ((no_presence || present) && get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE)) { *affected_parm = AC_PWRST_D0; /* if it's connected */ @@ -706,139 +618,124 @@ static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid, snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm); } -static int via_pin_power_ctl_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) +/* + * input MUX handling + */ +static int via_mux_enum_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) { - static const char * const texts[] = { - "Disabled", "Enabled" - }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - return 0; + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct via_spec *spec = codec->spec; + return snd_hda_input_mux_info(spec->input_mux, uinfo); } -static int via_pin_power_ctl_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int via_mux_enum_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct via_spec *spec = codec->spec; - ucontrol->value.enumerated.item[0] = !spec->no_pin_power_ctl; + unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + + ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; return 0; } -static int via_pin_power_ctl_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int via_mux_enum_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct via_spec *spec = codec->spec; - unsigned int val = !ucontrol->value.enumerated.item[0]; + unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + int ret; - if (val == spec->no_pin_power_ctl) - return 0; - spec->no_pin_power_ctl = val; - set_widgets_power_state(codec); - return 1; -} + if (!spec->mux_nids[adc_idx]) + return -EINVAL; + /* switch to D0 beofre change index */ + if (snd_hda_codec_read(codec, spec->mux_nids[adc_idx], 0, + AC_VERB_GET_POWER_STATE, 0x00) != AC_PWRST_D0) + snd_hda_codec_write(codec, spec->mux_nids[adc_idx], 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); -static const struct snd_kcontrol_new via_pin_power_ctl_enum = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Dynamic Power-Control", - .info = via_pin_power_ctl_info, - .get = via_pin_power_ctl_get, - .put = via_pin_power_ctl_put, -}; + ret = snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, + spec->mux_nids[adc_idx], + &spec->cur_mux[adc_idx]); + /* update jack power state */ + set_widgets_power_state(codec); + return ret; +} static int via_independent_hp_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static const char * const texts[] = { "OFF", "ON" }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item >= 2) - uinfo->value.enumerated.item = 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - return 0; + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct via_spec *spec = codec->spec; + return snd_hda_input_mux_info(spec->hp_mux, uinfo); } static int via_independent_hp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct via_spec *spec = codec->spec; + hda_nid_t nid = kcontrol->private_value; + unsigned int pinsel; + + /* use !! to translate conn sel 2 for VT1718S */ + pinsel = !!snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_CONNECT_SEL, + 0x00); + ucontrol->value.enumerated.item[0] = pinsel; - ucontrol->value.enumerated.item[0] = spec->hp_independent_mode; return 0; } -/* adjust spec->multiout setup according to the current flags */ -static void setup_playback_multi_pcm(struct via_spec *spec) +static void activate_ctl(struct hda_codec *codec, const char *name, int active) { - const struct auto_pin_cfg *cfg = &spec->autocfg; - spec->multiout.num_dacs = cfg->line_outs + spec->smart51_nums; - spec->multiout.hp_nid = 0; - if (!spec->hp_independent_mode) { - if (!spec->hp_indep_shared) - spec->multiout.hp_nid = spec->hp_dac_nid; - } else { - if (spec->hp_indep_shared) - spec->multiout.num_dacs = cfg->line_outs - 1; + struct snd_kcontrol *ctl = snd_hda_find_mixer_ctl(codec, name); + if (ctl) { + ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; + ctl->vd[0].access |= active + ? 0 : SNDRV_CTL_ELEM_ACCESS_INACTIVE; + snd_ctl_notify(codec->bus->card, + SNDRV_CTL_EVENT_MASK_VALUE, &ctl->id); } } -/* update DAC setups according to indep-HP switch; - * this function is called only when indep-HP is modified - */ -static void switch_indep_hp_dacs(struct hda_codec *codec) +static hda_nid_t side_mute_channel(struct via_spec *spec) { - struct via_spec *spec = codec->spec; - int shared = spec->hp_indep_shared; - hda_nid_t shared_dac, hp_dac; + switch (spec->codec_type) { + case VT1708: return 0x1b; + case VT1709_10CH: return 0x29; + case VT1708B_8CH: /* fall thru */ + case VT1708S: return 0x27; + case VT2002P: return 0x19; + case VT1802: return 0x15; + case VT1812: return 0x15; + default: return 0; + } +} - if (!spec->opened_streams) - return; +static int update_side_mute_status(struct hda_codec *codec) +{ + /* mute side channel */ + struct via_spec *spec = codec->spec; + unsigned int parm; + hda_nid_t sw3 = side_mute_channel(spec); - shared_dac = shared ? spec->multiout.dac_nids[shared] : 0; - hp_dac = spec->hp_dac_nid; - if (spec->hp_independent_mode) { - /* switch to indep-HP mode */ - if (spec->active_streams & STREAM_MULTI_OUT) { - __snd_hda_codec_cleanup_stream(codec, hp_dac, 1); - __snd_hda_codec_cleanup_stream(codec, shared_dac, 1); - } - if (spec->active_streams & STREAM_INDEP_HP) - snd_hda_codec_setup_stream(codec, hp_dac, - spec->cur_hp_stream_tag, 0, - spec->cur_hp_format); - } else { - /* back to HP or shared-DAC */ - if (spec->active_streams & STREAM_INDEP_HP) - __snd_hda_codec_cleanup_stream(codec, hp_dac, 1); - if (spec->active_streams & STREAM_MULTI_OUT) { - hda_nid_t dac; - int ch; - if (shared_dac) { /* reset mutli-ch DAC */ - dac = shared_dac; - ch = shared * 2; - } else { /* reset HP DAC */ - dac = hp_dac; - ch = 0; - } - snd_hda_codec_setup_stream(codec, dac, - spec->cur_dac_stream_tag, ch, - spec->cur_dac_format); - } + if (sw3) { + if (VT2002P_COMPATIBLE(spec)) + parm = spec->hp_independent_mode ? + AMP_IN_MUTE(1) : AMP_IN_UNMUTE(1); + else + parm = spec->hp_independent_mode ? + AMP_OUT_MUTE : AMP_OUT_UNMUTE; + snd_hda_codec_write(codec, sw3, 0, + AC_VERB_SET_AMP_GAIN_MUTE, parm); + if (spec->codec_type == VT1812) + snd_hda_codec_write(codec, 0x1d, 0, + AC_VERB_SET_AMP_GAIN_MUTE, parm); } - setup_playback_multi_pcm(spec); + return 0; } static int via_independent_hp_put(struct snd_kcontrol *kcontrol, @@ -846,46 +743,66 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct via_spec *spec = codec->spec; - int cur, shared; - - mutex_lock(&spec->config_mutex); - cur = !!ucontrol->value.enumerated.item[0]; - if (spec->hp_independent_mode == cur) { - mutex_unlock(&spec->config_mutex); - return 0; - } - spec->hp_independent_mode = cur; - shared = spec->hp_indep_shared; - deactivate_hp_paths(codec); - if (cur) - activate_output_path(codec, &spec->hp_indep_path, true, false); - else { - if (shared) - activate_output_path(codec, &spec->out_path[shared], - true, false); - if (spec->aamix_mode || !spec->hp_path.depth) - activate_output_path(codec, &spec->hp_mix_path, - true, false); - else - activate_output_path(codec, &spec->hp_path, - true, false); + hda_nid_t nid = kcontrol->private_value; + unsigned int pinsel = ucontrol->value.enumerated.item[0]; + unsigned int parm0, parm1; + /* Get Independent Mode index of headphone pin widget */ + spec->hp_independent_mode = spec->hp_independent_mode_index == pinsel + ? 1 : 0; + if (spec->codec_type == VT1718S) { + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_CONNECT_SEL, pinsel ? 2 : 0); + /* Set correct mute switch for MW3 */ + parm0 = spec->hp_independent_mode ? + AMP_IN_UNMUTE(0) : AMP_IN_MUTE(0); + parm1 = spec->hp_independent_mode ? + AMP_IN_MUTE(1) : AMP_IN_UNMUTE(1); + snd_hda_codec_write(codec, 0x1b, 0, + AC_VERB_SET_AMP_GAIN_MUTE, parm0); + snd_hda_codec_write(codec, 0x1b, 0, + AC_VERB_SET_AMP_GAIN_MUTE, parm1); } + else + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_CONNECT_SEL, pinsel); - switch_indep_hp_dacs(codec); - mutex_unlock(&spec->config_mutex); - + if (spec->codec_type == VT1812) + snd_hda_codec_write(codec, 0x35, 0, + AC_VERB_SET_CONNECT_SEL, pinsel); + if (spec->multiout.hp_nid && spec->multiout.hp_nid + != spec->multiout.dac_nids[HDA_FRONT]) + snd_hda_codec_setup_stream(codec, spec->multiout.hp_nid, + 0, 0, 0); + + update_side_mute_status(codec); + /* update HP volume/swtich active state */ + if (spec->codec_type == VT1708S + || spec->codec_type == VT1702 + || spec->codec_type == VT1718S + || spec->codec_type == VT1716S + || VT2002P_COMPATIBLE(spec)) { + activate_ctl(codec, "Headphone Playback Volume", + spec->hp_independent_mode); + activate_ctl(codec, "Headphone Playback Switch", + spec->hp_independent_mode); + } /* update jack power state */ set_widgets_power_state(codec); - via_hp_automute(codec); - return 1; + return 0; } -static const struct snd_kcontrol_new via_hp_mixer = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Independent HP", - .info = via_independent_hp_info, - .get = via_independent_hp_get, - .put = via_independent_hp_put, +static const struct snd_kcontrol_new via_hp_mixer[2] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Independent HP", + .info = via_independent_hp_info, + .get = via_independent_hp_get, + .put = via_independent_hp_put, + }, + { + .iface = NID_MAPPING, + .name = "Independent HP", + }, }; static int via_hp_build(struct hda_codec *codec) @@ -893,28 +810,61 @@ static int via_hp_build(struct hda_codec *codec) struct via_spec *spec = codec->spec; struct snd_kcontrol_new *knew; hda_nid_t nid; + int nums; + hda_nid_t conn[HDA_MAX_CONNECTIONS]; + + switch (spec->codec_type) { + case VT1718S: + nid = 0x34; + break; + case VT2002P: + case VT1802: + nid = 0x35; + break; + case VT1812: + nid = 0x3d; + break; + default: + nid = spec->autocfg.hp_pins[0]; + break; + } + + if (spec->codec_type != VT1708) { + nums = snd_hda_get_connections(codec, nid, + conn, HDA_MAX_CONNECTIONS); + if (nums <= 1) + return 0; + } - nid = spec->autocfg.hp_pins[0]; - knew = via_clone_control(spec, &via_hp_mixer); + knew = via_clone_control(spec, &via_hp_mixer[0]); if (knew == NULL) return -ENOMEM; knew->subdevice = HDA_SUBDEV_NID_FLAG | nid; + knew->private_value = nid; + + nid = side_mute_channel(spec); + if (nid) { + knew = via_clone_control(spec, &via_hp_mixer[1]); + if (knew == NULL) + return -ENOMEM; + knew->subdevice = nid; + } + + return 0; +} - return 0; -} - static void notify_aa_path_ctls(struct hda_codec *codec) { - struct via_spec *spec = codec->spec; int i; - - for (i = 0; i < spec->smart51_nums; i++) { - struct snd_kcontrol *ctl; - struct snd_ctl_elem_id id; - memset(&id, 0, sizeof(id)); - id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - sprintf(id.name, "%s Playback Volume", spec->smart51_labels[i]); + struct snd_ctl_elem_id id; + const char *labels[] = {"Mic", "Front Mic", "Line", "Rear Mic"}; + struct snd_kcontrol *ctl; + + memset(&id, 0, sizeof(id)); + id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + for (i = 0; i < ARRAY_SIZE(labels); i++) { + sprintf(id.name, "%s Playback Volume", labels[i]); ctl = snd_hda_find_mixer_ctl(codec, id.name); if (ctl) snd_ctl_notify(codec->bus->card, @@ -926,28 +876,66 @@ static void notify_aa_path_ctls(struct hda_codec *codec) static void mute_aa_path(struct hda_codec *codec, int mute) { struct via_spec *spec = codec->spec; - int val = mute ? HDA_AMP_MUTE : HDA_AMP_UNMUTE; + hda_nid_t nid_mixer; + int start_idx; + int end_idx; int i; - + /* get nid of MW0 and start & end index */ + switch (spec->codec_type) { + case VT1708: + nid_mixer = 0x17; + start_idx = 2; + end_idx = 4; + break; + case VT1709_10CH: + case VT1709_6CH: + nid_mixer = 0x18; + start_idx = 2; + end_idx = 4; + break; + case VT1708B_8CH: + case VT1708B_4CH: + case VT1708S: + case VT1716S: + nid_mixer = 0x16; + start_idx = 2; + end_idx = 4; + break; + case VT1718S: + nid_mixer = 0x21; + start_idx = 1; + end_idx = 3; + break; + default: + return; + } /* check AA path's mute status */ - for (i = 0; i < spec->smart51_nums; i++) { - if (spec->smart51_idxs[i] < 0) - continue; - snd_hda_codec_amp_stereo(codec, spec->aa_mix_nid, - HDA_INPUT, spec->smart51_idxs[i], + for (i = start_idx; i <= end_idx; i++) { + int val = mute ? HDA_AMP_MUTE : HDA_AMP_UNMUTE; + snd_hda_codec_amp_stereo(codec, nid_mixer, HDA_INPUT, i, HDA_AMP_MUTE, val); } } - -static bool is_smart51_pins(struct hda_codec *codec, hda_nid_t pin) +static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin) { - struct via_spec *spec = codec->spec; + const struct auto_pin_cfg *cfg = &spec->autocfg; int i; - for (i = 0; i < spec->smart51_nums; i++) - if (spec->smart51_pins[i] == pin) - return true; - return false; + for (i = 0; i < cfg->num_inputs; i++) { + if (pin == cfg->inputs[i].pin) + return cfg->inputs[i].type <= AUTO_PIN_LINE_IN; + } + return 0; +} + +static int via_smart51_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; } static int via_smart51_get(struct snd_kcontrol *kcontrol, @@ -955,8 +943,23 @@ static int via_smart51_get(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct via_spec *spec = codec->spec; + const struct auto_pin_cfg *cfg = &spec->autocfg; + int on = 1; + int i; - *ucontrol->value.integer.value = spec->smart51_enabled; + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; + int ctl = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + if (cfg->inputs[i].type > AUTO_PIN_LINE_IN) + continue; + if (cfg->inputs[i].type == AUTO_PIN_MIC && + spec->hp_independent_mode && spec->codec_type != VT1718S) + continue; /* ignore FMic for independent HP */ + if ((ctl & AC_PINCTL_IN_EN) && !(ctl & AC_PINCTL_OUT_EN)) + on = 0; + } + *ucontrol->value.integer.value = on; return 0; } @@ -965,14 +968,21 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct via_spec *spec = codec->spec; + const struct auto_pin_cfg *cfg = &spec->autocfg; int out_in = *ucontrol->value.integer.value ? AC_PINCTL_OUT_EN : AC_PINCTL_IN_EN; int i; - for (i = 0; i < spec->smart51_nums; i++) { - hda_nid_t nid = spec->smart51_pins[i]; + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; unsigned int parm; + if (cfg->inputs[i].type > AUTO_PIN_LINE_IN) + continue; + if (cfg->inputs[i].type == AUTO_PIN_MIC && + spec->hp_independent_mode && spec->codec_type != VT1718S) + continue; /* don't retask FMic for independent HP */ + parm = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); parm &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN); @@ -984,59 +994,171 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol, mute_aa_path(codec, 1); notify_aa_path_ctls(codec); } + if (spec->codec_type == VT1718S) { + snd_hda_codec_amp_stereo( + codec, nid, HDA_OUTPUT, 0, HDA_AMP_MUTE, + HDA_AMP_UNMUTE); + } + if (cfg->inputs[i].type == AUTO_PIN_MIC) { + if (spec->codec_type == VT1708S + || spec->codec_type == VT1716S) { + /* input = index 1 (AOW3) */ + snd_hda_codec_write( + codec, nid, 0, + AC_VERB_SET_CONNECT_SEL, 1); + snd_hda_codec_amp_stereo( + codec, nid, HDA_OUTPUT, + 0, HDA_AMP_MUTE, HDA_AMP_UNMUTE); + } + } } spec->smart51_enabled = *ucontrol->value.integer.value; set_widgets_power_state(codec); return 1; } -static const struct snd_kcontrol_new via_smart51_mixer = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Smart 5.1", - .count = 1, - .info = snd_ctl_boolean_mono_info, - .get = via_smart51_get, - .put = via_smart51_put, +static const struct snd_kcontrol_new via_smart51_mixer[2] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Smart 5.1", + .count = 1, + .info = via_smart51_info, + .get = via_smart51_get, + .put = via_smart51_put, + }, + { + .iface = NID_MAPPING, + .name = "Smart 5.1", + } }; -static int via_smart51_build(struct hda_codec *codec) +static int via_smart51_build(struct via_spec *spec) { - struct via_spec *spec = codec->spec; + struct snd_kcontrol_new *knew; + const struct auto_pin_cfg *cfg = &spec->autocfg; + hda_nid_t nid; + int i; - if (!spec->smart51_nums) + if (!cfg) + return 0; + if (cfg->line_outs > 2) return 0; - if (!via_clone_control(spec, &via_smart51_mixer)) + + knew = via_clone_control(spec, &via_smart51_mixer[0]); + if (knew == NULL) return -ENOMEM; + + for (i = 0; i < cfg->num_inputs; i++) { + nid = cfg->inputs[i].pin; + if (cfg->inputs[i].type <= AUTO_PIN_LINE_IN) { + knew = via_clone_control(spec, &via_smart51_mixer[1]); + if (knew == NULL) + return -ENOMEM; + knew->subdevice = nid; + break; + } + } + return 0; } -/* check AA path's mute status */ -static bool is_aa_path_mute(struct hda_codec *codec) +/* capture mixer elements */ +static const struct snd_kcontrol_new vt1708_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x27, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x27, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 1, + .info = via_mux_enum_info, + .get = via_mux_enum_get, + .put = via_mux_enum_put, + }, + { } /* end */ +}; + +/* check AA path's mute statue */ +static int is_aa_path_mute(struct hda_codec *codec) { + int mute = 1; + hda_nid_t nid_mixer; + int start_idx; + int end_idx; + int i; struct via_spec *spec = codec->spec; - const struct hda_amp_list *p; - int i, ch, v; - - for (i = 0; i < spec->num_loopbacks; i++) { - p = &spec->loopback_list[i]; - for (ch = 0; ch < 2; ch++) { - v = snd_hda_codec_amp_read(codec, p->nid, ch, p->dir, - p->idx); - if (!(v & HDA_AMP_MUTE) && v > 0) - return false; + /* get nid of MW0 and start & end index */ + switch (spec->codec_type) { + case VT1708B_8CH: + case VT1708B_4CH: + case VT1708S: + case VT1716S: + nid_mixer = 0x16; + start_idx = 2; + end_idx = 4; + break; + case VT1702: + nid_mixer = 0x1a; + start_idx = 1; + end_idx = 3; + break; + case VT1718S: + nid_mixer = 0x21; + start_idx = 1; + end_idx = 3; + break; + case VT2002P: + case VT1812: + case VT1802: + nid_mixer = 0x21; + start_idx = 0; + end_idx = 2; + break; + default: + return 0; + } + /* check AA path's mute status */ + for (i = start_idx; i <= end_idx; i++) { + unsigned int con_list = snd_hda_codec_read( + codec, nid_mixer, 0, AC_VERB_GET_CONNECT_LIST, i/4*4); + int shift = 8 * (i % 4); + hda_nid_t nid_pin = (con_list & (0xff << shift)) >> shift; + unsigned int defconf = snd_hda_codec_get_pincfg(codec, nid_pin); + if (get_defcfg_connect(defconf) == AC_JACK_PORT_COMPLEX) { + /* check mute status while the pin is connected */ + int mute_l = snd_hda_codec_amp_read(codec, nid_mixer, 0, + HDA_INPUT, i) >> 7; + int mute_r = snd_hda_codec_amp_read(codec, nid_mixer, 1, + HDA_INPUT, i) >> 7; + if (!mute_l || !mute_r) { + mute = 0; + break; + } } } - return true; + return mute; } /* enter/exit analog low-current mode */ -static void analog_low_current_mode(struct hda_codec *codec) +static void analog_low_current_mode(struct hda_codec *codec, int stream_idle) { struct via_spec *spec = codec->spec; - bool enable; - unsigned int verb, parm; + static int saved_stream_idle = 1; /* saved stream idle status */ + int enable = is_aa_path_mute(codec); + unsigned int verb = 0; + unsigned int parm = 0; - enable = is_aa_path_mute(codec) && (spec->opened_streams != 0); + if (stream_idle == -1) /* stream status did not change */ + enable = enable && saved_stream_idle; + else { + enable = enable && stream_idle; + saved_stream_idle = stream_idle; + } /* decide low current mode's verb & parameter */ switch (spec->codec_type) { @@ -1071,69 +1193,119 @@ static void analog_low_current_mode(struct hda_codec *codec) /* * generic initialization of ADC, input mixers and output mixers */ -static const struct hda_verb vt1708_init_verbs[] = { +static const struct hda_verb vt1708_volume_init_verbs[] = { + /* + * Unmute ADC0-1 and set the default input to mic-in + */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + + /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + */ + /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + + /* + * Set up output mixers (0x19 - 0x1b) + */ + /* set vol=0 to output mixers */ + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* Setup default input MW0 to PW4 */ + {0x20, AC_VERB_SET_CONNECT_SEL, 0}, + /* PW9 Output enable */ + {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, /* power down jack detect function */ {0x1, 0xf81, 0x1}, { } }; -static void set_stream_open(struct hda_codec *codec, int bit, bool active) -{ - struct via_spec *spec = codec->spec; - - if (active) - spec->opened_streams |= bit; - else - spec->opened_streams &= ~bit; - analog_low_current_mode(codec); -} - -static int via_playback_multi_pcm_open(struct hda_pcm_stream *hinfo, +static int via_playback_pcm_open(struct hda_pcm_stream *hinfo, struct hda_codec *codec, struct snd_pcm_substream *substream) { struct via_spec *spec = codec->spec; - const struct auto_pin_cfg *cfg = &spec->autocfg; - int err; - - spec->multiout.num_dacs = cfg->line_outs + spec->smart51_nums; - spec->multiout.max_channels = spec->multiout.num_dacs * 2; - set_stream_open(codec, STREAM_MULTI_OUT, true); - err = snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, - hinfo); - if (err < 0) { - set_stream_open(codec, STREAM_MULTI_OUT, false); - return err; - } - return 0; -} - -static int via_playback_multi_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - set_stream_open(codec, STREAM_MULTI_OUT, false); - return 0; + int idle = substream->pstr->substream_opened == 1 + && substream->ref_count == 0; + analog_low_current_mode(codec, idle); + return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, + hinfo); } -static int via_playback_hp_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) +static void playback_multi_pcm_prep_0(struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) { struct via_spec *spec = codec->spec; + struct hda_multi_out *mout = &spec->multiout; + const hda_nid_t *nids = mout->dac_nids; + int chs = substream->runtime->channels; + int i; - if (snd_BUG_ON(!spec->hp_dac_nid)) - return -EINVAL; - set_stream_open(codec, STREAM_INDEP_HP, true); - return 0; -} - -static int via_playback_hp_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - set_stream_open(codec, STREAM_INDEP_HP, false); - return 0; + mutex_lock(&codec->spdif_mutex); + if (mout->dig_out_nid && mout->dig_out_used != HDA_DIG_EXCLUSIVE) { + if (chs == 2 && + snd_hda_is_supported_format(codec, mout->dig_out_nid, + format) && + !(codec->spdif_status & IEC958_AES0_NONAUDIO)) { + mout->dig_out_used = HDA_DIG_ANALOG_DUP; + /* turn off SPDIF once; otherwise the IEC958 bits won't + * be updated */ + if (codec->spdif_ctls & AC_DIG1_ENABLE) + snd_hda_codec_write(codec, mout->dig_out_nid, 0, + AC_VERB_SET_DIGI_CONVERT_1, + codec->spdif_ctls & + ~AC_DIG1_ENABLE & 0xff); + snd_hda_codec_setup_stream(codec, mout->dig_out_nid, + stream_tag, 0, format); + /* turn on again (if needed) */ + if (codec->spdif_ctls & AC_DIG1_ENABLE) + snd_hda_codec_write(codec, mout->dig_out_nid, 0, + AC_VERB_SET_DIGI_CONVERT_1, + codec->spdif_ctls & 0xff); + } else { + mout->dig_out_used = 0; + snd_hda_codec_setup_stream(codec, mout->dig_out_nid, + 0, 0, 0); + } + } + mutex_unlock(&codec->spdif_mutex); + + /* front */ + snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag, + 0, format); + + if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] + && !spec->hp_independent_mode) + /* headphone out will just decode front left/right (stereo) */ + snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, + 0, format); + + /* extra outputs copied from front */ + for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++) + if (mout->extra_out_nid[i]) + snd_hda_codec_setup_stream(codec, + mout->extra_out_nid[i], + stream_tag, 0, format); + + /* surrounds */ + for (i = 1; i < mout->num_dacs; i++) { + if (chs >= (i + 1) * 2) /* independent out */ + snd_hda_codec_setup_stream(codec, nids[i], stream_tag, + i * 2, format); + else /* copy front */ + snd_hda_codec_setup_stream(codec, nids[i], stream_tag, + 0, format); + } } static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo, @@ -1143,36 +1315,18 @@ static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) { struct via_spec *spec = codec->spec; + struct hda_multi_out *mout = &spec->multiout; + const hda_nid_t *nids = mout->dac_nids; - mutex_lock(&spec->config_mutex); - setup_playback_multi_pcm(spec); - snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, - format, substream); - /* remember for dynamic DAC switch with indep-HP */ - spec->active_streams |= STREAM_MULTI_OUT; - spec->cur_dac_stream_tag = stream_tag; - spec->cur_dac_format = format; - mutex_unlock(&spec->config_mutex); - vt1708_start_hp_work(spec); - return 0; -} - -static int via_playback_hp_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - - mutex_lock(&spec->config_mutex); - if (spec->hp_independent_mode) - snd_hda_codec_setup_stream(codec, spec->hp_dac_nid, - stream_tag, 0, format); - spec->active_streams |= STREAM_INDEP_HP; - spec->cur_hp_stream_tag = stream_tag; - spec->cur_hp_format = format; - mutex_unlock(&spec->config_mutex); + if (substream->number == 0) + playback_multi_pcm_prep_0(codec, stream_tag, format, + substream); + else { + if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] && + spec->hp_independent_mode) + snd_hda_codec_setup_stream(codec, mout->hp_nid, + stream_tag, 0, format); + } vt1708_start_hp_work(spec); return 0; } @@ -1182,26 +1336,37 @@ static int via_playback_multi_pcm_cleanup(struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) { struct via_spec *spec = codec->spec; + struct hda_multi_out *mout = &spec->multiout; + const hda_nid_t *nids = mout->dac_nids; + int i; - mutex_lock(&spec->config_mutex); - snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); - spec->active_streams &= ~STREAM_MULTI_OUT; - mutex_unlock(&spec->config_mutex); - vt1708_stop_hp_work(spec); - return 0; -} - -static int via_playback_hp_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - - mutex_lock(&spec->config_mutex); - if (spec->hp_independent_mode) - snd_hda_codec_setup_stream(codec, spec->hp_dac_nid, 0, 0, 0); - spec->active_streams &= ~STREAM_INDEP_HP; - mutex_unlock(&spec->config_mutex); + if (substream->number == 0) { + for (i = 0; i < mout->num_dacs; i++) + snd_hda_codec_setup_stream(codec, nids[i], 0, 0, 0); + + if (mout->hp_nid && !spec->hp_independent_mode) + snd_hda_codec_setup_stream(codec, mout->hp_nid, + 0, 0, 0); + + for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++) + if (mout->extra_out_nid[i]) + snd_hda_codec_setup_stream(codec, + mout->extra_out_nid[i], + 0, 0, 0); + mutex_lock(&codec->spdif_mutex); + if (mout->dig_out_nid && + mout->dig_out_used == HDA_DIG_ANALOG_DUP) { + snd_hda_codec_setup_stream(codec, mout->dig_out_nid, + 0, 0, 0); + mout->dig_out_used = 0; + } + mutex_unlock(&codec->spdif_mutex); + } else { + if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] && + spec->hp_independent_mode) + snd_hda_codec_setup_stream(codec, mout->hp_nid, + 0, 0, 0); + } vt1708_stop_hp_work(spec); return 0; } @@ -1270,127 +1435,47 @@ static int via_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, return 0; } -/* analog capture with dynamic ADC switching */ -static int via_dyn_adc_capture_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - int adc_idx = spec->inputs[spec->cur_mux[0]].adc_idx; - - mutex_lock(&spec->config_mutex); - spec->cur_adc = spec->adc_nids[adc_idx]; - spec->cur_adc_stream_tag = stream_tag; - spec->cur_adc_format = format; - snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); - mutex_unlock(&spec->config_mutex); - return 0; -} - -static int via_dyn_adc_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - - mutex_lock(&spec->config_mutex); - snd_hda_codec_cleanup_stream(codec, spec->cur_adc); - spec->cur_adc = 0; - mutex_unlock(&spec->config_mutex); - return 0; -} - -/* re-setup the stream if running; called from input-src put */ -static bool via_dyn_adc_pcm_resetup(struct hda_codec *codec, int cur) -{ - struct via_spec *spec = codec->spec; - int adc_idx = spec->inputs[cur].adc_idx; - hda_nid_t adc = spec->adc_nids[adc_idx]; - bool ret = false; - - mutex_lock(&spec->config_mutex); - if (spec->cur_adc && spec->cur_adc != adc) { - /* stream is running, let's swap the current ADC */ - __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); - spec->cur_adc = adc; - snd_hda_codec_setup_stream(codec, adc, - spec->cur_adc_stream_tag, 0, - spec->cur_adc_format); - ret = true; - } - mutex_unlock(&spec->config_mutex); - return ret; -} - -static const struct hda_pcm_stream via_pcm_analog_playback = { - .substreams = 1, +static const struct hda_pcm_stream vt1708_pcm_analog_playback = { + .substreams = 2, .channels_min = 2, .channels_max = 8, - /* NID is set in via_build_pcms */ + .nid = 0x10, /* NID to query formats and rates */ .ops = { - .open = via_playback_multi_pcm_open, - .close = via_playback_multi_pcm_close, + .open = via_playback_pcm_open, .prepare = via_playback_multi_pcm_prepare, .cleanup = via_playback_multi_pcm_cleanup }, }; -static const struct hda_pcm_stream via_pcm_hp_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in via_build_pcms */ - .ops = { - .open = via_playback_hp_pcm_open, - .close = via_playback_hp_pcm_close, - .prepare = via_playback_hp_pcm_prepare, - .cleanup = via_playback_hp_pcm_cleanup - }, -}; - static const struct hda_pcm_stream vt1708_pcm_analog_s16_playback = { - .substreams = 1, + .substreams = 2, .channels_min = 2, .channels_max = 8, - /* NID is set in via_build_pcms */ + .nid = 0x10, /* NID to query formats and rates */ /* We got noisy outputs on the right channel on VT1708 when * 24bit samples are used. Until any workaround is found, * disable the 24bit format, so far. */ .formats = SNDRV_PCM_FMTBIT_S16_LE, .ops = { - .open = via_playback_multi_pcm_open, - .close = via_playback_multi_pcm_close, + .open = via_playback_pcm_open, .prepare = via_playback_multi_pcm_prepare, .cleanup = via_playback_multi_pcm_cleanup }, }; -static const struct hda_pcm_stream via_pcm_analog_capture = { - .substreams = 1, /* will be changed in via_build_pcms() */ +static const struct hda_pcm_stream vt1708_pcm_analog_capture = { + .substreams = 2, .channels_min = 2, .channels_max = 2, - /* NID is set in via_build_pcms */ + .nid = 0x15, /* NID to query formats and rates */ .ops = { .prepare = via_capture_pcm_prepare, .cleanup = via_capture_pcm_cleanup }, }; -static const struct hda_pcm_stream via_pcm_dyn_adc_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in via_build_pcms */ - .ops = { - .prepare = via_dyn_adc_capture_pcm_prepare, - .cleanup = via_dyn_adc_capture_pcm_cleanup, - }, -}; - -static const struct hda_pcm_stream via_pcm_digital_playback = { +static const struct hda_pcm_stream vt1708_pcm_digital_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -1403,47 +1488,19 @@ static const struct hda_pcm_stream via_pcm_digital_playback = { }, }; -static const struct hda_pcm_stream via_pcm_digital_capture = { +static const struct hda_pcm_stream vt1708_pcm_digital_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, }; -/* - * slave controls for virtual master - */ -static const char * const via_slave_vols[] = { - "Front Playback Volume", - "Surround Playback Volume", - "Center Playback Volume", - "LFE Playback Volume", - "Side Playback Volume", - "Headphone Playback Volume", - "Speaker Playback Volume", - NULL, -}; - -static const char * const via_slave_sws[] = { - "Front Playback Switch", - "Surround Playback Switch", - "Center Playback Switch", - "LFE Playback Switch", - "Side Playback Switch", - "Headphone Playback Switch", - "Speaker Playback Switch", - NULL, -}; - static int via_build_controls(struct hda_codec *codec) { struct via_spec *spec = codec->spec; struct snd_kcontrol *kctl; + const struct snd_kcontrol_new *knew; int err, i; - if (spec->set_widgets_power_state) - if (!via_clone_control(spec, &via_pin_power_ctl_enum)) - return -ENOMEM; - for (i = 0; i < spec->num_mixers; i++) { err = snd_hda_add_new_ctls(codec, spec->mixers[i]); if (err < 0) @@ -1452,7 +1509,6 @@ static int via_build_controls(struct hda_codec *codec) if (spec->multiout.dig_out_nid) { err = snd_hda_create_spdif_out_ctls(codec, - spec->multiout.dig_out_nid, spec->multiout.dig_out_nid); if (err < 0) return err; @@ -1468,23 +1524,6 @@ static int via_build_controls(struct hda_codec *codec) return err; } - /* if we have no master control, let's create it */ - if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { - unsigned int vmaster_tlv[4]; - snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0], - HDA_OUTPUT, vmaster_tlv); - err = snd_hda_add_vmaster(codec, "Master Playback Volume", - vmaster_tlv, via_slave_vols); - if (err < 0) - return err; - } - if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { - err = snd_hda_add_vmaster(codec, "Master Playback Switch", - NULL, via_slave_sws); - if (err < 0) - return err; - } - /* assign Capture Source enums to NID */ kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); for (i = 0; kctl && i < kctl->count; i++) { @@ -1493,9 +1532,22 @@ static int via_build_controls(struct hda_codec *codec) return err; } + /* other nid->control mapping */ + for (i = 0; i < spec->num_mixers; i++) { + for (knew = spec->mixers[i]; knew->name; knew++) { + if (knew->iface != NID_MAPPING) + continue; + kctl = snd_hda_find_mixer_ctl(codec, knew->name); + if (kctl == NULL) + continue; + err = snd_hda_add_nid(codec, kctl, 0, + knew->subdevice); + } + } + /* init power states */ set_widgets_power_state(codec); - analog_low_current_mode(codec); + analog_low_current_mode(codec, 1); via_free_kctls(codec); /* no longer needed */ return 0; @@ -1509,71 +1561,36 @@ static int via_build_pcms(struct hda_codec *codec) codec->num_pcms = 1; codec->pcm_info = info; - snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog), - "%s Analog", codec->chip_name); info->name = spec->stream_name_analog; - - if (!spec->stream_analog_playback) - spec->stream_analog_playback = &via_pcm_analog_playback; info->stream[SNDRV_PCM_STREAM_PLAYBACK] = - *spec->stream_analog_playback; + *(spec->stream_analog_playback); info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; + info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture); + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->multiout.max_channels; - if (!spec->stream_analog_capture) { - if (spec->dyn_adc_switch) - spec->stream_analog_capture = - &via_pcm_dyn_adc_analog_capture; - else - spec->stream_analog_capture = &via_pcm_analog_capture; - } - info->stream[SNDRV_PCM_STREAM_CAPTURE] = - *spec->stream_analog_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; - if (!spec->dyn_adc_switch) - info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = - spec->num_adc_nids; - if (spec->multiout.dig_out_nid || spec->dig_in_nid) { codec->num_pcms++; info++; - snprintf(spec->stream_name_digital, - sizeof(spec->stream_name_digital), - "%s Digital", codec->chip_name); info->name = spec->stream_name_digital; info->pcm_type = HDA_PCM_TYPE_SPDIF; if (spec->multiout.dig_out_nid) { - if (!spec->stream_digital_playback) - spec->stream_digital_playback = - &via_pcm_digital_playback; info->stream[SNDRV_PCM_STREAM_PLAYBACK] = - *spec->stream_digital_playback; + *(spec->stream_digital_playback); info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; } if (spec->dig_in_nid) { - if (!spec->stream_digital_capture) - spec->stream_digital_capture = - &via_pcm_digital_capture; info->stream[SNDRV_PCM_STREAM_CAPTURE] = - *spec->stream_digital_capture; + *(spec->stream_digital_capture); info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; } } - if (spec->hp_dac_nid) { - codec->num_pcms++; - info++; - snprintf(spec->stream_name_hp, sizeof(spec->stream_name_hp), - "%s HP", codec->chip_name); - info->name = spec->stream_name_hp; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = via_pcm_hp_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = - spec->hp_dac_nid; - } return 0; } @@ -1586,62 +1603,57 @@ static void via_free(struct hda_codec *codec) via_free_kctls(codec); vt1708_stop_hp_work(spec); - kfree(spec->bind_cap_vol); - kfree(spec->bind_cap_sw); - kfree(spec); + kfree(codec->spec); } -/* mute/unmute outputs */ -static void toggle_output_mutes(struct hda_codec *codec, int num_pins, - hda_nid_t *pins, bool mute) +/* mute internal speaker if HP is plugged */ +static void via_hp_automute(struct hda_codec *codec) { - int i; - for (i = 0; i < num_pins; i++) { - unsigned int parm = snd_hda_codec_read(codec, pins[i], 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - if (parm & AC_PINCTL_IN_EN) - continue; - if (mute) - parm &= ~AC_PINCTL_OUT_EN; - else - parm |= AC_PINCTL_OUT_EN; - snd_hda_codec_write(codec, pins[i], 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, parm); + unsigned int present = 0; + struct via_spec *spec = codec->spec; + + present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]); + + if (!spec->hp_independent_mode) { + struct snd_ctl_elem_id id; + /* auto mute */ + snd_hda_codec_amp_stereo( + codec, spec->autocfg.line_out_pins[0], HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + /* notify change */ + memset(&id, 0, sizeof(id)); + id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + strcpy(id.name, "Front Playback Switch"); + snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE, + &id); } } -/* mute internal speaker if line-out is plugged */ -static void via_line_automute(struct hda_codec *codec, int present) +/* mute mono out if HP or Line out is plugged */ +static void via_mono_automute(struct hda_codec *codec) { + unsigned int hp_present, lineout_present; struct via_spec *spec = codec->spec; - if (!spec->autocfg.speaker_outs) + if (spec->codec_type != VT1716S) return; - if (!present) - present = snd_hda_jack_detect(codec, + + lineout_present = snd_hda_jack_detect(codec, spec->autocfg.line_out_pins[0]); - toggle_output_mutes(codec, spec->autocfg.speaker_outs, - spec->autocfg.speaker_pins, - present); -} - -/* mute internal speaker if HP is plugged */ -static void via_hp_automute(struct hda_codec *codec) -{ - int present = 0; - int nums; - struct via_spec *spec = codec->spec; - - if (!spec->hp_independent_mode && spec->autocfg.hp_pins[0]) - present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]); - - if (spec->smart51_enabled) - nums = spec->autocfg.line_outs + spec->smart51_nums; - else - nums = spec->autocfg.line_outs; - toggle_output_mutes(codec, nums, spec->autocfg.line_out_pins, present); - - via_line_automute(codec, present); + + /* Mute Mono Out if Line Out is plugged */ + if (lineout_present) { + snd_hda_codec_amp_stereo( + codec, 0x2A, HDA_OUTPUT, 0, HDA_AMP_MUTE, HDA_AMP_MUTE); + return; + } + + hp_present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]); + + if (!spec->hp_independent_mode) + snd_hda_codec_amp_stereo( + codec, 0x2A, HDA_OUTPUT, 0, HDA_AMP_MUTE, + hp_present ? HDA_AMP_MUTE : 0); } static void via_gpio_control(struct hda_codec *codec) @@ -1666,9 +1678,9 @@ static void via_gpio_control(struct hda_codec *codec) if (gpio_data == 0x02) { /* unmute line out */ - snd_hda_codec_write(codec, spec->autocfg.line_out_pins[0], 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - PIN_OUT); + snd_hda_codec_amp_stereo(codec, spec->autocfg.line_out_pins[0], + HDA_OUTPUT, 0, HDA_AMP_MUTE, 0); + if (vol_counter & 0x20) { /* decrease volume */ if (vol > master_vol) @@ -1685,12 +1697,73 @@ static void via_gpio_control(struct hda_codec *codec) } } else if (!(gpio_data & 0x02)) { /* mute line out */ - snd_hda_codec_write(codec, spec->autocfg.line_out_pins[0], 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - 0); + snd_hda_codec_amp_stereo(codec, + spec->autocfg.line_out_pins[0], + HDA_OUTPUT, 0, HDA_AMP_MUTE, + HDA_AMP_MUTE); + } +} + +/* mute Internal-Speaker if HP is plugged */ +static void via_speaker_automute(struct hda_codec *codec) +{ + unsigned int hp_present; + struct via_spec *spec = codec->spec; + + if (!VT2002P_COMPATIBLE(spec)) + return; + + hp_present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]); + + if (!spec->hp_independent_mode) { + struct snd_ctl_elem_id id; + snd_hda_codec_amp_stereo( + codec, spec->autocfg.speaker_pins[0], HDA_OUTPUT, 0, + HDA_AMP_MUTE, hp_present ? HDA_AMP_MUTE : 0); + /* notify change */ + memset(&id, 0, sizeof(id)); + id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + strcpy(id.name, "Speaker Playback Switch"); + snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE, + &id); + } +} + +/* mute line-out and internal speaker if HP is plugged */ +static void via_hp_bind_automute(struct hda_codec *codec) +{ + /* use long instead of int below just to avoid an internal compiler + * error with gcc 4.0.x + */ + unsigned long hp_present, present = 0; + struct via_spec *spec = codec->spec; + int i; + + if (!spec->autocfg.hp_pins[0] || !spec->autocfg.line_out_pins[0]) + return; + + hp_present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]); + + present = snd_hda_jack_detect(codec, spec->autocfg.line_out_pins[0]); + + if (!spec->hp_independent_mode) { + /* Mute Line-Outs */ + for (i = 0; i < spec->autocfg.line_outs; i++) + snd_hda_codec_amp_stereo( + codec, spec->autocfg.line_out_pins[i], + HDA_OUTPUT, 0, + HDA_AMP_MUTE, hp_present ? HDA_AMP_MUTE : 0); + if (hp_present) + present = hp_present; } + /* Speakers */ + for (i = 0; i < spec->autocfg.speaker_outs; i++) + snd_hda_codec_amp_stereo( + codec, spec->autocfg.speaker_pins[i], HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); } + /* unsolicited event for jack sensing */ static void via_unsol_event(struct hda_codec *codec, unsigned int res) @@ -1702,10 +1775,43 @@ static void via_unsol_event(struct hda_codec *codec, res &= ~VIA_JACK_EVENT; - if (res == VIA_HP_EVENT || res == VIA_LINE_EVENT) + if (res == VIA_HP_EVENT) via_hp_automute(codec); else if (res == VIA_GPIO_EVENT) via_gpio_control(codec); + else if (res == VIA_MONO_EVENT) + via_mono_automute(codec); + else if (res == VIA_SPEAKER_EVENT) + via_speaker_automute(codec); + else if (res == VIA_BIND_HP_EVENT) + via_hp_bind_automute(codec); +} + +static int via_init(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int i; + for (i = 0; i < spec->num_iverbs; i++) + snd_hda_sequence_write(codec, spec->init_verbs[i]); + + /* Lydia Add for EAPD enable */ + if (!spec->dig_in_nid) { /* No Digital In connection */ + if (spec->dig_in_pin) { + snd_hda_codec_write(codec, spec->dig_in_pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + PIN_OUT); + snd_hda_codec_write(codec, spec->dig_in_pin, 0, + AC_VERB_SET_EAPD_BTLENABLE, 0x02); + } + } else /* enable SPDIF-input pin */ + snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN); + + /* assign slave outs */ + if (spec->slave_dig_outs[0]) + codec->slave_dig_outs = spec->slave_dig_outs; + + return 0; } #ifdef SND_HDA_NEEDS_RESUME @@ -1727,15 +1833,11 @@ static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid) /* */ - -static int via_init(struct hda_codec *codec); - static const struct hda_codec_ops via_patch_ops = { .build_controls = via_build_controls, .build_pcms = via_build_pcms, .init = via_init, .free = via_free, - .unsol_event = via_unsol_event, #ifdef SND_HDA_NEEDS_RESUME .suspend = via_suspend, #endif @@ -1744,899 +1846,803 @@ static const struct hda_codec_ops via_patch_ops = { #endif }; -static bool is_empty_dac(struct hda_codec *codec, hda_nid_t dac) +/* fill in the dac_nids table from the parsed pin configuration */ +static int vt1708_auto_fill_dac_nids(struct via_spec *spec, + const struct auto_pin_cfg *cfg) { - struct via_spec *spec = codec->spec; int i; + hda_nid_t nid; - for (i = 0; i < spec->multiout.num_dacs; i++) { - if (spec->multiout.dac_nids[i] == dac) - return false; - } - if (spec->hp_dac_nid == dac) - return false; - return true; -} - -static bool __parse_output_path(struct hda_codec *codec, hda_nid_t nid, - hda_nid_t target_dac, int with_aa_mix, - struct nid_path *path, int depth) -{ - struct via_spec *spec = codec->spec; - hda_nid_t conn[8]; - int i, nums; + spec->multiout.num_dacs = cfg->line_outs; - if (nid == spec->aa_mix_nid) { - if (!with_aa_mix) - return false; - with_aa_mix = 2; /* mark aa-mix is included */ - } + spec->multiout.dac_nids = spec->private_dac_nids; - nums = snd_hda_get_connections(codec, nid, conn, ARRAY_SIZE(conn)); - for (i = 0; i < nums; i++) { - if (get_wcaps_type(get_wcaps(codec, conn[i])) != AC_WID_AUD_OUT) - continue; - if (conn[i] == target_dac || is_empty_dac(codec, conn[i])) { - /* aa-mix is requested but not included? */ - if (!(spec->aa_mix_nid && with_aa_mix == 1)) - goto found; + for (i = 0; i < 4; i++) { + nid = cfg->line_out_pins[i]; + if (nid) { + /* config dac list */ + switch (i) { + case AUTO_SEQ_FRONT: + spec->private_dac_nids[i] = 0x10; + break; + case AUTO_SEQ_CENLFE: + spec->private_dac_nids[i] = 0x12; + break; + case AUTO_SEQ_SURROUND: + spec->private_dac_nids[i] = 0x11; + break; + case AUTO_SEQ_SIDE: + spec->private_dac_nids[i] = 0x13; + break; + } } } - if (depth >= MAX_NID_PATH_DEPTH) - return false; - for (i = 0; i < nums; i++) { - unsigned int type; - type = get_wcaps_type(get_wcaps(codec, conn[i])); - if (type == AC_WID_AUD_OUT) - continue; - if (__parse_output_path(codec, conn[i], target_dac, - with_aa_mix, path, depth + 1)) - goto found; - } - return false; - - found: - path->path[path->depth] = conn[i]; - path->idx[path->depth] = i; - if (nums > 1 && get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_AUD_MIX) - path->multi[path->depth] = 1; - path->depth++; - return true; -} -static bool parse_output_path(struct hda_codec *codec, hda_nid_t nid, - hda_nid_t target_dac, int with_aa_mix, - struct nid_path *path) -{ - if (__parse_output_path(codec, nid, target_dac, with_aa_mix, path, 1)) { - path->path[path->depth] = nid; - path->depth++; - snd_printdd("output-path: depth=%d, %02x/%02x/%02x/%02x/%02x\n", - path->depth, path->path[0], path->path[1], - path->path[2], path->path[3], path->path[4]); - return true; - } - return false; + return 0; } -static int via_auto_fill_dac_nids(struct hda_codec *codec) +/* add playback controls from the parsed DAC table */ +static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec, + const struct auto_pin_cfg *cfg) { - struct via_spec *spec = codec->spec; - const struct auto_pin_cfg *cfg = &spec->autocfg; - int i, dac_num; - hda_nid_t nid; + char name[32]; + static const char * const chname[4] = { + "Front", "Surround", "C/LFE", "Side" + }; + hda_nid_t nid, nid_vol, nid_vols[] = {0x17, 0x19, 0x1a, 0x1b}; + int i, err; - spec->multiout.dac_nids = spec->private_dac_nids; - dac_num = 0; - for (i = 0; i < cfg->line_outs; i++) { - hda_nid_t dac = 0; + for (i = 0; i <= AUTO_SEQ_SIDE; i++) { nid = cfg->line_out_pins[i]; + if (!nid) continue; - if (parse_output_path(codec, nid, 0, 0, &spec->out_path[i])) - dac = spec->out_path[i].path[0]; - if (!i && parse_output_path(codec, nid, dac, 1, - &spec->out_mix_path)) - dac = spec->out_mix_path.path[0]; - if (dac) { - spec->private_dac_nids[i] = dac; - dac_num++; - } - } - if (!spec->out_path[0].depth && spec->out_mix_path.depth) { - spec->out_path[0] = spec->out_mix_path; - spec->out_mix_path.depth = 0; - } - spec->multiout.num_dacs = dac_num; - return 0; -} -static int create_ch_ctls(struct hda_codec *codec, const char *pfx, - int chs, bool check_dac, struct nid_path *path) -{ - struct via_spec *spec = codec->spec; - char name[32]; - hda_nid_t dac, pin, sel, nid; - int err; + nid_vol = nid_vols[i]; - dac = check_dac ? path->path[0] : 0; - pin = path->path[path->depth - 1]; - sel = path->depth > 1 ? path->path[1] : 0; + if (i == AUTO_SEQ_CENLFE) { + /* Center/LFE */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Center Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "LFE Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Center Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "LFE Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } else if (i == AUTO_SEQ_FRONT) { + /* add control to mixer index 0 */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Master Front Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, + HDA_INPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Master Front Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, + HDA_INPUT)); + if (err < 0) + return err; - if (dac && check_amp_caps(codec, dac, HDA_OUTPUT, AC_AMPCAP_NUM_STEPS)) - nid = dac; - else if (check_amp_caps(codec, pin, HDA_OUTPUT, AC_AMPCAP_NUM_STEPS)) - nid = pin; - else if (check_amp_caps(codec, sel, HDA_OUTPUT, AC_AMPCAP_NUM_STEPS)) - nid = sel; - else - nid = 0; - if (nid) { - sprintf(name, "%s Playback Volume", pfx); - err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); - if (err < 0) - return err; - path->vol_ctl = nid; + /* add control to PW3 */ + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } else { + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } } - if (dac && check_amp_caps(codec, dac, HDA_OUTPUT, AC_AMPCAP_MUTE)) - nid = dac; - else if (check_amp_caps(codec, pin, HDA_OUTPUT, AC_AMPCAP_MUTE)) - nid = pin; - else if (check_amp_caps(codec, sel, HDA_OUTPUT, AC_AMPCAP_MUTE)) - nid = sel; - else - nid = 0; - if (nid) { - sprintf(name, "%s Playback Switch", pfx); - err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, - HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); - if (err < 0) - return err; - path->mute_ctl = nid; - } return 0; } -static void mangle_smart51(struct hda_codec *codec) +static void create_hp_imux(struct via_spec *spec) { - struct via_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - struct auto_pin_cfg_item *ins = cfg->inputs; - int i, j, nums, attr; - int pins[AUTO_CFG_MAX_INS]; + int i; + struct hda_input_mux *imux = &spec->private_imux[1]; + static const char * const texts[] = { "OFF", "ON", NULL}; - for (attr = INPUT_PIN_ATTR_REAR; attr >= INPUT_PIN_ATTR_NORMAL; attr--) { - nums = 0; - for (i = 0; i < cfg->num_inputs; i++) { - unsigned int def; - if (ins[i].type > AUTO_PIN_LINE_IN) - continue; - def = snd_hda_codec_get_pincfg(codec, ins[i].pin); - if (snd_hda_get_input_pin_attr(def) != attr) - continue; - for (j = 0; j < nums; j++) - if (ins[pins[j]].type < ins[i].type) { - memmove(pins + j + 1, pins + j, - (nums - j) * sizeof(int)); - break; - } - pins[j] = i; - nums++; - } - if (cfg->line_outs + nums < 3) - continue; - for (i = 0; i < nums; i++) { - hda_nid_t pin = ins[pins[i]].pin; - spec->smart51_pins[spec->smart51_nums++] = pin; - cfg->line_out_pins[cfg->line_outs++] = pin; - if (cfg->line_outs == 3) - break; - } - return; - } -} + /* for hp mode select */ + for (i = 0; texts[i]; i++) + snd_hda_add_imux_item(imux, texts[i], i, NULL); -static void copy_path_mixer_ctls(struct nid_path *dst, struct nid_path *src) -{ - dst->vol_ctl = src->vol_ctl; - dst->mute_ctl = src->mute_ctl; + spec->hp_mux = &spec->private_imux[1]; } -/* add playback controls from the parsed DAC table */ -static int via_auto_create_multi_out_ctls(struct hda_codec *codec) +static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) { - struct via_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - struct nid_path *path; - static const char * const chname[4] = { - "Front", "Surround", "C/LFE", "Side" - }; - int i, idx, err; - int old_line_outs; + int err; + + if (!pin) + return 0; - /* check smart51 */ - old_line_outs = cfg->line_outs; - if (cfg->line_outs == 1) - mangle_smart51(codec); + spec->multiout.hp_nid = VT1708_HP_NID; /* AOW3 */ + spec->hp_independent_mode_index = 1; - err = via_auto_fill_dac_nids(codec); + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Headphone Playback Volume", + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Headphone Playback Switch", + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); if (err < 0) return err; - if (spec->multiout.num_dacs < 3) { - spec->smart51_nums = 0; - cfg->line_outs = old_line_outs; - } - for (i = 0; i < cfg->line_outs; i++) { - hda_nid_t pin, dac; - pin = cfg->line_out_pins[i]; - dac = spec->multiout.dac_nids[i]; - if (!pin || !dac) - continue; - path = spec->out_path + i; - if (i == HDA_CLFE) { - err = create_ch_ctls(codec, "Center", 1, true, path); - if (err < 0) - return err; - err = create_ch_ctls(codec, "LFE", 2, true, path); - if (err < 0) - return err; - } else { - const char *pfx = chname[i]; - if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && - cfg->line_outs == 1) - pfx = "Speaker"; - err = create_ch_ctls(codec, pfx, 3, true, path); - if (err < 0) - return err; - } - if (path != spec->out_path + i) - copy_path_mixer_ctls(&spec->out_path[i], path); - if (path == spec->out_path && spec->out_mix_path.depth) - copy_path_mixer_ctls(&spec->out_mix_path, path); - } - - idx = get_connection_index(codec, spec->aa_mix_nid, - spec->multiout.dac_nids[0]); - if (idx >= 0) { - /* add control to mixer */ - const char *name; - name = spec->out_mix_path.depth ? - "PCM Loopback Playback Volume" : "PCM Playback Volume"; - err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(spec->aa_mix_nid, 3, - idx, HDA_INPUT)); - if (err < 0) - return err; - name = spec->out_mix_path.depth ? - "PCM Loopback Playback Switch" : "PCM Playback Switch"; - err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, - HDA_COMPOSE_AMP_VAL(spec->aa_mix_nid, 3, - idx, HDA_INPUT)); - if (err < 0) - return err; - } - - cfg->line_outs = old_line_outs; + create_hp_imux(spec); return 0; } -static int via_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin) +/* create playback/capture controls for input pins */ +static int vt_auto_create_analog_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg, + hda_nid_t cap_nid, + const hda_nid_t pin_idxs[], + int num_idxs) { struct via_spec *spec = codec->spec; - struct nid_path *path; - bool check_dac; - int i, err; - - if (!pin) - return 0; + struct hda_input_mux *imux = &spec->private_imux[0]; + int i, err, idx, type, type_idx = 0; - if (!parse_output_path(codec, pin, 0, 0, &spec->hp_indep_path)) { - for (i = HDA_SIDE; i >= HDA_CLFE; i--) { - if (i < spec->multiout.num_dacs && - parse_output_path(codec, pin, - spec->multiout.dac_nids[i], 0, - &spec->hp_indep_path)) { - spec->hp_indep_shared = i; - break; - } + /* for internal loopback recording select */ + for (idx = 0; idx < num_idxs; idx++) { + if (pin_idxs[idx] == 0xff) { + snd_hda_add_imux_item(imux, "Stereo Mixer", idx, NULL); + break; } } - if (spec->hp_indep_path.depth) { - spec->hp_dac_nid = spec->hp_indep_path.path[0]; - if (!spec->hp_indep_shared) - spec->hp_path = spec->hp_indep_path; - } - /* optionally check front-path w/o AA-mix */ - if (!spec->hp_path.depth) - parse_output_path(codec, pin, - spec->multiout.dac_nids[HDA_FRONT], 0, - &spec->hp_path); - - if (!parse_output_path(codec, pin, spec->multiout.dac_nids[HDA_FRONT], - 1, &spec->hp_mix_path) && !spec->hp_path.depth) - return 0; - if (spec->hp_path.depth) { - path = &spec->hp_path; - check_dac = true; - } else { - path = &spec->hp_mix_path; - check_dac = false; + for (i = 0; i < cfg->num_inputs; i++) { + const char *label; + type = cfg->inputs[i].type; + for (idx = 0; idx < num_idxs; idx++) + if (pin_idxs[idx] == cfg->inputs[i].pin) + break; + if (idx >= num_idxs) + continue; + if (i > 0 && type == cfg->inputs[i - 1].type) + type_idx++; + else + type_idx = 0; + label = hda_get_autocfg_input_label(codec, cfg, i); + if (spec->codec_type == VT1708S || + spec->codec_type == VT1702 || + spec->codec_type == VT1716S) + err = via_new_analog_input(spec, label, type_idx, + idx+1, cap_nid); + else + err = via_new_analog_input(spec, label, type_idx, + idx, cap_nid); + if (err < 0) + return err; + snd_hda_add_imux_item(imux, label, idx, NULL); } - err = create_ch_ctls(codec, "Headphone", 3, check_dac, path); - if (err < 0) - return err; - if (check_dac) - copy_path_mixer_ctls(&spec->hp_mix_path, path); - else - copy_path_mixer_ctls(&spec->hp_path, path); - if (spec->hp_indep_path.depth) - copy_path_mixer_ctls(&spec->hp_indep_path, path); return 0; } -static int via_auto_create_speaker_ctls(struct hda_codec *codec) +/* create playback/capture controls for input pins */ +static int vt1708_auto_create_analog_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) { - struct via_spec *spec = codec->spec; - struct nid_path *path; - bool check_dac; - hda_nid_t pin, dac; - int err; - - pin = spec->autocfg.speaker_pins[0]; - if (!spec->autocfg.speaker_outs || !pin) - return 0; + static const hda_nid_t pin_idxs[] = { 0xff, 0x24, 0x1d, 0x1e, 0x21 }; + return vt_auto_create_analog_input_ctls(codec, cfg, 0x17, pin_idxs, + ARRAY_SIZE(pin_idxs)); +} - if (parse_output_path(codec, pin, 0, 0, &spec->speaker_path)) - dac = spec->speaker_path.path[0]; - if (!dac) - parse_output_path(codec, pin, - spec->multiout.dac_nids[HDA_FRONT], 0, - &spec->speaker_path); - if (!parse_output_path(codec, pin, spec->multiout.dac_nids[HDA_FRONT], - 1, &spec->speaker_mix_path) && !dac) - return 0; +#ifdef CONFIG_SND_HDA_POWER_SAVE +static const struct hda_amp_list vt1708_loopbacks[] = { + { 0x17, HDA_INPUT, 1 }, + { 0x17, HDA_INPUT, 2 }, + { 0x17, HDA_INPUT, 3 }, + { 0x17, HDA_INPUT, 4 }, + { } /* end */ +}; +#endif - /* no AA-path for front? */ - if (!spec->out_mix_path.depth && spec->speaker_mix_path.depth) - dac = 0; +static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid) +{ + unsigned int def_conf; + unsigned char seqassoc; - spec->speaker_dac_nid = dac; - spec->multiout.extra_out_nid[0] = dac; - if (dac) { - path = &spec->speaker_path; - check_dac = true; - } else { - path = &spec->speaker_mix_path; - check_dac = false; + def_conf = snd_hda_codec_get_pincfg(codec, nid); + seqassoc = (unsigned char) get_defcfg_association(def_conf); + seqassoc = (seqassoc << 4) | get_defcfg_sequence(def_conf); + if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE + && (seqassoc == 0xf0 || seqassoc == 0xff)) { + def_conf = def_conf & (~(AC_JACK_PORT_BOTH << 30)); + snd_hda_codec_set_pincfg(codec, nid, def_conf); } - err = create_ch_ctls(codec, "Speaker", 3, check_dac, path); - if (err < 0) - return err; - if (check_dac) - copy_path_mixer_ctls(&spec->speaker_mix_path, path); - else - copy_path_mixer_ctls(&spec->speaker_path, path); - return 0; -} -#define via_aamix_ctl_info via_pin_power_ctl_info + return; +} -static int via_aamix_ctl_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int vt1708_jack_detectect_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct via_spec *spec = codec->spec; - ucontrol->value.enumerated.item[0] = spec->aamix_mode; - return 0; -} -static void update_aamix_paths(struct hda_codec *codec, int do_mix, - struct nid_path *nomix, struct nid_path *mix) -{ - if (do_mix) { - activate_output_path(codec, nomix, false, false); - activate_output_path(codec, mix, true, false); - } else { - activate_output_path(codec, mix, false, false); - activate_output_path(codec, nomix, true, false); - } + if (spec->codec_type != VT1708) + return 0; + spec->vt1708_jack_detectect = + !((snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8) & 0x1); + ucontrol->value.integer.value[0] = spec->vt1708_jack_detectect; + return 0; } -static int via_aamix_ctl_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int vt1708_jack_detectect_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct via_spec *spec = codec->spec; - unsigned int val = ucontrol->value.enumerated.item[0]; + int change; - if (val == spec->aamix_mode) + if (spec->codec_type != VT1708) return 0; - spec->aamix_mode = val; - /* update front path */ - update_aamix_paths(codec, val, &spec->out_path[0], &spec->out_mix_path); - /* update HP path */ - if (!spec->hp_independent_mode) { - update_aamix_paths(codec, val, &spec->hp_path, - &spec->hp_mix_path); + spec->vt1708_jack_detectect = ucontrol->value.integer.value[0]; + change = (0x1 & (snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8)) + == !spec->vt1708_jack_detectect; + if (spec->vt1708_jack_detectect) { + mute_aa_path(codec, 1); + notify_aa_path_ctls(codec); } - /* update speaker path */ - update_aamix_paths(codec, val, &spec->speaker_path, - &spec->speaker_mix_path); - return 1; + return change; } -static const struct snd_kcontrol_new via_aamix_ctl_enum = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Loopback Mixing", - .info = via_aamix_ctl_info, - .get = via_aamix_ctl_get, - .put = via_aamix_ctl_put, +static const struct snd_kcontrol_new vt1708_jack_detectect[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Jack Detect", + .count = 1, + .info = snd_ctl_boolean_mono_info, + .get = vt1708_jack_detectect_get, + .put = vt1708_jack_detectect_put, + }, + {} /* end */ }; -static int via_auto_create_loopback_switch(struct hda_codec *codec) +static int vt1708_parse_auto_config(struct hda_codec *codec) { struct via_spec *spec = codec->spec; + int err; - if (!spec->aa_mix_nid || !spec->out_mix_path.depth) - return 0; /* no loopback switching available */ - if (!via_clone_control(spec, &via_aamix_ctl_enum)) - return -ENOMEM; - return 0; -} - -/* look for ADCs */ -static int via_fill_adcs(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - hda_nid_t nid = codec->start_nid; - int i; + /* Add HP and CD pin config connect bit re-config action */ + vt1708_set_pinconfig_connect(codec, VT1708_HP_PIN_NID); + vt1708_set_pinconfig_connect(codec, VT1708_CD_PIN_NID); - for (i = 0; i < codec->num_nodes; i++, nid++) { - unsigned int wcaps = get_wcaps(codec, nid); - if (get_wcaps_type(wcaps) != AC_WID_AUD_IN) - continue; - if (wcaps & AC_WCAP_DIGITAL) - continue; - if (!(wcaps & AC_WCAP_CONN_LIST)) - continue; - if (spec->num_adc_nids >= ARRAY_SIZE(spec->adc_nids)) - return -ENOMEM; - spec->adc_nids[spec->num_adc_nids++] = nid; - } - return 0; -} + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); + if (err < 0) + return err; + err = vt1708_auto_fill_dac_nids(spec, &spec->autocfg); + if (err < 0) + return err; + if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) + return 0; /* can't find valid BIOS pin config */ -/* input-src control */ -static int via_mux_enum_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct via_spec *spec = codec->spec; + err = vt1708_auto_create_multi_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + err = vt1708_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); + if (err < 0) + return err; + err = vt1708_auto_create_analog_input_ctls(codec, &spec->autocfg); + if (err < 0) + return err; + /* add jack detect on/off control */ + err = snd_hda_add_new_ctls(codec, vt1708_jack_detectect); + if (err < 0) + return err; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = spec->num_inputs; - if (uinfo->value.enumerated.item >= spec->num_inputs) - uinfo->value.enumerated.item = spec->num_inputs - 1; - strcpy(uinfo->value.enumerated.name, - spec->inputs[uinfo->value.enumerated.item].label); - return 0; -} + spec->multiout.max_channels = spec->multiout.num_dacs * 2; -static int via_mux_enum_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct via_spec *spec = codec->spec; - unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + if (spec->autocfg.dig_outs) + spec->multiout.dig_out_nid = VT1708_DIGOUT_NID; + spec->dig_in_pin = VT1708_DIGIN_PIN; + if (spec->autocfg.dig_in_pin) + spec->dig_in_nid = VT1708_DIGIN_NID; - ucontrol->value.enumerated.item[0] = spec->cur_mux[idx]; - return 0; -} + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; -static int via_mux_enum_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct via_spec *spec = codec->spec; - unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - hda_nid_t mux; - int cur; + spec->init_verbs[spec->num_iverbs++] = vt1708_volume_init_verbs; - cur = ucontrol->value.enumerated.item[0]; - if (cur < 0 || cur >= spec->num_inputs) - return -EINVAL; - if (spec->cur_mux[idx] == cur) - return 0; - spec->cur_mux[idx] = cur; - if (spec->dyn_adc_switch) { - int adc_idx = spec->inputs[cur].adc_idx; - mux = spec->mux_nids[adc_idx]; - via_dyn_adc_pcm_resetup(codec, cur); - } else { - mux = spec->mux_nids[idx]; - if (snd_BUG_ON(!mux)) - return -EINVAL; - } + spec->input_mux = &spec->private_imux[0]; - if (mux) { - /* switch to D0 beofre change index */ - if (snd_hda_codec_read(codec, mux, 0, - AC_VERB_GET_POWER_STATE, 0x00) != AC_PWRST_D0) - snd_hda_codec_write(codec, mux, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - snd_hda_codec_write(codec, mux, 0, - AC_VERB_SET_CONNECT_SEL, - spec->inputs[cur].mux_idx); - } + if (spec->hp_mux) + via_hp_build(codec); - /* update jack power state */ - set_widgets_power_state(codec); - return 0; + via_smart51_build(spec); + return 1; } -static const struct snd_kcontrol_new via_input_src_ctl = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .info = via_mux_enum_info, - .get = via_mux_enum_get, - .put = via_mux_enum_put, -}; - -static int create_input_src_ctls(struct hda_codec *codec, int count) +/* init callback for auto-configuration model -- overriding the default init */ +static int via_auto_init(struct hda_codec *codec) { struct via_spec *spec = codec->spec; - struct snd_kcontrol_new *knew; - if (spec->num_inputs <= 1 || !count) - return 0; /* no need for single src */ + via_init(codec); + via_auto_init_multi_out(codec); + via_auto_init_hp_out(codec); + via_auto_init_analog_input(codec); + + if (VT2002P_COMPATIBLE(spec)) { + via_hp_bind_automute(codec); + } else { + via_hp_automute(codec); + via_speaker_automute(codec); + } - knew = via_clone_control(spec, &via_input_src_ctl); - if (!knew) - return -ENOMEM; - knew->count = count; return 0; } -/* add the powersave loopback-list entry */ -static void add_loopback_list(struct via_spec *spec, hda_nid_t mix, int idx) +static void vt1708_update_hp_jack_state(struct work_struct *work) { - struct hda_amp_list *list; - - if (spec->num_loopbacks >= ARRAY_SIZE(spec->loopback_list) - 1) + struct via_spec *spec = container_of(work, struct via_spec, + vt1708_hp_work.work); + if (spec->codec_type != VT1708) return; - list = spec->loopback_list + spec->num_loopbacks; - list->nid = mix; - list->dir = HDA_INPUT; - list->idx = idx; - spec->num_loopbacks++; - spec->loopback.amplist = spec->loopback_list; -} - -static bool is_reachable_nid(struct hda_codec *codec, hda_nid_t src, - hda_nid_t dst) -{ - return snd_hda_get_conn_index(codec, src, dst, 1) >= 0; + /* if jack state toggled */ + if (spec->vt1708_hp_present + != snd_hda_jack_detect(spec->codec, spec->autocfg.hp_pins[0])) { + spec->vt1708_hp_present ^= 1; + via_hp_automute(spec->codec); + } + vt1708_start_hp_work(spec); } -/* add the input-route to the given pin */ -static bool add_input_route(struct hda_codec *codec, hda_nid_t pin) +static int get_mux_nids(struct hda_codec *codec) { struct via_spec *spec = codec->spec; - int c, idx; + hda_nid_t nid, conn[8]; + unsigned int type; + int i, n; - spec->inputs[spec->num_inputs].adc_idx = -1; - spec->inputs[spec->num_inputs].pin = pin; - for (c = 0; c < spec->num_adc_nids; c++) { - if (spec->mux_nids[c]) { - idx = get_connection_index(codec, spec->mux_nids[c], - pin); - if (idx < 0) - continue; - spec->inputs[spec->num_inputs].mux_idx = idx; - } else { - if (!is_reachable_nid(codec, spec->adc_nids[c], pin)) - continue; - } - spec->inputs[spec->num_inputs].adc_idx = c; - /* Can primary ADC satisfy all inputs? */ - if (!spec->dyn_adc_switch && - spec->num_inputs > 0 && spec->inputs[0].adc_idx != c) { - snd_printd(KERN_INFO - "via: dynamic ADC switching enabled\n"); - spec->dyn_adc_switch = 1; + for (i = 0; i < spec->num_adc_nids; i++) { + nid = spec->adc_nids[i]; + while (nid) { + type = get_wcaps_type(get_wcaps(codec, nid)); + if (type == AC_WID_PIN) + break; + n = snd_hda_get_connections(codec, nid, conn, + ARRAY_SIZE(conn)); + if (n <= 0) + break; + if (n > 1) { + spec->mux_nids[i] = nid; + break; + } + nid = conn[0]; } - return true; } - return false; + return 0; } -static int get_mux_nids(struct hda_codec *codec); - -/* parse input-routes; fill ADCs, MUXs and input-src entries */ -static int parse_analog_inputs(struct hda_codec *codec) +static int patch_vt1708(struct hda_codec *codec) { - struct via_spec *spec = codec->spec; - const struct auto_pin_cfg *cfg = &spec->autocfg; - int i, err; + struct via_spec *spec; + int err; - err = via_fill_adcs(codec); - if (err < 0) - return err; - err = get_mux_nids(codec); - if (err < 0) + /* create a codec specific record */ + spec = via_new_spec(codec); + if (spec == NULL) + return -ENOMEM; + + /* automatic parse from the BIOS config */ + err = vt1708_parse_auto_config(codec); + if (err < 0) { + via_free(codec); return err; + } else if (!err) { + printk(KERN_INFO "hda_codec: Cannot set up configuration " + "from BIOS. Using genenic mode...\n"); + } - /* fill all input-routes */ - for (i = 0; i < cfg->num_inputs; i++) { - if (add_input_route(codec, cfg->inputs[i].pin)) - spec->inputs[spec->num_inputs++].label = - hda_get_autocfg_input_label(codec, cfg, i); + + spec->stream_name_analog = "VT1708 Analog"; + spec->stream_analog_playback = &vt1708_pcm_analog_playback; + /* disable 32bit format on VT1708 */ + if (codec->vendor_id == 0x11061708) + spec->stream_analog_playback = &vt1708_pcm_analog_s16_playback; + spec->stream_analog_capture = &vt1708_pcm_analog_capture; + + spec->stream_name_digital = "VT1708 Digital"; + spec->stream_digital_playback = &vt1708_pcm_digital_playback; + spec->stream_digital_capture = &vt1708_pcm_digital_capture; + + + if (!spec->adc_nids && spec->input_mux) { + spec->adc_nids = vt1708_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(vt1708_adc_nids); + get_mux_nids(codec); + spec->mixers[spec->num_mixers] = vt1708_capture_mixer; + spec->num_mixers++; } - /* check for internal loopback recording */ - if (spec->aa_mix_nid && - add_input_route(codec, spec->aa_mix_nid)) - spec->inputs[spec->num_inputs++].label = "Stereo Mixer"; + codec->patch_ops = via_patch_ops; + codec->patch_ops.init = via_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt1708_loopbacks; +#endif + INIT_DELAYED_WORK(&spec->vt1708_hp_work, vt1708_update_hp_jack_state); return 0; } -/* create analog-loopback volume/switch controls */ -static int create_loopback_ctls(struct hda_codec *codec) +/* capture mixer elements */ +static const struct snd_kcontrol_new vt1709_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x14, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x15, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x15, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x16, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x16, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 1, + .info = via_mux_enum_info, + .get = via_mux_enum_get, + .put = via_mux_enum_put, + }, + { } /* end */ +}; + +static const struct hda_verb vt1709_uniwill_init_verbs[] = { + {0x20, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, + { } +}; + +/* + * generic initialization of ADC, input mixers and output mixers + */ +static const struct hda_verb vt1709_10ch_volume_init_verbs[] = { + /* + * Unmute ADC0-2 and set the default input to mic-in + */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + + /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + */ + /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + + /* + * Set up output selector (0x1a, 0x1b, 0x29) + */ + /* set vol=0 to output mixers */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* + * Unmute PW3 and PW4 + */ + {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* Set input of PW4 as MW0 */ + {0x20, AC_VERB_SET_CONNECT_SEL, 0}, + /* PW9 Output enable */ + {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + { } +}; + +static const struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 10, + .nid = 0x10, /* NID to query formats and rates */ + .ops = { + .open = via_playback_pcm_open, + .prepare = via_playback_multi_pcm_prepare, + .cleanup = via_playback_multi_pcm_cleanup, + }, +}; + +static const struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 6, + .nid = 0x10, /* NID to query formats and rates */ + .ops = { + .open = via_playback_pcm_open, + .prepare = via_playback_multi_pcm_prepare, + .cleanup = via_playback_multi_pcm_cleanup, + }, +}; + +static const struct hda_pcm_stream vt1709_pcm_analog_capture = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + .nid = 0x14, /* NID to query formats and rates */ + .ops = { + .prepare = via_capture_pcm_prepare, + .cleanup = via_capture_pcm_cleanup + }, +}; + +static const struct hda_pcm_stream vt1709_pcm_digital_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in via_build_pcms */ + .ops = { + .open = via_dig_playback_pcm_open, + .close = via_dig_playback_pcm_close + }, +}; + +static const struct hda_pcm_stream vt1709_pcm_digital_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, +}; + +static int vt1709_auto_fill_dac_nids(struct via_spec *spec, + const struct auto_pin_cfg *cfg) { - struct via_spec *spec = codec->spec; - const struct auto_pin_cfg *cfg = &spec->autocfg; - const char *prev_label = NULL; - int type_idx = 0; - int i, j, err, idx; + int i; + hda_nid_t nid; - if (!spec->aa_mix_nid) - return 0; + if (cfg->line_outs == 4) /* 10 channels */ + spec->multiout.num_dacs = cfg->line_outs+1; /* AOW0~AOW4 */ + else if (cfg->line_outs == 3) /* 6 channels */ + spec->multiout.num_dacs = cfg->line_outs; /* AOW0~AOW2 */ - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t pin = cfg->inputs[i].pin; - const char *label = hda_get_autocfg_input_label(codec, cfg, i); + spec->multiout.dac_nids = spec->private_dac_nids; - if (prev_label && !strcmp(label, prev_label)) - type_idx++; - else - type_idx = 0; - prev_label = label; - idx = get_connection_index(codec, spec->aa_mix_nid, pin); - if (idx >= 0) { - err = via_new_analog_input(spec, label, type_idx, - idx, spec->aa_mix_nid); - if (err < 0) - return err; - add_loopback_list(spec, spec->aa_mix_nid, idx); + if (cfg->line_outs == 4) { /* 10 channels */ + for (i = 0; i < cfg->line_outs; i++) { + nid = cfg->line_out_pins[i]; + if (nid) { + /* config dac list */ + switch (i) { + case AUTO_SEQ_FRONT: + /* AOW0 */ + spec->private_dac_nids[i] = 0x10; + break; + case AUTO_SEQ_CENLFE: + /* AOW2 */ + spec->private_dac_nids[i] = 0x12; + break; + case AUTO_SEQ_SURROUND: + /* AOW3 */ + spec->private_dac_nids[i] = 0x11; + break; + case AUTO_SEQ_SIDE: + /* AOW1 */ + spec->private_dac_nids[i] = 0x27; + break; + default: + break; + } + } } - - /* remember the label for smart51 control */ - for (j = 0; j < spec->smart51_nums; j++) { - if (spec->smart51_pins[j] == pin) { - spec->smart51_idxs[j] = idx; - spec->smart51_labels[j] = label; - break; + spec->private_dac_nids[cfg->line_outs] = 0x28; /* AOW4 */ + + } else if (cfg->line_outs == 3) { /* 6 channels */ + for (i = 0; i < cfg->line_outs; i++) { + nid = cfg->line_out_pins[i]; + if (nid) { + /* config dac list */ + switch (i) { + case AUTO_SEQ_FRONT: + /* AOW0 */ + spec->private_dac_nids[i] = 0x10; + break; + case AUTO_SEQ_CENLFE: + /* AOW2 */ + spec->private_dac_nids[i] = 0x12; + break; + case AUTO_SEQ_SURROUND: + /* AOW1 */ + spec->private_dac_nids[i] = 0x11; + break; + default: + break; + } } } } + return 0; } -/* create mic-boost controls (if present) */ -static int create_mic_boost_ctls(struct hda_codec *codec) +/* add playback controls from the parsed DAC table */ +static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec, + const struct auto_pin_cfg *cfg) { - struct via_spec *spec = codec->spec; - const struct auto_pin_cfg *cfg = &spec->autocfg; + char name[32]; + static const char * const chname[4] = { + "Front", "Surround", "C/LFE", "Side" + }; + hda_nid_t nid, nid_vol, nid_vols[] = {0x18, 0x1a, 0x1b, 0x29}; int i, err; - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t pin = cfg->inputs[i].pin; - unsigned int caps; - const char *label; - char name[32]; + for (i = 0; i <= AUTO_SEQ_SIDE; i++) { + nid = cfg->line_out_pins[i]; - if (cfg->inputs[i].type != AUTO_PIN_MIC) - continue; - caps = query_amp_caps(codec, pin, HDA_INPUT); - if (caps == -1 || !(caps & AC_AMPCAP_NUM_STEPS)) + if (!nid) continue; - label = hda_get_autocfg_input_label(codec, cfg, i); - snprintf(name, sizeof(name), "%s Boost Volume", label); - err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_INPUT)); - if (err < 0) - return err; - } - return 0; -} -/* create capture and input-src controls for multiple streams */ -static int create_multi_adc_ctls(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int i, err; + nid_vol = nid_vols[i]; - /* create capture mixer elements */ - for (i = 0; i < spec->num_adc_nids; i++) { - hda_nid_t adc = spec->adc_nids[i]; - err = __via_add_control(spec, VIA_CTL_WIDGET_VOL, - "Capture Volume", i, - HDA_COMPOSE_AMP_VAL(adc, 3, 0, - HDA_INPUT)); - if (err < 0) - return err; - err = __via_add_control(spec, VIA_CTL_WIDGET_MUTE, - "Capture Switch", i, - HDA_COMPOSE_AMP_VAL(adc, 3, 0, - HDA_INPUT)); - if (err < 0) - return err; - } - - /* input-source control */ - for (i = 0; i < spec->num_adc_nids; i++) - if (!spec->mux_nids[i]) - break; - err = create_input_src_ctls(codec, i); - if (err < 0) - return err; - return 0; -} - -/* bind capture volume/switch */ -static struct snd_kcontrol_new via_bind_cap_vol_ctl = - HDA_BIND_VOL("Capture Volume", 0); -static struct snd_kcontrol_new via_bind_cap_sw_ctl = - HDA_BIND_SW("Capture Switch", 0); + if (i == AUTO_SEQ_CENLFE) { + /* Center/LFE */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Center Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "LFE Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Center Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "LFE Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } else if (i == AUTO_SEQ_FRONT) { + /* ADD control to mixer index 0 */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Master Front Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, + HDA_INPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Master Front Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, + HDA_INPUT)); + if (err < 0) + return err; -static int init_bind_ctl(struct via_spec *spec, struct hda_bind_ctls **ctl_ret, - struct hda_ctl_ops *ops) -{ - struct hda_bind_ctls *ctl; - int i; + /* add control to PW3 */ + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } else if (i == AUTO_SEQ_SURROUND) { + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } else if (i == AUTO_SEQ_SIDE) { + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } + } - ctl = kzalloc(sizeof(*ctl) + sizeof(long) * 4, GFP_KERNEL); - if (!ctl) - return -ENOMEM; - ctl->ops = ops; - for (i = 0; i < spec->num_adc_nids; i++) - ctl->values[i] = - HDA_COMPOSE_AMP_VAL(spec->adc_nids[i], 3, 0, HDA_INPUT); - *ctl_ret = ctl; return 0; } -/* create capture and input-src controls for dynamic ADC-switch case */ -static int create_dyn_adc_ctls(struct hda_codec *codec) +static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) { - struct via_spec *spec = codec->spec; - struct snd_kcontrol_new *knew; int err; - /* set up the bind capture ctls */ - err = init_bind_ctl(spec, &spec->bind_cap_vol, &snd_hda_bind_vol); - if (err < 0) - return err; - err = init_bind_ctl(spec, &spec->bind_cap_sw, &snd_hda_bind_sw); - if (err < 0) - return err; - - /* create capture mixer elements */ - knew = via_clone_control(spec, &via_bind_cap_vol_ctl); - if (!knew) - return -ENOMEM; - knew->private_value = (long)spec->bind_cap_vol; - - knew = via_clone_control(spec, &via_bind_cap_sw_ctl); - if (!knew) - return -ENOMEM; - knew->private_value = (long)spec->bind_cap_sw; - - /* input-source control */ - err = create_input_src_ctls(codec, 1); - if (err < 0) - return err; - return 0; -} + if (!pin) + return 0; -/* parse and create capture-related stuff */ -static int via_auto_create_analog_input_ctls(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int err; + if (spec->multiout.num_dacs == 5) /* 10 channels */ + spec->multiout.hp_nid = VT1709_HP_DAC_NID; + else if (spec->multiout.num_dacs == 3) /* 6 channels */ + spec->multiout.hp_nid = 0; + spec->hp_independent_mode_index = 1; - err = parse_analog_inputs(codec); - if (err < 0) - return err; - if (spec->dyn_adc_switch) - err = create_dyn_adc_ctls(codec); - else - err = create_multi_adc_ctls(codec); - if (err < 0) - return err; - err = create_loopback_ctls(codec); + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Headphone Playback Volume", + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); if (err < 0) return err; - err = create_mic_boost_ctls(codec); + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Headphone Playback Switch", + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); if (err < 0) return err; - return 0; -} - -static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid) -{ - unsigned int def_conf; - unsigned char seqassoc; - - def_conf = snd_hda_codec_get_pincfg(codec, nid); - seqassoc = (unsigned char) get_defcfg_association(def_conf); - seqassoc = (seqassoc << 4) | get_defcfg_sequence(def_conf); - if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE - && (seqassoc == 0xf0 || seqassoc == 0xff)) { - def_conf = def_conf & (~(AC_JACK_PORT_BOTH << 30)); - snd_hda_codec_set_pincfg(codec, nid, def_conf); - } - - return; -} - -static int vt1708_jack_detect_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct via_spec *spec = codec->spec; - if (spec->codec_type != VT1708) - return 0; - spec->vt1708_jack_detect = - !((snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8) & 0x1); - ucontrol->value.integer.value[0] = spec->vt1708_jack_detect; return 0; } -static int vt1708_jack_detect_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +/* create playback/capture controls for input pins */ +static int vt1709_auto_create_analog_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct via_spec *spec = codec->spec; - int change; - - if (spec->codec_type != VT1708) - return 0; - spec->vt1708_jack_detect = ucontrol->value.integer.value[0]; - change = (0x1 & (snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8)) - == !spec->vt1708_jack_detect; - if (spec->vt1708_jack_detect) { - mute_aa_path(codec, 1); - notify_aa_path_ctls(codec); - } - return change; + static const hda_nid_t pin_idxs[] = { 0xff, 0x23, 0x1d, 0x1e, 0x21 }; + return vt_auto_create_analog_input_ctls(codec, cfg, 0x18, pin_idxs, + ARRAY_SIZE(pin_idxs)); } -static const struct snd_kcontrol_new vt1708_jack_detect_ctl = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Jack Detect", - .count = 1, - .info = snd_ctl_boolean_mono_info, - .get = vt1708_jack_detect_get, - .put = vt1708_jack_detect_put, -}; - -static void fill_dig_outs(struct hda_codec *codec); -static void fill_dig_in(struct hda_codec *codec); - -static int via_parse_auto_config(struct hda_codec *codec) +static int vt1709_parse_auto_config(struct hda_codec *codec) { struct via_spec *spec = codec->spec; int err; @@ -2644,167 +2650,145 @@ static int via_parse_auto_config(struct hda_codec *codec) err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); if (err < 0) return err; - if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) - return -EINVAL; - - err = via_auto_create_multi_out_ctls(codec); - if (err < 0) - return err; - err = via_auto_create_hp_ctls(codec, spec->autocfg.hp_pins[0]); + err = vt1709_auto_fill_dac_nids(spec, &spec->autocfg); if (err < 0) return err; - err = via_auto_create_speaker_ctls(codec); + if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) + return 0; /* can't find valid BIOS pin config */ + + err = vt1709_auto_create_multi_out_ctls(spec, &spec->autocfg); if (err < 0) return err; - err = via_auto_create_loopback_switch(codec); + err = vt1709_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); if (err < 0) return err; - err = via_auto_create_analog_input_ctls(codec); + err = vt1709_auto_create_analog_input_ctls(codec, &spec->autocfg); if (err < 0) return err; spec->multiout.max_channels = spec->multiout.num_dacs * 2; - fill_dig_outs(codec); - fill_dig_in(codec); + if (spec->autocfg.dig_outs) + spec->multiout.dig_out_nid = VT1709_DIGOUT_NID; + spec->dig_in_pin = VT1709_DIGIN_PIN; + if (spec->autocfg.dig_in_pin) + spec->dig_in_nid = VT1709_DIGIN_NID; if (spec->kctls.list) spec->mixers[spec->num_mixers++] = spec->kctls.list; + spec->input_mux = &spec->private_imux[0]; - if (spec->hp_dac_nid && spec->hp_mix_path.depth) { - err = via_hp_build(codec); - if (err < 0) - return err; - } - - err = via_smart51_build(codec); - if (err < 0) - return err; - - /* assign slave outs */ - if (spec->slave_dig_outs[0]) - codec->slave_dig_outs = spec->slave_dig_outs; + if (spec->hp_mux) + via_hp_build(codec); + via_smart51_build(spec); return 1; } -static void via_auto_init_dig_outs(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - if (spec->multiout.dig_out_nid) - init_output_pin(codec, spec->autocfg.dig_out_pins[0], PIN_OUT); - if (spec->slave_dig_outs[0]) - init_output_pin(codec, spec->autocfg.dig_out_pins[1], PIN_OUT); -} - -static void via_auto_init_dig_in(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - if (!spec->dig_in_nid) - return; - snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN); -} +#ifdef CONFIG_SND_HDA_POWER_SAVE +static const struct hda_amp_list vt1709_loopbacks[] = { + { 0x18, HDA_INPUT, 1 }, + { 0x18, HDA_INPUT, 2 }, + { 0x18, HDA_INPUT, 3 }, + { 0x18, HDA_INPUT, 4 }, + { } /* end */ +}; +#endif -/* initialize the unsolicited events */ -static void via_auto_init_unsol_event(struct hda_codec *codec) +static int patch_vt1709_10ch(struct hda_codec *codec) { - struct via_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - unsigned int ev; - int i; + struct via_spec *spec; + int err; - if (cfg->hp_pins[0] && is_jack_detectable(codec, cfg->hp_pins[0])) - snd_hda_codec_write(codec, cfg->hp_pins[0], 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT); + /* create a codec specific record */ + spec = via_new_spec(codec); + if (spec == NULL) + return -ENOMEM; - if (cfg->speaker_pins[0]) - ev = VIA_LINE_EVENT; - else - ev = 0; - for (i = 0; i < cfg->line_outs; i++) { - if (cfg->line_out_pins[i] && - is_jack_detectable(codec, cfg->line_out_pins[i])) - snd_hda_codec_write(codec, cfg->line_out_pins[i], 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | ev | VIA_JACK_EVENT); + err = vt1709_parse_auto_config(codec); + if (err < 0) { + via_free(codec); + return err; + } else if (!err) { + printk(KERN_INFO "hda_codec: Cannot set up configuration. " + "Using genenic mode...\n"); } - for (i = 0; i < cfg->num_inputs; i++) { - if (is_jack_detectable(codec, cfg->inputs[i].pin)) - snd_hda_codec_write(codec, cfg->inputs[i].pin, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | VIA_JACK_EVENT); - } -} + spec->init_verbs[spec->num_iverbs++] = vt1709_10ch_volume_init_verbs; + spec->init_verbs[spec->num_iverbs++] = vt1709_uniwill_init_verbs; -static int via_init(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int i; + spec->stream_name_analog = "VT1709 Analog"; + spec->stream_analog_playback = &vt1709_10ch_pcm_analog_playback; + spec->stream_analog_capture = &vt1709_pcm_analog_capture; - for (i = 0; i < spec->num_iverbs; i++) - snd_hda_sequence_write(codec, spec->init_verbs[i]); + spec->stream_name_digital = "VT1709 Digital"; + spec->stream_digital_playback = &vt1709_pcm_digital_playback; + spec->stream_digital_capture = &vt1709_pcm_digital_capture; - via_auto_init_multi_out(codec); - via_auto_init_hp_out(codec); - via_auto_init_speaker_out(codec); - via_auto_init_analog_input(codec); - via_auto_init_dig_outs(codec); - via_auto_init_dig_in(codec); - via_auto_init_unsol_event(codec); + if (!spec->adc_nids && spec->input_mux) { + spec->adc_nids = vt1709_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids); + get_mux_nids(codec); + spec->mixers[spec->num_mixers] = vt1709_capture_mixer; + spec->num_mixers++; + } + + codec->patch_ops = via_patch_ops; - via_hp_automute(codec); + codec->patch_ops.init = via_auto_init; + codec->patch_ops.unsol_event = via_unsol_event; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt1709_loopbacks; +#endif return 0; } +/* + * generic initialization of ADC, input mixers and output mixers + */ +static const struct hda_verb vt1709_6ch_volume_init_verbs[] = { + /* + * Unmute ADC0-2 and set the default input to mic-in + */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, -static void vt1708_update_hp_jack_state(struct work_struct *work) -{ - struct via_spec *spec = container_of(work, struct via_spec, - vt1708_hp_work.work); - if (spec->codec_type != VT1708) - return; - /* if jack state toggled */ - if (spec->vt1708_hp_present - != snd_hda_jack_detect(spec->codec, spec->autocfg.hp_pins[0])) { - spec->vt1708_hp_present ^= 1; - via_hp_automute(spec->codec); - } - vt1708_start_hp_work(spec); -} -static int get_mux_nids(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - hda_nid_t nid, conn[8]; - unsigned int type; - int i, n; + /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + */ + /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + + /* + * Set up output selector (0x1a, 0x1b, 0x29) + */ + /* set vol=0 to output mixers */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - for (i = 0; i < spec->num_adc_nids; i++) { - nid = spec->adc_nids[i]; - while (nid) { - type = get_wcaps_type(get_wcaps(codec, nid)); - if (type == AC_WID_PIN) - break; - n = snd_hda_get_connections(codec, nid, conn, - ARRAY_SIZE(conn)); - if (n <= 0) - break; - if (n > 1) { - spec->mux_nids[i] = nid; - break; - } - nid = conn[0]; - } - } - return 0; -} + /* + * Unmute PW3 and PW4 + */ + {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, -static int patch_vt1708(struct hda_codec *codec) + /* Set input of PW4 as MW0 */ + {0x20, AC_VERB_SET_CONNECT_SEL, 0}, + /* PW9 Output enable */ + {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + { } +}; + +static int patch_vt1709_6ch(struct hda_codec *codec) { struct via_spec *spec; int err; @@ -2814,66 +2798,444 @@ static int patch_vt1708(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - spec->aa_mix_nid = 0x17; - - /* Add HP and CD pin config connect bit re-config action */ - vt1708_set_pinconfig_connect(codec, VT1708_HP_PIN_NID); - vt1708_set_pinconfig_connect(codec, VT1708_CD_PIN_NID); - - /* automatic parse from the BIOS config */ - err = via_parse_auto_config(codec); + err = vt1709_parse_auto_config(codec); if (err < 0) { via_free(codec); return err; + } else if (!err) { + printk(KERN_INFO "hda_codec: Cannot set up configuration. " + "Using genenic mode...\n"); } - /* add jack detect on/off control */ - if (!via_clone_control(spec, &vt1708_jack_detect_ctl)) - return -ENOMEM; - - /* disable 32bit format on VT1708 */ - if (codec->vendor_id == 0x11061708) - spec->stream_analog_playback = &vt1708_pcm_analog_s16_playback; - - spec->init_verbs[spec->num_iverbs++] = vt1708_init_verbs; - - codec->patch_ops = via_patch_ops; - - INIT_DELAYED_WORK(&spec->vt1708_hp_work, vt1708_update_hp_jack_state); - return 0; -} + spec->init_verbs[spec->num_iverbs++] = vt1709_6ch_volume_init_verbs; + spec->init_verbs[spec->num_iverbs++] = vt1709_uniwill_init_verbs; -static int patch_vt1709(struct hda_codec *codec) -{ - struct via_spec *spec; - int err; + spec->stream_name_analog = "VT1709 Analog"; + spec->stream_analog_playback = &vt1709_6ch_pcm_analog_playback; + spec->stream_analog_capture = &vt1709_pcm_analog_capture; - /* create a codec specific record */ - spec = via_new_spec(codec); - if (spec == NULL) - return -ENOMEM; + spec->stream_name_digital = "VT1709 Digital"; + spec->stream_digital_playback = &vt1709_pcm_digital_playback; + spec->stream_digital_capture = &vt1709_pcm_digital_capture; - spec->aa_mix_nid = 0x18; - err = via_parse_auto_config(codec); - if (err < 0) { - via_free(codec); - return err; + if (!spec->adc_nids && spec->input_mux) { + spec->adc_nids = vt1709_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids); + get_mux_nids(codec); + spec->mixers[spec->num_mixers] = vt1709_capture_mixer; + spec->num_mixers++; } codec->patch_ops = via_patch_ops; + codec->patch_ops.init = via_auto_init; + codec->patch_ops.unsol_event = via_unsol_event; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt1709_loopbacks; +#endif return 0; } -static void set_widgets_power_state_vt1708B(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int imux_is_smixer; - unsigned int parm; - int is_8ch = 0; - if ((spec->codec_type != VT1708B_4CH) && - (codec->vendor_id != 0x11064397)) +/* capture mixer elements */ +static const struct snd_kcontrol_new vt1708B_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 1, + .info = via_mux_enum_info, + .get = via_mux_enum_get, + .put = via_mux_enum_put, + }, + { } /* end */ +}; +/* + * generic initialization of ADC, input mixers and output mixers + */ +static const struct hda_verb vt1708B_8ch_volume_init_verbs[] = { + /* + * Unmute ADC0-1 and set the default input to mic-in + */ + {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + + /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + */ + /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + + /* + * Set up output mixers + */ + /* set vol=0 to output mixers */ + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* Setup default input to PW4 */ + {0x1d, AC_VERB_SET_CONNECT_SEL, 0}, + /* PW9 Output enable */ + {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + /* PW10 Input enable */ + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + { } +}; + +static const struct hda_verb vt1708B_4ch_volume_init_verbs[] = { + /* + * Unmute ADC0-1 and set the default input to mic-in + */ + {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + + /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + */ + /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + + /* + * Set up output mixers + */ + /* set vol=0 to output mixers */ + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* Setup default input of PW4 to MW0 */ + {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0}, + /* PW9 Output enable */ + {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + /* PW10 Input enable */ + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + { } +}; + +static const struct hda_verb vt1708B_uniwill_init_verbs[] = { + {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, + {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x22, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + { } +}; + +static int via_pcm_open_close(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + int idle = substream->pstr->substream_opened == 1 + && substream->ref_count == 0; + + analog_low_current_mode(codec, idle); + return 0; +} + +static const struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = { + .substreams = 2, + .channels_min = 2, + .channels_max = 8, + .nid = 0x10, /* NID to query formats and rates */ + .ops = { + .open = via_playback_pcm_open, + .prepare = via_playback_multi_pcm_prepare, + .cleanup = via_playback_multi_pcm_cleanup, + .close = via_pcm_open_close + }, +}; + +static const struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = { + .substreams = 2, + .channels_min = 2, + .channels_max = 4, + .nid = 0x10, /* NID to query formats and rates */ + .ops = { + .open = via_playback_pcm_open, + .prepare = via_playback_multi_pcm_prepare, + .cleanup = via_playback_multi_pcm_cleanup + }, +}; + +static const struct hda_pcm_stream vt1708B_pcm_analog_capture = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + .nid = 0x13, /* NID to query formats and rates */ + .ops = { + .open = via_pcm_open_close, + .prepare = via_capture_pcm_prepare, + .cleanup = via_capture_pcm_cleanup, + .close = via_pcm_open_close + }, +}; + +static const struct hda_pcm_stream vt1708B_pcm_digital_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in via_build_pcms */ + .ops = { + .open = via_dig_playback_pcm_open, + .close = via_dig_playback_pcm_close, + .prepare = via_dig_playback_pcm_prepare, + .cleanup = via_dig_playback_pcm_cleanup + }, +}; + +static const struct hda_pcm_stream vt1708B_pcm_digital_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, +}; + +/* fill in the dac_nids table from the parsed pin configuration */ +static int vt1708B_auto_fill_dac_nids(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + int i; + hda_nid_t nid; + + spec->multiout.num_dacs = cfg->line_outs; + + spec->multiout.dac_nids = spec->private_dac_nids; + + for (i = 0; i < 4; i++) { + nid = cfg->line_out_pins[i]; + if (nid) { + /* config dac list */ + switch (i) { + case AUTO_SEQ_FRONT: + spec->private_dac_nids[i] = 0x10; + break; + case AUTO_SEQ_CENLFE: + spec->private_dac_nids[i] = 0x24; + break; + case AUTO_SEQ_SURROUND: + spec->private_dac_nids[i] = 0x11; + break; + case AUTO_SEQ_SIDE: + spec->private_dac_nids[i] = 0x25; + break; + } + } + } + + return 0; +} + +/* add playback controls from the parsed DAC table */ +static int vt1708B_auto_create_multi_out_ctls(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + char name[32]; + static const char * const chname[4] = { + "Front", "Surround", "C/LFE", "Side" + }; + hda_nid_t nid_vols[] = {0x16, 0x18, 0x26, 0x27}; + hda_nid_t nid, nid_vol = 0; + int i, err; + + for (i = 0; i <= AUTO_SEQ_SIDE; i++) { + nid = cfg->line_out_pins[i]; + + if (!nid) + continue; + + nid_vol = nid_vols[i]; + + if (i == AUTO_SEQ_CENLFE) { + /* Center/LFE */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Center Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "LFE Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Center Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "LFE Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } else if (i == AUTO_SEQ_FRONT) { + /* add control to mixer index 0 */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Master Front Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, + HDA_INPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Master Front Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, + HDA_INPUT)); + if (err < 0) + return err; + + /* add control to PW3 */ + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } else { + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } + } + + return 0; +} + +static int vt1708B_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) +{ + int err; + + if (!pin) + return 0; + + spec->multiout.hp_nid = VT1708B_HP_NID; /* AOW3 */ + spec->hp_independent_mode_index = 1; + + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Headphone Playback Volume", + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Headphone Playback Switch", + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + create_hp_imux(spec); + + return 0; +} + +/* create playback/capture controls for input pins */ +static int vt1708B_auto_create_analog_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) +{ + static const hda_nid_t pin_idxs[] = { 0xff, 0x1f, 0x1a, 0x1b, 0x1e }; + return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs, + ARRAY_SIZE(pin_idxs)); +} + +static int vt1708B_parse_auto_config(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int err; + + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); + if (err < 0) + return err; + err = vt1708B_auto_fill_dac_nids(spec, &spec->autocfg); + if (err < 0) + return err; + if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) + return 0; /* can't find valid BIOS pin config */ + + err = vt1708B_auto_create_multi_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + err = vt1708B_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); + if (err < 0) + return err; + err = vt1708B_auto_create_analog_input_ctls(codec, &spec->autocfg); + if (err < 0) + return err; + + spec->multiout.max_channels = spec->multiout.num_dacs * 2; + + if (spec->autocfg.dig_outs) + spec->multiout.dig_out_nid = VT1708B_DIGOUT_NID; + spec->dig_in_pin = VT1708B_DIGIN_PIN; + if (spec->autocfg.dig_in_pin) + spec->dig_in_nid = VT1708B_DIGIN_NID; + + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; + + spec->input_mux = &spec->private_imux[0]; + + if (spec->hp_mux) + via_hp_build(codec); + + via_smart51_build(spec); + return 1; +} + +#ifdef CONFIG_SND_HDA_POWER_SAVE +static const struct hda_amp_list vt1708B_loopbacks[] = { + { 0x16, HDA_INPUT, 1 }, + { 0x16, HDA_INPUT, 2 }, + { 0x16, HDA_INPUT, 3 }, + { 0x16, HDA_INPUT, 4 }, + { } /* end */ +}; +#endif + +static void set_widgets_power_state_vt1708B(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int imux_is_smixer; + unsigned int parm; + int is_8ch = 0; + if ((spec->codec_type != VT1708B_4CH) && + (codec->vendor_id != 0x11064397)) is_8ch = 1; /* SW0 (17h) = stereo mixer */ @@ -2947,107 +3309,61 @@ static void set_widgets_power_state_vt1708B(struct hda_codec *codec) } static int patch_vt1708S(struct hda_codec *codec); -static int patch_vt1708B(struct hda_codec *codec) +static int patch_vt1708B_8ch(struct hda_codec *codec) { struct via_spec *spec; int err; if (get_codec_type(codec) == VT1708BCE) return patch_vt1708S(codec); - /* create a codec specific record */ spec = via_new_spec(codec); if (spec == NULL) return -ENOMEM; - spec->aa_mix_nid = 0x16; - /* automatic parse from the BIOS config */ - err = via_parse_auto_config(codec); + err = vt1708B_parse_auto_config(codec); if (err < 0) { via_free(codec); return err; + } else if (!err) { + printk(KERN_INFO "hda_codec: Cannot set up configuration " + "from BIOS. Using genenic mode...\n"); } - codec->patch_ops = via_patch_ops; - - spec->set_widgets_power_state = set_widgets_power_state_vt1708B; - - return 0; -} - -/* Patch for VT1708S */ -static const struct hda_verb vt1708S_init_verbs[] = { - /* Enable Mic Boost Volume backdoor */ - {0x1, 0xf98, 0x1}, - /* don't bybass mixer */ - {0x1, 0xf88, 0xc0}, - { } -}; + spec->init_verbs[spec->num_iverbs++] = vt1708B_8ch_volume_init_verbs; + spec->init_verbs[spec->num_iverbs++] = vt1708B_uniwill_init_verbs; -/* fill out digital output widgets; one for master and one for slave outputs */ -static void fill_dig_outs(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int i; + spec->stream_name_analog = "VT1708B Analog"; + spec->stream_analog_playback = &vt1708B_8ch_pcm_analog_playback; + spec->stream_analog_capture = &vt1708B_pcm_analog_capture; - for (i = 0; i < spec->autocfg.dig_outs; i++) { - hda_nid_t nid; - int conn; + spec->stream_name_digital = "VT1708B Digital"; + spec->stream_digital_playback = &vt1708B_pcm_digital_playback; + spec->stream_digital_capture = &vt1708B_pcm_digital_capture; - nid = spec->autocfg.dig_out_pins[i]; - if (!nid) - continue; - conn = snd_hda_get_connections(codec, nid, &nid, 1); - if (conn < 1) - continue; - if (!spec->multiout.dig_out_nid) - spec->multiout.dig_out_nid = nid; - else { - spec->slave_dig_outs[0] = nid; - break; /* at most two dig outs */ - } + if (!spec->adc_nids && spec->input_mux) { + spec->adc_nids = vt1708B_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids); + get_mux_nids(codec); + spec->mixers[spec->num_mixers] = vt1708B_capture_mixer; + spec->num_mixers++; } -} -static void fill_dig_in(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - hda_nid_t dig_nid; - int i, err; + codec->patch_ops = via_patch_ops; - if (!spec->autocfg.dig_in_pin) - return; + codec->patch_ops.init = via_auto_init; + codec->patch_ops.unsol_event = via_unsol_event; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt1708B_loopbacks; +#endif - dig_nid = codec->start_nid; - for (i = 0; i < codec->num_nodes; i++, dig_nid++) { - unsigned int wcaps = get_wcaps(codec, dig_nid); - if (get_wcaps_type(wcaps) != AC_WID_AUD_IN) - continue; - if (!(wcaps & AC_WCAP_DIGITAL)) - continue; - if (!(wcaps & AC_WCAP_CONN_LIST)) - continue; - err = get_connection_index(codec, dig_nid, - spec->autocfg.dig_in_pin); - if (err >= 0) { - spec->dig_in_nid = dig_nid; - break; - } - } -} + spec->set_widgets_power_state = set_widgets_power_state_vt1708B; -static void override_mic_boost(struct hda_codec *codec, hda_nid_t pin, - int offset, int num_steps, int step_size) -{ - snd_hda_override_amp_caps(codec, pin, HDA_INPUT, - (offset << AC_AMPCAP_OFFSET_SHIFT) | - (num_steps << AC_AMPCAP_NUM_STEPS_SHIFT) | - (step_size << AC_AMPCAP_STEP_SIZE_SHIFT) | - (0 << AC_AMPCAP_MUTE_SHIFT)); + return 0; } -static int patch_vt1708S(struct hda_codec *codec) +static int patch_vt1708B_4ch(struct hda_codec *codec) { struct via_spec *spec; int err; @@ -3057,28 +3373,536 @@ static int patch_vt1708S(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - spec->aa_mix_nid = 0x16; - override_mic_boost(codec, 0x1a, 0, 3, 40); - override_mic_boost(codec, 0x1e, 0, 3, 40); - /* automatic parse from the BIOS config */ - err = via_parse_auto_config(codec); + err = vt1708B_parse_auto_config(codec); if (err < 0) { via_free(codec); return err; + } else if (!err) { + printk(KERN_INFO "hda_codec: Cannot set up configuration " + "from BIOS. Using genenic mode...\n"); } - spec->init_verbs[spec->num_iverbs++] = vt1708S_init_verbs; + spec->init_verbs[spec->num_iverbs++] = vt1708B_4ch_volume_init_verbs; + spec->init_verbs[spec->num_iverbs++] = vt1708B_uniwill_init_verbs; - codec->patch_ops = via_patch_ops; + spec->stream_name_analog = "VT1708B Analog"; + spec->stream_analog_playback = &vt1708B_4ch_pcm_analog_playback; + spec->stream_analog_capture = &vt1708B_pcm_analog_capture; - /* correct names for VT1708BCE */ + spec->stream_name_digital = "VT1708B Digital"; + spec->stream_digital_playback = &vt1708B_pcm_digital_playback; + spec->stream_digital_capture = &vt1708B_pcm_digital_capture; + + if (!spec->adc_nids && spec->input_mux) { + spec->adc_nids = vt1708B_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids); + get_mux_nids(codec); + spec->mixers[spec->num_mixers] = vt1708B_capture_mixer; + spec->num_mixers++; + } + + codec->patch_ops = via_patch_ops; + + codec->patch_ops.init = via_auto_init; + codec->patch_ops.unsol_event = via_unsol_event; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt1708B_loopbacks; +#endif + + spec->set_widgets_power_state = set_widgets_power_state_vt1708B; + + return 0; +} + +/* Patch for VT1708S */ + +/* capture mixer elements */ +static const struct snd_kcontrol_new vt1708S_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x1A, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x1E, 0x0, + HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 1, + .info = via_mux_enum_info, + .get = via_mux_enum_get, + .put = via_mux_enum_put, + }, + { } /* end */ +}; + +static const struct hda_verb vt1708S_volume_init_verbs[] = { + /* Unmute ADC0-1 and set the default input to mic-in */ + {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the + * analog-loopback mixer widget */ + /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + + /* Setup default input of PW4 to MW0 */ + {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0}, + /* PW9, PW10 Output enable */ + {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + /* Enable Mic Boost Volume backdoor */ + {0x1, 0xf98, 0x1}, + /* don't bybass mixer */ + {0x1, 0xf88, 0xc0}, + { } +}; + +static const struct hda_verb vt1708S_uniwill_init_verbs[] = { + {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, + {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x22, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + { } +}; + +static const struct hda_verb vt1705_uniwill_init_verbs[] = { + {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, + {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + { } +}; + +static const struct hda_pcm_stream vt1708S_pcm_analog_playback = { + .substreams = 2, + .channels_min = 2, + .channels_max = 8, + .nid = 0x10, /* NID to query formats and rates */ + .ops = { + .open = via_playback_pcm_open, + .prepare = via_playback_multi_pcm_prepare, + .cleanup = via_playback_multi_pcm_cleanup, + .close = via_pcm_open_close + }, +}; + +static const struct hda_pcm_stream vt1705_pcm_analog_playback = { + .substreams = 2, + .channels_min = 2, + .channels_max = 6, + .nid = 0x10, /* NID to query formats and rates */ + .ops = { + .open = via_playback_pcm_open, + .prepare = via_playback_multi_pcm_prepare, + .cleanup = via_playback_multi_pcm_cleanup, + .close = via_pcm_open_close + }, +}; + +static const struct hda_pcm_stream vt1708S_pcm_analog_capture = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + .nid = 0x13, /* NID to query formats and rates */ + .ops = { + .open = via_pcm_open_close, + .prepare = via_capture_pcm_prepare, + .cleanup = via_capture_pcm_cleanup, + .close = via_pcm_open_close + }, +}; + +static const struct hda_pcm_stream vt1708S_pcm_digital_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in via_build_pcms */ + .ops = { + .open = via_dig_playback_pcm_open, + .close = via_dig_playback_pcm_close, + .prepare = via_dig_playback_pcm_prepare, + .cleanup = via_dig_playback_pcm_cleanup + }, +}; + +/* fill in the dac_nids table from the parsed pin configuration */ +static int vt1708S_auto_fill_dac_nids(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + int i; + hda_nid_t nid; + + spec->multiout.num_dacs = cfg->line_outs; + + spec->multiout.dac_nids = spec->private_dac_nids; + + for (i = 0; i < 4; i++) { + nid = cfg->line_out_pins[i]; + if (nid) { + /* config dac list */ + switch (i) { + case AUTO_SEQ_FRONT: + spec->private_dac_nids[i] = 0x10; + break; + case AUTO_SEQ_CENLFE: + if (spec->codec->vendor_id == 0x11064397) + spec->private_dac_nids[i] = 0x25; + else + spec->private_dac_nids[i] = 0x24; + break; + case AUTO_SEQ_SURROUND: + spec->private_dac_nids[i] = 0x11; + break; + case AUTO_SEQ_SIDE: + spec->private_dac_nids[i] = 0x25; + break; + } + } + } + + /* for Smart 5.1, line/mic inputs double as output pins */ + if (cfg->line_outs == 1) { + spec->multiout.num_dacs = 3; + spec->private_dac_nids[AUTO_SEQ_SURROUND] = 0x11; + if (spec->codec->vendor_id == 0x11064397) + spec->private_dac_nids[AUTO_SEQ_CENLFE] = 0x25; + else + spec->private_dac_nids[AUTO_SEQ_CENLFE] = 0x24; + } + + return 0; +} + +/* add playback controls from the parsed DAC table */ +static int vt1708S_auto_create_multi_out_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) +{ + struct via_spec *spec = codec->spec; + char name[32]; + static const char * const chname[4] = { + "Front", "Surround", "C/LFE", "Side" + }; + hda_nid_t nid_vols[2][4] = { {0x10, 0x11, 0x24, 0x25}, + {0x10, 0x11, 0x25, 0} }; + hda_nid_t nid_mutes[2][4] = { {0x1C, 0x18, 0x26, 0x27}, + {0x1C, 0x18, 0x27, 0} }; + hda_nid_t nid, nid_vol, nid_mute; + int i, err; + + for (i = 0; i <= AUTO_SEQ_SIDE; i++) { + nid = cfg->line_out_pins[i]; + + /* for Smart 5.1, there are always at least six channels */ + if (!nid && i > AUTO_SEQ_CENLFE) + continue; + + if (codec->vendor_id == 0x11064397) { + nid_vol = nid_vols[1][i]; + nid_mute = nid_mutes[1][i]; + } else { + nid_vol = nid_vols[0][i]; + nid_mute = nid_mutes[0][i]; + } + if (!nid_vol && !nid_mute) + continue; + + if (i == AUTO_SEQ_CENLFE) { + /* Center/LFE */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Center Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "LFE Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Center Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_mute, + 1, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "LFE Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_mute, + 2, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } else if (i == AUTO_SEQ_FRONT) { + /* add control to mixer index 0 */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Master Front Playback Volume", + HDA_COMPOSE_AMP_VAL(0x16, 3, 0, + HDA_INPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Master Front Playback Switch", + HDA_COMPOSE_AMP_VAL(0x16, 3, 0, + HDA_INPUT)); + if (err < 0) + return err; + + /* Front */ + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid_mute, + 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } else { + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid_mute, + 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } + } + + return 0; +} + +static int vt1708S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) +{ + int err; + + if (!pin) + return 0; + + spec->multiout.hp_nid = VT1708S_HP_NID; /* AOW3 */ + spec->hp_independent_mode_index = 1; + + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Headphone Playback Volume", + HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Headphone Playback Switch", + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + create_hp_imux(spec); + + return 0; +} + +/* create playback/capture controls for input pins */ +static int vt1708S_auto_create_analog_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) +{ + static const hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff }; + return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs, + ARRAY_SIZE(pin_idxs)); +} + +/* fill out digital output widgets; one for master and one for slave outputs */ +static void fill_dig_outs(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int i; + + for (i = 0; i < spec->autocfg.dig_outs; i++) { + hda_nid_t nid; + int conn; + + nid = spec->autocfg.dig_out_pins[i]; + if (!nid) + continue; + conn = snd_hda_get_connections(codec, nid, &nid, 1); + if (conn < 1) + continue; + if (!spec->multiout.dig_out_nid) + spec->multiout.dig_out_nid = nid; + else { + spec->slave_dig_outs[0] = nid; + break; /* at most two dig outs */ + } + } +} + +static int vt1708S_parse_auto_config(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int err; + + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); + if (err < 0) + return err; + err = vt1708S_auto_fill_dac_nids(spec, &spec->autocfg); + if (err < 0) + return err; + if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) + return 0; /* can't find valid BIOS pin config */ + + err = vt1708S_auto_create_multi_out_ctls(codec, &spec->autocfg); + if (err < 0) + return err; + err = vt1708S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); + if (err < 0) + return err; + err = vt1708S_auto_create_analog_input_ctls(codec, &spec->autocfg); + if (err < 0) + return err; + + spec->multiout.max_channels = spec->multiout.num_dacs * 2; + + fill_dig_outs(codec); + + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; + + spec->input_mux = &spec->private_imux[0]; + + if (spec->hp_mux) + via_hp_build(codec); + + via_smart51_build(spec); + return 1; +} + +#ifdef CONFIG_SND_HDA_POWER_SAVE +static const struct hda_amp_list vt1708S_loopbacks[] = { + { 0x16, HDA_INPUT, 1 }, + { 0x16, HDA_INPUT, 2 }, + { 0x16, HDA_INPUT, 3 }, + { 0x16, HDA_INPUT, 4 }, + { } /* end */ +}; +#endif + +static void override_mic_boost(struct hda_codec *codec, hda_nid_t pin, + int offset, int num_steps, int step_size) +{ + snd_hda_override_amp_caps(codec, pin, HDA_INPUT, + (offset << AC_AMPCAP_OFFSET_SHIFT) | + (num_steps << AC_AMPCAP_NUM_STEPS_SHIFT) | + (step_size << AC_AMPCAP_STEP_SIZE_SHIFT) | + (0 << AC_AMPCAP_MUTE_SHIFT)); +} + +static int patch_vt1708S(struct hda_codec *codec) +{ + struct via_spec *spec; + int err; + + /* create a codec specific record */ + spec = via_new_spec(codec); + if (spec == NULL) + return -ENOMEM; + + /* automatic parse from the BIOS config */ + err = vt1708S_parse_auto_config(codec); + if (err < 0) { + via_free(codec); + return err; + } else if (!err) { + printk(KERN_INFO "hda_codec: Cannot set up configuration " + "from BIOS. Using genenic mode...\n"); + } + + spec->init_verbs[spec->num_iverbs++] = vt1708S_volume_init_verbs; + if (codec->vendor_id == 0x11064397) + spec->init_verbs[spec->num_iverbs++] = + vt1705_uniwill_init_verbs; + else + spec->init_verbs[spec->num_iverbs++] = + vt1708S_uniwill_init_verbs; + + if (codec->vendor_id == 0x11060440) + spec->stream_name_analog = "VT1818S Analog"; + else if (codec->vendor_id == 0x11064397) + spec->stream_name_analog = "VT1705 Analog"; + else + spec->stream_name_analog = "VT1708S Analog"; + if (codec->vendor_id == 0x11064397) + spec->stream_analog_playback = &vt1705_pcm_analog_playback; + else + spec->stream_analog_playback = &vt1708S_pcm_analog_playback; + spec->stream_analog_capture = &vt1708S_pcm_analog_capture; + + if (codec->vendor_id == 0x11060440) + spec->stream_name_digital = "VT1818S Digital"; + else if (codec->vendor_id == 0x11064397) + spec->stream_name_digital = "VT1705 Digital"; + else + spec->stream_name_digital = "VT1708S Digital"; + spec->stream_digital_playback = &vt1708S_pcm_digital_playback; + + if (!spec->adc_nids && spec->input_mux) { + spec->adc_nids = vt1708S_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(vt1708S_adc_nids); + get_mux_nids(codec); + override_mic_boost(codec, 0x1a, 0, 3, 40); + override_mic_boost(codec, 0x1e, 0, 3, 40); + spec->mixers[spec->num_mixers] = vt1708S_capture_mixer; + spec->num_mixers++; + } + + codec->patch_ops = via_patch_ops; + + codec->patch_ops.init = via_auto_init; + codec->patch_ops.unsol_event = via_unsol_event; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt1708S_loopbacks; +#endif + + /* correct names for VT1708BCE */ if (get_codec_type(codec) == VT1708BCE) { kfree(codec->chip_name); codec->chip_name = kstrdup("VT1708BCE", GFP_KERNEL); snprintf(codec->bus->card->mixername, sizeof(codec->bus->card->mixername), "%s %s", codec->vendor_name, codec->chip_name); + spec->stream_name_analog = "VT1708BCE Analog"; + spec->stream_name_digital = "VT1708BCE Digital"; + } + /* correct names for VT1818S */ + if (codec->vendor_id == 0x11060440) { + spec->stream_name_analog = "VT1818S Analog"; + spec->stream_name_digital = "VT1818S Digital"; } /* correct names for VT1705 */ if (codec->vendor_id == 0x11064397) { @@ -3088,19 +3912,263 @@ static int patch_vt1708S(struct hda_codec *codec) sizeof(codec->bus->card->mixername), "%s %s", codec->vendor_name, codec->chip_name); } - spec->set_widgets_power_state = set_widgets_power_state_vt1708B; + spec->set_widgets_power_state = set_widgets_power_state_vt1708B; + return 0; +} + +/* Patch for VT1702 */ + +/* capture mixer elements */ +static const struct snd_kcontrol_new vt1702_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x20, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x20, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x1F, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x1F, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Digital Mic Boost Capture Volume", 0x1E, 0x0, + HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 1, + .info = via_mux_enum_info, + .get = via_mux_enum_get, + .put = via_mux_enum_put, + }, + { } /* end */ +}; + +static const struct hda_verb vt1702_volume_init_verbs[] = { + /* + * Unmute ADC0-1 and set the default input to mic-in + */ + {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x1F, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + + /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + */ + /* Amp Indices: Mic1 = 1, Line = 1, Mic2 = 3 */ + {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + + /* Setup default input of PW4 to MW0 */ + {0x17, AC_VERB_SET_CONNECT_SEL, 0x1}, + /* PW6 PW7 Output enable */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x1C, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + /* mixer enable */ + {0x1, 0xF88, 0x3}, + /* GPIO 0~2 */ + {0x1, 0xF82, 0x3F}, + { } +}; + +static const struct hda_verb vt1702_uniwill_init_verbs[] = { + {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + { } +}; + +static const struct hda_pcm_stream vt1702_pcm_analog_playback = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + .nid = 0x10, /* NID to query formats and rates */ + .ops = { + .open = via_playback_pcm_open, + .prepare = via_playback_multi_pcm_prepare, + .cleanup = via_playback_multi_pcm_cleanup, + .close = via_pcm_open_close + }, +}; + +static const struct hda_pcm_stream vt1702_pcm_analog_capture = { + .substreams = 3, + .channels_min = 2, + .channels_max = 2, + .nid = 0x12, /* NID to query formats and rates */ + .ops = { + .open = via_pcm_open_close, + .prepare = via_capture_pcm_prepare, + .cleanup = via_capture_pcm_cleanup, + .close = via_pcm_open_close + }, +}; + +static const struct hda_pcm_stream vt1702_pcm_digital_playback = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + /* NID is set in via_build_pcms */ + .ops = { + .open = via_dig_playback_pcm_open, + .close = via_dig_playback_pcm_close, + .prepare = via_dig_playback_pcm_prepare, + .cleanup = via_dig_playback_pcm_cleanup + }, +}; + +/* fill in the dac_nids table from the parsed pin configuration */ +static int vt1702_auto_fill_dac_nids(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + spec->multiout.num_dacs = 1; + spec->multiout.dac_nids = spec->private_dac_nids; + + if (cfg->line_out_pins[0]) { + /* config dac list */ + spec->private_dac_nids[0] = 0x10; + } + return 0; } -/* Patch for VT1702 */ +/* add playback controls from the parsed DAC table */ +static int vt1702_auto_create_line_out_ctls(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + int err; -static const struct hda_verb vt1702_init_verbs[] = { - /* mixer enable */ - {0x1, 0xF88, 0x3}, - /* GPIO 0~2 */ - {0x1, 0xF82, 0x3F}, - { } + if (!cfg->line_out_pins[0]) + return -1; + + /* add control to mixer index 0 */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Master Front Playback Volume", + HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Master Front Playback Switch", + HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT)); + if (err < 0) + return err; + + /* Front */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Front Playback Volume", + HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Front Playback Switch", + HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + return 0; +} + +static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) +{ + int err, i; + struct hda_input_mux *imux; + static const char * const texts[] = { "ON", "OFF", NULL}; + if (!pin) + return 0; + spec->multiout.hp_nid = 0x1D; + spec->hp_independent_mode_index = 0; + + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Headphone Playback Volume", + HDA_COMPOSE_AMP_VAL(0x1D, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Headphone Playback Switch", + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + imux = &spec->private_imux[1]; + + /* for hp mode select */ + for (i = 0; texts[i]; i++) + snd_hda_add_imux_item(imux, texts[i], i, NULL); + + spec->hp_mux = &spec->private_imux[1]; + return 0; +} + +/* create playback/capture controls for input pins */ +static int vt1702_auto_create_analog_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) +{ + static const hda_nid_t pin_idxs[] = { 0x14, 0x15, 0x18, 0xff }; + return vt_auto_create_analog_input_ctls(codec, cfg, 0x1a, pin_idxs, + ARRAY_SIZE(pin_idxs)); +} + +static int vt1702_parse_auto_config(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int err; + + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); + if (err < 0) + return err; + err = vt1702_auto_fill_dac_nids(spec, &spec->autocfg); + if (err < 0) + return err; + if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) + return 0; /* can't find valid BIOS pin config */ + + err = vt1702_auto_create_line_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + err = vt1702_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); + if (err < 0) + return err; + /* limit AA path volume to 0 dB */ + snd_hda_override_amp_caps(codec, 0x1A, HDA_INPUT, + (0x17 << AC_AMPCAP_OFFSET_SHIFT) | + (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | + (0x5 << AC_AMPCAP_STEP_SIZE_SHIFT) | + (1 << AC_AMPCAP_MUTE_SHIFT)); + err = vt1702_auto_create_analog_input_ctls(codec, &spec->autocfg); + if (err < 0) + return err; + + spec->multiout.max_channels = spec->multiout.num_dacs * 2; + + fill_dig_outs(codec); + + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; + + spec->input_mux = &spec->private_imux[0]; + + if (spec->hp_mux) + via_hp_build(codec); + + return 1; +} + +#ifdef CONFIG_SND_HDA_POWER_SAVE +static const struct hda_amp_list vt1702_loopbacks[] = { + { 0x1A, HDA_INPUT, 1 }, + { 0x1A, HDA_INPUT, 2 }, + { 0x1A, HDA_INPUT, 3 }, + { 0x1A, HDA_INPUT, 4 }, + { } /* end */ }; +#endif static void set_widgets_power_state_vt1702(struct hda_codec *codec) { @@ -3121,62 +4189,414 @@ static void set_widgets_power_state_vt1702(struct hda_codec *codec) snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm); snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_POWER_STATE, parm); - /* outputs */ - /* PW 3/4 (16h/17h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x17, &parm); - set_pin_power_state(codec, 0x16, &parm); - /* MW0 (1ah), AOW 0/1 (10h/1dh) */ - snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE, - imux_is_smixer ? AC_PWRST_D0 : parm); - snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE, parm); + /* outputs */ + /* PW 3/4 (16h/17h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x17, &parm); + set_pin_power_state(codec, 0x16, &parm); + /* MW0 (1ah), AOW 0/1 (10h/1dh) */ + snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE, + imux_is_smixer ? AC_PWRST_D0 : parm); + snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE, parm); +} + +static int patch_vt1702(struct hda_codec *codec) +{ + struct via_spec *spec; + int err; + + /* create a codec specific record */ + spec = via_new_spec(codec); + if (spec == NULL) + return -ENOMEM; + + /* automatic parse from the BIOS config */ + err = vt1702_parse_auto_config(codec); + if (err < 0) { + via_free(codec); + return err; + } else if (!err) { + printk(KERN_INFO "hda_codec: Cannot set up configuration " + "from BIOS. Using genenic mode...\n"); + } + + spec->init_verbs[spec->num_iverbs++] = vt1702_volume_init_verbs; + spec->init_verbs[spec->num_iverbs++] = vt1702_uniwill_init_verbs; + + spec->stream_name_analog = "VT1702 Analog"; + spec->stream_analog_playback = &vt1702_pcm_analog_playback; + spec->stream_analog_capture = &vt1702_pcm_analog_capture; + + spec->stream_name_digital = "VT1702 Digital"; + spec->stream_digital_playback = &vt1702_pcm_digital_playback; + + if (!spec->adc_nids && spec->input_mux) { + spec->adc_nids = vt1702_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(vt1702_adc_nids); + get_mux_nids(codec); + spec->mixers[spec->num_mixers] = vt1702_capture_mixer; + spec->num_mixers++; + } + + codec->patch_ops = via_patch_ops; + + codec->patch_ops.init = via_auto_init; + codec->patch_ops.unsol_event = via_unsol_event; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt1702_loopbacks; +#endif + + spec->set_widgets_power_state = set_widgets_power_state_vt1702; + return 0; +} + +/* Patch for VT1718S */ + +/* capture mixer elements */ +static const struct snd_kcontrol_new vt1718S_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x29, 0x0, + HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + */ + .name = "Input Source", + .count = 2, + .info = via_mux_enum_info, + .get = via_mux_enum_get, + .put = via_mux_enum_put, + }, + { } /* end */ +}; + +static const struct hda_verb vt1718S_volume_init_verbs[] = { + /* + * Unmute ADC0-1 and set the default input to mic-in + */ + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Enable MW0 adjust Gain 5 */ + {0x1, 0xfb2, 0x10}, + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + */ + /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)}, + /* PW9 PW10 Output enable */ + {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN}, + {0x2e, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN}, + /* PW11 Input enable */ + {0x2f, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_IN_EN}, + /* Enable Boost Volume backdoor */ + {0x1, 0xf88, 0x8}, + /* MW0/1/2/3/4: un-mute index 0 (AOWx), mute index 1 (MW9) */ + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* set MUX1 = 2 (AOW4), MUX2 = 1 (AOW3) */ + {0x34, AC_VERB_SET_CONNECT_SEL, 0x2}, + {0x35, AC_VERB_SET_CONNECT_SEL, 0x1}, + { } +}; + + +static const struct hda_verb vt1718S_uniwill_init_verbs[] = { + {0x28, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, + {0x24, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x25, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x26, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x27, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + { } +}; + +static const struct hda_pcm_stream vt1718S_pcm_analog_playback = { + .substreams = 2, + .channels_min = 2, + .channels_max = 10, + .nid = 0x8, /* NID to query formats and rates */ + .ops = { + .open = via_playback_pcm_open, + .prepare = via_playback_multi_pcm_prepare, + .cleanup = via_playback_multi_pcm_cleanup, + .close = via_pcm_open_close, + }, +}; + +static const struct hda_pcm_stream vt1718S_pcm_analog_capture = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + .nid = 0x10, /* NID to query formats and rates */ + .ops = { + .open = via_pcm_open_close, + .prepare = via_capture_pcm_prepare, + .cleanup = via_capture_pcm_cleanup, + .close = via_pcm_open_close, + }, +}; + +static const struct hda_pcm_stream vt1718S_pcm_digital_playback = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + /* NID is set in via_build_pcms */ + .ops = { + .open = via_dig_playback_pcm_open, + .close = via_dig_playback_pcm_close, + .prepare = via_dig_playback_pcm_prepare, + .cleanup = via_dig_playback_pcm_cleanup + }, +}; + +static const struct hda_pcm_stream vt1718S_pcm_digital_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, +}; + +/* fill in the dac_nids table from the parsed pin configuration */ +static int vt1718S_auto_fill_dac_nids(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + int i; + hda_nid_t nid; + + spec->multiout.num_dacs = cfg->line_outs; + + spec->multiout.dac_nids = spec->private_dac_nids; + + for (i = 0; i < 4; i++) { + nid = cfg->line_out_pins[i]; + if (nid) { + /* config dac list */ + switch (i) { + case AUTO_SEQ_FRONT: + spec->private_dac_nids[i] = 0x8; + break; + case AUTO_SEQ_CENLFE: + spec->private_dac_nids[i] = 0xa; + break; + case AUTO_SEQ_SURROUND: + spec->private_dac_nids[i] = 0x9; + break; + case AUTO_SEQ_SIDE: + spec->private_dac_nids[i] = 0xb; + break; + } + } + } + + return 0; +} + +/* add playback controls from the parsed DAC table */ +static int vt1718S_auto_create_multi_out_ctls(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + char name[32]; + static const char * const chname[4] = { + "Front", "Surround", "C/LFE", "Side" + }; + hda_nid_t nid_vols[] = {0x8, 0x9, 0xa, 0xb}; + hda_nid_t nid_mutes[] = {0x24, 0x25, 0x26, 0x27}; + hda_nid_t nid, nid_vol, nid_mute = 0; + int i, err; + + for (i = 0; i <= AUTO_SEQ_SIDE; i++) { + nid = cfg->line_out_pins[i]; + + if (!nid) + continue; + nid_vol = nid_vols[i]; + nid_mute = nid_mutes[i]; + + if (i == AUTO_SEQ_CENLFE) { + /* Center/LFE */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Center Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "LFE Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control( + spec, VIA_CTL_WIDGET_MUTE, + "Center Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_mute, 1, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control( + spec, VIA_CTL_WIDGET_MUTE, + "LFE Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_mute, 2, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } else if (i == AUTO_SEQ_FRONT) { + /* add control to mixer index 0 */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Master Front Playback Volume", + HDA_COMPOSE_AMP_VAL(0x21, 3, 5, + HDA_INPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Master Front Playback Switch", + HDA_COMPOSE_AMP_VAL(0x21, 3, 5, + HDA_INPUT)); + if (err < 0) + return err; + /* Front */ + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control( + spec, VIA_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control( + spec, VIA_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } else { + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control( + spec, VIA_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control( + spec, VIA_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } + } + return 0; +} + +static int vt1718S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) +{ + int err; + + if (!pin) + return 0; + + spec->multiout.hp_nid = 0xc; /* AOW4 */ + spec->hp_independent_mode_index = 1; + + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Headphone Playback Volume", + HDA_COMPOSE_AMP_VAL(0xc, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Headphone Playback Switch", + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + create_hp_imux(spec); + return 0; } -static int patch_vt1702(struct hda_codec *codec) +/* create playback/capture controls for input pins */ +static int vt1718S_auto_create_analog_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) { - struct via_spec *spec; - int err; + static const hda_nid_t pin_idxs[] = { 0x2c, 0x2b, 0x2a, 0x29, 0, 0xff }; + return vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs, + ARRAY_SIZE(pin_idxs)); +} - /* create a codec specific record */ - spec = via_new_spec(codec); - if (spec == NULL) - return -ENOMEM; +static int vt1718S_parse_auto_config(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int err; - spec->aa_mix_nid = 0x1a; + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); - /* limit AA path volume to 0 dB */ - snd_hda_override_amp_caps(codec, 0x1A, HDA_INPUT, - (0x17 << AC_AMPCAP_OFFSET_SHIFT) | - (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | - (0x5 << AC_AMPCAP_STEP_SIZE_SHIFT) | - (1 << AC_AMPCAP_MUTE_SHIFT)); + if (err < 0) + return err; + err = vt1718S_auto_fill_dac_nids(spec, &spec->autocfg); + if (err < 0) + return err; + if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) + return 0; /* can't find valid BIOS pin config */ - /* automatic parse from the BIOS config */ - err = via_parse_auto_config(codec); - if (err < 0) { - via_free(codec); + err = vt1718S_auto_create_multi_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + err = vt1718S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); + if (err < 0) + return err; + err = vt1718S_auto_create_analog_input_ctls(codec, &spec->autocfg); + if (err < 0) return err; - } - spec->init_verbs[spec->num_iverbs++] = vt1702_init_verbs; + spec->multiout.max_channels = spec->multiout.num_dacs * 2; - codec->patch_ops = via_patch_ops; + fill_dig_outs(codec); - spec->set_widgets_power_state = set_widgets_power_state_vt1702; - return 0; -} + if (spec->autocfg.dig_in_pin && codec->vendor_id == 0x11060428) + spec->dig_in_nid = 0x13; -/* Patch for VT1718S */ + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; -static const struct hda_verb vt1718S_init_verbs[] = { - /* Enable MW0 adjust Gain 5 */ - {0x1, 0xfb2, 0x10}, - /* Enable Boost Volume backdoor */ - {0x1, 0xf88, 0x8}, + spec->input_mux = &spec->private_imux[0]; - { } + if (spec->hp_mux) + via_hp_build(codec); + + via_smart51_build(spec); + + return 1; +} + +#ifdef CONFIG_SND_HDA_POWER_SAVE +static const struct hda_amp_list vt1718S_loopbacks[] = { + { 0x21, HDA_INPUT, 1 }, + { 0x21, HDA_INPUT, 2 }, + { 0x21, HDA_INPUT, 3 }, + { 0x21, HDA_INPUT, 4 }, + { } /* end */ }; +#endif static void set_widgets_power_state_vt1718S(struct hda_codec *codec) { @@ -3244,41 +4664,6 @@ static void set_widgets_power_state_vt1718S(struct hda_codec *codec) } } -/* Add a connection to the primary DAC from AA-mixer for some codecs - * This isn't listed from the raw info, but the chip has a secret connection. - */ -static int add_secret_dac_path(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int i, nums; - hda_nid_t conn[8]; - hda_nid_t nid; - - if (!spec->aa_mix_nid) - return 0; - nums = snd_hda_get_connections(codec, spec->aa_mix_nid, conn, - ARRAY_SIZE(conn) - 1); - for (i = 0; i < nums; i++) { - if (get_wcaps_type(get_wcaps(codec, conn[i])) == AC_WID_AUD_OUT) - return 0; - } - - /* find the primary DAC and add to the connection list */ - nid = codec->start_nid; - for (i = 0; i < codec->num_nodes; i++, nid++) { - unsigned int caps = get_wcaps(codec, nid); - if (get_wcaps_type(caps) == AC_WID_AUD_OUT && - !(caps & AC_WCAP_DIGITAL)) { - conn[nums++] = nid; - return snd_hda_override_conn_list(codec, - spec->aa_mix_nid, - nums, conn); - } - } - return 0; -} - - static int patch_vt1718S(struct hda_codec *codec) { struct via_spec *spec; @@ -3289,22 +4674,57 @@ static int patch_vt1718S(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - spec->aa_mix_nid = 0x21; - override_mic_boost(codec, 0x2b, 0, 3, 40); - override_mic_boost(codec, 0x29, 0, 3, 40); - add_secret_dac_path(codec); - /* automatic parse from the BIOS config */ - err = via_parse_auto_config(codec); + err = vt1718S_parse_auto_config(codec); if (err < 0) { via_free(codec); return err; + } else if (!err) { + printk(KERN_INFO "hda_codec: Cannot set up configuration " + "from BIOS. Using genenic mode...\n"); } - spec->init_verbs[spec->num_iverbs++] = vt1718S_init_verbs; + spec->init_verbs[spec->num_iverbs++] = vt1718S_volume_init_verbs; + spec->init_verbs[spec->num_iverbs++] = vt1718S_uniwill_init_verbs; + + if (codec->vendor_id == 0x11060441) + spec->stream_name_analog = "VT2020 Analog"; + else if (codec->vendor_id == 0x11064441) + spec->stream_name_analog = "VT1828S Analog"; + else + spec->stream_name_analog = "VT1718S Analog"; + spec->stream_analog_playback = &vt1718S_pcm_analog_playback; + spec->stream_analog_capture = &vt1718S_pcm_analog_capture; + + if (codec->vendor_id == 0x11060441) + spec->stream_name_digital = "VT2020 Digital"; + else if (codec->vendor_id == 0x11064441) + spec->stream_name_digital = "VT1828S Digital"; + else + spec->stream_name_digital = "VT1718S Digital"; + spec->stream_digital_playback = &vt1718S_pcm_digital_playback; + if (codec->vendor_id == 0x11060428 || codec->vendor_id == 0x11060441) + spec->stream_digital_capture = &vt1718S_pcm_digital_capture; + + if (!spec->adc_nids && spec->input_mux) { + spec->adc_nids = vt1718S_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(vt1718S_adc_nids); + get_mux_nids(codec); + override_mic_boost(codec, 0x2b, 0, 3, 40); + override_mic_boost(codec, 0x29, 0, 3, 40); + spec->mixers[spec->num_mixers] = vt1718S_capture_mixer; + spec->num_mixers++; + } codec->patch_ops = via_patch_ops; + codec->patch_ops.init = via_auto_init; + codec->patch_ops.unsol_event = via_unsol_event; + +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt1718S_loopbacks; +#endif + spec->set_widgets_power_state = set_widgets_power_state_vt1718S; return 0; @@ -3322,64 +4742,388 @@ static int vt1716s_dmic_info(struct snd_kcontrol *kcontrol, return 0; } -static int vt1716s_dmic_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int vt1716s_dmic_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + int index = 0; + + index = snd_hda_codec_read(codec, 0x26, 0, + AC_VERB_GET_CONNECT_SEL, 0); + if (index != -1) + *ucontrol->value.integer.value = index; + + return 0; +} + +static int vt1716s_dmic_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct via_spec *spec = codec->spec; + int index = *ucontrol->value.integer.value; + + snd_hda_codec_write(codec, 0x26, 0, + AC_VERB_SET_CONNECT_SEL, index); + spec->dmic_enabled = index; + set_widgets_power_state(codec); + return 1; +} + +/* capture mixer elements */ +static const struct snd_kcontrol_new vt1716S_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x1A, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x1E, 0x0, + HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Input Source", + .count = 1, + .info = via_mux_enum_info, + .get = via_mux_enum_get, + .put = via_mux_enum_put, + }, + { } /* end */ +}; + +static const struct snd_kcontrol_new vt1716s_dmic_mixer[] = { + HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x22, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Digital Mic Capture Switch", + .subdevice = HDA_SUBDEV_NID_FLAG | 0x26, + .count = 1, + .info = vt1716s_dmic_info, + .get = vt1716s_dmic_get, + .put = vt1716s_dmic_put, + }, + {} /* end */ +}; + + +/* mono-out mixer elements */ +static const struct snd_kcontrol_new vt1716S_mono_out_mixer[] = { + HDA_CODEC_MUTE("Mono Playback Switch", 0x2a, 0x0, HDA_OUTPUT), + { } /* end */ +}; + +static const struct hda_verb vt1716S_volume_init_verbs[] = { + /* + * Unmute ADC0-1 and set the default input to mic-in + */ + {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + */ + /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + + /* MUX Indices: Stereo Mixer = 5 */ + {0x17, AC_VERB_SET_CONNECT_SEL, 0x5}, + + /* Setup default input of PW4 to MW0 */ + {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0}, + + /* Setup default input of SW1 as MW0 */ + {0x18, AC_VERB_SET_CONNECT_SEL, 0x1}, + + /* Setup default input of SW4 as AOW0 */ + {0x28, AC_VERB_SET_CONNECT_SEL, 0x1}, + + /* PW9 PW10 Output enable */ + {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + + /* Unmute SW1, PW12 */ + {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* PW12 Output enable */ + {0x2a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + /* Enable Boost Volume backdoor */ + {0x1, 0xf8a, 0x80}, + /* don't bybass mixer */ + {0x1, 0xf88, 0xc0}, + /* Enable mono output */ + {0x1, 0xf90, 0x08}, + { } +}; + + +static const struct hda_verb vt1716S_uniwill_init_verbs[] = { + {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, + {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_MONO_EVENT | VIA_JACK_EVENT}, + {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + { } +}; + +static const struct hda_pcm_stream vt1716S_pcm_analog_playback = { + .substreams = 2, + .channels_min = 2, + .channels_max = 6, + .nid = 0x10, /* NID to query formats and rates */ + .ops = { + .open = via_playback_pcm_open, + .prepare = via_playback_multi_pcm_prepare, + .cleanup = via_playback_multi_pcm_cleanup, + .close = via_pcm_open_close, + }, +}; + +static const struct hda_pcm_stream vt1716S_pcm_analog_capture = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + .nid = 0x13, /* NID to query formats and rates */ + .ops = { + .open = via_pcm_open_close, + .prepare = via_capture_pcm_prepare, + .cleanup = via_capture_pcm_cleanup, + .close = via_pcm_open_close, + }, +}; + +static const struct hda_pcm_stream vt1716S_pcm_digital_playback = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + /* NID is set in via_build_pcms */ + .ops = { + .open = via_dig_playback_pcm_open, + .close = via_dig_playback_pcm_close, + .prepare = via_dig_playback_pcm_prepare, + .cleanup = via_dig_playback_pcm_cleanup + }, +}; + +/* fill in the dac_nids table from the parsed pin configuration */ +static int vt1716S_auto_fill_dac_nids(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ int i; + hda_nid_t nid; + + spec->multiout.num_dacs = cfg->line_outs; + + spec->multiout.dac_nids = spec->private_dac_nids; + + for (i = 0; i < 3; i++) { + nid = cfg->line_out_pins[i]; + if (nid) { + /* config dac list */ + switch (i) { + case AUTO_SEQ_FRONT: + spec->private_dac_nids[i] = 0x10; + break; + case AUTO_SEQ_CENLFE: + spec->private_dac_nids[i] = 0x25; + break; + case AUTO_SEQ_SURROUND: + spec->private_dac_nids[i] = 0x11; + break; + } + } + } + + return 0; +} + +/* add playback controls from the parsed DAC table */ +static int vt1716S_auto_create_multi_out_ctls(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + char name[32]; + static const char * const chname[3] = { + "Front", "Surround", "C/LFE" + }; + hda_nid_t nid_vols[] = {0x10, 0x11, 0x25}; + hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x27}; + hda_nid_t nid, nid_vol, nid_mute; + int i, err; + + for (i = 0; i <= AUTO_SEQ_CENLFE; i++) { + nid = cfg->line_out_pins[i]; + + if (!nid) + continue; + + nid_vol = nid_vols[i]; + nid_mute = nid_mutes[i]; + + if (i == AUTO_SEQ_CENLFE) { + err = via_add_control( + spec, VIA_CTL_WIDGET_VOL, + "Center Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control( + spec, VIA_CTL_WIDGET_VOL, + "LFE Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control( + spec, VIA_CTL_WIDGET_MUTE, + "Center Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_mute, 1, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control( + spec, VIA_CTL_WIDGET_MUTE, + "LFE Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_mute, 2, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } else if (i == AUTO_SEQ_FRONT) { + + err = via_add_control( + spec, VIA_CTL_WIDGET_VOL, + "Master Front Playback Volume", + HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_INPUT)); + if (err < 0) + return err; + err = via_add_control( + spec, VIA_CTL_WIDGET_MUTE, + "Master Front Playback Switch", + HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_INPUT)); + if (err < 0) + return err; + + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control( + spec, VIA_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control( + spec, VIA_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } else { + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control( + spec, VIA_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control( + spec, VIA_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } + } + return 0; +} + +static int vt1716S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) +{ + int err; + + if (!pin) + return 0; + + spec->multiout.hp_nid = 0x25; /* AOW3 */ + spec->hp_independent_mode_index = 1; + + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Headphone Playback Volume", + HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Headphone Playback Switch", + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + create_hp_imux(spec); + return 0; +} + +/* create playback/capture controls for input pins */ +static int vt1716S_auto_create_analog_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - int index = 0; - - index = snd_hda_codec_read(codec, 0x26, 0, - AC_VERB_GET_CONNECT_SEL, 0); - if (index != -1) - *ucontrol->value.integer.value = index; - - return 0; + static const hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff }; + return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs, + ARRAY_SIZE(pin_idxs)); } -static int vt1716s_dmic_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int vt1716S_parse_auto_config(struct hda_codec *codec) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct via_spec *spec = codec->spec; - int index = *ucontrol->value.integer.value; + int err; - snd_hda_codec_write(codec, 0x26, 0, - AC_VERB_SET_CONNECT_SEL, index); - spec->dmic_enabled = index; - set_widgets_power_state(codec); - return 1; -} + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); + if (err < 0) + return err; + err = vt1716S_auto_fill_dac_nids(spec, &spec->autocfg); + if (err < 0) + return err; + if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) + return 0; /* can't find valid BIOS pin config */ -static const struct snd_kcontrol_new vt1716s_dmic_mixer[] = { - HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x22, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Digital Mic Capture Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | 0x26, - .count = 1, - .info = vt1716s_dmic_info, - .get = vt1716s_dmic_get, - .put = vt1716s_dmic_put, - }, - {} /* end */ -}; + err = vt1716S_auto_create_multi_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + err = vt1716S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); + if (err < 0) + return err; + err = vt1716S_auto_create_analog_input_ctls(codec, &spec->autocfg); + if (err < 0) + return err; + + spec->multiout.max_channels = spec->multiout.num_dacs * 2; + fill_dig_outs(codec); -/* mono-out mixer elements */ -static const struct snd_kcontrol_new vt1716S_mono_out_mixer[] = { - HDA_CODEC_MUTE("Mono Playback Switch", 0x2a, 0x0, HDA_OUTPUT), - { } /* end */ -}; + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; -static const struct hda_verb vt1716S_init_verbs[] = { - /* Enable Boost Volume backdoor */ - {0x1, 0xf8a, 0x80}, - /* don't bybass mixer */ - {0x1, 0xf88, 0xc0}, - /* Enable mono output */ - {0x1, 0xf90, 0x08}, - { } + spec->input_mux = &spec->private_imux[0]; + + if (spec->hp_mux) + via_hp_build(codec); + + via_smart51_build(spec); + + return 1; +} + +#ifdef CONFIG_SND_HDA_POWER_SAVE +static const struct hda_amp_list vt1716S_loopbacks[] = { + { 0x16, HDA_INPUT, 1 }, + { 0x16, HDA_INPUT, 2 }, + { 0x16, HDA_INPUT, 3 }, + { 0x16, HDA_INPUT, 4 }, + { } /* end */ }; +#endif static void set_widgets_power_state_vt1716S(struct hda_codec *codec) { @@ -3434,101 +5178,440 @@ static void set_widgets_power_state_vt1716S(struct hda_codec *codec) set_pin_power_state(codec, 0x1a, &parm); snd_hda_codec_write(codec, 0x27, 0, AC_VERB_SET_POWER_STATE, parm); - /* Smart 5.1 PW5(1eh) */ - if (spec->smart51_enabled) - set_pin_power_state(codec, 0x1e, &parm); - snd_hda_codec_write(codec, 0x25, 0, AC_VERB_SET_POWER_STATE, parm); + /* Smart 5.1 PW5(1eh) */ + if (spec->smart51_enabled) + set_pin_power_state(codec, 0x1e, &parm); + snd_hda_codec_write(codec, 0x25, 0, AC_VERB_SET_POWER_STATE, parm); + + /* Mono out */ + /* SW4(28h)->MW1(29h)-> PW12 (2ah)*/ + present = snd_hda_jack_detect(codec, 0x1c); + + if (present) + mono_out = 0; + else { + present = snd_hda_jack_detect(codec, 0x1d); + if (!spec->hp_independent_mode && present) + mono_out = 0; + else + mono_out = 1; + } + parm = mono_out ? AC_PWRST_D0 : AC_PWRST_D3; + snd_hda_codec_write(codec, 0x28, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x29, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x2a, 0, AC_VERB_SET_POWER_STATE, parm); + + /* PW 3/4 (1ch/1dh) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x1c, &parm); + set_pin_power_state(codec, 0x1d, &parm); + /* HP Independent Mode, power on AOW3 */ + if (spec->hp_independent_mode) + snd_hda_codec_write(codec, 0x25, 0, + AC_VERB_SET_POWER_STATE, parm); + + /* force to D0 for internal Speaker */ + /* MW0 (16h), AOW0 (10h) */ + snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE, + imux_is_smixer ? AC_PWRST_D0 : parm); + snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, + mono_out ? AC_PWRST_D0 : parm); +} + +static int patch_vt1716S(struct hda_codec *codec) +{ + struct via_spec *spec; + int err; + + /* create a codec specific record */ + spec = via_new_spec(codec); + if (spec == NULL) + return -ENOMEM; + + /* automatic parse from the BIOS config */ + err = vt1716S_parse_auto_config(codec); + if (err < 0) { + via_free(codec); + return err; + } else if (!err) { + printk(KERN_INFO "hda_codec: Cannot set up configuration " + "from BIOS. Using genenic mode...\n"); + } + + spec->init_verbs[spec->num_iverbs++] = vt1716S_volume_init_verbs; + spec->init_verbs[spec->num_iverbs++] = vt1716S_uniwill_init_verbs; + + spec->stream_name_analog = "VT1716S Analog"; + spec->stream_analog_playback = &vt1716S_pcm_analog_playback; + spec->stream_analog_capture = &vt1716S_pcm_analog_capture; + + spec->stream_name_digital = "VT1716S Digital"; + spec->stream_digital_playback = &vt1716S_pcm_digital_playback; + + if (!spec->adc_nids && spec->input_mux) { + spec->adc_nids = vt1716S_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(vt1716S_adc_nids); + get_mux_nids(codec); + override_mic_boost(codec, 0x1a, 0, 3, 40); + override_mic_boost(codec, 0x1e, 0, 3, 40); + spec->mixers[spec->num_mixers] = vt1716S_capture_mixer; + spec->num_mixers++; + } + + spec->mixers[spec->num_mixers] = vt1716s_dmic_mixer; + spec->num_mixers++; + + spec->mixers[spec->num_mixers++] = vt1716S_mono_out_mixer; + + codec->patch_ops = via_patch_ops; + + codec->patch_ops.init = via_auto_init; + codec->patch_ops.unsol_event = via_unsol_event; + +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt1716S_loopbacks; +#endif + + spec->set_widgets_power_state = set_widgets_power_state_vt1716S; + return 0; +} + +/* for vt2002P */ + +/* capture mixer elements */ +static const struct snd_kcontrol_new vt2002P_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x29, 0x0, + HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 2, + .info = via_mux_enum_info, + .get = via_mux_enum_get, + .put = via_mux_enum_put, + }, + { } /* end */ +}; + +static const struct hda_verb vt2002P_volume_init_verbs[] = { + /* Class-D speaker related verbs */ + {0x1, 0xfe0, 0x4}, + {0x1, 0xfe9, 0x80}, + {0x1, 0xfe2, 0x22}, + /* + * Unmute ADC0-1 and set the default input to mic-in + */ + {0x8, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x9, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + */ + /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + + /* MUX Indices: Mic = 0 */ + {0x1e, AC_VERB_SET_CONNECT_SEL, 0}, + {0x1f, AC_VERB_SET_CONNECT_SEL, 0}, + + /* PW9 Output enable */ + {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN}, + + /* Enable Boost Volume backdoor */ + {0x1, 0xfb9, 0x24}, + + /* MW0/1/4/8: un-mute index 0 (MUXx), un-mute index 1 (MW9) */ + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* set MUX0/1/4/8 = 0 (AOW0) */ + {0x34, AC_VERB_SET_CONNECT_SEL, 0}, + {0x35, AC_VERB_SET_CONNECT_SEL, 0}, + {0x37, AC_VERB_SET_CONNECT_SEL, 0}, + {0x3b, AC_VERB_SET_CONNECT_SEL, 0}, + + /* set PW0 index=0 (MW0) */ + {0x24, AC_VERB_SET_CONNECT_SEL, 0}, + + /* Enable AOW0 to MW9 */ + {0x1, 0xfb8, 0x88}, + { } +}; +static const struct hda_verb vt1802_volume_init_verbs[] = { + /* + * Unmute ADC0-1 and set the default input to mic-in + */ + {0x8, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x9, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + */ + /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + + /* MUX Indices: Mic = 0 */ + {0x1e, AC_VERB_SET_CONNECT_SEL, 0}, + {0x1f, AC_VERB_SET_CONNECT_SEL, 0}, + + /* PW9 Output enable */ + {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN}, + + /* Enable Boost Volume backdoor */ + {0x1, 0xfb9, 0x24}, + + /* MW0/1/4/8: un-mute index 0 (MUXx), un-mute index 1 (MW9) */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* set MUX0/1/4/8 = 0 (AOW0) */ + {0x34, AC_VERB_SET_CONNECT_SEL, 0}, + {0x35, AC_VERB_SET_CONNECT_SEL, 0}, + {0x38, AC_VERB_SET_CONNECT_SEL, 0}, + {0x3c, AC_VERB_SET_CONNECT_SEL, 0}, + + /* set PW0 index=0 (MW0) */ + {0x24, AC_VERB_SET_CONNECT_SEL, 0}, + + /* Enable AOW0 to MW9 */ + {0x1, 0xfb8, 0x88}, + { } +}; + + +static const struct hda_verb vt2002P_uniwill_init_verbs[] = { + {0x25, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT}, + {0x26, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT}, + {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + { } +}; +static const struct hda_verb vt1802_uniwill_init_verbs[] = { + {0x25, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT}, + {0x28, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT}, + {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + { } +}; + +static const struct hda_pcm_stream vt2002P_pcm_analog_playback = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + .nid = 0x8, /* NID to query formats and rates */ + .ops = { + .open = via_playback_pcm_open, + .prepare = via_playback_multi_pcm_prepare, + .cleanup = via_playback_multi_pcm_cleanup, + .close = via_pcm_open_close, + }, +}; + +static const struct hda_pcm_stream vt2002P_pcm_analog_capture = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + .nid = 0x10, /* NID to query formats and rates */ + .ops = { + .open = via_pcm_open_close, + .prepare = via_capture_pcm_prepare, + .cleanup = via_capture_pcm_cleanup, + .close = via_pcm_open_close, + }, +}; + +static const struct hda_pcm_stream vt2002P_pcm_digital_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in via_build_pcms */ + .ops = { + .open = via_dig_playback_pcm_open, + .close = via_dig_playback_pcm_close, + .prepare = via_dig_playback_pcm_prepare, + .cleanup = via_dig_playback_pcm_cleanup + }, +}; + +/* fill in the dac_nids table from the parsed pin configuration */ +static int vt2002P_auto_fill_dac_nids(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + spec->multiout.num_dacs = 1; + spec->multiout.dac_nids = spec->private_dac_nids; + if (cfg->line_out_pins[0]) + spec->private_dac_nids[0] = 0x8; + return 0; +} + +/* add playback controls from the parsed DAC table */ +static int vt2002P_auto_create_multi_out_ctls(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + int err; + hda_nid_t sw_nid; + + if (!cfg->line_out_pins[0]) + return -1; + + if (spec->codec_type == VT1802) + sw_nid = 0x28; + else + sw_nid = 0x26; + + /* Line-Out: PortE */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Master Front Playback Volume", + HDA_COMPOSE_AMP_VAL(0x8, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_BIND_PIN_MUTE, + "Master Front Playback Switch", + HDA_COMPOSE_AMP_VAL(sw_nid, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + return 0; +} + +static int vt2002P_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) +{ + int err; + + if (!pin) + return 0; + + spec->multiout.hp_nid = 0x9; + spec->hp_independent_mode_index = 1; + + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Headphone Playback Volume", + HDA_COMPOSE_AMP_VAL( + spec->multiout.hp_nid, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Headphone Playback Switch", + HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + create_hp_imux(spec); + return 0; +} - /* Mono out */ - /* SW4(28h)->MW1(29h)-> PW12 (2ah)*/ - present = snd_hda_jack_detect(codec, 0x1c); +/* create playback/capture controls for input pins */ +static int vt2002P_auto_create_analog_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) +{ + struct via_spec *spec = codec->spec; + struct hda_input_mux *imux = &spec->private_imux[0]; + static const hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0xff }; + int err; - if (present) - mono_out = 0; - else { - present = snd_hda_jack_detect(codec, 0x1d); - if (!spec->hp_independent_mode && present) - mono_out = 0; - else - mono_out = 1; - } - parm = mono_out ? AC_PWRST_D0 : AC_PWRST_D3; - snd_hda_codec_write(codec, 0x28, 0, AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x29, 0, AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x2a, 0, AC_VERB_SET_POWER_STATE, parm); + err = vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs, + ARRAY_SIZE(pin_idxs)); + if (err < 0) + return err; + /* build volume/mute control of loopback */ + err = via_new_analog_input(spec, "Stereo Mixer", 0, 3, 0x21); + if (err < 0) + return err; - /* PW 3/4 (1ch/1dh) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x1c, &parm); - set_pin_power_state(codec, 0x1d, &parm); - /* HP Independent Mode, power on AOW3 */ - if (spec->hp_independent_mode) - snd_hda_codec_write(codec, 0x25, 0, - AC_VERB_SET_POWER_STATE, parm); + /* for digital mic select */ + snd_hda_add_imux_item(imux, "Digital Mic", 4, NULL); - /* force to D0 for internal Speaker */ - /* MW0 (16h), AOW0 (10h) */ - snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE, - imux_is_smixer ? AC_PWRST_D0 : parm); - snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, - mono_out ? AC_PWRST_D0 : parm); + return 0; } -static int patch_vt1716S(struct hda_codec *codec) +static int vt2002P_parse_auto_config(struct hda_codec *codec) { - struct via_spec *spec; + struct via_spec *spec = codec->spec; int err; - /* create a codec specific record */ - spec = via_new_spec(codec); - if (spec == NULL) - return -ENOMEM; - spec->aa_mix_nid = 0x16; - override_mic_boost(codec, 0x1a, 0, 3, 40); - override_mic_boost(codec, 0x1e, 0, 3, 40); + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); + if (err < 0) + return err; - /* automatic parse from the BIOS config */ - err = via_parse_auto_config(codec); - if (err < 0) { - via_free(codec); + err = vt2002P_auto_fill_dac_nids(spec, &spec->autocfg); + if (err < 0) return err; - } - spec->init_verbs[spec->num_iverbs++] = vt1716S_init_verbs; + if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) + return 0; /* can't find valid BIOS pin config */ - spec->mixers[spec->num_mixers] = vt1716s_dmic_mixer; - spec->num_mixers++; + err = vt2002P_auto_create_multi_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + err = vt2002P_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); + if (err < 0) + return err; + err = vt2002P_auto_create_analog_input_ctls(codec, &spec->autocfg); + if (err < 0) + return err; - spec->mixers[spec->num_mixers++] = vt1716S_mono_out_mixer; + spec->multiout.max_channels = spec->multiout.num_dacs * 2; - codec->patch_ops = via_patch_ops; + fill_dig_outs(codec); - spec->set_widgets_power_state = set_widgets_power_state_vt1716S; - return 0; -} + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; -/* for vt2002P */ + spec->input_mux = &spec->private_imux[0]; -static const struct hda_verb vt2002P_init_verbs[] = { - /* Class-D speaker related verbs */ - {0x1, 0xfe0, 0x4}, - {0x1, 0xfe9, 0x80}, - {0x1, 0xfe2, 0x22}, - /* Enable Boost Volume backdoor */ - {0x1, 0xfb9, 0x24}, - /* Enable AOW0 to MW9 */ - {0x1, 0xfb8, 0x88}, - { } -}; + if (spec->hp_mux) + via_hp_build(codec); -static const struct hda_verb vt1802_init_verbs[] = { - /* Enable Boost Volume backdoor */ - {0x1, 0xfb9, 0x24}, - /* Enable AOW0 to MW9 */ - {0x1, 0xfb8, 0x88}, - { } + return 1; +} + +#ifdef CONFIG_SND_HDA_POWER_SAVE +static const struct hda_amp_list vt2002P_loopbacks[] = { + { 0x21, HDA_INPUT, 0 }, + { 0x21, HDA_INPUT, 1 }, + { 0x21, HDA_INPUT, 2 }, + { } /* end */ }; +#endif static void set_widgets_power_state_vt2002P(struct hda_codec *codec) { @@ -3652,39 +5735,334 @@ static int patch_vt2002P(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - spec->aa_mix_nid = 0x21; - override_mic_boost(codec, 0x2b, 0, 3, 40); - override_mic_boost(codec, 0x29, 0, 3, 40); - add_secret_dac_path(codec); - /* automatic parse from the BIOS config */ - err = via_parse_auto_config(codec); + err = vt2002P_parse_auto_config(codec); if (err < 0) { via_free(codec); return err; + } else if (!err) { + printk(KERN_INFO "hda_codec: Cannot set up configuration " + "from BIOS. Using genenic mode...\n"); } if (spec->codec_type == VT1802) - spec->init_verbs[spec->num_iverbs++] = vt1802_init_verbs; + spec->init_verbs[spec->num_iverbs++] = + vt1802_volume_init_verbs; + else + spec->init_verbs[spec->num_iverbs++] = + vt2002P_volume_init_verbs; + + if (spec->codec_type == VT1802) + spec->init_verbs[spec->num_iverbs++] = + vt1802_uniwill_init_verbs; else - spec->init_verbs[spec->num_iverbs++] = vt2002P_init_verbs; + spec->init_verbs[spec->num_iverbs++] = + vt2002P_uniwill_init_verbs; + + if (spec->codec_type == VT1802) + spec->stream_name_analog = "VT1802 Analog"; + else + spec->stream_name_analog = "VT2002P Analog"; + spec->stream_analog_playback = &vt2002P_pcm_analog_playback; + spec->stream_analog_capture = &vt2002P_pcm_analog_capture; + + if (spec->codec_type == VT1802) + spec->stream_name_digital = "VT1802 Digital"; + else + spec->stream_name_digital = "VT2002P Digital"; + spec->stream_digital_playback = &vt2002P_pcm_digital_playback; + + if (!spec->adc_nids && spec->input_mux) { + spec->adc_nids = vt2002P_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(vt2002P_adc_nids); + get_mux_nids(codec); + override_mic_boost(codec, 0x2b, 0, 3, 40); + override_mic_boost(codec, 0x29, 0, 3, 40); + spec->mixers[spec->num_mixers] = vt2002P_capture_mixer; + spec->num_mixers++; + } codec->patch_ops = via_patch_ops; + codec->patch_ops.init = via_auto_init; + codec->patch_ops.unsol_event = via_unsol_event; + +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt2002P_loopbacks; +#endif + spec->set_widgets_power_state = set_widgets_power_state_vt2002P; return 0; } /* for vt1812 */ -static const struct hda_verb vt1812_init_verbs[] = { +/* capture mixer elements */ +static const struct snd_kcontrol_new vt1812_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Boost Capture Volume", 0x29, 0x0, + HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + */ + .name = "Input Source", + .count = 2, + .info = via_mux_enum_info, + .get = via_mux_enum_get, + .put = via_mux_enum_put, + }, + { } /* end */ +}; + +static const struct hda_verb vt1812_volume_init_verbs[] = { + /* + * Unmute ADC0-1 and set the default input to mic-in + */ + {0x8, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x9, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + */ + /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + + /* MUX Indices: Mic = 0 */ + {0x1e, AC_VERB_SET_CONNECT_SEL, 0}, + {0x1f, AC_VERB_SET_CONNECT_SEL, 0}, + + /* PW9 Output enable */ + {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN}, + /* Enable Boost Volume backdoor */ {0x1, 0xfb9, 0x24}, + + /* MW0/1/4/13/15: un-mute index 0 (MUXx), un-mute index 1 (MW9) */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* set MUX0/1/4/13/15 = 0 (AOW0) */ + {0x34, AC_VERB_SET_CONNECT_SEL, 0}, + {0x35, AC_VERB_SET_CONNECT_SEL, 0}, + {0x38, AC_VERB_SET_CONNECT_SEL, 0}, + {0x3c, AC_VERB_SET_CONNECT_SEL, 0}, + {0x3d, AC_VERB_SET_CONNECT_SEL, 0}, + /* Enable AOW0 to MW9 */ {0x1, 0xfb8, 0xa8}, { } }; + +static const struct hda_verb vt1812_uniwill_init_verbs[] = { + {0x33, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT}, + {0x25, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT }, + {0x28, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT}, + {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + { } +}; + +static const struct hda_pcm_stream vt1812_pcm_analog_playback = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + .nid = 0x8, /* NID to query formats and rates */ + .ops = { + .open = via_playback_pcm_open, + .prepare = via_playback_multi_pcm_prepare, + .cleanup = via_playback_multi_pcm_cleanup, + .close = via_pcm_open_close, + }, +}; + +static const struct hda_pcm_stream vt1812_pcm_analog_capture = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + .nid = 0x10, /* NID to query formats and rates */ + .ops = { + .open = via_pcm_open_close, + .prepare = via_capture_pcm_prepare, + .cleanup = via_capture_pcm_cleanup, + .close = via_pcm_open_close, + }, +}; + +static const struct hda_pcm_stream vt1812_pcm_digital_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in via_build_pcms */ + .ops = { + .open = via_dig_playback_pcm_open, + .close = via_dig_playback_pcm_close, + .prepare = via_dig_playback_pcm_prepare, + .cleanup = via_dig_playback_pcm_cleanup + }, +}; +/* fill in the dac_nids table from the parsed pin configuration */ +static int vt1812_auto_fill_dac_nids(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + spec->multiout.num_dacs = 1; + spec->multiout.dac_nids = spec->private_dac_nids; + if (cfg->line_out_pins[0]) + spec->private_dac_nids[0] = 0x8; + return 0; +} + + +/* add playback controls from the parsed DAC table */ +static int vt1812_auto_create_multi_out_ctls(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + int err; + + if (!cfg->line_out_pins[0]) + return -1; + + /* Line-Out: PortE */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Front Playback Volume", + HDA_COMPOSE_AMP_VAL(0x8, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_BIND_PIN_MUTE, + "Front Playback Switch", + HDA_COMPOSE_AMP_VAL(0x28, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + return 0; +} + +static int vt1812_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) +{ + int err; + + if (!pin) + return 0; + + spec->multiout.hp_nid = 0x9; + spec->hp_independent_mode_index = 1; + + + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Headphone Playback Volume", + HDA_COMPOSE_AMP_VAL( + spec->multiout.hp_nid, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Headphone Playback Switch", + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + create_hp_imux(spec); + return 0; +} + +/* create playback/capture controls for input pins */ +static int vt1812_auto_create_analog_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) +{ + struct via_spec *spec = codec->spec; + struct hda_input_mux *imux = &spec->private_imux[0]; + static const hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0, 0, 0xff }; + int err; + + err = vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs, + ARRAY_SIZE(pin_idxs)); + if (err < 0) + return err; + + /* build volume/mute control of loopback */ + err = via_new_analog_input(spec, "Stereo Mixer", 0, 5, 0x21); + if (err < 0) + return err; + + /* for digital mic select */ + snd_hda_add_imux_item(imux, "Digital Mic", 6, NULL); + + return 0; +} + +static int vt1812_parse_auto_config(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int err; + + + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); + if (err < 0) + return err; + fill_dig_outs(codec); + err = vt1812_auto_fill_dac_nids(spec, &spec->autocfg); + if (err < 0) + return err; + + if (!spec->autocfg.line_outs && !spec->autocfg.hp_outs) + return 0; /* can't find valid BIOS pin config */ + + err = vt1812_auto_create_multi_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + err = vt1812_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); + if (err < 0) + return err; + err = vt1812_auto_create_analog_input_ctls(codec, &spec->autocfg); + if (err < 0) + return err; + + spec->multiout.max_channels = spec->multiout.num_dacs * 2; + + fill_dig_outs(codec); + + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; + + spec->input_mux = &spec->private_imux[0]; + + if (spec->hp_mux) + via_hp_build(codec); + + return 1; +} + +#ifdef CONFIG_SND_HDA_POWER_SAVE +static const struct hda_amp_list vt1812_loopbacks[] = { + { 0x21, HDA_INPUT, 0 }, + { 0x21, HDA_INPUT, 1 }, + { 0x21, HDA_INPUT, 2 }, + { } /* end */ +}; +#endif + static void set_widgets_power_state_vt1812(struct hda_codec *codec) { struct via_spec *spec = codec->spec; @@ -3788,22 +6166,47 @@ static int patch_vt1812(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - spec->aa_mix_nid = 0x21; - override_mic_boost(codec, 0x2b, 0, 3, 40); - override_mic_boost(codec, 0x29, 0, 3, 40); - add_secret_dac_path(codec); - /* automatic parse from the BIOS config */ - err = via_parse_auto_config(codec); + err = vt1812_parse_auto_config(codec); if (err < 0) { via_free(codec); return err; + } else if (!err) { + printk(KERN_INFO "hda_codec: Cannot set up configuration " + "from BIOS. Using genenic mode...\n"); } - spec->init_verbs[spec->num_iverbs++] = vt1812_init_verbs; + + spec->init_verbs[spec->num_iverbs++] = vt1812_volume_init_verbs; + spec->init_verbs[spec->num_iverbs++] = vt1812_uniwill_init_verbs; + + spec->stream_name_analog = "VT1812 Analog"; + spec->stream_analog_playback = &vt1812_pcm_analog_playback; + spec->stream_analog_capture = &vt1812_pcm_analog_capture; + + spec->stream_name_digital = "VT1812 Digital"; + spec->stream_digital_playback = &vt1812_pcm_digital_playback; + + + if (!spec->adc_nids && spec->input_mux) { + spec->adc_nids = vt1812_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(vt1812_adc_nids); + get_mux_nids(codec); + override_mic_boost(codec, 0x2b, 0, 3, 40); + override_mic_boost(codec, 0x29, 0, 3, 40); + spec->mixers[spec->num_mixers] = vt1812_capture_mixer; + spec->num_mixers++; + } codec->patch_ops = via_patch_ops; + codec->patch_ops.init = via_auto_init; + codec->patch_ops.unsol_event = via_unsol_event; + +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt1812_loopbacks; +#endif + spec->set_widgets_power_state = set_widgets_power_state_vt1812; return 0; } @@ -3817,37 +6220,37 @@ static const struct hda_codec_preset snd_hda_preset_via[] = { { .id = 0x1106170a, .name = "VT1708", .patch = patch_vt1708}, { .id = 0x1106170b, .name = "VT1708", .patch = patch_vt1708}, { .id = 0x1106e710, .name = "VT1709 10-Ch", - .patch = patch_vt1709}, + .patch = patch_vt1709_10ch}, { .id = 0x1106e711, .name = "VT1709 10-Ch", - .patch = patch_vt1709}, + .patch = patch_vt1709_10ch}, { .id = 0x1106e712, .name = "VT1709 10-Ch", - .patch = patch_vt1709}, + .patch = patch_vt1709_10ch}, { .id = 0x1106e713, .name = "VT1709 10-Ch", - .patch = patch_vt1709}, + .patch = patch_vt1709_10ch}, { .id = 0x1106e714, .name = "VT1709 6-Ch", - .patch = patch_vt1709}, + .patch = patch_vt1709_6ch}, { .id = 0x1106e715, .name = "VT1709 6-Ch", - .patch = patch_vt1709}, + .patch = patch_vt1709_6ch}, { .id = 0x1106e716, .name = "VT1709 6-Ch", - .patch = patch_vt1709}, + .patch = patch_vt1709_6ch}, { .id = 0x1106e717, .name = "VT1709 6-Ch", - .patch = patch_vt1709}, + .patch = patch_vt1709_6ch}, { .id = 0x1106e720, .name = "VT1708B 8-Ch", - .patch = patch_vt1708B}, + .patch = patch_vt1708B_8ch}, { .id = 0x1106e721, .name = "VT1708B 8-Ch", - .patch = patch_vt1708B}, + .patch = patch_vt1708B_8ch}, { .id = 0x1106e722, .name = "VT1708B 8-Ch", - .patch = patch_vt1708B}, + .patch = patch_vt1708B_8ch}, { .id = 0x1106e723, .name = "VT1708B 8-Ch", - .patch = patch_vt1708B}, + .patch = patch_vt1708B_8ch}, { .id = 0x1106e724, .name = "VT1708B 4-Ch", - .patch = patch_vt1708B}, + .patch = patch_vt1708B_4ch}, { .id = 0x1106e725, .name = "VT1708B 4-Ch", - .patch = patch_vt1708B}, + .patch = patch_vt1708B_4ch}, { .id = 0x1106e726, .name = "VT1708B 4-Ch", - .patch = patch_vt1708B}, + .patch = patch_vt1708B_4ch}, { .id = 0x1106e727, .name = "VT1708B 4-Ch", - .patch = patch_vt1708B}, + .patch = patch_vt1708B_4ch}, { .id = 0x11060397, .name = "VT1708S", .patch = patch_vt1708S}, { .id = 0x11061397, .name = "VT1708S", diff --git a/trunk/sound/pci/ice1712/ice1712.c b/trunk/sound/pci/ice1712/ice1712.c index be06fb3e45a1..f4594d76b6ea 100644 --- a/trunk/sound/pci/ice1712/ice1712.c +++ b/trunk/sound/pci/ice1712/ice1712.c @@ -2607,7 +2607,7 @@ static int __devinit snd_ice1712_create(struct snd_card *card, ice->profi_port = pci_resource_start(pci, 3); if (request_irq(pci->irq, snd_ice1712_interrupt, IRQF_SHARED, - KBUILD_MODNAME, ice)) { + "ICE1712", ice)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_ice1712_free(ice); return -EIO; @@ -2802,7 +2802,7 @@ static void __devexit snd_ice1712_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "ICE1712", .id_table = snd_ice1712_ids, .probe = snd_ice1712_probe, .remove = __devexit_p(snd_ice1712_remove), diff --git a/trunk/sound/pci/ice1712/ice1724.c b/trunk/sound/pci/ice1712/ice1724.c index c2b7f8bc41e4..c1498fa5545f 100644 --- a/trunk/sound/pci/ice1712/ice1724.c +++ b/trunk/sound/pci/ice1712/ice1724.c @@ -2509,7 +2509,7 @@ static int __devinit snd_vt1724_create(struct snd_card *card, ice->profi_port = pci_resource_start(pci, 1); if (request_irq(pci->irq, snd_vt1724_interrupt, - IRQF_SHARED, KBUILD_MODNAME, ice)) { + IRQF_SHARED, "ICE1724", ice)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_vt1724_free(ice); return -EIO; @@ -2802,7 +2802,7 @@ static int snd_vt1724_resume(struct pci_dev *pci) #endif static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "ICE1724", .id_table = snd_vt1724_ids, .probe = snd_vt1724_probe, .remove = __devexit_p(snd_vt1724_remove), diff --git a/trunk/sound/pci/intel8x0.c b/trunk/sound/pci/intel8x0.c index 6a5b387b97fd..6c896dbfd796 100644 --- a/trunk/sound/pci/intel8x0.c +++ b/trunk/sound/pci/intel8x0.c @@ -1882,12 +1882,6 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = { .name = "Dell Inspiron 6000", .type = AC97_TUNE_HP_MUTE_LED /* cf. Malone #41015 */ }, - { - .subvendor = 0x1028, - .subdevice = 0x0189, - .name = "Dell Inspiron 9300", - .type = AC97_TUNE_HP_MUTE_LED - }, { .subvendor = 0x1028, .subdevice = 0x0191, @@ -2653,7 +2647,7 @@ static int intel8x0_resume(struct pci_dev *pci) pci_set_master(pci); snd_intel8x0_chip_init(chip, 0); if (request_irq(pci->irq, snd_intel8x0_interrupt, - IRQF_SHARED, KBUILD_MODNAME, chip)) { + IRQF_SHARED, card->shortname, chip)) { printk(KERN_ERR "intel8x0: unable to grab IRQ %d, " "disabling device\n", pci->irq); snd_card_disconnect(card); @@ -3112,7 +3106,7 @@ static int __devinit snd_intel8x0_create(struct snd_card *card, /* request irq after initializaing int_sta_mask, etc */ if (request_irq(pci->irq, snd_intel8x0_interrupt, - IRQF_SHARED, KBUILD_MODNAME, chip)) { + IRQF_SHARED, card->shortname, chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_intel8x0_free(chip); return -EBUSY; @@ -3272,7 +3266,7 @@ static void __devexit snd_intel8x0_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "Intel ICH", .id_table = snd_intel8x0_ids, .probe = snd_intel8x0_probe, .remove = __devexit_p(snd_intel8x0_remove), diff --git a/trunk/sound/pci/intel8x0m.c b/trunk/sound/pci/intel8x0m.c index 7c161645d865..f3353b49c785 100644 --- a/trunk/sound/pci/intel8x0m.c +++ b/trunk/sound/pci/intel8x0m.c @@ -1047,7 +1047,7 @@ static int intel8x0m_resume(struct pci_dev *pci) } pci_set_master(pci); if (request_irq(pci->irq, snd_intel8x0m_interrupt, - IRQF_SHARED, KBUILD_MODNAME, chip)) { + IRQF_SHARED, card->shortname, chip)) { printk(KERN_ERR "intel8x0m: unable to grab IRQ %d, " "disabling device\n", pci->irq); snd_card_disconnect(card); @@ -1174,7 +1174,7 @@ static int __devinit snd_intel8x0m_create(struct snd_card *card, port_inited: if (request_irq(pci->irq, snd_intel8x0m_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + card->shortname, chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_intel8x0m_free(chip); return -EBUSY; @@ -1325,7 +1325,7 @@ static void __devexit snd_intel8x0m_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "Intel ICH Modem", .id_table = snd_intel8x0m_ids, .probe = snd_intel8x0m_probe, .remove = __devexit_p(snd_intel8x0m_remove), diff --git a/trunk/sound/pci/korg1212/korg1212.c b/trunk/sound/pci/korg1212/korg1212.c index fc1d573cf306..6d795700be79 100644 --- a/trunk/sound/pci/korg1212/korg1212.c +++ b/trunk/sound/pci/korg1212/korg1212.c @@ -2241,7 +2241,7 @@ static int __devinit snd_korg1212_create(struct snd_card *card, struct pci_dev * err = request_irq(pci->irq, snd_korg1212_interrupt, IRQF_SHARED, - KBUILD_MODNAME, korg1212); + "korg1212", korg1212); if (err) { snd_printk(KERN_ERR "korg1212: unable to grab IRQ %d\n", pci->irq); @@ -2477,7 +2477,7 @@ static void __devexit snd_korg1212_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "korg1212", .id_table = snd_korg1212_ids, .probe = snd_korg1212_probe, .remove = __devexit_p(snd_korg1212_remove), diff --git a/trunk/sound/pci/lola/lola.c b/trunk/sound/pci/lola/lola.c index 3e92e5b5ec3d..2692e5ae5f2d 100644 --- a/trunk/sound/pci/lola/lola.c +++ b/trunk/sound/pci/lola/lola.c @@ -648,7 +648,7 @@ static int __devinit lola_create(struct snd_card *card, struct pci_dev *pci, goto errout; if (request_irq(pci->irq, lola_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + DRVNAME, chip)) { printk(KERN_ERR SFX "unable to grab IRQ %d\n", pci->irq); err = -EBUSY; goto errout; @@ -771,7 +771,7 @@ MODULE_DEVICE_TABLE(pci, lola_ids); /* pci_driver definition */ static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = DRVNAME, .id_table = lola_ids, .probe = lola_probe, .remove = __devexit_p(lola_remove), diff --git a/trunk/sound/pci/lola/lola.h b/trunk/sound/pci/lola/lola.h index f0b100059efd..d5708e29b16d 100644 --- a/trunk/sound/pci/lola/lola.h +++ b/trunk/sound/pci/lola/lola.h @@ -480,7 +480,7 @@ struct lola { /* count values in the Vendor Specific Mixer Widget's Audio Widget Capabilities */ #define LOLA_MIXER_SRC_INPUT_PLAY_SEPARATION(res) ((res >> 2) & 0x1f) -#define LOLA_MIXER_DEST_REC_OUTPUT_SEPARATION(res) ((res >> 7) & 0x1f) +#define LOLA_MIXER_DEST_REC_OUTPUT_SEPATATION(res) ((res >> 7) & 0x1f) int lola_codec_write(struct lola *chip, unsigned int nid, unsigned int verb, unsigned int data, unsigned int extdata); diff --git a/trunk/sound/pci/lola/lola_mixer.c b/trunk/sound/pci/lola/lola_mixer.c index 6b8d64812951..5d518f1a712c 100644 --- a/trunk/sound/pci/lola/lola_mixer.c +++ b/trunk/sound/pci/lola/lola_mixer.c @@ -144,61 +144,40 @@ int __devinit lola_init_mixer_widget(struct lola *chip, int nid) chip->mixer.dest_stream_ins = chip->pcm[CAPT].num_streams; chip->mixer.dest_phys_outs = chip->pin[PLAY].num_pins; - /* mixer matrix may have unused areas between PhysIn and + /* mixer matrix can have unused areas between PhysIn and * Play or Record and PhysOut zones */ chip->mixer.src_stream_out_ofs = chip->mixer.src_phys_ins + LOLA_MIXER_SRC_INPUT_PLAY_SEPARATION(val); chip->mixer.dest_phys_out_ofs = chip->mixer.dest_stream_ins + - LOLA_MIXER_DEST_REC_OUTPUT_SEPARATION(val); - - /* example : MixerMatrix of LoLa881 (LoLa16161 uses unused zones) - * +-+ 0-------8------16-------8------16 - * | | | | | | | - * |s| | INPUT | | INPUT | | - * | |->| -> |unused | -> |unused | - * |r| |CAPTURE| | OUTPUT| | - * | | | MIX | | MIX | | - * |c| 8-------------------------------- - * | | | | | | | - * | | | | | | | - * |g| |unused |unused |unused |unused | - * | | | | | | | - * |a| | | | | | - * | | 16------------------------------- - * |i| | | | | | - * | | | PLAYBK| | PLAYBK| | - * |n|->| -> |unused | -> |unused | - * | | |CAPTURE| | OUTPUT| | - * | | | MIX | | MIX | | - * |a| 8-------------------------------- - * |r| | | | | | - * |r| | | | | | - * |a| |unused |unused |unused |unused | - * |y| | | | | | - * | | | | | | | - * +++ 16--|---------------|------------ - * +---V---------------V-----------+ - * | dest_mix_gain_enable array | - * +-------------------------------+ - */ - /* example : MixerMatrix of LoLa280 - * +-+ 0-------8-2 - * | | | | | - * |s| | INPUT | | INPUT - * |r|->| -> | | -> - * |c| |CAPTURE| | <- OUTPUT - * | | | MIX | | MIX - * |g| 8---------- - * |a| | | | - * |i| | PLAYBK| | PLAYBACK - * |n|->| -> | | -> - * | | |CAPTURE| | <- OUTPUT - * |a| | MIX | | MIX - * |r| 8---|----|- - * |r| +---V----V-------------------+ - * |a| | dest_mix_gain_enable array | - * |y| +----------------------------+ + LOLA_MIXER_DEST_REC_OUTPUT_SEPATATION(val); + + /* example : MixerMatrix of LoLa881 + * 0-------8------16-------8------16 + * | | | | | + * | INPUT | | INPUT | | + * | -> |unused | -> |unused | + * | RECORD| | OUTPUT| | + * | | | | | + * 8-------------------------------- + * | | | | | + * | | | | | + * |unused |unused |unused |unused | + * | | | | | + * | | | | | + * 16------------------------------- + * | | | | | + * | PLAY | | PLAY | | + * | -> |unused | -> |unused | + * | RECORD| | OUTPUT| | + * | | | | | + * 8-------------------------------- + * | | | | | + * | | | | | + * |unused |unused |unused |unused | + * | | | | | + * | | | | | + * 16------------------------------- */ if (chip->mixer.src_stream_out_ofs > MAX_AUDIO_INOUT_COUNT || chip->mixer.dest_phys_out_ofs > MAX_STREAM_IN_COUNT) { @@ -213,9 +192,6 @@ int __devinit lola_init_mixer_widget(struct lola *chip, int nid) (((1U << chip->mixer.dest_phys_outs) - 1) << chip->mixer.dest_phys_out_ofs); - snd_printdd("Mixer src_mask=%x, dest_mask=%x\n", - chip->mixer.src_mask, chip->mixer.dest_mask); - return 0; } @@ -226,19 +202,12 @@ static int lola_mixer_set_src_gain(struct lola *chip, unsigned int id, if (!(chip->mixer.src_mask & (1 << id))) return -EINVAL; + writew(gain, &chip->mixer.array->src_gain[id]); oldval = val = readl(&chip->mixer.array->src_gain_enable); if (on) val |= (1 << id); else val &= ~(1 << id); - /* test if values unchanged */ - if ((val == oldval) && - (gain == readw(&chip->mixer.array->src_gain[id]))) - return 0; - - snd_printdd("lola_mixer_set_src_gain (id=%d, gain=%d) enable=%x\n", - id, gain, val); - writew(gain, &chip->mixer.array->src_gain[id]); writel(val, &chip->mixer.array->src_gain_enable); lola_codec_flush(chip); /* inform micro-controller about the new source gain */ @@ -300,7 +269,6 @@ static int lola_mixer_set_mapping_gain(struct lola *chip, src, dest); } -#if 0 /* not used */ static int lola_mixer_set_dest_gains(struct lola *chip, unsigned int id, unsigned int mask, unsigned short *gains) { @@ -321,7 +289,6 @@ static int lola_mixer_set_dest_gains(struct lola *chip, unsigned int id, return lola_codec_write(chip, chip->mixer.nid, LOLA_VERB_SET_DESTINATION_GAIN, id, 0); } -#endif /* not used */ /* */ @@ -409,8 +376,6 @@ static int set_analog_volume(struct lola *chip, int dir, return 0; if (external_call) lola_codec_flush(chip); - snd_printdd("set_analog_volume (dir=%d idx=%d, volume=%d)\n", - dir, idx, val); err = lola_codec_write(chip, pin->nid, LOLA_VERB_SET_AMP_GAIN_MUTE, val, 0); if (err < 0) @@ -462,40 +427,23 @@ static int init_mixer_values(struct lola *chip) { int i; - /* all sample rate converters on */ + /* all src on */ lola_set_src_config(chip, (1 << chip->pin[CAPT].num_pins) - 1, false); - /* clear all mixer matrix settings */ + /* clear all matrix */ memset_io(chip->mixer.array, 0, sizeof(*chip->mixer.array)); - /* inform firmware about all updated matrix columns - capture part */ - for (i = 0; i < chip->mixer.dest_stream_ins; i++) - lola_codec_write(chip, chip->mixer.nid, - LOLA_VERB_SET_DESTINATION_GAIN, - i, 0); - /* inform firmware about all updated matrix columns - output part */ - for (i = 0; i < chip->mixer.dest_phys_outs; i++) - lola_codec_write(chip, chip->mixer.nid, - LOLA_VERB_SET_DESTINATION_GAIN, - chip->mixer.dest_phys_out_ofs + i, 0); - - /* set all digital input source (master) gains to 0dB */ + /* set src gain to 0dB */ for (i = 0; i < chip->mixer.src_phys_ins; i++) lola_mixer_set_src_gain(chip, i, 336, true); /* 0dB */ - - /* set all digital playback source (master) gains to 0dB */ for (i = 0; i < chip->mixer.src_stream_outs; i++) lola_mixer_set_src_gain(chip, i + chip->mixer.src_stream_out_ofs, 336, true); /* 0dB */ - /* set gain value 0dB diagonally in matrix - part INPUT -> CAPTURE */ + /* set 1:1 dest gain */ for (i = 0; i < chip->mixer.dest_stream_ins; i++) { int src = i % chip->mixer.src_phys_ins; lola_mixer_set_mapping_gain(chip, src, i, 336, true); } - /* set gain value 0dB diagonally in matrix , part PLAYBACK -> OUTPUT - * (LoLa280 : playback channel 0,2,4,6 linked to output channel 0) - * (LoLa280 : playback channel 1,3,5,7 linked to output channel 1) - */ for (i = 0; i < chip->mixer.src_stream_outs; i++) { int src = chip->mixer.src_stream_out_ofs + i; int dst = chip->mixer.dest_phys_out_ofs + @@ -745,7 +693,6 @@ static int __devinit create_src_gain_mixer(struct lola *chip, snd_ctl_new1(&lola_src_gain_mixer, chip)); } -#if 0 /* not used */ /* * destination gain (matrix-like) mixer */ @@ -834,7 +781,6 @@ static int __devinit create_dest_gain_mixer(struct lola *chip, return snd_ctl_add(chip->card, snd_ctl_new1(&lola_dest_gain_mixer, chip)); } -#endif /* not used */ /* */ @@ -852,16 +798,14 @@ int __devinit lola_create_mixer(struct lola *chip) if (err < 0) return err; err = create_src_gain_mixer(chip, chip->mixer.src_phys_ins, 0, - "Digital Capture Volume"); + "Line Source Gain Volume"); if (err < 0) return err; err = create_src_gain_mixer(chip, chip->mixer.src_stream_outs, chip->mixer.src_stream_out_ofs, - "Digital Playback Volume"); + "Stream Source Gain Volume"); if (err < 0) return err; -#if 0 -/* FIXME: buggy mixer matrix handling */ err = create_dest_gain_mixer(chip, chip->mixer.src_phys_ins, 0, chip->mixer.dest_stream_ins, 0, @@ -890,6 +834,6 @@ int __devinit lola_create_mixer(struct lola *chip) "Stream Playback Volume"); if (err < 0) return err; -#endif /* FIXME */ + return init_mixer_values(chip); } diff --git a/trunk/sound/pci/lx6464es/lx6464es.c b/trunk/sound/pci/lx6464es/lx6464es.c index 04ae84b2a107..1bd7a540fd49 100644 --- a/trunk/sound/pci/lx6464es/lx6464es.c +++ b/trunk/sound/pci/lx6464es/lx6464es.c @@ -762,6 +762,7 @@ static int lx_set_granularity(struct lx6464es *chip, u32 gran) static int __devinit lx_init_dsp(struct lx6464es *chip) { int err; + u8 mac_address[6]; int i; snd_printdd("->lx_init_dsp\n"); @@ -786,11 +787,11 @@ static int __devinit lx_init_dsp(struct lx6464es *chip) /** \todo the mac address should be ready by not, but it isn't, * so we wait for it */ for (i = 0; i != 1000; ++i) { - err = lx_dsp_get_mac(chip); + err = lx_dsp_get_mac(chip, mac_address); if (err) return err; - if (chip->mac_address[0] || chip->mac_address[1] || chip->mac_address[2] || - chip->mac_address[3] || chip->mac_address[4] || chip->mac_address[5]) + if (mac_address[0] || mac_address[1] || mac_address[2] || + mac_address[3] || mac_address[4] || mac_address[5]) goto mac_ready; msleep(1); } @@ -799,8 +800,8 @@ static int __devinit lx_init_dsp(struct lx6464es *chip) mac_ready: snd_printd(LXP "mac address ready read after: %dms\n", i); snd_printk(LXP "mac address: %02X.%02X.%02X.%02X.%02X.%02X\n", - chip->mac_address[0], chip->mac_address[1], chip->mac_address[2], - chip->mac_address[3], chip->mac_address[4], chip->mac_address[5]); + mac_address[0], mac_address[1], mac_address[2], + mac_address[3], mac_address[4], mac_address[5]); err = lx_init_get_version_features(chip); if (err) @@ -1030,7 +1031,7 @@ static int __devinit snd_lx6464es_create(struct snd_card *card, chip->port_dsp_bar = pci_ioremap_bar(pci, 2); err = request_irq(pci->irq, lx_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip); + card_name, chip); if (err) { snd_printk(KERN_ERR LXP "unable to grab IRQ %d\n", pci->irq); goto request_irq_failed; @@ -1107,14 +1108,8 @@ static int __devinit snd_lx6464es_probe(struct pci_dev *pci, goto out_free; } - strcpy(card->driver, "LX6464ES"); - sprintf(card->id, "LX6464ES_%02X%02X%02X", - chip->mac_address[3], chip->mac_address[4], chip->mac_address[5]); - - sprintf(card->shortname, "LX6464ES %02X.%02X.%02X.%02X.%02X.%02X", - chip->mac_address[0], chip->mac_address[1], chip->mac_address[2], - chip->mac_address[3], chip->mac_address[4], chip->mac_address[5]); - + strcpy(card->driver, "lx6464es"); + strcpy(card->shortname, "Digigram LX6464ES"); sprintf(card->longname, "%s at 0x%lx, 0x%p, irq %i", card->shortname, chip->port_plx, chip->port_dsp_bar, chip->irq); @@ -1142,7 +1137,7 @@ static void __devexit snd_lx6464es_remove(struct pci_dev *pci) static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "Digigram LX6464ES", .id_table = snd_lx6464es_ids, .probe = snd_lx6464es_probe, .remove = __devexit_p(snd_lx6464es_remove), diff --git a/trunk/sound/pci/lx6464es/lx6464es.h b/trunk/sound/pci/lx6464es/lx6464es.h index e2a124ae27e8..aea621eafbb5 100644 --- a/trunk/sound/pci/lx6464es/lx6464es.h +++ b/trunk/sound/pci/lx6464es/lx6464es.h @@ -69,8 +69,6 @@ struct lx6464es { struct pci_dev *pci; int irq; - u8 mac_address[6]; - spinlock_t lock; /* interrupt spinlock */ struct mutex setup_mutex; /* mutex used in hw_params, open * and close */ diff --git a/trunk/sound/pci/lx6464es/lx_core.c b/trunk/sound/pci/lx6464es/lx_core.c index 5c8717e29eeb..617f98b0cbae 100644 --- a/trunk/sound/pci/lx6464es/lx_core.c +++ b/trunk/sound/pci/lx6464es/lx_core.c @@ -424,7 +424,7 @@ int lx_dsp_get_clock_frequency(struct lx6464es *chip, u32 *rfreq) return ret; } -int lx_dsp_get_mac(struct lx6464es *chip) +int lx_dsp_get_mac(struct lx6464es *chip, u8 *mac_address) { u32 macmsb, maclsb; @@ -432,12 +432,12 @@ int lx_dsp_get_mac(struct lx6464es *chip) maclsb = lx_dsp_reg_read(chip, eReg_ADMACESLSB) & 0x00FFFFFF; /* todo: endianess handling */ - chip->mac_address[5] = ((u8 *)(&maclsb))[0]; - chip->mac_address[4] = ((u8 *)(&maclsb))[1]; - chip->mac_address[3] = ((u8 *)(&maclsb))[2]; - chip->mac_address[2] = ((u8 *)(&macmsb))[0]; - chip->mac_address[1] = ((u8 *)(&macmsb))[1]; - chip->mac_address[0] = ((u8 *)(&macmsb))[2]; + mac_address[5] = ((u8 *)(&maclsb))[0]; + mac_address[4] = ((u8 *)(&maclsb))[1]; + mac_address[3] = ((u8 *)(&maclsb))[2]; + mac_address[2] = ((u8 *)(&macmsb))[0]; + mac_address[1] = ((u8 *)(&macmsb))[1]; + mac_address[0] = ((u8 *)(&macmsb))[2]; return 0; } diff --git a/trunk/sound/pci/lx6464es/lx_core.h b/trunk/sound/pci/lx6464es/lx_core.h index 1dd562980b6c..6bd9cbbbc68d 100644 --- a/trunk/sound/pci/lx6464es/lx_core.h +++ b/trunk/sound/pci/lx6464es/lx_core.h @@ -116,7 +116,7 @@ int __devinit lx_dsp_get_version(struct lx6464es *chip, u32 *rdsp_version); int lx_dsp_get_clock_frequency(struct lx6464es *chip, u32 *rfreq); int lx_dsp_set_granularity(struct lx6464es *chip, u32 gran); int lx_dsp_read_async_events(struct lx6464es *chip, u32 *data); -int lx_dsp_get_mac(struct lx6464es *chip); +int lx_dsp_get_mac(struct lx6464es *chip, u8 *mac_address); /* low-level pipe handling */ diff --git a/trunk/sound/pci/maestro3.c b/trunk/sound/pci/maestro3.c index 0378126e6272..3c40d726b46e 100644 --- a/trunk/sound/pci/maestro3.c +++ b/trunk/sound/pci/maestro3.c @@ -850,10 +850,11 @@ struct snd_m3 { struct input_dev *input_dev; char phys[64]; /* physical device path */ #else + spinlock_t ac97_lock; struct snd_kcontrol *master_switch; struct snd_kcontrol *master_volume; + struct tasklet_struct hwvol_tq; #endif - struct work_struct hwvol_work; unsigned int in_suspend; @@ -1608,10 +1609,13 @@ static void snd_m3_update_ptr(struct snd_m3 *chip, struct m3_dma *s) (without wrap around) in response to volume button presses and then generating an interrupt. The pair of counters is stored in bits 1-3 and 5-7 of a byte wide register. The meaning of bits 0 and 4 is unknown. */ -static void snd_m3_update_hw_volume(struct work_struct *work) +static void snd_m3_update_hw_volume(unsigned long private_data) { - struct snd_m3 *chip = container_of(work, struct snd_m3, hwvol_work); + struct snd_m3 *chip = (struct snd_m3 *) private_data; int x, val; +#ifndef CONFIG_SND_MAESTRO3_INPUT + unsigned long flags; +#endif /* Figure out which volume control button was pushed, based on differences from the default register @@ -1641,13 +1645,21 @@ static void snd_m3_update_hw_volume(struct work_struct *work) if (!chip->master_switch || !chip->master_volume) return; - val = snd_ac97_read(chip->ac97, AC97_MASTER); + /* FIXME: we can't call snd_ac97_* functions since here is in tasklet. */ + spin_lock_irqsave(&chip->ac97_lock, flags); + + val = chip->ac97->regs[AC97_MASTER_VOL]; switch (x) { case 0x88: /* The counters have not changed, yet we've received a HV interrupt. According to tests run by various people this happens when pressing the mute button. */ val ^= 0x8000; + chip->ac97->regs[AC97_MASTER_VOL] = val; + outw(val, chip->iobase + CODEC_DATA); + outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND); + snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, + &chip->master_switch->id); break; case 0xaa: /* counters increased by 1 -> volume up */ @@ -1655,6 +1667,11 @@ static void snd_m3_update_hw_volume(struct work_struct *work) val--; if ((val & 0x7f00) > 0) val -= 0x0100; + chip->ac97->regs[AC97_MASTER_VOL] = val; + outw(val, chip->iobase + CODEC_DATA); + outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND); + snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, + &chip->master_volume->id); break; case 0x66: /* counters decreased by 1 -> volume down */ @@ -1662,11 +1679,14 @@ static void snd_m3_update_hw_volume(struct work_struct *work) val++; if ((val & 0x7f00) < 0x1f00) val += 0x0100; + chip->ac97->regs[AC97_MASTER_VOL] = val; + outw(val, chip->iobase + CODEC_DATA); + outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND); + snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, + &chip->master_volume->id); break; } - if (snd_ac97_update(chip->ac97, AC97_MASTER, val)) - snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, - &chip->master_switch->id); + spin_unlock_irqrestore(&chip->ac97_lock, flags); #else if (!chip->input_dev) return; @@ -1710,7 +1730,11 @@ static irqreturn_t snd_m3_interrupt(int irq, void *dev_id) return IRQ_NONE; if (status & HV_INT_PENDING) - schedule_work(&chip->hwvol_work); +#ifdef CONFIG_SND_MAESTRO3_INPUT + snd_m3_update_hw_volume((unsigned long)chip); +#else + tasklet_schedule(&chip->hwvol_tq); +#endif /* * ack an assp int if its running @@ -1976,14 +2000,24 @@ static unsigned short snd_m3_ac97_read(struct snd_ac97 *ac97, unsigned short reg) { struct snd_m3 *chip = ac97->private_data; +#ifndef CONFIG_SND_MAESTRO3_INPUT + unsigned long flags; +#endif unsigned short data = 0xffff; if (snd_m3_ac97_wait(chip)) goto fail; +#ifndef CONFIG_SND_MAESTRO3_INPUT + spin_lock_irqsave(&chip->ac97_lock, flags); +#endif snd_m3_outb(chip, 0x80 | (reg & 0x7f), CODEC_COMMAND); if (snd_m3_ac97_wait(chip)) - goto fail; + goto fail_unlock; data = snd_m3_inw(chip, CODEC_DATA); +fail_unlock: +#ifndef CONFIG_SND_MAESTRO3_INPUT + spin_unlock_irqrestore(&chip->ac97_lock, flags); +#endif fail: return data; } @@ -1992,11 +2026,20 @@ static void snd_m3_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val) { struct snd_m3 *chip = ac97->private_data; +#ifndef CONFIG_SND_MAESTRO3_INPUT + unsigned long flags; +#endif if (snd_m3_ac97_wait(chip)) return; +#ifndef CONFIG_SND_MAESTRO3_INPUT + spin_lock_irqsave(&chip->ac97_lock, flags); +#endif snd_m3_outw(chip, val, CODEC_DATA); snd_m3_outb(chip, reg & 0x7f, CODEC_COMMAND); +#ifndef CONFIG_SND_MAESTRO3_INPUT + spin_unlock_irqrestore(&chip->ac97_lock, flags); +#endif } @@ -2415,7 +2458,6 @@ static int snd_m3_free(struct snd_m3 *chip) struct m3_dma *s; int i; - cancel_work_sync(&chip->hwvol_work); #ifdef CONFIG_SND_MAESTRO3_INPUT if (chip->input_dev) input_unregister_device(chip->input_dev); @@ -2469,7 +2511,6 @@ static int m3_suspend(struct pci_dev *pci, pm_message_t state) return 0; chip->in_suspend = 1; - cancel_work_sync(&chip->hwvol_work); snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); snd_pcm_suspend_all(chip->pcm); snd_ac97_suspend(chip->ac97); @@ -2626,6 +2667,9 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci, } spin_lock_init(&chip->reg_lock); +#ifndef CONFIG_SND_MAESTRO3_INPUT + spin_lock_init(&chip->ac97_lock); +#endif switch (pci->device) { case PCI_DEVICE_ID_ESS_ALLEGRO: @@ -2639,7 +2683,6 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci, chip->card = card; chip->pci = pci; chip->irq = -1; - INIT_WORK(&chip->hwvol_work, snd_m3_update_hw_volume); chip->external_amp = enable_amp; if (amp_gpio >= 0 && amp_gpio <= 0x0f) @@ -2709,8 +2752,12 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci, snd_m3_hv_init(chip); +#ifndef CONFIG_SND_MAESTRO3_INPUT + tasklet_init(&chip->hwvol_tq, snd_m3_update_hw_volume, (unsigned long)chip); +#endif + if (request_irq(pci->irq, snd_m3_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + card->driver, chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_m3_free(chip); return -ENOMEM; @@ -2838,7 +2885,7 @@ static void __devexit snd_m3_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "Maestro3", .id_table = snd_m3_ids, .probe = snd_m3_probe, .remove = __devexit_p(snd_m3_remove), diff --git a/trunk/sound/pci/mixart/mixart.c b/trunk/sound/pci/mixart/mixart.c index dbee59906ae1..6c3fd4d1c49d 100644 --- a/trunk/sound/pci/mixart/mixart.c +++ b/trunk/sound/pci/mixart/mixart.c @@ -1268,7 +1268,7 @@ static int __devinit snd_mixart_probe(struct pci_dev *pci, } if (request_irq(pci->irq, snd_mixart_interrupt, IRQF_SHARED, - KBUILD_MODNAME, mgr)) { + CARD_NAME, mgr)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_mixart_free(mgr); return -EBUSY; @@ -1381,7 +1381,7 @@ static void __devexit snd_mixart_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "Digigram miXart", .id_table = snd_mixart_ids, .probe = snd_mixart_probe, .remove = __devexit_p(snd_mixart_remove), diff --git a/trunk/sound/pci/nm256/nm256.c b/trunk/sound/pci/nm256/nm256.c index 83ea7a7d3eec..5a60492ac7b3 100644 --- a/trunk/sound/pci/nm256/nm256.c +++ b/trunk/sound/pci/nm256/nm256.c @@ -465,7 +465,7 @@ static int snd_nm256_acquire_irq(struct nm256 *chip) mutex_lock(&chip->irq_mutex); if (chip->irq < 0) { if (request_irq(chip->pci->irq, chip->interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + chip->card->driver, chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->pci->irq); mutex_unlock(&chip->irq_mutex); return -EBUSY; @@ -1743,7 +1743,7 @@ static void __devexit snd_nm256_remove(struct pci_dev *pci) static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "NeoMagic 256", .id_table = snd_nm256_ids, .probe = snd_nm256_probe, .remove = __devexit_p(snd_nm256_remove), diff --git a/trunk/sound/pci/oxygen/oxygen.c b/trunk/sound/pci/oxygen/oxygen.c index 218d9854e5cb..d7e8ddd9a67b 100644 --- a/trunk/sound/pci/oxygen/oxygen.c +++ b/trunk/sound/pci/oxygen/oxygen.c @@ -859,7 +859,7 @@ static int __devinit generic_oxygen_probe(struct pci_dev *pci, } static struct pci_driver oxygen_driver = { - .name = KBUILD_MODNAME, + .name = "CMI8788", .id_table = oxygen_ids, .probe = generic_oxygen_probe, .remove = __devexit_p(oxygen_pci_remove), diff --git a/trunk/sound/pci/oxygen/oxygen_lib.c b/trunk/sound/pci/oxygen/oxygen_lib.c index 82311fcb86f6..70b739816fcc 100644 --- a/trunk/sound/pci/oxygen/oxygen_lib.c +++ b/trunk/sound/pci/oxygen/oxygen_lib.c @@ -655,7 +655,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, chip->model.init(chip); err = request_irq(pci->irq, oxygen_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip); + DRIVER, chip); if (err < 0) { snd_printk(KERN_ERR "cannot grab interrupt %d\n", pci->irq); goto err_card; diff --git a/trunk/sound/pci/oxygen/oxygen_pcm.c b/trunk/sound/pci/oxygen/oxygen_pcm.c index cc0bcd9f3350..d5533e34ece9 100644 --- a/trunk/sound/pci/oxygen/oxygen_pcm.c +++ b/trunk/sound/pci/oxygen/oxygen_pcm.c @@ -168,6 +168,12 @@ static int oxygen_open(struct snd_pcm_substream *substream, if (err < 0) return err; } + if (channel == PCM_MULTICH) { + err = snd_pcm_hw_constraint_minmax + (runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 0, 8192000); + if (err < 0) + return err; + } snd_pcm_set_sync(substream); chip->streams[channel] = substream; diff --git a/trunk/sound/pci/oxygen/virtuoso.c b/trunk/sound/pci/oxygen/virtuoso.c index 773db794b43f..469010a8b849 100644 --- a/trunk/sound/pci/oxygen/virtuoso.c +++ b/trunk/sound/pci/oxygen/virtuoso.c @@ -88,7 +88,7 @@ static int __devinit xonar_probe(struct pci_dev *pci, } static struct pci_driver xonar_driver = { - .name = KBUILD_MODNAME, + .name = "AV200", .id_table = xonar_ids, .probe = xonar_probe, .remove = __devexit_p(oxygen_pci_remove), diff --git a/trunk/sound/pci/oxygen/xonar_pcm179x.c b/trunk/sound/pci/oxygen/xonar_pcm179x.c index 32d096c98f5b..54cad38ec30a 100644 --- a/trunk/sound/pci/oxygen/xonar_pcm179x.c +++ b/trunk/sound/pci/oxygen/xonar_pcm179x.c @@ -327,10 +327,8 @@ static void pcm1796_init(struct oxygen *chip) { struct xonar_pcm179x *data = chip->model_data; - data->pcm1796_regs[0][18 - PCM1796_REG_BASE] = + data->pcm1796_regs[0][18 - PCM1796_REG_BASE] = PCM1796_MUTE | PCM1796_DMF_DISABLED | PCM1796_FMT_24_I2S | PCM1796_ATLD; - if (!data->broken_i2c) - data->pcm1796_regs[0][18 - PCM1796_REG_BASE] |= PCM1796_MUTE; data->pcm1796_regs[0][19 - PCM1796_REG_BASE] = PCM1796_FLT_SHARP | PCM1796_ATS_1; data->pcm1796_regs[0][20 - PCM1796_REG_BASE] = @@ -1125,7 +1123,6 @@ int __devinit get_xonar_pcm179x_model(struct oxygen *chip, chip->model.control_filter = xonar_st_h6_control_filter; chip->model.dac_channels_pcm = 8; chip->model.dac_channels_mixer = 8; - chip->model.dac_volume_min = 255; chip->model.dac_mclks = OXYGEN_MCLKS(256, 128, 128); break; } diff --git a/trunk/sound/pci/pcxhr/pcxhr.c b/trunk/sound/pci/pcxhr/pcxhr.c index 046578d26f98..95cfde27d25c 100644 --- a/trunk/sound/pci/pcxhr/pcxhr.c +++ b/trunk/sound/pci/pcxhr/pcxhr.c @@ -1501,7 +1501,7 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, mgr->irq = -1; if (request_irq(pci->irq, pcxhr_interrupt, IRQF_SHARED, - KBUILD_MODNAME, mgr)) { + card_name, mgr)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); pcxhr_free(mgr); return -EBUSY; @@ -1608,7 +1608,7 @@ static void __devexit pcxhr_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "Digigram pcxhr", .id_table = pcxhr_ids, .probe = pcxhr_probe, .remove = __devexit_p(pcxhr_remove), diff --git a/trunk/sound/pci/riptide/riptide.c b/trunk/sound/pci/riptide/riptide.c index e34ae14908b3..ad5202efd7a9 100644 --- a/trunk/sound/pci/riptide/riptide.c +++ b/trunk/sound/pci/riptide/riptide.c @@ -1890,7 +1890,7 @@ snd_riptide_create(struct snd_card *card, struct pci_dev *pci, UNSET_AIE(hwport); if (request_irq(pci->irq, snd_riptide_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + "RIPTIDE", chip)) { snd_printk(KERN_ERR "Riptide: unable to grab IRQ %d\n", pci->irq); snd_riptide_free(chip); @@ -2176,7 +2176,7 @@ static void __devexit snd_card_riptide_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "RIPTIDE", .id_table = snd_riptide_ids, .probe = snd_card_riptide_probe, .remove = __devexit_p(snd_card_riptide_remove), @@ -2188,7 +2188,7 @@ static struct pci_driver driver = { #ifdef SUPPORT_JOYSTICK static struct pci_driver joystick_driver = { - .name = KBUILD_MODNAME "-joystick", + .name = "Riptide Joystick", .id_table = snd_riptide_joystick_ids, .probe = snd_riptide_joystick_probe, .remove = __devexit_p(snd_riptide_joystick_remove), diff --git a/trunk/sound/pci/rme32.c b/trunk/sound/pci/rme32.c index 6be77a264d47..3c04524de37c 100644 --- a/trunk/sound/pci/rme32.c +++ b/trunk/sound/pci/rme32.c @@ -1355,7 +1355,7 @@ static int __devinit snd_rme32_create(struct rme32 * rme32) } if (request_irq(pci->irq, snd_rme32_interrupt, IRQF_SHARED, - KBUILD_MODNAME, rme32)) { + "RME32", rme32)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); return -EBUSY; } @@ -1985,7 +1985,7 @@ static void __devexit snd_rme32_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "RME Digi32", .id_table = snd_rme32_ids, .probe = snd_rme32_probe, .remove = __devexit_p(snd_rme32_remove), diff --git a/trunk/sound/pci/rme96.c b/trunk/sound/pci/rme96.c index 409e5b89519d..9ff247fc8871 100644 --- a/trunk/sound/pci/rme96.c +++ b/trunk/sound/pci/rme96.c @@ -1561,7 +1561,7 @@ snd_rme96_create(struct rme96 *rme96) } if (request_irq(pci->irq, snd_rme96_interrupt, IRQF_SHARED, - KBUILD_MODNAME, rme96)) { + "RME96", rme96)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); return -EBUSY; } @@ -2396,7 +2396,7 @@ static void __devexit snd_rme96_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "RME Digi96", .id_table = snd_rme96_ids, .probe = snd_rme96_probe, .remove = __devexit_p(snd_rme96_remove), diff --git a/trunk/sound/pci/rme9652/hdsp.c b/trunk/sound/pci/rme9652/hdsp.c index 1c6d1e1c27c1..2d8332416c83 100644 --- a/trunk/sound/pci/rme9652/hdsp.c +++ b/trunk/sound/pci/rme9652/hdsp.c @@ -5482,7 +5482,7 @@ static int __devinit snd_hdsp_create(struct snd_card *card, } if (request_irq(pci->irq, snd_hdsp_interrupt, IRQF_SHARED, - KBUILD_MODNAME, hdsp)) { + "hdsp", hdsp)) { snd_printk(KERN_ERR "Hammerfall-DSP: unable to use IRQ %d\n", pci->irq); return -EBUSY; } @@ -5637,7 +5637,7 @@ static void __devexit snd_hdsp_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "RME Hammerfall DSP", .id_table = snd_hdsp_ids, .probe = snd_hdsp_probe, .remove = __devexit_p(snd_hdsp_remove), diff --git a/trunk/sound/pci/rme9652/hdspm.c b/trunk/sound/pci/rme9652/hdspm.c index af130ee0c45d..c8e402fc3782 100644 --- a/trunk/sound/pci/rme9652/hdspm.c +++ b/trunk/sound/pci/rme9652/hdspm.c @@ -6441,7 +6441,7 @@ static int __devinit snd_hdspm_create(struct snd_card *card, hdspm->port + io_extent - 1); if (request_irq(pci->irq, snd_hdspm_interrupt, - IRQF_SHARED, KBUILD_MODNAME, hdspm)) { + IRQF_SHARED, "hdspm", hdspm)) { snd_printk(KERN_ERR "HDSPM: unable to use IRQ %d\n", pci->irq); return -EBUSY; } @@ -6779,7 +6779,7 @@ static void __devexit snd_hdspm_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "RME Hammerfall DSP MADI", .id_table = snd_hdspm_ids, .probe = snd_hdspm_probe, .remove = __devexit_p(snd_hdspm_remove), diff --git a/trunk/sound/pci/rme9652/rme9652.c b/trunk/sound/pci/rme9652/rme9652.c index 1c7bc1ef8186..c492af5b25f3 100644 --- a/trunk/sound/pci/rme9652/rme9652.c +++ b/trunk/sound/pci/rme9652/rme9652.c @@ -2479,7 +2479,7 @@ static int __devinit snd_rme9652_create(struct snd_card *card, } if (request_irq(pci->irq, snd_rme9652_interrupt, IRQF_SHARED, - KBUILD_MODNAME, rme9652)) { + "rme9652", rme9652)) { snd_printk(KERN_ERR "unable to request IRQ %d\n", pci->irq); return -EBUSY; } @@ -2632,7 +2632,7 @@ static void __devexit snd_rme9652_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "RME Digi9652 (Hammerfall)", .id_table = snd_rme9652_ids, .probe = snd_rme9652_probe, .remove = __devexit_p(snd_rme9652_remove), diff --git a/trunk/sound/pci/sis7019.c b/trunk/sound/pci/sis7019.c index bcf61524a13f..2b5c7a95ae1f 100644 --- a/trunk/sound/pci/sis7019.c +++ b/trunk/sound/pci/sis7019.c @@ -1235,7 +1235,7 @@ static int sis_resume(struct pci_dev *pci) } if (request_irq(pci->irq, sis_interrupt, IRQF_DISABLED|IRQF_SHARED, - KBUILD_MODNAME, sis)) { + card->shortname, sis)) { printk(KERN_ERR "sis7019: unable to regain IRQ %d\n", pci->irq); goto error; } @@ -1341,7 +1341,7 @@ static int __devinit sis_chip_create(struct snd_card *card, goto error_out_cleanup; if (request_irq(pci->irq, sis_interrupt, IRQF_DISABLED|IRQF_SHARED, - KBUILD_MODNAME, sis)) { + card->shortname, sis)) { printk(KERN_ERR "unable to allocate irq %d\n", sis->irq); goto error_out_cleanup; } @@ -1436,7 +1436,7 @@ static void __devexit snd_sis7019_remove(struct pci_dev *pci) } static struct pci_driver sis7019_driver = { - .name = KBUILD_MODNAME, + .name = "SiS7019", .id_table = snd_sis7019_ids, .probe = snd_sis7019_probe, .remove = __devexit_p(snd_sis7019_remove), diff --git a/trunk/sound/pci/sonicvibes.c b/trunk/sound/pci/sonicvibes.c index 2571a67b389a..337b9facadfd 100644 --- a/trunk/sound/pci/sonicvibes.c +++ b/trunk/sound/pci/sonicvibes.c @@ -1294,7 +1294,7 @@ static int __devinit snd_sonicvibes_create(struct snd_card *card, sonic->game_port = pci_resource_start(pci, 4); if (request_irq(pci->irq, snd_sonicvibes_interrupt, IRQF_SHARED, - KBUILD_MODNAME, sonic)) { + "S3 SonicVibes", sonic)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_sonicvibes_free(sonic); return -EBUSY; @@ -1530,7 +1530,7 @@ static void __devexit snd_sonic_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "S3 SonicVibes", .id_table = snd_sonic_ids, .probe = snd_sonic_probe, .remove = __devexit_p(snd_sonic_remove), diff --git a/trunk/sound/pci/trident/trident.c b/trunk/sound/pci/trident/trident.c index d8a128f6fc02..6d0581841d7a 100644 --- a/trunk/sound/pci/trident/trident.c +++ b/trunk/sound/pci/trident/trident.c @@ -172,7 +172,7 @@ static void __devexit snd_trident_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "Trident4DWaveAudio", .id_table = snd_trident_ids, .probe = snd_trident_probe, .remove = __devexit_p(snd_trident_remove), diff --git a/trunk/sound/pci/trident/trident_main.c b/trunk/sound/pci/trident/trident_main.c index 5bd57a7c52d2..2870a4fdc130 100644 --- a/trunk/sound/pci/trident/trident_main.c +++ b/trunk/sound/pci/trident/trident_main.c @@ -3598,7 +3598,7 @@ int __devinit snd_trident_create(struct snd_card *card, trident->port = pci_resource_start(pci, 0); if (request_irq(pci->irq, snd_trident_interrupt, IRQF_SHARED, - KBUILD_MODNAME, trident)) { + "Trident Audio", trident)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_trident_free(trident); return -EBUSY; diff --git a/trunk/sound/pci/via82xx.c b/trunk/sound/pci/via82xx.c index f03fd620a2a0..8c5f8b5a59f0 100644 --- a/trunk/sound/pci/via82xx.c +++ b/trunk/sound/pci/via82xx.c @@ -2377,7 +2377,7 @@ static int __devinit snd_via82xx_create(struct snd_card *card, chip_type == TYPE_VIA8233 ? snd_via8233_interrupt : snd_via686_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + card->driver, chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_via82xx_free(chip); return -EBUSY; @@ -2611,7 +2611,7 @@ static void __devexit snd_via82xx_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "VIA 82xx Audio", .id_table = snd_via82xx_ids, .probe = snd_via82xx_probe, .remove = __devexit_p(snd_via82xx_remove), diff --git a/trunk/sound/pci/via82xx_modem.c b/trunk/sound/pci/via82xx_modem.c index a386dd9f6732..f7e8bbbe3953 100644 --- a/trunk/sound/pci/via82xx_modem.c +++ b/trunk/sound/pci/via82xx_modem.c @@ -1129,7 +1129,7 @@ static int __devinit snd_via82xx_create(struct snd_card *card, } chip->port = pci_resource_start(pci, 0); if (request_irq(pci->irq, snd_via82xx_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + card->driver, chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_via82xx_free(chip); return -EBUSY; @@ -1224,7 +1224,7 @@ static void __devexit snd_via82xx_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "VIA 82xx Modem", .id_table = snd_via82xx_modem_ids, .probe = snd_via82xx_probe, .remove = __devexit_p(snd_via82xx_remove), diff --git a/trunk/sound/pci/vx222/vx222.c b/trunk/sound/pci/vx222/vx222.c index 5342d5e1366a..99a9a814be0b 100644 --- a/trunk/sound/pci/vx222/vx222.c +++ b/trunk/sound/pci/vx222/vx222.c @@ -169,7 +169,7 @@ static int __devinit snd_vx222_create(struct snd_card *card, struct pci_dev *pci vx->port[i] = pci_resource_start(pci, i + 1); if (request_irq(pci->irq, snd_vx_irq_handler, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + CARD_NAME, chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_vx222_free(chip); return -EBUSY; @@ -290,7 +290,7 @@ static int snd_vx222_resume(struct pci_dev *pci) #endif static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "Digigram VX222", .id_table = snd_vx222_ids, .probe = snd_vx222_probe, .remove = __devexit_p(snd_vx222_remove), diff --git a/trunk/sound/pci/ymfpci/ymfpci.c b/trunk/sound/pci/ymfpci/ymfpci.c index 511d57653124..80c682113381 100644 --- a/trunk/sound/pci/ymfpci/ymfpci.c +++ b/trunk/sound/pci/ymfpci/ymfpci.c @@ -345,7 +345,7 @@ static void __devexit snd_card_ymfpci_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "Yamaha DS-1 PCI", .id_table = snd_ymfpci_ids, .probe = snd_card_ymfpci_probe, .remove = __devexit_p(snd_card_ymfpci_remove), diff --git a/trunk/sound/pci/ymfpci/ymfpci_main.c b/trunk/sound/pci/ymfpci/ymfpci_main.c index f3260e658b8a..c94c051ad0c8 100644 --- a/trunk/sound/pci/ymfpci/ymfpci_main.c +++ b/trunk/sound/pci/ymfpci/ymfpci_main.c @@ -2380,7 +2380,7 @@ int __devinit snd_ymfpci_create(struct snd_card *card, return -EBUSY; } if (request_irq(pci->irq, snd_ymfpci_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + "YMFPCI", chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_ymfpci_free(chip); return -EBUSY; diff --git a/trunk/sound/pcmcia/pdaudiocf/pdaudiocf.c b/trunk/sound/pcmcia/pdaudiocf/pdaudiocf.c index 66488a7a5706..ce33be0e4e98 100644 --- a/trunk/sound/pcmcia/pdaudiocf/pdaudiocf.c +++ b/trunk/sound/pcmcia/pdaudiocf/pdaudiocf.c @@ -223,7 +223,7 @@ static int pdacf_config(struct pcmcia_device *link) if (ret) goto failed; - ret = pcmcia_request_irq(link, pdacf_interrupt); + ret = pcmcia_request_exclusive_irq(link, pdacf_interrupt); if (ret) goto failed; diff --git a/trunk/sound/pcmcia/vx/vxpocket.c b/trunk/sound/pcmcia/vx/vxpocket.c index 31777d1ea49f..d9ef21d8fa73 100644 --- a/trunk/sound/pcmcia/vx/vxpocket.c +++ b/trunk/sound/pcmcia/vx/vxpocket.c @@ -229,7 +229,7 @@ static int vxpocket_config(struct pcmcia_device *link) if (ret) goto failed; - ret = pcmcia_request_irq(link, snd_vx_irq_handler); + ret = pcmcia_request_exclusive_irq(link, snd_vx_irq_handler); if (ret) goto failed; diff --git a/trunk/sound/soc/Makefile b/trunk/sound/soc/Makefile index 4f913876f332..1ed61c5df2c5 100644 --- a/trunk/sound/soc/Makefile +++ b/trunk/sound/soc/Makefile @@ -1,5 +1,4 @@ snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o -snd-soc-core-objs += soc-pcm.o soc-io.o obj-$(CONFIG_SND_SOC) += snd-soc-core.o obj-$(CONFIG_SND_SOC) += codecs/ diff --git a/trunk/sound/soc/atmel/atmel-pcm.c b/trunk/sound/soc/atmel/atmel-pcm.c index f81d4c3f8956..d0e75323ec19 100644 --- a/trunk/sound/soc/atmel/atmel-pcm.c +++ b/trunk/sound/soc/atmel/atmel-pcm.c @@ -364,11 +364,9 @@ static struct snd_pcm_ops atmel_pcm_ops = { \*--------------------------------------------------------------------------*/ static u64 atmel_pcm_dmamask = 0xffffffff; -static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd) +static int atmel_pcm_new(struct snd_card *card, + struct snd_soc_dai *dai, struct snd_pcm *pcm) { - struct snd_card *card = rtd->card->snd_card; - struct snd_soc_dai *dai = rtd->cpu_dai; - struct snd_pcm *pcm = rtd->pcm; int ret = 0; if (!card->dev->dma_mask) @@ -384,7 +382,7 @@ static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd) } if (dai->driver->capture.channels_min) { - pr_debug("atmel-pcm:" + pr_debug("at32-pcm:" "Allocating PCM capture DMA buffer\n"); ret = atmel_pcm_preallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE); diff --git a/trunk/sound/soc/atmel/atmel-pcm.h b/trunk/sound/soc/atmel/atmel-pcm.h index 5e0a95e64329..2597329302e7 100644 --- a/trunk/sound/soc/atmel/atmel-pcm.h +++ b/trunk/sound/soc/atmel/atmel-pcm.h @@ -60,7 +60,7 @@ struct atmel_ssc_mask { * This structure, shared between the PCM driver and the interface, * contains all information required by the PCM driver to perform the * PDC DMA operation. All fields except dma_intr_handler() are initialized - * by the interface. The dma_intr_handler() pointer is set by the PCM + * by the interface. The dms_intr_handler() pointer is set by the PCM * driver and called by the interface SSC interrupt handler if it is * non-NULL. */ diff --git a/trunk/sound/soc/atmel/atmel_ssc_dai.c b/trunk/sound/soc/atmel/atmel_ssc_dai.c index 71225090c49f..eda955b15834 100644 --- a/trunk/sound/soc/atmel/atmel_ssc_dai.c +++ b/trunk/sound/soc/atmel/atmel_ssc_dai.c @@ -402,7 +402,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, if ((ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S && bits > 16) { printk(KERN_WARNING - "atmel_ssc_dai: sample size %d " + "atmel_ssc_dai: sample size %d" "is too large for I2S\n", bits); return -EINVAL; } @@ -838,8 +838,10 @@ int atmel_ssc_set_audio(int ssc_id) } ssc_pdev = platform_device_alloc("atmel-ssc-dai", ssc_id); - if (!ssc_pdev) + if (!ssc_pdev) { + ssc_free(ssc); return -ENOMEM; + } /* If we can grab the SSC briefly to parent the DAI device off it */ ssc = ssc_request(ssc_id); diff --git a/trunk/sound/soc/atmel/sam9g20_wm8731.c b/trunk/sound/soc/atmel/sam9g20_wm8731.c index bad3aa14d5b3..95572d290c27 100644 --- a/trunk/sound/soc/atmel/sam9g20_wm8731.c +++ b/trunk/sound/soc/atmel/sam9g20_wm8731.c @@ -92,7 +92,6 @@ static struct snd_soc_ops at91sam9g20ek_ops = { }; static int at91sam9g20ek_set_bias_level(struct snd_soc_card *card, - struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) { static int mclk_on; diff --git a/trunk/sound/soc/au1x/dbdma2.c b/trunk/sound/soc/au1x/dbdma2.c index 20bb53a837b1..10fdd2854e58 100644 --- a/trunk/sound/soc/au1x/dbdma2.c +++ b/trunk/sound/soc/au1x/dbdma2.c @@ -319,11 +319,10 @@ static void au1xpsc_pcm_free_dma_buffers(struct snd_pcm *pcm) snd_pcm_lib_preallocate_free_for_all(pcm); } -static int au1xpsc_pcm_new(struct snd_soc_pcm_runtime *rtd) +static int au1xpsc_pcm_new(struct snd_card *card, + struct snd_soc_dai *dai, + struct snd_pcm *pcm) { - struct snd_card *card = rtd->card->snd_card; - struct snd_pcm *pcm = rtd->pcm; - snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, card->dev, AU1XPSC_BUFFER_MIN_BYTES, (4096 * 1024) - 1); diff --git a/trunk/sound/soc/blackfin/Kconfig b/trunk/sound/soc/blackfin/Kconfig index fe9d548a6837..ae403597fd31 100644 --- a/trunk/sound/soc/blackfin/Kconfig +++ b/trunk/sound/soc/blackfin/Kconfig @@ -10,35 +10,12 @@ config SND_BF5XX_I2S config SND_BF5XX_SOC_SSM2602 tristate "SoC SSM2602 Audio support for BF52x ezkit" - depends on SND_BF5XX_I2S && (SPI_MASTER || I2C) - select SND_BF5XX_SOC_I2S - select SND_SOC_SSM2602 - help - Say Y if you want to add support for SoC audio on BF527-EZKIT. - -config SND_SOC_BFIN_EVAL_ADAU1701 - tristate "Support for the EVAL-ADAU1701MINIZ board on Blackfin eval boards" depends on SND_BF5XX_I2S select SND_BF5XX_SOC_I2S - select SND_SOC_ADAU1701 + select SND_SOC_SSM2602 select I2C help - Say Y if you want to add support for the Analog Devices EVAL-ADAU1701MINIZ - board connected to one of the Blackfin evaluation boards like the - BF5XX-STAMP or BF5XX-EZKIT. - -config SND_SOC_BFIN_EVAL_ADAV80X - tristate "Support for the EVAL-ADAV80X boards on Blackfin eval boards" - depends on SND_BF5XX_I2S && (SPI_MASTER || I2C) - select SND_BF5XX_SOC_I2S - select SND_SOC_ADAV80X - help - Say Y if you want to add support for the Analog Devices EVAL-ADAV801 or - EVAL-ADAV803 board connected to one of the Blackfin evaluation boards - like the BF5XX-STAMP or BF5XX-EZKIT. - - Note: This driver assumes that the ADAV80X digital record and playback - interfaces are connected to the first SPORT port on the BF5XX board. + Say Y if you want to add support for SoC audio on BF527-EZKIT. config SND_BF5XX_SOC_AD73311 tristate "SoC AD73311 Audio support for Blackfin" diff --git a/trunk/sound/soc/blackfin/Makefile b/trunk/sound/soc/blackfin/Makefile index 6018bf52a234..49af3f32aec8 100644 --- a/trunk/sound/soc/blackfin/Makefile +++ b/trunk/sound/soc/blackfin/Makefile @@ -21,13 +21,9 @@ snd-ad1980-objs := bf5xx-ad1980.o snd-ssm2602-objs := bf5xx-ssm2602.o snd-ad73311-objs := bf5xx-ad73311.o snd-ad193x-objs := bf5xx-ad193x.o -snd-soc-bfin-eval-adau1701-objs := bfin-eval-adau1701.o -snd-soc-bfin-eval-adav80x-objs := bfin-eval-adav80x.o obj-$(CONFIG_SND_BF5XX_SOC_AD1836) += snd-ad1836.o obj-$(CONFIG_SND_BF5XX_SOC_AD1980) += snd-ad1980.o obj-$(CONFIG_SND_BF5XX_SOC_SSM2602) += snd-ssm2602.o obj-$(CONFIG_SND_BF5XX_SOC_AD73311) += snd-ad73311.o obj-$(CONFIG_SND_BF5XX_SOC_AD193X) += snd-ad193x.o -obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAU1701) += snd-soc-bfin-eval-adau1701.o -obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAV80X) += snd-soc-bfin-eval-adav80x.o diff --git a/trunk/sound/soc/blackfin/bf5xx-ac97-pcm.c b/trunk/sound/soc/blackfin/bf5xx-ac97-pcm.c index 9e59f680bc19..98b44b316e78 100644 --- a/trunk/sound/soc/blackfin/bf5xx-ac97-pcm.c +++ b/trunk/sound/soc/blackfin/bf5xx-ac97-pcm.c @@ -418,11 +418,9 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm) static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32); -int bf5xx_pcm_ac97_new(struct snd_soc_pcm_runtime *rtd) +int bf5xx_pcm_ac97_new(struct snd_card *card, struct snd_soc_dai *dai, + struct snd_pcm *pcm) { - struct snd_card *card = rtd->card->snd_card; - struct snd_soc_dai *dai = rtd->cpu_dai; - struct snd_pcm *pcm = rtd->pcm; int ret = 0; pr_debug("%s enter\n", __func__); diff --git a/trunk/sound/soc/blackfin/bf5xx-i2s-pcm.c b/trunk/sound/soc/blackfin/bf5xx-i2s-pcm.c index 61ddf942fd4d..f1fd95bb6416 100644 --- a/trunk/sound/soc/blackfin/bf5xx-i2s-pcm.c +++ b/trunk/sound/soc/blackfin/bf5xx-i2s-pcm.c @@ -168,7 +168,7 @@ static int bf5xx_pcm_open(struct snd_pcm_substream *substream) snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware); - ret = snd_pcm_hw_constraint_integer(runtime, + ret = snd_pcm_hw_constraint_integer(runtime, \ SNDRV_PCM_HW_PARAM_PERIODS); if (ret < 0) goto out; @@ -257,11 +257,9 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm) static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32); -int bf5xx_pcm_i2s_new(struct snd_soc_pcm_runtime *rtd) +int bf5xx_pcm_i2s_new(struct snd_card *card, struct snd_soc_dai *dai, + struct snd_pcm *pcm) { - struct snd_card *card = rtd->card->snd_card; - struct snd_soc_dai *dai = rtd->cpu_dai; - struct snd_pcm *pcm = rtd->pcm; int ret = 0; pr_debug("%s enter\n", __func__); @@ -306,8 +304,8 @@ static int __devexit bfin_i2s_soc_platform_remove(struct platform_device *pdev) static struct platform_driver bfin_i2s_pcm_driver = { .driver = { - .name = "bfin-i2s-pcm-audio", - .owner = THIS_MODULE, + .name = "bfin-i2s-pcm-audio", + .owner = THIS_MODULE, }, .probe = bfin_i2s_soc_platform_probe, diff --git a/trunk/sound/soc/blackfin/bf5xx-tdm-pcm.c b/trunk/sound/soc/blackfin/bf5xx-tdm-pcm.c index c95cc03d583d..07cfc7a9e49a 100644 --- a/trunk/sound/soc/blackfin/bf5xx-tdm-pcm.c +++ b/trunk/sound/soc/blackfin/bf5xx-tdm-pcm.c @@ -283,11 +283,9 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm) static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32); -static int bf5xx_pcm_tdm_new(struct snd_soc_pcm_runtime *rtd) +static int bf5xx_pcm_tdm_new(struct snd_card *card, struct snd_soc_dai *dai, + struct snd_pcm *pcm) { - struct snd_card *card = rtd->card->snd_card; - struct snd_soc_dai *dai = rtd->cpu_dai; - struct snd_pcm *pcm = rtd->pcm; int ret = 0; if (!card->dev->dma_mask) diff --git a/trunk/sound/soc/blackfin/bfin-eval-adau1701.c b/trunk/sound/soc/blackfin/bfin-eval-adau1701.c deleted file mode 100644 index e5550acba2c2..000000000000 --- a/trunk/sound/soc/blackfin/bfin-eval-adau1701.c +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Machine driver for EVAL-ADAU1701MINIZ on Analog Devices bfin - * evaluation boards. - * - * Copyright 2011 Analog Devices Inc. - * Author: Lars-Peter Clausen - * - * Licensed under the GPL-2 or later. - */ - -#include -#include -#include -#include -#include -#include - -#include "../codecs/adau1701.h" - -static const struct snd_soc_dapm_widget bfin_eval_adau1701_dapm_widgets[] = { - SND_SOC_DAPM_SPK("Speaker", NULL), - SND_SOC_DAPM_LINE("Line Out", NULL), - SND_SOC_DAPM_LINE("Line In", NULL), -}; - -static const struct snd_soc_dapm_route bfin_eval_adau1701_dapm_routes[] = { - { "Speaker", NULL, "OUT0" }, - { "Speaker", NULL, "OUT1" }, - { "Line Out", NULL, "OUT2" }, - { "Line Out", NULL, "OUT3" }, - - { "IN0", NULL, "Line In" }, - { "IN1", NULL, "Line In" }, -}; - -static int bfin_eval_adau1701_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - int ret; - - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); - if (ret) - return ret; - - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); - if (ret) - return ret; - - ret = snd_soc_dai_set_sysclk(codec_dai, ADAU1701_CLK_SRC_OSC, 12288000, - SND_SOC_CLOCK_IN); - - return ret; -} - -static struct snd_soc_ops bfin_eval_adau1701_ops = { - .hw_params = bfin_eval_adau1701_hw_params, -}; - -static struct snd_soc_dai_link bfin_eval_adau1701_dai[] = { - { - .name = "adau1701", - .stream_name = "adau1701", - .cpu_dai_name = "bfin-i2s.0", - .codec_dai_name = "adau1701", - .platform_name = "bfin-i2s-pcm-audio", - .codec_name = "adau1701.0-0034", - .ops = &bfin_eval_adau1701_ops, - }, - { - .name = "adau1701", - .stream_name = "adau1701", - .cpu_dai_name = "bfin-i2s.1", - .codec_dai_name = "adau1701", - .platform_name = "bfin-i2s-pcm-audio", - .codec_name = "adau1701.0-0034", - .ops = &bfin_eval_adau1701_ops, - }, -}; - -static struct snd_soc_card bfin_eval_adau1701 = { - .name = "bfin-eval-adau1701", - .dai_link = &bfin_eval_adau1701_dai[CONFIG_SND_BF5XX_SPORT_NUM], - .num_links = 1, - - .dapm_widgets = bfin_eval_adau1701_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(bfin_eval_adau1701_dapm_widgets), - .dapm_routes = bfin_eval_adau1701_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(bfin_eval_adau1701_dapm_routes), -}; - -static int bfin_eval_adau1701_probe(struct platform_device *pdev) -{ - struct snd_soc_card *card = &bfin_eval_adau1701; - - card->dev = &pdev->dev; - - return snd_soc_register_card(&bfin_eval_adau1701); -} - -static int __devexit bfin_eval_adau1701_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - - snd_soc_unregister_card(card); - - return 0; -} - -static struct platform_driver bfin_eval_adau1701_driver = { - .driver = { - .name = "bfin-eval-adau1701", - .owner = THIS_MODULE, - .pm = &snd_soc_pm_ops, - }, - .probe = bfin_eval_adau1701_probe, - .remove = __devexit_p(bfin_eval_adau1701_remove), -}; - -static int __init bfin_eval_adau1701_init(void) -{ - return platform_driver_register(&bfin_eval_adau1701_driver); -} -module_init(bfin_eval_adau1701_init); - -static void __exit bfin_eval_adau1701_exit(void) -{ - platform_driver_unregister(&bfin_eval_adau1701_driver); -} -module_exit(bfin_eval_adau1701_exit); - -MODULE_AUTHOR("Lars-Peter Clausen "); -MODULE_DESCRIPTION("ALSA SoC bfin ADAU1701 driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:bfin-eval-adau1701"); diff --git a/trunk/sound/soc/blackfin/bfin-eval-adav80x.c b/trunk/sound/soc/blackfin/bfin-eval-adav80x.c deleted file mode 100644 index 8d014d01626e..000000000000 --- a/trunk/sound/soc/blackfin/bfin-eval-adav80x.c +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Machine driver for EVAL-ADAV801 and EVAL-ADAV803 on Analog Devices bfin - * evaluation boards. - * - * Copyright 2011 Analog Devices Inc. - * Author: Lars-Peter Clausen - * - * Licensed under the GPL-2 or later. - */ - -#include -#include -#include -#include -#include - -#include "../codecs/adav80x.h" - -static const struct snd_soc_dapm_widget bfin_eval_adav80x_dapm_widgets[] = { - SND_SOC_DAPM_LINE("Line Out", NULL), - SND_SOC_DAPM_LINE("Line In", NULL), -}; - -static const struct snd_soc_dapm_route bfin_eval_adav80x_dapm_routes[] = { - { "Line Out", NULL, "VOUTL" }, - { "Line Out", NULL, "VOUTR" }, - - { "VINL", NULL, "Line In" }, - { "VINR", NULL, "Line In" }, -}; - -static int bfin_eval_adav80x_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - int ret; - - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); - if (ret) - return ret; - - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); - if (ret) - return ret; - - ret = snd_soc_dai_set_pll(codec_dai, ADAV80X_PLL1, ADAV80X_PLL_SRC_XTAL, - 27000000, params_rate(params) * 256); - if (ret) - return ret; - - ret = snd_soc_dai_set_sysclk(codec_dai, ADAV80X_CLK_PLL1, - params_rate(params) * 256, SND_SOC_CLOCK_IN); - - return ret; -} - -static int bfin_eval_adav80x_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dai *codec_dai = rtd->codec_dai; - - snd_soc_dai_set_sysclk(codec_dai, ADAV80X_CLK_SYSCLK1, 0, - SND_SOC_CLOCK_OUT); - snd_soc_dai_set_sysclk(codec_dai, ADAV80X_CLK_SYSCLK2, 0, - SND_SOC_CLOCK_OUT); - snd_soc_dai_set_sysclk(codec_dai, ADAV80X_CLK_SYSCLK3, 0, - SND_SOC_CLOCK_OUT); - - snd_soc_dai_set_sysclk(codec_dai, ADAV80X_CLK_XTAL, 2700000, 0); - - return 0; -} - -static struct snd_soc_ops bfin_eval_adav80x_ops = { - .hw_params = bfin_eval_adav80x_hw_params, -}; - -static struct snd_soc_dai_link bfin_eval_adav80x_dais[] = { - { - .name = "adav80x", - .stream_name = "ADAV80x HiFi", - .cpu_dai_name = "bfin-i2s.0", - .codec_dai_name = "adav80x-hifi", - .platform_name = "bfin-i2s-pcm-audio", - .init = bfin_eval_adav80x_codec_init, - .ops = &bfin_eval_adav80x_ops, - }, -}; - -static struct snd_soc_card bfin_eval_adav80x = { - .name = "bfin-eval-adav80x", - .dai_link = bfin_eval_adav80x_dais, - .num_links = ARRAY_SIZE(bfin_eval_adav80x_dais), - - .dapm_widgets = bfin_eval_adav80x_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(bfin_eval_adav80x_dapm_widgets), - .dapm_routes = bfin_eval_adav80x_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(bfin_eval_adav80x_dapm_routes), -}; - -enum bfin_eval_adav80x_type { - BFIN_EVAL_ADAV801, - BFIN_EVAL_ADAV803, -}; - -static int bfin_eval_adav80x_probe(struct platform_device *pdev) -{ - struct snd_soc_card *card = &bfin_eval_adav80x; - const char *codec_name; - - switch (platform_get_device_id(pdev)->driver_data) { - case BFIN_EVAL_ADAV801: - codec_name = "spi0.1"; - break; - case BFIN_EVAL_ADAV803: - codec_name = "adav803.0-0034"; - break; - default: - return -EINVAL; - } - - bfin_eval_adav80x_dais[0].codec_name = codec_name; - - card->dev = &pdev->dev; - - return snd_soc_register_card(&bfin_eval_adav80x); -} - -static int __devexit bfin_eval_adav80x_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - - snd_soc_unregister_card(card); - - return 0; -} - -static const struct platform_device_id bfin_eval_adav80x_ids[] = { - { "bfin-eval-adav801", BFIN_EVAL_ADAV801 }, - { "bfin-eval-adav803", BFIN_EVAL_ADAV803 }, - { }, -}; -MODULE_DEVICE_TABLE(platform, bfin_eval_adav80x_ids); - -static struct platform_driver bfin_eval_adav80x_driver = { - .driver = { - .name = "bfin-eval-adav80x", - .owner = THIS_MODULE, - .pm = &snd_soc_pm_ops, - }, - .probe = bfin_eval_adav80x_probe, - .remove = __devexit_p(bfin_eval_adav80x_remove), - .id_table = bfin_eval_adav80x_ids, -}; - -static int __init bfin_eval_adav80x_init(void) -{ - return platform_driver_register(&bfin_eval_adav80x_driver); -} -module_init(bfin_eval_adav80x_init); - -static void __exit bfin_eval_adav80x_exit(void) -{ - platform_driver_unregister(&bfin_eval_adav80x_driver); -} -module_exit(bfin_eval_adav80x_exit); - -MODULE_AUTHOR("Lars-Peter Clausen "); -MODULE_DESCRIPTION("ALSA SoC bfin adav80x driver"); -MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/codecs/Kconfig b/trunk/sound/soc/codecs/Kconfig index 36a030f1d1f5..98175a096df2 100644 --- a/trunk/sound/soc/codecs/Kconfig +++ b/trunk/sound/soc/codecs/Kconfig @@ -17,7 +17,6 @@ config SND_SOC_ALL_CODECS select SND_SOC_AD193X if SND_SOC_I2C_AND_SPI select SND_SOC_AD1980 if SND_SOC_AC97_BUS select SND_SOC_AD73311 - select SND_SOC_ADAV80X select SND_SOC_ADS117X select SND_SOC_AK4104 if SPI_MASTER select SND_SOC_AK4535 if I2C @@ -43,7 +42,6 @@ config SND_SOC_ALL_CODECS select SND_SOC_SN95031 if INTEL_SCU_IPC select SND_SOC_SPDIF select SND_SOC_SSM2602 if SND_SOC_I2C_AND_SPI - select SND_SOC_STA32X if I2C select SND_SOC_STAC9766 if SND_SOC_AC97_BUS select SND_SOC_TLV320AIC23 if I2C select SND_SOC_TLV320AIC26 if SPI_MASTER @@ -73,7 +71,6 @@ config SND_SOC_ALL_CODECS select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8770 if SPI_MASTER select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI - select SND_SOC_WM8782 select SND_SOC_WM8804 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8900 if I2C select SND_SOC_WM8903 if I2C @@ -87,7 +84,6 @@ config SND_SOC_ALL_CODECS select SND_SOC_WM8971 if I2C select SND_SOC_WM8974 if I2C select SND_SOC_WM8978 if I2C - select SND_SOC_WM8983 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8985 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8990 if I2C @@ -134,14 +130,7 @@ config SND_SOC_AD1980 config SND_SOC_AD73311 tristate - -config SND_SOC_ADAU1701 - select SIGMA - tristate - -config SND_SOC_ADAV80X - tristate - + config SND_SOC_ADS117X tristate @@ -227,9 +216,6 @@ config SND_SOC_SPDIF config SND_SOC_SSM2602 tristate -config SND_SOC_STA32X - tristate - config SND_SOC_STAC9766 tristate @@ -313,9 +299,6 @@ config SND_SOC_WM8770 config SND_SOC_WM8776 tristate -config SND_SOC_WM8782 - tristate - config SND_SOC_WM8804 tristate @@ -355,9 +338,6 @@ config SND_SOC_WM8974 config SND_SOC_WM8978 tristate -config SND_SOC_WM8983 - tristate - config SND_SOC_WM8985 tristate diff --git a/trunk/sound/soc/codecs/Makefile b/trunk/sound/soc/codecs/Makefile index da9990fb8569..fd8558406ef0 100644 --- a/trunk/sound/soc/codecs/Makefile +++ b/trunk/sound/soc/codecs/Makefile @@ -4,8 +4,6 @@ snd-soc-ad1836-objs := ad1836.o snd-soc-ad193x-objs := ad193x.o snd-soc-ad1980-objs := ad1980.o snd-soc-ad73311-objs := ad73311.o -snd-soc-adau1701-objs := adau1701.o -snd-soc-adav80x-objs := adav80x.o snd-soc-ads117x-objs := ads117x.o snd-soc-ak4104-objs := ak4104.o snd-soc-ak4535-objs := ak4535.o @@ -30,7 +28,6 @@ snd-soc-alc5623-objs := alc5623.o snd-soc-sn95031-objs := sn95031.o snd-soc-spdif-objs := spdif_transciever.o snd-soc-ssm2602-objs := ssm2602.o -snd-soc-sta32x-objs := sta32x.o snd-soc-stac9766-objs := stac9766.o snd-soc-tlv320aic23-objs := tlv320aic23.o snd-soc-tlv320aic26-objs := tlv320aic26.o @@ -58,7 +55,6 @@ snd-soc-wm8750-objs := wm8750.o snd-soc-wm8753-objs := wm8753.o snd-soc-wm8770-objs := wm8770.o snd-soc-wm8776-objs := wm8776.o -snd-soc-wm8782-objs := wm8782.o snd-soc-wm8804-objs := wm8804.o snd-soc-wm8900-objs := wm8900.o snd-soc-wm8903-objs := wm8903.o @@ -72,7 +68,6 @@ snd-soc-wm8962-objs := wm8962.o snd-soc-wm8971-objs := wm8971.o snd-soc-wm8974-objs := wm8974.o snd-soc-wm8978-objs := wm8978.o -snd-soc-wm8983-objs := wm8983.o snd-soc-wm8985-objs := wm8985.o snd-soc-wm8988-objs := wm8988.o snd-soc-wm8990-objs := wm8990.o @@ -100,8 +95,6 @@ obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o obj-$(CONFIG_SND_SOC_AD193X) += snd-soc-ad193x.o obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o -obj-$(CONFIG_SND_SOC_ADAU1701) += snd-soc-adau1701.o -obj-$(CONFIG_SND_SOC_ADAV80X) += snd-soc-adav80x.o obj-$(CONFIG_SND_SOC_ADS117X) += snd-soc-ads117x.o obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o @@ -127,7 +120,6 @@ obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o obj-$(CONFIG_SND_SOC_SN95031) +=snd-soc-sn95031.o obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o -obj-$(CONFIG_SND_SOC_STA32X) += snd-soc-sta32x.o obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o @@ -155,7 +147,6 @@ obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o obj-$(CONFIG_SND_SOC_WM8770) += snd-soc-wm8770.o obj-$(CONFIG_SND_SOC_WM8776) += snd-soc-wm8776.o -obj-$(CONFIG_SND_SOC_WM8782) += snd-soc-wm8782.o obj-$(CONFIG_SND_SOC_WM8804) += snd-soc-wm8804.o obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o @@ -169,7 +160,6 @@ obj-$(CONFIG_SND_SOC_WM8962) += snd-soc-wm8962.o obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o obj-$(CONFIG_SND_SOC_WM8974) += snd-soc-wm8974.o obj-$(CONFIG_SND_SOC_WM8978) += snd-soc-wm8978.o -obj-$(CONFIG_SND_SOC_WM8983) += snd-soc-wm8983.o obj-$(CONFIG_SND_SOC_WM8985) += snd-soc-wm8985.o obj-$(CONFIG_SND_SOC_WM8988) += snd-soc-wm8988.o obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o diff --git a/trunk/sound/soc/codecs/ad1836.c b/trunk/sound/soc/codecs/ad1836.c index 4e5c5726366b..754c496412bd 100644 --- a/trunk/sound/soc/codecs/ad1836.c +++ b/trunk/sound/soc/codecs/ad1836.c @@ -1,10 +1,19 @@ - /* - * Audio Codec driver supporting: - * AD1835A, AD1836, AD1837A, AD1838A, AD1839A +/* + * File: sound/soc/codecs/ad1836.c + * Author: Barry Song + * + * Created: Aug 04 2009 + * Description: Driver for AD1836 sound chip + * + * Modified: + * Copyright 2009 Analog Devices Inc. * - * Copyright 2009-2011 Analog Devices Inc. + * Bugs: Enter bugs at http://blackfin.uclinux.org/ * - * Licensed under the GPL-2 or later. + * 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 @@ -21,15 +30,10 @@ #include #include "ad1836.h" -enum ad1836_type { - AD1835, - AD1836, - AD1838, -}; - /* codec private data */ struct ad1836_priv { - enum ad1836_type type; + enum snd_soc_control_type control_type; + void *control_data; }; /* @@ -40,60 +44,29 @@ static const char *ad1836_deemp[] = {"None", "44.1kHz", "32kHz", "48kHz"}; static const struct soc_enum ad1836_deemp_enum = SOC_ENUM_SINGLE(AD1836_DAC_CTRL1, 8, 4, ad1836_deemp); -#define AD1836_DAC_VOLUME(x) \ - SOC_DOUBLE_R("DAC" #x " Playback Volume", AD1836_DAC_L_VOL(x), \ - AD1836_DAC_R_VOL(x), 0, 0x3FF, 0) - -#define AD1836_DAC_SWITCH(x) \ - SOC_DOUBLE("DAC" #x " Playback Switch", AD1836_DAC_CTRL2, \ - AD1836_MUTE_LEFT(x), AD1836_MUTE_RIGHT(x), 1, 1) - -#define AD1836_ADC_SWITCH(x) \ - SOC_DOUBLE("ADC" #x " Capture Switch", AD1836_ADC_CTRL2, \ - AD1836_MUTE_LEFT(x), AD1836_MUTE_RIGHT(x), 1, 1) - -static const struct snd_kcontrol_new ad183x_dac_controls[] = { - AD1836_DAC_VOLUME(1), - AD1836_DAC_SWITCH(1), - AD1836_DAC_VOLUME(2), - AD1836_DAC_SWITCH(2), - AD1836_DAC_VOLUME(3), - AD1836_DAC_SWITCH(3), - AD1836_DAC_VOLUME(4), - AD1836_DAC_SWITCH(4), -}; - -static const struct snd_soc_dapm_widget ad183x_dac_dapm_widgets[] = { - SND_SOC_DAPM_OUTPUT("DAC1OUT"), - SND_SOC_DAPM_OUTPUT("DAC2OUT"), - SND_SOC_DAPM_OUTPUT("DAC3OUT"), - SND_SOC_DAPM_OUTPUT("DAC4OUT"), -}; - -static const struct snd_soc_dapm_route ad183x_dac_routes[] = { - { "DAC1OUT", NULL, "DAC" }, - { "DAC2OUT", NULL, "DAC" }, - { "DAC3OUT", NULL, "DAC" }, - { "DAC4OUT", NULL, "DAC" }, -}; - -static const struct snd_kcontrol_new ad183x_adc_controls[] = { - AD1836_ADC_SWITCH(1), - AD1836_ADC_SWITCH(2), - AD1836_ADC_SWITCH(3), -}; - -static const struct snd_soc_dapm_widget ad183x_adc_dapm_widgets[] = { - SND_SOC_DAPM_INPUT("ADC1IN"), - SND_SOC_DAPM_INPUT("ADC2IN"), -}; - -static const struct snd_soc_dapm_route ad183x_adc_routes[] = { - { "ADC", NULL, "ADC1IN" }, - { "ADC", NULL, "ADC2IN" }, -}; +static const struct snd_kcontrol_new ad1836_snd_controls[] = { + /* DAC volume control */ + SOC_DOUBLE_R("DAC1 Volume", AD1836_DAC_L1_VOL, + AD1836_DAC_R1_VOL, 0, 0x3FF, 0), + SOC_DOUBLE_R("DAC2 Volume", AD1836_DAC_L2_VOL, + AD1836_DAC_R2_VOL, 0, 0x3FF, 0), + SOC_DOUBLE_R("DAC3 Volume", AD1836_DAC_L3_VOL, + AD1836_DAC_R3_VOL, 0, 0x3FF, 0), + + /* ADC switch control */ + SOC_DOUBLE("ADC1 Switch", AD1836_ADC_CTRL2, AD1836_ADCL1_MUTE, + AD1836_ADCR1_MUTE, 1, 1), + SOC_DOUBLE("ADC2 Switch", AD1836_ADC_CTRL2, AD1836_ADCL2_MUTE, + AD1836_ADCR2_MUTE, 1, 1), + + /* DAC switch control */ + SOC_DOUBLE("DAC1 Switch", AD1836_DAC_CTRL2, AD1836_DACL1_MUTE, + AD1836_DACR1_MUTE, 1, 1), + SOC_DOUBLE("DAC2 Switch", AD1836_DAC_CTRL2, AD1836_DACL2_MUTE, + AD1836_DACR2_MUTE, 1, 1), + SOC_DOUBLE("DAC3 Switch", AD1836_DAC_CTRL2, AD1836_DACL3_MUTE, + AD1836_DACR3_MUTE, 1, 1), -static const struct snd_kcontrol_new ad183x_controls[] = { /* ADC high-pass filter */ SOC_SINGLE("ADC High Pass Filter Switch", AD1836_ADC_CTRL1, AD1836_ADC_HIGHPASS_FILTER, 1, 0), @@ -102,24 +75,27 @@ static const struct snd_kcontrol_new ad183x_controls[] = { SOC_ENUM("Playback Deemphasis", ad1836_deemp_enum), }; -static const struct snd_soc_dapm_widget ad183x_dapm_widgets[] = { +static const struct snd_soc_dapm_widget ad1836_dapm_widgets[] = { SND_SOC_DAPM_DAC("DAC", "Playback", AD1836_DAC_CTRL1, AD1836_DAC_POWERDOWN, 1), SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_SUPPLY("ADC_PWR", AD1836_ADC_CTRL1, AD1836_ADC_POWERDOWN, 1, NULL, 0), + SND_SOC_DAPM_OUTPUT("DAC1OUT"), + SND_SOC_DAPM_OUTPUT("DAC2OUT"), + SND_SOC_DAPM_OUTPUT("DAC3OUT"), + SND_SOC_DAPM_INPUT("ADC1IN"), + SND_SOC_DAPM_INPUT("ADC2IN"), }; -static const struct snd_soc_dapm_route ad183x_dapm_routes[] = { +static const struct snd_soc_dapm_route audio_paths[] = { { "DAC", NULL, "ADC_PWR" }, { "ADC", NULL, "ADC_PWR" }, -}; - -static const DECLARE_TLV_DB_SCALE(ad1836_in_tlv, 0, 300, 0); - -static const struct snd_kcontrol_new ad1836_controls[] = { - SOC_DOUBLE_TLV("ADC2 Capture Volume", AD1836_ADC_CTRL1, 3, 0, 4, 0, - ad1836_in_tlv), + { "DAC1OUT", "DAC1 Switch", "DAC" }, + { "DAC2OUT", "DAC2 Switch", "DAC" }, + { "DAC3OUT", "DAC3 Switch", "DAC" }, + { "ADC", "ADC1 Switch", "ADC1IN" }, + { "ADC", "ADC2 Switch", "ADC2IN" }, }; /* @@ -189,69 +165,64 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_dai_ops ad1836_dai_ops = { - .hw_params = ad1836_hw_params, - .set_fmt = ad1836_set_dai_fmt, -}; - -#define AD183X_DAI(_name, num_dacs, num_adcs) \ -{ \ - .name = _name "-hifi", \ - .playback = { \ - .stream_name = "Playback", \ - .channels_min = 2, \ - .channels_max = (num_dacs) * 2, \ - .rates = SNDRV_PCM_RATE_48000, \ - .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE | \ - SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE, \ - }, \ - .capture = { \ - .stream_name = "Capture", \ - .channels_min = 2, \ - .channels_max = (num_adcs) * 2, \ - .rates = SNDRV_PCM_RATE_48000, \ - .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE | \ - SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE, \ - }, \ - .ops = &ad1836_dai_ops, \ -} - -static struct snd_soc_dai_driver ad183x_dais[] = { - [AD1835] = AD183X_DAI("ad1835", 4, 1), - [AD1836] = AD183X_DAI("ad1836", 3, 2), - [AD1838] = AD183X_DAI("ad1838", 3, 1), -}; - #ifdef CONFIG_PM -static int ad1836_suspend(struct snd_soc_codec *codec, pm_message_t state) +static int ad1836_soc_suspend(struct snd_soc_codec *codec, + pm_message_t state) { /* reset clock control mode */ - return snd_soc_update_bits(codec, AD1836_ADC_CTRL2, - AD1836_ADC_SERFMT_MASK, 0); + u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2); + adc_ctrl2 &= ~AD1836_ADC_SERFMT_MASK; + + return snd_soc_write(codec, AD1836_ADC_CTRL2, adc_ctrl2); } -static int ad1836_resume(struct snd_soc_codec *codec) +static int ad1836_soc_resume(struct snd_soc_codec *codec) { /* restore clock control mode */ - return snd_soc_update_bits(codec, AD1836_ADC_CTRL2, - AD1836_ADC_SERFMT_MASK, AD1836_ADC_AUX); + u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2); + adc_ctrl2 |= AD1836_ADC_AUX; + + return snd_soc_write(codec, AD1836_ADC_CTRL2, adc_ctrl2); } #else -#define ad1836_suspend NULL -#define ad1836_resume NULL +#define ad1836_soc_suspend NULL +#define ad1836_soc_resume NULL #endif +static struct snd_soc_dai_ops ad1836_dai_ops = { + .hw_params = ad1836_hw_params, + .set_fmt = ad1836_set_dai_fmt, +}; + +/* codec DAI instance */ +static struct snd_soc_dai_driver ad1836_dai = { + .name = "ad1836-hifi", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 6, + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 4, + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE, + }, + .ops = &ad1836_dai_ops, +}; + static int ad1836_probe(struct snd_soc_codec *codec) { struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec); struct snd_soc_dapm_context *dapm = &codec->dapm; - int num_dacs, num_adcs; int ret = 0; - int i; - - num_dacs = ad183x_dais[ad1836->type].playback.channels_max / 2; - num_adcs = ad183x_dais[ad1836->type].capture.channels_max / 2; + codec->control_data = ad1836->control_data; ret = snd_soc_codec_set_cache_io(codec, 4, 12, SND_SOC_SPI); if (ret < 0) { dev_err(codec->dev, "failed to set cache I/O: %d\n", @@ -268,46 +239,21 @@ static int ad1836_probe(struct snd_soc_codec *codec) snd_soc_write(codec, AD1836_ADC_CTRL1, 0x100); /* unmute adc channles, adc aux mode */ snd_soc_write(codec, AD1836_ADC_CTRL2, 0x180); + /* left/right diff:PGA/MUX */ + snd_soc_write(codec, AD1836_ADC_CTRL3, 0x3A); /* volume */ - for (i = 1; i <= num_dacs; ++i) { - snd_soc_write(codec, AD1836_DAC_L_VOL(i), 0x3FF); - snd_soc_write(codec, AD1836_DAC_R_VOL(i), 0x3FF); - } - - if (ad1836->type == AD1836) { - /* left/right diff:PGA/MUX */ - snd_soc_write(codec, AD1836_ADC_CTRL3, 0x3A); - ret = snd_soc_add_controls(codec, ad1836_controls, - ARRAY_SIZE(ad1836_controls)); - if (ret) - return ret; - } else { - snd_soc_write(codec, AD1836_ADC_CTRL3, 0x00); - } - - ret = snd_soc_add_controls(codec, ad183x_dac_controls, num_dacs * 2); - if (ret) - return ret; - - ret = snd_soc_add_controls(codec, ad183x_adc_controls, num_adcs); - if (ret) - return ret; - - ret = snd_soc_dapm_new_controls(dapm, ad183x_dac_dapm_widgets, num_dacs); - if (ret) - return ret; - - ret = snd_soc_dapm_new_controls(dapm, ad183x_adc_dapm_widgets, num_adcs); - if (ret) - return ret; - - ret = snd_soc_dapm_add_routes(dapm, ad183x_dac_routes, num_dacs); - if (ret) - return ret; - - ret = snd_soc_dapm_add_routes(dapm, ad183x_adc_routes, num_adcs); - if (ret) - return ret; + snd_soc_write(codec, AD1836_DAC_L1_VOL, 0x3FF); + snd_soc_write(codec, AD1836_DAC_R1_VOL, 0x3FF); + snd_soc_write(codec, AD1836_DAC_L2_VOL, 0x3FF); + snd_soc_write(codec, AD1836_DAC_R2_VOL, 0x3FF); + snd_soc_write(codec, AD1836_DAC_L3_VOL, 0x3FF); + snd_soc_write(codec, AD1836_DAC_R3_VOL, 0x3FF); + + snd_soc_add_controls(codec, ad1836_snd_controls, + ARRAY_SIZE(ad1836_snd_controls)); + snd_soc_dapm_new_controls(dapm, ad1836_dapm_widgets, + ARRAY_SIZE(ad1836_dapm_widgets)); + snd_soc_dapm_add_routes(dapm, audio_paths, ARRAY_SIZE(audio_paths)); return ret; } @@ -316,24 +262,19 @@ static int ad1836_probe(struct snd_soc_codec *codec) static int ad1836_remove(struct snd_soc_codec *codec) { /* reset clock control mode */ - return snd_soc_update_bits(codec, AD1836_ADC_CTRL2, - AD1836_ADC_SERFMT_MASK, 0); + u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2); + adc_ctrl2 &= ~AD1836_ADC_SERFMT_MASK; + + return snd_soc_write(codec, AD1836_ADC_CTRL2, adc_ctrl2); } static struct snd_soc_codec_driver soc_codec_dev_ad1836 = { - .probe = ad1836_probe, - .remove = ad1836_remove, - .suspend = ad1836_suspend, - .resume = ad1836_resume, + .probe = ad1836_probe, + .remove = ad1836_remove, + .suspend = ad1836_soc_suspend, + .resume = ad1836_soc_resume, .reg_cache_size = AD1836_NUM_REGS, .reg_word_size = sizeof(u16), - - .controls = ad183x_controls, - .num_controls = ARRAY_SIZE(ad183x_controls), - .dapm_widgets = ad183x_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(ad183x_dapm_widgets), - .dapm_routes = ad183x_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(ad183x_dapm_routes), }; static int __devinit ad1836_spi_probe(struct spi_device *spi) @@ -345,12 +286,12 @@ static int __devinit ad1836_spi_probe(struct spi_device *spi) if (ad1836 == NULL) return -ENOMEM; - ad1836->type = spi_get_device_id(spi)->driver_data; - spi_set_drvdata(spi, ad1836); + ad1836->control_data = spi; + ad1836->control_type = SND_SOC_SPI; ret = snd_soc_register_codec(&spi->dev, - &soc_codec_dev_ad1836, &ad183x_dais[ad1836->type], 1); + &soc_codec_dev_ad1836, &ad1836_dai, 1); if (ret < 0) kfree(ad1836); return ret; @@ -362,29 +303,27 @@ static int __devexit ad1836_spi_remove(struct spi_device *spi) kfree(spi_get_drvdata(spi)); return 0; } -static const struct spi_device_id ad1836_ids[] = { - { "ad1835", AD1835 }, - { "ad1836", AD1836 }, - { "ad1837", AD1835 }, - { "ad1838", AD1838 }, - { "ad1839", AD1838 }, - { }, -}; -MODULE_DEVICE_TABLE(spi, ad1836_ids); static struct spi_driver ad1836_spi_driver = { .driver = { - .name = "ad1836", + .name = "ad1836-codec", .owner = THIS_MODULE, }, .probe = ad1836_spi_probe, .remove = __devexit_p(ad1836_spi_remove), - .id_table = ad1836_ids, }; static int __init ad1836_init(void) { - return spi_register_driver(&ad1836_spi_driver); + int ret; + + ret = spi_register_driver(&ad1836_spi_driver); + if (ret != 0) { + printk(KERN_ERR "Failed to register ad1836 SPI driver: %d\n", + ret); + } + + return ret; } module_init(ad1836_init); diff --git a/trunk/sound/soc/codecs/ad1836.h b/trunk/sound/soc/codecs/ad1836.h index 444747f0db26..9d6a3f8f8aaf 100644 --- a/trunk/sound/soc/codecs/ad1836.h +++ b/trunk/sound/soc/codecs/ad1836.h @@ -1,10 +1,19 @@ /* - * Audio Codec driver supporting: - * AD1835A, AD1836, AD1837A, AD1838A, AD1839A + * File: sound/soc/codecs/ad1836.h + * Based on: + * Author: Barry Song * - * Copyright 2009-2011 Analog Devices Inc. + * Created: Aug 04, 2009 + * Description: definitions for AD1836 registers * - * Licensed under the GPL-2 or later. + * Modified: + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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 __AD1836_H__ @@ -12,30 +21,39 @@ #define AD1836_DAC_CTRL1 0 #define AD1836_DAC_POWERDOWN 2 -#define AD1836_DAC_SERFMT_MASK 0xE0 +#define AD1836_DAC_SERFMT_MASK 0xE0 #define AD1836_DAC_SERFMT_PCK256 (0x4 << 5) #define AD1836_DAC_SERFMT_PCK128 (0x5 << 5) #define AD1836_DAC_WORD_LEN_MASK 0x18 #define AD1836_DAC_WORD_LEN_OFFSET 3 #define AD1836_DAC_CTRL2 1 +#define AD1836_DACL1_MUTE 0 +#define AD1836_DACR1_MUTE 1 +#define AD1836_DACL2_MUTE 2 +#define AD1836_DACR2_MUTE 3 +#define AD1836_DACL3_MUTE 4 +#define AD1836_DACR3_MUTE 5 -/* These macros are one-based. So AD183X_MUTE_LEFT(1) will return the mute bit - * for the first ADC/DAC */ -#define AD1836_MUTE_LEFT(x) (((x) * 2) - 2) -#define AD1836_MUTE_RIGHT(x) (((x) * 2) - 1) - -#define AD1836_DAC_L_VOL(x) ((x) * 2) -#define AD1836_DAC_R_VOL(x) (1 + ((x) * 2)) +#define AD1836_DAC_L1_VOL 2 +#define AD1836_DAC_R1_VOL 3 +#define AD1836_DAC_L2_VOL 4 +#define AD1836_DAC_R2_VOL 5 +#define AD1836_DAC_L3_VOL 6 +#define AD1836_DAC_R3_VOL 7 #define AD1836_ADC_CTRL1 12 #define AD1836_ADC_POWERDOWN 7 #define AD1836_ADC_HIGHPASS_FILTER 8 #define AD1836_ADC_CTRL2 13 +#define AD1836_ADCL1_MUTE 0 +#define AD1836_ADCR1_MUTE 1 +#define AD1836_ADCL2_MUTE 2 +#define AD1836_ADCR2_MUTE 3 #define AD1836_ADC_WORD_LEN_MASK 0x30 #define AD1836_ADC_WORD_OFFSET 5 -#define AD1836_ADC_SERFMT_MASK (7 << 6) +#define AD1836_ADC_SERFMT_MASK (7 << 6) #define AD1836_ADC_SERFMT_PCK256 (0x4 << 6) #define AD1836_ADC_SERFMT_PCK128 (0x5 << 6) #define AD1836_ADC_AUX (0x6 << 6) diff --git a/trunk/sound/soc/codecs/adau1701.c b/trunk/sound/soc/codecs/adau1701.c deleted file mode 100644 index 2758d5fc60d6..000000000000 --- a/trunk/sound/soc/codecs/adau1701.c +++ /dev/null @@ -1,549 +0,0 @@ -/* - * Driver for ADAU1701 SigmaDSP processor - * - * Copyright 2011 Analog Devices Inc. - * Author: Lars-Peter Clausen - * based on an inital version by Cliff Cai - * - * Licensed under the GPL-2 or later. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "adau1701.h" - -#define ADAU1701_DSPCTRL 0x1c -#define ADAU1701_SEROCTL 0x1e -#define ADAU1701_SERICTL 0x1f - -#define ADAU1701_AUXNPOW 0x22 - -#define ADAU1701_OSCIPOW 0x26 -#define ADAU1701_DACSET 0x27 - -#define ADAU1701_NUM_REGS 0x28 - -#define ADAU1701_DSPCTRL_CR (1 << 2) -#define ADAU1701_DSPCTRL_DAM (1 << 3) -#define ADAU1701_DSPCTRL_ADM (1 << 4) -#define ADAU1701_DSPCTRL_SR_48 0x00 -#define ADAU1701_DSPCTRL_SR_96 0x01 -#define ADAU1701_DSPCTRL_SR_192 0x02 -#define ADAU1701_DSPCTRL_SR_MASK 0x03 - -#define ADAU1701_SEROCTL_INV_LRCLK 0x2000 -#define ADAU1701_SEROCTL_INV_BCLK 0x1000 -#define ADAU1701_SEROCTL_MASTER 0x0800 - -#define ADAU1701_SEROCTL_OBF16 0x0000 -#define ADAU1701_SEROCTL_OBF8 0x0200 -#define ADAU1701_SEROCTL_OBF4 0x0400 -#define ADAU1701_SEROCTL_OBF2 0x0600 -#define ADAU1701_SEROCTL_OBF_MASK 0x0600 - -#define ADAU1701_SEROCTL_OLF1024 0x0000 -#define ADAU1701_SEROCTL_OLF512 0x0080 -#define ADAU1701_SEROCTL_OLF256 0x0100 -#define ADAU1701_SEROCTL_OLF_MASK 0x0180 - -#define ADAU1701_SEROCTL_MSB_DEALY1 0x0000 -#define ADAU1701_SEROCTL_MSB_DEALY0 0x0004 -#define ADAU1701_SEROCTL_MSB_DEALY8 0x0008 -#define ADAU1701_SEROCTL_MSB_DEALY12 0x000c -#define ADAU1701_SEROCTL_MSB_DEALY16 0x0010 -#define ADAU1701_SEROCTL_MSB_DEALY_MASK 0x001c - -#define ADAU1701_SEROCTL_WORD_LEN_24 0x0000 -#define ADAU1701_SEROCTL_WORD_LEN_20 0x0001 -#define ADAU1701_SEROCTL_WORD_LEN_16 0x0010 -#define ADAU1701_SEROCTL_WORD_LEN_MASK 0x0003 - -#define ADAU1701_AUXNPOW_VBPD 0x40 -#define ADAU1701_AUXNPOW_VRPD 0x20 - -#define ADAU1701_SERICTL_I2S 0 -#define ADAU1701_SERICTL_LEFTJ 1 -#define ADAU1701_SERICTL_TDM 2 -#define ADAU1701_SERICTL_RIGHTJ_24 3 -#define ADAU1701_SERICTL_RIGHTJ_20 4 -#define ADAU1701_SERICTL_RIGHTJ_18 5 -#define ADAU1701_SERICTL_RIGHTJ_16 6 -#define ADAU1701_SERICTL_MODE_MASK 7 -#define ADAU1701_SERICTL_INV_BCLK BIT(3) -#define ADAU1701_SERICTL_INV_LRCLK BIT(4) - -#define ADAU1701_OSCIPOW_OPD 0x04 -#define ADAU1701_DACSET_DACINIT 1 - -#define ADAU1701_FIRMWARE "adau1701.bin" - -struct adau1701 { - unsigned int dai_fmt; -}; - -static const struct snd_kcontrol_new adau1701_controls[] = { - SOC_SINGLE("Master Capture Switch", ADAU1701_DSPCTRL, 4, 1, 0), -}; - -static const struct snd_soc_dapm_widget adau1701_dapm_widgets[] = { - SND_SOC_DAPM_DAC("DAC0", "Playback", ADAU1701_AUXNPOW, 3, 1), - SND_SOC_DAPM_DAC("DAC1", "Playback", ADAU1701_AUXNPOW, 2, 1), - SND_SOC_DAPM_DAC("DAC2", "Playback", ADAU1701_AUXNPOW, 1, 1), - SND_SOC_DAPM_DAC("DAC3", "Playback", ADAU1701_AUXNPOW, 0, 1), - SND_SOC_DAPM_ADC("ADC", "Capture", ADAU1701_AUXNPOW, 7, 1), - - SND_SOC_DAPM_OUTPUT("OUT0"), - SND_SOC_DAPM_OUTPUT("OUT1"), - SND_SOC_DAPM_OUTPUT("OUT2"), - SND_SOC_DAPM_OUTPUT("OUT3"), - SND_SOC_DAPM_INPUT("IN0"), - SND_SOC_DAPM_INPUT("IN1"), -}; - -static const struct snd_soc_dapm_route adau1701_dapm_routes[] = { - { "OUT0", NULL, "DAC0" }, - { "OUT1", NULL, "DAC1" }, - { "OUT2", NULL, "DAC2" }, - { "OUT3", NULL, "DAC3" }, - - { "ADC", NULL, "IN0" }, - { "ADC", NULL, "IN1" }, -}; - -static unsigned int adau1701_register_size(struct snd_soc_codec *codec, - unsigned int reg) -{ - switch (reg) { - case ADAU1701_DSPCTRL: - case ADAU1701_SEROCTL: - case ADAU1701_AUXNPOW: - case ADAU1701_OSCIPOW: - case ADAU1701_DACSET: - return 2; - case ADAU1701_SERICTL: - return 1; - } - - dev_err(codec->dev, "Unsupported register address: %d\n", reg); - return 0; -} - -static int adau1701_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - unsigned int i; - unsigned int size; - uint8_t buf[4]; - int ret; - - size = adau1701_register_size(codec, reg); - if (size == 0) - return -EINVAL; - - snd_soc_cache_write(codec, reg, value); - - buf[0] = 0x08; - buf[1] = reg; - - for (i = size + 1; i >= 2; --i) { - buf[i] = value; - value >>= 8; - } - - ret = i2c_master_send(to_i2c_client(codec->dev), buf, size + 2); - if (ret == size + 2) - return 0; - else if (ret < 0) - return ret; - else - return -EIO; -} - -static unsigned int adau1701_read(struct snd_soc_codec *codec, unsigned int reg) -{ - unsigned int value; - unsigned int ret; - - ret = snd_soc_cache_read(codec, reg, &value); - if (ret) - return ret; - - return value; -} - -static int adau1701_load_firmware(struct snd_soc_codec *codec) -{ - return process_sigma_firmware(codec->control_data, ADAU1701_FIRMWARE); -} - -static int adau1701_set_capture_pcm_format(struct snd_soc_codec *codec, - snd_pcm_format_t format) -{ - struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); - unsigned int mask = ADAU1701_SEROCTL_WORD_LEN_MASK; - unsigned int val; - - switch (format) { - case SNDRV_PCM_FORMAT_S16_LE: - val = ADAU1701_SEROCTL_WORD_LEN_16; - break; - case SNDRV_PCM_FORMAT_S20_3LE: - val = ADAU1701_SEROCTL_WORD_LEN_20; - break; - case SNDRV_PCM_FORMAT_S24_LE: - val = ADAU1701_SEROCTL_WORD_LEN_24; - break; - default: - return -EINVAL; - } - - if (adau1701->dai_fmt == SND_SOC_DAIFMT_RIGHT_J) { - switch (format) { - case SNDRV_PCM_FORMAT_S16_LE: - val |= ADAU1701_SEROCTL_MSB_DEALY16; - break; - case SNDRV_PCM_FORMAT_S20_3LE: - val |= ADAU1701_SEROCTL_MSB_DEALY12; - break; - case SNDRV_PCM_FORMAT_S24_LE: - val |= ADAU1701_SEROCTL_MSB_DEALY8; - break; - } - mask |= ADAU1701_SEROCTL_MSB_DEALY_MASK; - } - - snd_soc_update_bits(codec, ADAU1701_SEROCTL, mask, val); - - return 0; -} - -static int adau1701_set_playback_pcm_format(struct snd_soc_codec *codec, - snd_pcm_format_t format) -{ - struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); - unsigned int val; - - if (adau1701->dai_fmt != SND_SOC_DAIFMT_RIGHT_J) - return 0; - - switch (format) { - case SNDRV_PCM_FORMAT_S16_LE: - val = ADAU1701_SERICTL_RIGHTJ_16; - break; - case SNDRV_PCM_FORMAT_S20_3LE: - val = ADAU1701_SERICTL_RIGHTJ_20; - break; - case SNDRV_PCM_FORMAT_S24_LE: - val = ADAU1701_SERICTL_RIGHTJ_24; - break; - default: - return -EINVAL; - } - - snd_soc_update_bits(codec, ADAU1701_SERICTL, - ADAU1701_SERICTL_MODE_MASK, val); - - return 0; -} - -static int adau1701_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_codec *codec = rtd->codec; - snd_pcm_format_t format; - unsigned int val; - - switch (params_rate(params)) { - case 192000: - val = ADAU1701_DSPCTRL_SR_192; - break; - case 96000: - val = ADAU1701_DSPCTRL_SR_96; - break; - case 48000: - val = ADAU1701_DSPCTRL_SR_48; - break; - default: - return -EINVAL; - } - - snd_soc_update_bits(codec, ADAU1701_DSPCTRL, - ADAU1701_DSPCTRL_SR_MASK, val); - - format = params_format(params); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - return adau1701_set_playback_pcm_format(codec, format); - else - return adau1701_set_capture_pcm_format(codec, format); -} - -static int adau1701_set_dai_fmt(struct snd_soc_dai *codec_dai, - unsigned int fmt) -{ - struct snd_soc_codec *codec = codec_dai->codec; - struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); - unsigned int serictl = 0x00, seroctl = 0x00; - bool invert_lrclk; - - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - /* master, 64-bits per sample, 1 frame per sample */ - seroctl |= ADAU1701_SEROCTL_MASTER | ADAU1701_SEROCTL_OBF16 - | ADAU1701_SEROCTL_OLF1024; - break; - case SND_SOC_DAIFMT_CBS_CFS: - break; - default: - return -EINVAL; - } - - /* clock inversion */ - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - invert_lrclk = false; - break; - case SND_SOC_DAIFMT_NB_IF: - invert_lrclk = true; - break; - case SND_SOC_DAIFMT_IB_NF: - invert_lrclk = false; - serictl |= ADAU1701_SERICTL_INV_BCLK; - seroctl |= ADAU1701_SEROCTL_INV_BCLK; - break; - case SND_SOC_DAIFMT_IB_IF: - invert_lrclk = true; - serictl |= ADAU1701_SERICTL_INV_BCLK; - seroctl |= ADAU1701_SEROCTL_INV_BCLK; - break; - default: - return -EINVAL; - } - - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - break; - case SND_SOC_DAIFMT_LEFT_J: - serictl |= ADAU1701_SERICTL_LEFTJ; - seroctl |= ADAU1701_SEROCTL_MSB_DEALY0; - invert_lrclk = !invert_lrclk; - break; - case SND_SOC_DAIFMT_RIGHT_J: - serictl |= ADAU1701_SERICTL_RIGHTJ_24; - seroctl |= ADAU1701_SEROCTL_MSB_DEALY8; - invert_lrclk = !invert_lrclk; - break; - default: - return -EINVAL; - } - - if (invert_lrclk) { - seroctl |= ADAU1701_SEROCTL_INV_LRCLK; - serictl |= ADAU1701_SERICTL_INV_LRCLK; - } - - adau1701->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK; - - snd_soc_write(codec, ADAU1701_SERICTL, serictl); - snd_soc_update_bits(codec, ADAU1701_SEROCTL, - ~ADAU1701_SEROCTL_WORD_LEN_MASK, seroctl); - - return 0; -} - -static int adau1701_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) -{ - unsigned int mask = ADAU1701_AUXNPOW_VBPD | ADAU1701_AUXNPOW_VRPD; - - switch (level) { - case SND_SOC_BIAS_ON: - break; - case SND_SOC_BIAS_PREPARE: - break; - case SND_SOC_BIAS_STANDBY: - /* Enable VREF and VREF buffer */ - snd_soc_update_bits(codec, ADAU1701_AUXNPOW, mask, 0x00); - break; - case SND_SOC_BIAS_OFF: - /* Disable VREF and VREF buffer */ - snd_soc_update_bits(codec, ADAU1701_AUXNPOW, mask, mask); - break; - } - - codec->dapm.bias_level = level; - return 0; -} - -static int adau1701_digital_mute(struct snd_soc_dai *dai, int mute) -{ - struct snd_soc_codec *codec = dai->codec; - unsigned int mask = ADAU1701_DSPCTRL_DAM; - unsigned int val; - - if (mute) - val = 0; - else - val = mask; - - snd_soc_update_bits(codec, ADAU1701_DSPCTRL, mask, val); - - return 0; -} - -static int adau1701_set_sysclk(struct snd_soc_codec *codec, int clk_id, - unsigned int freq, int dir) -{ - unsigned int val; - - switch (clk_id) { - case ADAU1701_CLK_SRC_OSC: - val = 0x0; - break; - case ADAU1701_CLK_SRC_MCLK: - val = ADAU1701_OSCIPOW_OPD; - break; - default: - return -EINVAL; - } - - snd_soc_update_bits(codec, ADAU1701_OSCIPOW, ADAU1701_OSCIPOW_OPD, val); - - return 0; -} - -#define ADAU1701_RATES (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | \ - SNDRV_PCM_RATE_192000) - -#define ADAU1701_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ - SNDRV_PCM_FMTBIT_S24_LE) - -static const struct snd_soc_dai_ops adau1701_dai_ops = { - .set_fmt = adau1701_set_dai_fmt, - .hw_params = adau1701_hw_params, - .digital_mute = adau1701_digital_mute, -}; - -static struct snd_soc_dai_driver adau1701_dai = { - .name = "adau1701", - .playback = { - .stream_name = "Playback", - .channels_min = 2, - .channels_max = 8, - .rates = ADAU1701_RATES, - .formats = ADAU1701_FORMATS, - }, - .capture = { - .stream_name = "Capture", - .channels_min = 2, - .channels_max = 8, - .rates = ADAU1701_RATES, - .formats = ADAU1701_FORMATS, - }, - .ops = &adau1701_dai_ops, - .symmetric_rates = 1, -}; - -static int adau1701_probe(struct snd_soc_codec *codec) -{ - int ret; - - codec->dapm.idle_bias_off = 1; - - ret = adau1701_load_firmware(codec); - if (ret) - dev_warn(codec->dev, "Failed to load firmware\n"); - - snd_soc_write(codec, ADAU1701_DACSET, ADAU1701_DACSET_DACINIT); - snd_soc_write(codec, ADAU1701_DSPCTRL, ADAU1701_DSPCTRL_CR); - - return 0; -} - -static struct snd_soc_codec_driver adau1701_codec_drv = { - .probe = adau1701_probe, - .set_bias_level = adau1701_set_bias_level, - - .reg_cache_size = ADAU1701_NUM_REGS, - .reg_word_size = sizeof(u16), - - .controls = adau1701_controls, - .num_controls = ARRAY_SIZE(adau1701_controls), - .dapm_widgets = adau1701_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(adau1701_dapm_widgets), - .dapm_routes = adau1701_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(adau1701_dapm_routes), - - .write = adau1701_write, - .read = adau1701_read, - - .set_sysclk = adau1701_set_sysclk, -}; - -static __devinit int adau1701_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct adau1701 *adau1701; - int ret; - - adau1701 = kzalloc(sizeof(*adau1701), GFP_KERNEL); - if (!adau1701) - return -ENOMEM; - - i2c_set_clientdata(client, adau1701); - ret = snd_soc_register_codec(&client->dev, &adau1701_codec_drv, - &adau1701_dai, 1); - if (ret < 0) - kfree(adau1701); - - return ret; -} - -static __devexit int adau1701_i2c_remove(struct i2c_client *client) -{ - snd_soc_unregister_codec(&client->dev); - kfree(i2c_get_clientdata(client)); - return 0; -} - -static const struct i2c_device_id adau1701_i2c_id[] = { - { "adau1701", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, adau1701_i2c_id); - -static struct i2c_driver adau1701_i2c_driver = { - .driver = { - .name = "adau1701", - .owner = THIS_MODULE, - }, - .probe = adau1701_i2c_probe, - .remove = __devexit_p(adau1701_i2c_remove), - .id_table = adau1701_i2c_id, -}; - -static int __init adau1701_init(void) -{ - return i2c_add_driver(&adau1701_i2c_driver); -} -module_init(adau1701_init); - -static void __exit adau1701_exit(void) -{ - i2c_del_driver(&adau1701_i2c_driver); -} -module_exit(adau1701_exit); - -MODULE_DESCRIPTION("ASoC ADAU1701 SigmaDSP driver"); -MODULE_AUTHOR("Cliff Cai "); -MODULE_AUTHOR("Lars-Peter Clausen "); -MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/codecs/adau1701.h b/trunk/sound/soc/codecs/adau1701.h deleted file mode 100644 index 8d0949a2aec9..000000000000 --- a/trunk/sound/soc/codecs/adau1701.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * header file for ADAU1701 SigmaDSP processor - * - * Copyright 2011 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ - -#ifndef _ADAU1701_H -#define _ADAU1701_H - -enum adau1701_clk_src { - ADAU1701_CLK_SRC_OSC, - ADAU1701_CLK_SRC_MCLK, -}; - -#endif diff --git a/trunk/sound/soc/codecs/adav80x.c b/trunk/sound/soc/codecs/adav80x.c deleted file mode 100644 index 300c04b70e71..000000000000 --- a/trunk/sound/soc/codecs/adav80x.c +++ /dev/null @@ -1,951 +0,0 @@ -/* - * ADAV80X Audio Codec driver supporting ADAV801, ADAV803 - * - * Copyright 2011 Analog Devices Inc. - * Author: Yi Li - * Author: Lars-Peter Clausen - * - * Licensed under the GPL-2 or later. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "adav80x.h" - -#define ADAV80X_PLAYBACK_CTRL 0x04 -#define ADAV80X_AUX_IN_CTRL 0x05 -#define ADAV80X_REC_CTRL 0x06 -#define ADAV80X_AUX_OUT_CTRL 0x07 -#define ADAV80X_DPATH_CTRL1 0x62 -#define ADAV80X_DPATH_CTRL2 0x63 -#define ADAV80X_DAC_CTRL1 0x64 -#define ADAV80X_DAC_CTRL2 0x65 -#define ADAV80X_DAC_CTRL3 0x66 -#define ADAV80X_DAC_L_VOL 0x68 -#define ADAV80X_DAC_R_VOL 0x69 -#define ADAV80X_PGA_L_VOL 0x6c -#define ADAV80X_PGA_R_VOL 0x6d -#define ADAV80X_ADC_CTRL1 0x6e -#define ADAV80X_ADC_CTRL2 0x6f -#define ADAV80X_ADC_L_VOL 0x70 -#define ADAV80X_ADC_R_VOL 0x71 -#define ADAV80X_PLL_CTRL1 0x74 -#define ADAV80X_PLL_CTRL2 0x75 -#define ADAV80X_ICLK_CTRL1 0x76 -#define ADAV80X_ICLK_CTRL2 0x77 -#define ADAV80X_PLL_CLK_SRC 0x78 -#define ADAV80X_PLL_OUTE 0x7a - -#define ADAV80X_PLL_CLK_SRC_PLL_XIN(pll) 0x00 -#define ADAV80X_PLL_CLK_SRC_PLL_MCLKI(pll) (0x40 << (pll)) -#define ADAV80X_PLL_CLK_SRC_PLL_MASK(pll) (0x40 << (pll)) - -#define ADAV80X_ICLK_CTRL1_DAC_SRC(src) ((src) << 5) -#define ADAV80X_ICLK_CTRL1_ADC_SRC(src) ((src) << 2) -#define ADAV80X_ICLK_CTRL1_ICLK2_SRC(src) (src) -#define ADAV80X_ICLK_CTRL2_ICLK1_SRC(src) ((src) << 3) - -#define ADAV80X_PLL_CTRL1_PLLDIV 0x10 -#define ADAV80X_PLL_CTRL1_PLLPD(pll) (0x04 << (pll)) -#define ADAV80X_PLL_CTRL1_XTLPD 0x02 - -#define ADAV80X_PLL_CTRL2_FIELD(pll, x) ((x) << ((pll) * 4)) - -#define ADAV80X_PLL_CTRL2_FS_48(pll) ADAV80X_PLL_CTRL2_FIELD((pll), 0x00) -#define ADAV80X_PLL_CTRL2_FS_32(pll) ADAV80X_PLL_CTRL2_FIELD((pll), 0x08) -#define ADAV80X_PLL_CTRL2_FS_44(pll) ADAV80X_PLL_CTRL2_FIELD((pll), 0x0c) - -#define ADAV80X_PLL_CTRL2_SEL(pll) ADAV80X_PLL_CTRL2_FIELD((pll), 0x02) -#define ADAV80X_PLL_CTRL2_DOUB(pll) ADAV80X_PLL_CTRL2_FIELD((pll), 0x01) -#define ADAV80X_PLL_CTRL2_PLL_MASK(pll) ADAV80X_PLL_CTRL2_FIELD((pll), 0x0f) - -#define ADAV80X_ADC_CTRL1_MODULATOR_MASK 0x80 -#define ADAV80X_ADC_CTRL1_MODULATOR_128FS 0x00 -#define ADAV80X_ADC_CTRL1_MODULATOR_64FS 0x80 - -#define ADAV80X_DAC_CTRL1_PD 0x80 - -#define ADAV80X_DAC_CTRL2_DIV1 0x00 -#define ADAV80X_DAC_CTRL2_DIV1_5 0x10 -#define ADAV80X_DAC_CTRL2_DIV2 0x20 -#define ADAV80X_DAC_CTRL2_DIV3 0x30 -#define ADAV80X_DAC_CTRL2_DIV_MASK 0x30 - -#define ADAV80X_DAC_CTRL2_INTERPOL_256FS 0x00 -#define ADAV80X_DAC_CTRL2_INTERPOL_128FS 0x40 -#define ADAV80X_DAC_CTRL2_INTERPOL_64FS 0x80 -#define ADAV80X_DAC_CTRL2_INTERPOL_MASK 0xc0 - -#define ADAV80X_DAC_CTRL2_DEEMPH_NONE 0x00 -#define ADAV80X_DAC_CTRL2_DEEMPH_44 0x01 -#define ADAV80X_DAC_CTRL2_DEEMPH_32 0x02 -#define ADAV80X_DAC_CTRL2_DEEMPH_48 0x03 -#define ADAV80X_DAC_CTRL2_DEEMPH_MASK 0x01 - -#define ADAV80X_CAPTURE_MODE_MASTER 0x20 -#define ADAV80X_CAPTURE_WORD_LEN24 0x00 -#define ADAV80X_CAPTURE_WORD_LEN20 0x04 -#define ADAV80X_CAPTRUE_WORD_LEN18 0x08 -#define ADAV80X_CAPTURE_WORD_LEN16 0x0c -#define ADAV80X_CAPTURE_WORD_LEN_MASK 0x0c - -#define ADAV80X_CAPTURE_MODE_LEFT_J 0x00 -#define ADAV80X_CAPTURE_MODE_I2S 0x01 -#define ADAV80X_CAPTURE_MODE_RIGHT_J 0x03 -#define ADAV80X_CAPTURE_MODE_MASK 0x03 - -#define ADAV80X_PLAYBACK_MODE_MASTER 0x10 -#define ADAV80X_PLAYBACK_MODE_LEFT_J 0x00 -#define ADAV80X_PLAYBACK_MODE_I2S 0x01 -#define ADAV80X_PLAYBACK_MODE_RIGHT_J_24 0x04 -#define ADAV80X_PLAYBACK_MODE_RIGHT_J_20 0x05 -#define ADAV80X_PLAYBACK_MODE_RIGHT_J_18 0x06 -#define ADAV80X_PLAYBACK_MODE_RIGHT_J_16 0x07 -#define ADAV80X_PLAYBACK_MODE_MASK 0x07 - -#define ADAV80X_PLL_OUTE_SYSCLKPD(x) BIT(2 - (x)) - -static u8 adav80x_default_regs[] = { - 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x01, 0x80, 0x26, 0x00, 0x00, - 0x02, 0x40, 0x20, 0x00, 0x09, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd1, 0x92, 0xb1, 0x37, - 0x48, 0xd2, 0xfb, 0xca, 0xd2, 0x15, 0xe8, 0x29, 0xb9, 0x6a, 0xda, 0x2b, - 0xb7, 0xc0, 0x11, 0x65, 0x5c, 0xf6, 0xff, 0x8d, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, - 0x00, 0xe8, 0x46, 0xe1, 0x5b, 0xd3, 0x43, 0x77, 0x93, 0xa7, 0x44, 0xee, - 0x32, 0x12, 0xc0, 0x11, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x3f, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x52, 0x00, -}; - -struct adav80x { - enum snd_soc_control_type control_type; - - enum adav80x_clk_src clk_src; - unsigned int sysclk; - enum adav80x_pll_src pll_src; - - unsigned int dai_fmt[2]; - unsigned int rate; - bool deemph; - bool sysclk_pd[3]; -}; - -static const char *adav80x_mux_text[] = { - "ADC", - "Playback", - "Aux Playback", -}; - -static const unsigned int adav80x_mux_values[] = { - 0, 2, 3, -}; - -#define ADAV80X_MUX_ENUM_DECL(name, reg, shift) \ - SOC_VALUE_ENUM_DOUBLE_DECL(name, reg, shift, 7, \ - ARRAY_SIZE(adav80x_mux_text), adav80x_mux_text, \ - adav80x_mux_values) - -static ADAV80X_MUX_ENUM_DECL(adav80x_aux_capture_enum, ADAV80X_DPATH_CTRL1, 0); -static ADAV80X_MUX_ENUM_DECL(adav80x_capture_enum, ADAV80X_DPATH_CTRL1, 3); -static ADAV80X_MUX_ENUM_DECL(adav80x_dac_enum, ADAV80X_DPATH_CTRL2, 3); - -static const struct snd_kcontrol_new adav80x_aux_capture_mux_ctrl = - SOC_DAPM_VALUE_ENUM("Route", adav80x_aux_capture_enum); -static const struct snd_kcontrol_new adav80x_capture_mux_ctrl = - SOC_DAPM_VALUE_ENUM("Route", adav80x_capture_enum); -static const struct snd_kcontrol_new adav80x_dac_mux_ctrl = - SOC_DAPM_VALUE_ENUM("Route", adav80x_dac_enum); - -#define ADAV80X_MUX(name, ctrl) \ - SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl) - -static const struct snd_soc_dapm_widget adav80x_dapm_widgets[] = { - SND_SOC_DAPM_DAC("DAC", NULL, ADAV80X_DAC_CTRL1, 7, 1), - SND_SOC_DAPM_ADC("ADC", NULL, ADAV80X_ADC_CTRL1, 5, 1), - - SND_SOC_DAPM_PGA("Right PGA", ADAV80X_ADC_CTRL1, 0, 1, NULL, 0), - SND_SOC_DAPM_PGA("Left PGA", ADAV80X_ADC_CTRL1, 1, 1, NULL, 0), - - SND_SOC_DAPM_AIF_OUT("AIFOUT", "HiFi Capture", 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_IN("AIFIN", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0), - - SND_SOC_DAPM_AIF_OUT("AIFAUXOUT", "Aux Capture", 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_IN("AIFAUXIN", "Aux Playback", 0, SND_SOC_NOPM, 0, 0), - - ADAV80X_MUX("Aux Capture Select", &adav80x_aux_capture_mux_ctrl), - ADAV80X_MUX("Capture Select", &adav80x_capture_mux_ctrl), - ADAV80X_MUX("DAC Select", &adav80x_dac_mux_ctrl), - - SND_SOC_DAPM_INPUT("VINR"), - SND_SOC_DAPM_INPUT("VINL"), - SND_SOC_DAPM_OUTPUT("VOUTR"), - SND_SOC_DAPM_OUTPUT("VOUTL"), - - SND_SOC_DAPM_SUPPLY("SYSCLK", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("PLL1", ADAV80X_PLL_CTRL1, 2, 1, NULL, 0), - SND_SOC_DAPM_SUPPLY("PLL2", ADAV80X_PLL_CTRL1, 3, 1, NULL, 0), - SND_SOC_DAPM_SUPPLY("OSC", ADAV80X_PLL_CTRL1, 1, 1, NULL, 0), -}; - -static int adav80x_dapm_sysclk_check(struct snd_soc_dapm_widget *source, - struct snd_soc_dapm_widget *sink) -{ - struct snd_soc_codec *codec = source->codec; - struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); - const char *clk; - - switch (adav80x->clk_src) { - case ADAV80X_CLK_PLL1: - clk = "PLL1"; - break; - case ADAV80X_CLK_PLL2: - clk = "PLL2"; - break; - case ADAV80X_CLK_XTAL: - clk = "OSC"; - break; - default: - return 0; - } - - return strcmp(source->name, clk) == 0; -} - -static int adav80x_dapm_pll_check(struct snd_soc_dapm_widget *source, - struct snd_soc_dapm_widget *sink) -{ - struct snd_soc_codec *codec = source->codec; - struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); - - return adav80x->pll_src == ADAV80X_PLL_SRC_XTAL; -} - - -static const struct snd_soc_dapm_route adav80x_dapm_routes[] = { - { "DAC Select", "ADC", "ADC" }, - { "DAC Select", "Playback", "AIFIN" }, - { "DAC Select", "Aux Playback", "AIFAUXIN" }, - { "DAC", NULL, "DAC Select" }, - - { "Capture Select", "ADC", "ADC" }, - { "Capture Select", "Playback", "AIFIN" }, - { "Capture Select", "Aux Playback", "AIFAUXIN" }, - { "AIFOUT", NULL, "Capture Select" }, - - { "Aux Capture Select", "ADC", "ADC" }, - { "Aux Capture Select", "Playback", "AIFIN" }, - { "Aux Capture Select", "Aux Playback", "AIFAUXIN" }, - { "AIFAUXOUT", NULL, "Aux Capture Select" }, - - { "VOUTR", NULL, "DAC" }, - { "VOUTL", NULL, "DAC" }, - - { "Left PGA", NULL, "VINL" }, - { "Right PGA", NULL, "VINR" }, - { "ADC", NULL, "Left PGA" }, - { "ADC", NULL, "Right PGA" }, - - { "SYSCLK", NULL, "PLL1", adav80x_dapm_sysclk_check }, - { "SYSCLK", NULL, "PLL2", adav80x_dapm_sysclk_check }, - { "SYSCLK", NULL, "OSC", adav80x_dapm_sysclk_check }, - { "PLL1", NULL, "OSC", adav80x_dapm_pll_check }, - { "PLL2", NULL, "OSC", adav80x_dapm_pll_check }, - - { "ADC", NULL, "SYSCLK" }, - { "DAC", NULL, "SYSCLK" }, - { "AIFOUT", NULL, "SYSCLK" }, - { "AIFAUXOUT", NULL, "SYSCLK" }, - { "AIFIN", NULL, "SYSCLK" }, - { "AIFAUXIN", NULL, "SYSCLK" }, -}; - -static int adav80x_set_deemph(struct snd_soc_codec *codec) -{ - struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); - unsigned int val; - - if (adav80x->deemph) { - switch (adav80x->rate) { - case 32000: - val = ADAV80X_DAC_CTRL2_DEEMPH_32; - break; - case 44100: - val = ADAV80X_DAC_CTRL2_DEEMPH_44; - break; - case 48000: - case 64000: - case 88200: - case 96000: - val = ADAV80X_DAC_CTRL2_DEEMPH_48; - break; - default: - val = ADAV80X_DAC_CTRL2_DEEMPH_NONE; - break; - } - } else { - val = ADAV80X_DAC_CTRL2_DEEMPH_NONE; - } - - return snd_soc_update_bits(codec, ADAV80X_DAC_CTRL2, - ADAV80X_DAC_CTRL2_DEEMPH_MASK, val); -} - -static int adav80x_put_deemph(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); - unsigned int deemph = ucontrol->value.enumerated.item[0]; - - if (deemph > 1) - return -EINVAL; - - adav80x->deemph = deemph; - - return adav80x_set_deemph(codec); -} - -static int adav80x_get_deemph(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); - - ucontrol->value.enumerated.item[0] = adav80x->deemph; - return 0; -}; - -static const DECLARE_TLV_DB_SCALE(adav80x_inpga_tlv, 0, 50, 0); -static const DECLARE_TLV_DB_MINMAX(adav80x_digital_tlv, -9563, 0); - -static const struct snd_kcontrol_new adav80x_controls[] = { - SOC_DOUBLE_R_TLV("Master Playback Volume", ADAV80X_DAC_L_VOL, - ADAV80X_DAC_R_VOL, 0, 0xff, 0, adav80x_digital_tlv), - SOC_DOUBLE_R_TLV("Master Capture Volume", ADAV80X_ADC_L_VOL, - ADAV80X_ADC_R_VOL, 0, 0xff, 0, adav80x_digital_tlv), - - SOC_DOUBLE_R_TLV("PGA Capture Volume", ADAV80X_PGA_L_VOL, - ADAV80X_PGA_R_VOL, 0, 0x30, 0, adav80x_inpga_tlv), - - SOC_DOUBLE("Master Playback Switch", ADAV80X_DAC_CTRL1, 0, 1, 1, 0), - SOC_DOUBLE("Master Capture Switch", ADAV80X_ADC_CTRL1, 2, 3, 1, 1), - - SOC_SINGLE("ADC High Pass Filter Switch", ADAV80X_ADC_CTRL1, 6, 1, 0), - - SOC_SINGLE_BOOL_EXT("Playback De-emphasis Switch", 0, - adav80x_get_deemph, adav80x_put_deemph), -}; - -static unsigned int adav80x_port_ctrl_regs[2][2] = { - { ADAV80X_REC_CTRL, ADAV80X_PLAYBACK_CTRL, }, - { ADAV80X_AUX_OUT_CTRL, ADAV80X_AUX_IN_CTRL }, -}; - -static int adav80x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) -{ - struct snd_soc_codec *codec = dai->codec; - struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); - unsigned int capture = 0x00; - unsigned int playback = 0x00; - - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - capture |= ADAV80X_CAPTURE_MODE_MASTER; - playback |= ADAV80X_PLAYBACK_MODE_MASTER; - case SND_SOC_DAIFMT_CBS_CFS: - break; - default: - return -EINVAL; - } - - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - capture |= ADAV80X_CAPTURE_MODE_I2S; - playback |= ADAV80X_PLAYBACK_MODE_I2S; - break; - case SND_SOC_DAIFMT_LEFT_J: - capture |= ADAV80X_CAPTURE_MODE_LEFT_J; - playback |= ADAV80X_PLAYBACK_MODE_LEFT_J; - break; - case SND_SOC_DAIFMT_RIGHT_J: - capture |= ADAV80X_CAPTURE_MODE_RIGHT_J; - playback |= ADAV80X_PLAYBACK_MODE_RIGHT_J_24; - break; - default: - return -EINVAL; - } - - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - break; - default: - return -EINVAL; - } - - snd_soc_update_bits(codec, adav80x_port_ctrl_regs[dai->id][0], - ADAV80X_CAPTURE_MODE_MASK | ADAV80X_CAPTURE_MODE_MASTER, - capture); - snd_soc_write(codec, adav80x_port_ctrl_regs[dai->id][1], playback); - - adav80x->dai_fmt[dai->id] = fmt & SND_SOC_DAIFMT_FORMAT_MASK; - - return 0; -} - -static int adav80x_set_adc_clock(struct snd_soc_codec *codec, - unsigned int sample_rate) -{ - unsigned int val; - - if (sample_rate <= 48000) - val = ADAV80X_ADC_CTRL1_MODULATOR_128FS; - else - val = ADAV80X_ADC_CTRL1_MODULATOR_64FS; - - snd_soc_update_bits(codec, ADAV80X_ADC_CTRL1, - ADAV80X_ADC_CTRL1_MODULATOR_MASK, val); - - return 0; -} - -static int adav80x_set_dac_clock(struct snd_soc_codec *codec, - unsigned int sample_rate) -{ - unsigned int val; - - if (sample_rate <= 48000) - val = ADAV80X_DAC_CTRL2_DIV1 | ADAV80X_DAC_CTRL2_INTERPOL_256FS; - else - val = ADAV80X_DAC_CTRL2_DIV2 | ADAV80X_DAC_CTRL2_INTERPOL_128FS; - - snd_soc_update_bits(codec, ADAV80X_DAC_CTRL2, - ADAV80X_DAC_CTRL2_DIV_MASK | ADAV80X_DAC_CTRL2_INTERPOL_MASK, - val); - - return 0; -} - -static int adav80x_set_capture_pcm_format(struct snd_soc_codec *codec, - struct snd_soc_dai *dai, snd_pcm_format_t format) -{ - unsigned int val; - - switch (format) { - case SNDRV_PCM_FORMAT_S16_LE: - val = ADAV80X_CAPTURE_WORD_LEN16; - break; - case SNDRV_PCM_FORMAT_S18_3LE: - val = ADAV80X_CAPTRUE_WORD_LEN18; - break; - case SNDRV_PCM_FORMAT_S20_3LE: - val = ADAV80X_CAPTURE_WORD_LEN20; - break; - case SNDRV_PCM_FORMAT_S24_LE: - val = ADAV80X_CAPTURE_WORD_LEN24; - break; - default: - return -EINVAL; - } - - snd_soc_update_bits(codec, adav80x_port_ctrl_regs[dai->id][0], - ADAV80X_CAPTURE_WORD_LEN_MASK, val); - - return 0; -} - -static int adav80x_set_playback_pcm_format(struct snd_soc_codec *codec, - struct snd_soc_dai *dai, snd_pcm_format_t format) -{ - struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); - unsigned int val; - - if (adav80x->dai_fmt[dai->id] != SND_SOC_DAIFMT_RIGHT_J) - return 0; - - switch (format) { - case SNDRV_PCM_FORMAT_S16_LE: - val = ADAV80X_PLAYBACK_MODE_RIGHT_J_16; - break; - case SNDRV_PCM_FORMAT_S18_3LE: - val = ADAV80X_PLAYBACK_MODE_RIGHT_J_18; - break; - case SNDRV_PCM_FORMAT_S20_3LE: - val = ADAV80X_PLAYBACK_MODE_RIGHT_J_20; - break; - case SNDRV_PCM_FORMAT_S24_LE: - val = ADAV80X_PLAYBACK_MODE_RIGHT_J_24; - break; - default: - return -EINVAL; - } - - snd_soc_update_bits(codec, adav80x_port_ctrl_regs[dai->id][1], - ADAV80X_PLAYBACK_MODE_MASK, val); - - return 0; -} - -static int adav80x_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) -{ - struct snd_soc_codec *codec = dai->codec; - struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); - unsigned int rate = params_rate(params); - - if (rate * 256 != adav80x->sysclk) - return -EINVAL; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - adav80x_set_playback_pcm_format(codec, dai, - params_format(params)); - adav80x_set_dac_clock(codec, rate); - } else { - adav80x_set_capture_pcm_format(codec, dai, - params_format(params)); - adav80x_set_adc_clock(codec, rate); - } - adav80x->rate = rate; - adav80x_set_deemph(codec); - - return 0; -} - -static int adav80x_set_sysclk(struct snd_soc_codec *codec, - int clk_id, unsigned int freq, int dir) -{ - struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); - - if (dir == SND_SOC_CLOCK_IN) { - switch (clk_id) { - case ADAV80X_CLK_XIN: - case ADAV80X_CLK_XTAL: - case ADAV80X_CLK_MCLKI: - case ADAV80X_CLK_PLL1: - case ADAV80X_CLK_PLL2: - break; - default: - return -EINVAL; - } - - adav80x->sysclk = freq; - - if (adav80x->clk_src != clk_id) { - unsigned int iclk_ctrl1, iclk_ctrl2; - - adav80x->clk_src = clk_id; - if (clk_id == ADAV80X_CLK_XTAL) - clk_id = ADAV80X_CLK_XIN; - - iclk_ctrl1 = ADAV80X_ICLK_CTRL1_DAC_SRC(clk_id) | - ADAV80X_ICLK_CTRL1_ADC_SRC(clk_id) | - ADAV80X_ICLK_CTRL1_ICLK2_SRC(clk_id); - iclk_ctrl2 = ADAV80X_ICLK_CTRL2_ICLK1_SRC(clk_id); - - snd_soc_write(codec, ADAV80X_ICLK_CTRL1, iclk_ctrl1); - snd_soc_write(codec, ADAV80X_ICLK_CTRL2, iclk_ctrl2); - - snd_soc_dapm_sync(&codec->dapm); - } - } else { - unsigned int mask; - - switch (clk_id) { - case ADAV80X_CLK_SYSCLK1: - case ADAV80X_CLK_SYSCLK2: - case ADAV80X_CLK_SYSCLK3: - break; - default: - return -EINVAL; - } - - clk_id -= ADAV80X_CLK_SYSCLK1; - mask = ADAV80X_PLL_OUTE_SYSCLKPD(clk_id); - - if (freq == 0) { - snd_soc_update_bits(codec, ADAV80X_PLL_OUTE, mask, mask); - adav80x->sysclk_pd[clk_id] = true; - } else { - snd_soc_update_bits(codec, ADAV80X_PLL_OUTE, mask, 0); - adav80x->sysclk_pd[clk_id] = false; - } - - if (adav80x->sysclk_pd[0]) - snd_soc_dapm_disable_pin(&codec->dapm, "PLL1"); - else - snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1"); - - if (adav80x->sysclk_pd[1] || adav80x->sysclk_pd[2]) - snd_soc_dapm_disable_pin(&codec->dapm, "PLL2"); - else - snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL2"); - - snd_soc_dapm_sync(&codec->dapm); - } - - return 0; -} - -static int adav80x_set_pll(struct snd_soc_codec *codec, int pll_id, - int source, unsigned int freq_in, unsigned int freq_out) -{ - struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); - unsigned int pll_ctrl1 = 0; - unsigned int pll_ctrl2 = 0; - unsigned int pll_src; - - switch (source) { - case ADAV80X_PLL_SRC_XTAL: - case ADAV80X_PLL_SRC_XIN: - case ADAV80X_PLL_SRC_MCLKI: - break; - default: - return -EINVAL; - } - - if (!freq_out) - return 0; - - switch (freq_in) { - case 27000000: - break; - case 54000000: - if (source == ADAV80X_PLL_SRC_XIN) { - pll_ctrl1 |= ADAV80X_PLL_CTRL1_PLLDIV; - break; - } - default: - return -EINVAL; - } - - if (freq_out > 12288000) { - pll_ctrl2 |= ADAV80X_PLL_CTRL2_DOUB(pll_id); - freq_out /= 2; - } - - /* freq_out = sample_rate * 256 */ - switch (freq_out) { - case 8192000: - pll_ctrl2 |= ADAV80X_PLL_CTRL2_FS_32(pll_id); - break; - case 11289600: - pll_ctrl2 |= ADAV80X_PLL_CTRL2_FS_44(pll_id); - break; - case 12288000: - pll_ctrl2 |= ADAV80X_PLL_CTRL2_FS_48(pll_id); - break; - default: - return -EINVAL; - } - - snd_soc_update_bits(codec, ADAV80X_PLL_CTRL1, ADAV80X_PLL_CTRL1_PLLDIV, - pll_ctrl1); - snd_soc_update_bits(codec, ADAV80X_PLL_CTRL2, - ADAV80X_PLL_CTRL2_PLL_MASK(pll_id), pll_ctrl2); - - if (source != adav80x->pll_src) { - if (source == ADAV80X_PLL_SRC_MCLKI) - pll_src = ADAV80X_PLL_CLK_SRC_PLL_MCLKI(pll_id); - else - pll_src = ADAV80X_PLL_CLK_SRC_PLL_XIN(pll_id); - - snd_soc_update_bits(codec, ADAV80X_PLL_CLK_SRC, - ADAV80X_PLL_CLK_SRC_PLL_MASK(pll_id), pll_src); - - adav80x->pll_src = source; - - snd_soc_dapm_sync(&codec->dapm); - } - - return 0; -} - -static int adav80x_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) -{ - unsigned int mask = ADAV80X_DAC_CTRL1_PD; - - switch (level) { - case SND_SOC_BIAS_ON: - break; - case SND_SOC_BIAS_PREPARE: - break; - case SND_SOC_BIAS_STANDBY: - snd_soc_update_bits(codec, ADAV80X_DAC_CTRL1, mask, 0x00); - break; - case SND_SOC_BIAS_OFF: - snd_soc_update_bits(codec, ADAV80X_DAC_CTRL1, mask, mask); - break; - } - - codec->dapm.bias_level = level; - return 0; -} - -/* Enforce the same sample rate on all audio interfaces */ -static int adav80x_dai_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_codec *codec = dai->codec; - struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); - - if (!codec->active || !adav80x->rate) - return 0; - - return snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_RATE, adav80x->rate, adav80x->rate); -} - -static void adav80x_dai_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_codec *codec = dai->codec; - struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); - - if (!codec->active) - adav80x->rate = 0; -} - -static const struct snd_soc_dai_ops adav80x_dai_ops = { - .set_fmt = adav80x_set_dai_fmt, - .hw_params = adav80x_hw_params, - .startup = adav80x_dai_startup, - .shutdown = adav80x_dai_shutdown, -}; - -#define ADAV80X_PLAYBACK_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | SNDRV_PCM_RATE_88200 | \ - SNDRV_PCM_RATE_96000) - -#define ADAV80X_CAPTURE_RATES (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000) - -#define ADAV80X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \ - SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE) - -static struct snd_soc_dai_driver adav80x_dais[] = { - { - .name = "adav80x-hifi", - .id = 0, - .playback = { - .stream_name = "HiFi Playback", - .channels_min = 2, - .channels_max = 2, - .rates = ADAV80X_PLAYBACK_RATES, - .formats = ADAV80X_FORMATS, - }, - .capture = { - .stream_name = "HiFi Capture", - .channels_min = 2, - .channels_max = 2, - .rates = ADAV80X_CAPTURE_RATES, - .formats = ADAV80X_FORMATS, - }, - .ops = &adav80x_dai_ops, - }, - { - .name = "adav80x-aux", - .id = 1, - .playback = { - .stream_name = "Aux Playback", - .channels_min = 2, - .channels_max = 2, - .rates = ADAV80X_PLAYBACK_RATES, - .formats = ADAV80X_FORMATS, - }, - .capture = { - .stream_name = "Aux Capture", - .channels_min = 2, - .channels_max = 2, - .rates = ADAV80X_CAPTURE_RATES, - .formats = ADAV80X_FORMATS, - }, - .ops = &adav80x_dai_ops, - }, -}; - -static int adav80x_probe(struct snd_soc_codec *codec) -{ - int ret; - struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); - - ret = snd_soc_codec_set_cache_io(codec, 7, 9, adav80x->control_type); - if (ret) { - dev_err(codec->dev, "failed to set cache I/O: %d\n", ret); - return ret; - } - - /* Force PLLs on for SYSCLK output */ - snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1"); - snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL2"); - - /* Power down S/PDIF receiver, since it is currently not supported */ - snd_soc_write(codec, ADAV80X_PLL_OUTE, 0x20); - /* Disable DAC zero flag */ - snd_soc_write(codec, ADAV80X_DAC_CTRL3, 0x6); - - return adav80x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); -} - -static int adav80x_suspend(struct snd_soc_codec *codec, pm_message_t state) -{ - return adav80x_set_bias_level(codec, SND_SOC_BIAS_OFF); -} - -static int adav80x_resume(struct snd_soc_codec *codec) -{ - adav80x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - codec->cache_sync = 1; - snd_soc_cache_sync(codec); - - return 0; -} - -static int adav80x_remove(struct snd_soc_codec *codec) -{ - return adav80x_set_bias_level(codec, SND_SOC_BIAS_OFF); -} - -static struct snd_soc_codec_driver adav80x_codec_driver = { - .probe = adav80x_probe, - .remove = adav80x_remove, - .suspend = adav80x_suspend, - .resume = adav80x_resume, - .set_bias_level = adav80x_set_bias_level, - - .set_pll = adav80x_set_pll, - .set_sysclk = adav80x_set_sysclk, - - .reg_word_size = sizeof(u8), - .reg_cache_size = ARRAY_SIZE(adav80x_default_regs), - .reg_cache_default = adav80x_default_regs, - - .controls = adav80x_controls, - .num_controls = ARRAY_SIZE(adav80x_controls), - .dapm_widgets = adav80x_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(adav80x_dapm_widgets), - .dapm_routes = adav80x_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(adav80x_dapm_routes), -}; - -static int __devinit adav80x_bus_probe(struct device *dev, - enum snd_soc_control_type control_type) -{ - struct adav80x *adav80x; - int ret; - - adav80x = kzalloc(sizeof(*adav80x), GFP_KERNEL); - if (!adav80x) - return -ENOMEM; - - dev_set_drvdata(dev, adav80x); - adav80x->control_type = control_type; - - ret = snd_soc_register_codec(dev, &adav80x_codec_driver, - adav80x_dais, ARRAY_SIZE(adav80x_dais)); - if (ret) - kfree(adav80x); - - return ret; -} - -static int __devexit adav80x_bus_remove(struct device *dev) -{ - snd_soc_unregister_codec(dev); - kfree(dev_get_drvdata(dev)); - return 0; -} - -#if defined(CONFIG_SPI_MASTER) -static int __devinit adav80x_spi_probe(struct spi_device *spi) -{ - return adav80x_bus_probe(&spi->dev, SND_SOC_SPI); -} - -static int __devexit adav80x_spi_remove(struct spi_device *spi) -{ - return adav80x_bus_remove(&spi->dev); -} - -static struct spi_driver adav80x_spi_driver = { - .driver = { - .name = "adav801", - .owner = THIS_MODULE, - }, - .probe = adav80x_spi_probe, - .remove = __devexit_p(adav80x_spi_remove), -}; -#endif - -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -static const struct i2c_device_id adav80x_id[] = { - { "adav803", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, adav80x_id); - -static int __devinit adav80x_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - return adav80x_bus_probe(&client->dev, SND_SOC_I2C); -} - -static int __devexit adav80x_i2c_remove(struct i2c_client *client) -{ - return adav80x_bus_remove(&client->dev); -} - -static struct i2c_driver adav80x_i2c_driver = { - .driver = { - .name = "adav803", - .owner = THIS_MODULE, - }, - .probe = adav80x_i2c_probe, - .remove = __devexit_p(adav80x_i2c_remove), - .id_table = adav80x_id, -}; -#endif - -static int __init adav80x_init(void) -{ - int ret = 0; - -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - ret = i2c_add_driver(&adav80x_i2c_driver); - if (ret) - return ret; -#endif - -#if defined(CONFIG_SPI_MASTER) - ret = spi_register_driver(&adav80x_spi_driver); -#endif - - return ret; -} -module_init(adav80x_init); - -static void __exit adav80x_exit(void) -{ -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - i2c_del_driver(&adav80x_i2c_driver); -#endif -#if defined(CONFIG_SPI_MASTER) - spi_unregister_driver(&adav80x_spi_driver); -#endif -} -module_exit(adav80x_exit); - -MODULE_DESCRIPTION("ASoC ADAV80x driver"); -MODULE_AUTHOR("Lars-Peter Clausen "); -MODULE_AUTHOR("Yi Li >"); -MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/codecs/adav80x.h b/trunk/sound/soc/codecs/adav80x.h deleted file mode 100644 index adb0fc76d4e3..000000000000 --- a/trunk/sound/soc/codecs/adav80x.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * header file for ADAV80X parts - * - * Copyright 2011 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ - -#ifndef _ADAV80X_H -#define _ADAV80X_H - -enum adav80x_pll_src { - ADAV80X_PLL_SRC_XIN, - ADAV80X_PLL_SRC_XTAL, - ADAV80X_PLL_SRC_MCLKI, -}; - -enum adav80x_pll { - ADAV80X_PLL1 = 0, - ADAV80X_PLL2 = 1, -}; - -enum adav80x_clk_src { - ADAV80X_CLK_XIN = 0, - ADAV80X_CLK_MCLKI = 1, - ADAV80X_CLK_PLL1 = 2, - ADAV80X_CLK_PLL2 = 3, - ADAV80X_CLK_XTAL = 6, - - ADAV80X_CLK_SYSCLK1 = 6, - ADAV80X_CLK_SYSCLK2 = 7, - ADAV80X_CLK_SYSCLK3 = 8, -}; - -#endif diff --git a/trunk/sound/soc/codecs/ak4641.c b/trunk/sound/soc/codecs/ak4641.c index 7a64e58cddc4..ed96f247c2da 100644 --- a/trunk/sound/soc/codecs/ak4641.c +++ b/trunk/sound/soc/codecs/ak4641.c @@ -457,7 +457,7 @@ static struct snd_soc_dai_ops ak4641_pcm_dai_ops = { .set_sysclk = ak4641_set_dai_sysclk, }; -static struct snd_soc_dai_driver ak4641_dai[] = { +struct snd_soc_dai_driver ak4641_dai[] = { { .name = "ak4641-hifi", .id = 1, diff --git a/trunk/sound/soc/codecs/cs4270.c b/trunk/sound/soc/codecs/cs4270.c index 6cc8678f49f3..0206a17d7283 100644 --- a/trunk/sound/soc/codecs/cs4270.c +++ b/trunk/sound/soc/codecs/cs4270.c @@ -636,7 +636,10 @@ static int cs4270_soc_resume(struct snd_soc_codec *codec) #endif /* CONFIG_PM */ /* - * ASoC codec driver structure + * ASoC codec device structure + * + * Assign this variable to the codec_dev field of the machine driver's + * snd_soc_device structure. */ static const struct snd_soc_codec_driver soc_codec_device_cs4270 = { .probe = cs4270_probe, diff --git a/trunk/sound/soc/codecs/max98088.c b/trunk/sound/soc/codecs/max98088.c index ac65a2d36408..4173b67c94d1 100644 --- a/trunk/sound/soc/codecs/max98088.c +++ b/trunk/sound/soc/codecs/max98088.c @@ -1397,6 +1397,8 @@ static int max98088_dai_set_sysclk(struct snd_soc_dai *dai, if (freq == max98088->sysclk) return 0; + max98088->sysclk = freq; /* remember current sysclk */ + /* Setup clocks for slave mode, and using the PLL * PSCLK = 0x01 (when master clk is 10MHz to 20MHz) * 0x02 (when master clk is 20MHz to 30MHz).. diff --git a/trunk/sound/soc/codecs/max98095.c b/trunk/sound/soc/codecs/max98095.c index 668434d44303..e1d282d477da 100644 --- a/trunk/sound/soc/codecs/max98095.c +++ b/trunk/sound/soc/codecs/max98095.c @@ -1517,6 +1517,8 @@ static int max98095_dai_set_sysclk(struct snd_soc_dai *dai, if (freq == max98095->sysclk) return 0; + max98095->sysclk = freq; /* remember current sysclk */ + /* Setup clocks for slave mode, and using the PLL * PSCLK = 0x01 (when master clk is 10MHz to 20MHz) * 0x02 (when master clk is 20MHz to 40MHz).. @@ -2259,11 +2261,11 @@ static int max98095_probe(struct snd_soc_codec *codec) ret = snd_soc_read(codec, M98095_0FF_REV_ID); if (ret < 0) { - dev_err(codec->dev, "Failure reading hardware revision: %d\n", + dev_err(codec->dev, "Failed to read device revision: %d\n", ret); goto err_access; } - dev_info(codec->dev, "Hardware revision: %c\n", ret - 0x40 + 'A'); + dev_info(codec->dev, "revision %c\n", ret + 'A'); snd_soc_write(codec, M98095_097_PWR_SYS, M98095_PWRSV); @@ -2340,8 +2342,8 @@ static int max98095_i2c_probe(struct i2c_client *i2c, max98095->control_data = i2c; max98095->pdata = i2c->dev.platform_data; - ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_max98095, - max98095_dai, ARRAY_SIZE(max98095_dai)); + ret = snd_soc_register_codec(&i2c->dev, + &soc_codec_dev_max98095, &max98095_dai[0], 3); if (ret < 0) kfree(max98095); return ret; diff --git a/trunk/sound/soc/codecs/sta32x.c b/trunk/sound/soc/codecs/sta32x.c deleted file mode 100644 index 409d89d1f34c..000000000000 --- a/trunk/sound/soc/codecs/sta32x.c +++ /dev/null @@ -1,917 +0,0 @@ -/* - * Codec driver for ST STA32x 2.1-channel high-efficiency digital audio system - * - * Copyright: 2011 Raumfeld GmbH - * Author: Johannes Stezenbach - * - * based on code from: - * Wolfson Microelectronics PLC. - * Mark Brown - * Freescale Semiconductor, Inc. - * Timur Tabi - * - * 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. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ":%s:%d: " fmt, __func__, __LINE__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sta32x.h" - -#define STA32X_RATES (SNDRV_PCM_RATE_32000 | \ - SNDRV_PCM_RATE_44100 | \ - SNDRV_PCM_RATE_48000 | \ - SNDRV_PCM_RATE_88200 | \ - SNDRV_PCM_RATE_96000 | \ - SNDRV_PCM_RATE_176400 | \ - SNDRV_PCM_RATE_192000) - -#define STA32X_FORMATS \ - (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \ - SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \ - SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \ - SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE | \ - SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE) - -/* Power-up register defaults */ -static const u8 sta32x_regs[STA32X_REGISTER_COUNT] = { - 0x63, 0x80, 0xc2, 0x40, 0xc2, 0x5c, 0x10, 0xff, 0x60, 0x60, - 0x60, 0x80, 0x00, 0x00, 0x00, 0x40, 0x80, 0x77, 0x6a, 0x69, - 0x6a, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, - 0xc0, 0xf3, 0x33, 0x00, 0x0c, -}; - -/* regulator power supply names */ -static const char *sta32x_supply_names[] = { - "Vdda", /* analog supply, 3.3VV */ - "Vdd3", /* digital supply, 3.3V */ - "Vcc" /* power amp spply, 10V - 36V */ -}; - -/* codec private data */ -struct sta32x_priv { - struct regulator_bulk_data supplies[ARRAY_SIZE(sta32x_supply_names)]; - struct snd_soc_codec *codec; - - unsigned int mclk; - unsigned int format; -}; - -static const DECLARE_TLV_DB_SCALE(mvol_tlv, -12700, 50, 1); -static const DECLARE_TLV_DB_SCALE(chvol_tlv, -7950, 50, 1); -static const DECLARE_TLV_DB_SCALE(tone_tlv, -120, 200, 0); - -static const char *sta32x_drc_ac[] = { - "Anti-Clipping", "Dynamic Range Compression" }; -static const char *sta32x_auto_eq_mode[] = { - "User", "Preset", "Loudness" }; -static const char *sta32x_auto_gc_mode[] = { - "User", "AC no clipping", "AC limited clipping (10%)", - "DRC nighttime listening mode" }; -static const char *sta32x_auto_xo_mode[] = { - "User", "80Hz", "100Hz", "120Hz", "140Hz", "160Hz", "180Hz", "200Hz", - "220Hz", "240Hz", "260Hz", "280Hz", "300Hz", "320Hz", "340Hz", "360Hz" }; -static const char *sta32x_preset_eq_mode[] = { - "Flat", "Rock", "Soft Rock", "Jazz", "Classical", "Dance", "Pop", "Soft", - "Hard", "Party", "Vocal", "Hip-Hop", "Dialog", "Bass-boost #1", - "Bass-boost #2", "Bass-boost #3", "Loudness 1", "Loudness 2", - "Loudness 3", "Loudness 4", "Loudness 5", "Loudness 6", "Loudness 7", - "Loudness 8", "Loudness 9", "Loudness 10", "Loudness 11", "Loudness 12", - "Loudness 13", "Loudness 14", "Loudness 15", "Loudness 16" }; -static const char *sta32x_limiter_select[] = { - "Limiter Disabled", "Limiter #1", "Limiter #2" }; -static const char *sta32x_limiter_attack_rate[] = { - "3.1584", "2.7072", "2.2560", "1.8048", "1.3536", "0.9024", - "0.4512", "0.2256", "0.1504", "0.1123", "0.0902", "0.0752", - "0.0645", "0.0564", "0.0501", "0.0451" }; -static const char *sta32x_limiter_release_rate[] = { - "0.5116", "0.1370", "0.0744", "0.0499", "0.0360", "0.0299", - "0.0264", "0.0208", "0.0198", "0.0172", "0.0147", "0.0137", - "0.0134", "0.0117", "0.0110", "0.0104" }; - -static const unsigned int sta32x_limiter_ac_attack_tlv[] = { - TLV_DB_RANGE_HEAD(2), - 0, 7, TLV_DB_SCALE_ITEM(-1200, 200, 0), - 8, 16, TLV_DB_SCALE_ITEM(300, 100, 0), -}; - -static const unsigned int sta32x_limiter_ac_release_tlv[] = { - TLV_DB_RANGE_HEAD(5), - 0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0), - 1, 1, TLV_DB_SCALE_ITEM(-2900, 0, 0), - 2, 2, TLV_DB_SCALE_ITEM(-2000, 0, 0), - 3, 8, TLV_DB_SCALE_ITEM(-1400, 200, 0), - 8, 16, TLV_DB_SCALE_ITEM(-700, 100, 0), -}; - -static const unsigned int sta32x_limiter_drc_attack_tlv[] = { - TLV_DB_RANGE_HEAD(3), - 0, 7, TLV_DB_SCALE_ITEM(-3100, 200, 0), - 8, 13, TLV_DB_SCALE_ITEM(-1600, 100, 0), - 14, 16, TLV_DB_SCALE_ITEM(-1000, 300, 0), -}; - -static const unsigned int sta32x_limiter_drc_release_tlv[] = { - TLV_DB_RANGE_HEAD(5), - 0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0), - 1, 2, TLV_DB_SCALE_ITEM(-3800, 200, 0), - 3, 4, TLV_DB_SCALE_ITEM(-3300, 200, 0), - 5, 12, TLV_DB_SCALE_ITEM(-3000, 200, 0), - 13, 16, TLV_DB_SCALE_ITEM(-1500, 300, 0), -}; - -static const struct soc_enum sta32x_drc_ac_enum = - SOC_ENUM_SINGLE(STA32X_CONFD, STA32X_CONFD_DRC_SHIFT, - 2, sta32x_drc_ac); -static const struct soc_enum sta32x_auto_eq_enum = - SOC_ENUM_SINGLE(STA32X_AUTO1, STA32X_AUTO1_AMEQ_SHIFT, - 3, sta32x_auto_eq_mode); -static const struct soc_enum sta32x_auto_gc_enum = - SOC_ENUM_SINGLE(STA32X_AUTO1, STA32X_AUTO1_AMGC_SHIFT, - 4, sta32x_auto_gc_mode); -static const struct soc_enum sta32x_auto_xo_enum = - SOC_ENUM_SINGLE(STA32X_AUTO2, STA32X_AUTO2_XO_SHIFT, - 16, sta32x_auto_xo_mode); -static const struct soc_enum sta32x_preset_eq_enum = - SOC_ENUM_SINGLE(STA32X_AUTO3, STA32X_AUTO3_PEQ_SHIFT, - 32, sta32x_preset_eq_mode); -static const struct soc_enum sta32x_limiter_ch1_enum = - SOC_ENUM_SINGLE(STA32X_C1CFG, STA32X_CxCFG_LS_SHIFT, - 3, sta32x_limiter_select); -static const struct soc_enum sta32x_limiter_ch2_enum = - SOC_ENUM_SINGLE(STA32X_C2CFG, STA32X_CxCFG_LS_SHIFT, - 3, sta32x_limiter_select); -static const struct soc_enum sta32x_limiter_ch3_enum = - SOC_ENUM_SINGLE(STA32X_C3CFG, STA32X_CxCFG_LS_SHIFT, - 3, sta32x_limiter_select); -static const struct soc_enum sta32x_limiter1_attack_rate_enum = - SOC_ENUM_SINGLE(STA32X_L1AR, STA32X_LxA_SHIFT, - 16, sta32x_limiter_attack_rate); -static const struct soc_enum sta32x_limiter2_attack_rate_enum = - SOC_ENUM_SINGLE(STA32X_L2AR, STA32X_LxA_SHIFT, - 16, sta32x_limiter_attack_rate); -static const struct soc_enum sta32x_limiter1_release_rate_enum = - SOC_ENUM_SINGLE(STA32X_L1AR, STA32X_LxR_SHIFT, - 16, sta32x_limiter_release_rate); -static const struct soc_enum sta32x_limiter2_release_rate_enum = - SOC_ENUM_SINGLE(STA32X_L2AR, STA32X_LxR_SHIFT, - 16, sta32x_limiter_release_rate); - -/* byte array controls for setting biquad, mixer, scaling coefficients; - * for biquads all five coefficients need to be set in one go, - * mixer and pre/postscale coefs can be set individually; - * each coef is 24bit, the bytes are ordered in the same way - * as given in the STA32x data sheet (big endian; b1, b2, a1, a2, b0) - */ - -static int sta32x_coefficient_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - int numcoef = kcontrol->private_value >> 16; - uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; - uinfo->count = 3 * numcoef; - return 0; -} - -static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - int numcoef = kcontrol->private_value >> 16; - int index = kcontrol->private_value & 0xffff; - unsigned int cfud; - int i; - - /* preserve reserved bits in STA32X_CFUD */ - cfud = snd_soc_read(codec, STA32X_CFUD) & 0xf0; - /* chip documentation does not say if the bits are self clearing, - * so do it explicitly */ - snd_soc_write(codec, STA32X_CFUD, cfud); - - snd_soc_write(codec, STA32X_CFADDR2, index); - if (numcoef == 1) - snd_soc_write(codec, STA32X_CFUD, cfud | 0x04); - else if (numcoef == 5) - snd_soc_write(codec, STA32X_CFUD, cfud | 0x08); - else - return -EINVAL; - for (i = 0; i < 3 * numcoef; i++) - ucontrol->value.bytes.data[i] = - snd_soc_read(codec, STA32X_B1CF1 + i); - - return 0; -} - -static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - int numcoef = kcontrol->private_value >> 16; - int index = kcontrol->private_value & 0xffff; - unsigned int cfud; - int i; - - /* preserve reserved bits in STA32X_CFUD */ - cfud = snd_soc_read(codec, STA32X_CFUD) & 0xf0; - /* chip documentation does not say if the bits are self clearing, - * so do it explicitly */ - snd_soc_write(codec, STA32X_CFUD, cfud); - - snd_soc_write(codec, STA32X_CFADDR2, index); - for (i = 0; i < 3 * numcoef; i++) - snd_soc_write(codec, STA32X_B1CF1 + i, - ucontrol->value.bytes.data[i]); - if (numcoef == 1) - snd_soc_write(codec, STA32X_CFUD, cfud | 0x01); - else if (numcoef == 5) - snd_soc_write(codec, STA32X_CFUD, cfud | 0x02); - else - return -EINVAL; - - return 0; -} - -#define SINGLE_COEF(xname, index) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ - .info = sta32x_coefficient_info, \ - .get = sta32x_coefficient_get,\ - .put = sta32x_coefficient_put, \ - .private_value = index | (1 << 16) } - -#define BIQUAD_COEFS(xname, index) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ - .info = sta32x_coefficient_info, \ - .get = sta32x_coefficient_get,\ - .put = sta32x_coefficient_put, \ - .private_value = index | (5 << 16) } - -static const struct snd_kcontrol_new sta32x_snd_controls[] = { -SOC_SINGLE_TLV("Master Volume", STA32X_MVOL, 0, 0xff, 1, mvol_tlv), -SOC_SINGLE("Master Switch", STA32X_MMUTE, 0, 1, 1), -SOC_SINGLE("Ch1 Switch", STA32X_MMUTE, 1, 1, 1), -SOC_SINGLE("Ch2 Switch", STA32X_MMUTE, 2, 1, 1), -SOC_SINGLE("Ch3 Switch", STA32X_MMUTE, 3, 1, 1), -SOC_SINGLE_TLV("Ch1 Volume", STA32X_C1VOL, 0, 0xff, 1, chvol_tlv), -SOC_SINGLE_TLV("Ch2 Volume", STA32X_C2VOL, 0, 0xff, 1, chvol_tlv), -SOC_SINGLE_TLV("Ch3 Volume", STA32X_C3VOL, 0, 0xff, 1, chvol_tlv), -SOC_SINGLE("De-emphasis Filter Switch", STA32X_CONFD, STA32X_CONFD_DEMP_SHIFT, 1, 0), -SOC_ENUM("Compressor/Limiter Switch", sta32x_drc_ac_enum), -SOC_SINGLE("Miami Mode Switch", STA32X_CONFD, STA32X_CONFD_MME_SHIFT, 1, 0), -SOC_SINGLE("Zero Cross Switch", STA32X_CONFE, STA32X_CONFE_ZCE_SHIFT, 1, 0), -SOC_SINGLE("Soft Ramp Switch", STA32X_CONFE, STA32X_CONFE_SVE_SHIFT, 1, 0), -SOC_SINGLE("Auto-Mute Switch", STA32X_CONFF, STA32X_CONFF_IDE_SHIFT, 1, 0), -SOC_ENUM("Automode EQ", sta32x_auto_eq_enum), -SOC_ENUM("Automode GC", sta32x_auto_gc_enum), -SOC_ENUM("Automode XO", sta32x_auto_xo_enum), -SOC_ENUM("Preset EQ", sta32x_preset_eq_enum), -SOC_SINGLE("Ch1 Tone Control Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_TCB_SHIFT, 1, 0), -SOC_SINGLE("Ch2 Tone Control Bypass Switch", STA32X_C2CFG, STA32X_CxCFG_TCB_SHIFT, 1, 0), -SOC_SINGLE("Ch1 EQ Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_EQBP_SHIFT, 1, 0), -SOC_SINGLE("Ch2 EQ Bypass Switch", STA32X_C2CFG, STA32X_CxCFG_EQBP_SHIFT, 1, 0), -SOC_SINGLE("Ch1 Master Volume Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_VBP_SHIFT, 1, 0), -SOC_SINGLE("Ch2 Master Volume Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_VBP_SHIFT, 1, 0), -SOC_SINGLE("Ch3 Master Volume Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_VBP_SHIFT, 1, 0), -SOC_ENUM("Ch1 Limiter Select", sta32x_limiter_ch1_enum), -SOC_ENUM("Ch2 Limiter Select", sta32x_limiter_ch2_enum), -SOC_ENUM("Ch3 Limiter Select", sta32x_limiter_ch3_enum), -SOC_SINGLE_TLV("Bass Tone Control", STA32X_TONE, STA32X_TONE_BTC_SHIFT, 15, 0, tone_tlv), -SOC_SINGLE_TLV("Treble Tone Control", STA32X_TONE, STA32X_TONE_TTC_SHIFT, 15, 0, tone_tlv), -SOC_ENUM("Limiter1 Attack Rate (dB/ms)", sta32x_limiter1_attack_rate_enum), -SOC_ENUM("Limiter2 Attack Rate (dB/ms)", sta32x_limiter2_attack_rate_enum), -SOC_ENUM("Limiter1 Release Rate (dB/ms)", sta32x_limiter1_release_rate_enum), -SOC_ENUM("Limiter2 Release Rate (dB/ms)", sta32x_limiter1_release_rate_enum), - -/* depending on mode, the attack/release thresholds have - * two different enum definitions; provide both - */ -SOC_SINGLE_TLV("Limiter1 Attack Threshold (AC Mode)", STA32X_L1ATRT, STA32X_LxA_SHIFT, - 16, 0, sta32x_limiter_ac_attack_tlv), -SOC_SINGLE_TLV("Limiter2 Attack Threshold (AC Mode)", STA32X_L2ATRT, STA32X_LxA_SHIFT, - 16, 0, sta32x_limiter_ac_attack_tlv), -SOC_SINGLE_TLV("Limiter1 Release Threshold (AC Mode)", STA32X_L1ATRT, STA32X_LxR_SHIFT, - 16, 0, sta32x_limiter_ac_release_tlv), -SOC_SINGLE_TLV("Limiter2 Release Threshold (AC Mode)", STA32X_L2ATRT, STA32X_LxR_SHIFT, - 16, 0, sta32x_limiter_ac_release_tlv), -SOC_SINGLE_TLV("Limiter1 Attack Threshold (DRC Mode)", STA32X_L1ATRT, STA32X_LxA_SHIFT, - 16, 0, sta32x_limiter_drc_attack_tlv), -SOC_SINGLE_TLV("Limiter2 Attack Threshold (DRC Mode)", STA32X_L2ATRT, STA32X_LxA_SHIFT, - 16, 0, sta32x_limiter_drc_attack_tlv), -SOC_SINGLE_TLV("Limiter1 Release Threshold (DRC Mode)", STA32X_L1ATRT, STA32X_LxR_SHIFT, - 16, 0, sta32x_limiter_drc_release_tlv), -SOC_SINGLE_TLV("Limiter2 Release Threshold (DRC Mode)", STA32X_L2ATRT, STA32X_LxR_SHIFT, - 16, 0, sta32x_limiter_drc_release_tlv), - -BIQUAD_COEFS("Ch1 - Biquad 1", 0), -BIQUAD_COEFS("Ch1 - Biquad 2", 5), -BIQUAD_COEFS("Ch1 - Biquad 3", 10), -BIQUAD_COEFS("Ch1 - Biquad 4", 15), -BIQUAD_COEFS("Ch2 - Biquad 1", 20), -BIQUAD_COEFS("Ch2 - Biquad 2", 25), -BIQUAD_COEFS("Ch2 - Biquad 3", 30), -BIQUAD_COEFS("Ch2 - Biquad 4", 35), -BIQUAD_COEFS("High-pass", 40), -BIQUAD_COEFS("Low-pass", 45), -SINGLE_COEF("Ch1 - Prescale", 50), -SINGLE_COEF("Ch2 - Prescale", 51), -SINGLE_COEF("Ch1 - Postscale", 52), -SINGLE_COEF("Ch2 - Postscale", 53), -SINGLE_COEF("Ch3 - Postscale", 54), -SINGLE_COEF("Thermal warning - Postscale", 55), -SINGLE_COEF("Ch1 - Mix 1", 56), -SINGLE_COEF("Ch1 - Mix 2", 57), -SINGLE_COEF("Ch2 - Mix 1", 58), -SINGLE_COEF("Ch2 - Mix 2", 59), -SINGLE_COEF("Ch3 - Mix 1", 60), -SINGLE_COEF("Ch3 - Mix 2", 61), -}; - -static const struct snd_soc_dapm_widget sta32x_dapm_widgets[] = { -SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0), -SND_SOC_DAPM_OUTPUT("LEFT"), -SND_SOC_DAPM_OUTPUT("RIGHT"), -SND_SOC_DAPM_OUTPUT("SUB"), -}; - -static const struct snd_soc_dapm_route sta32x_dapm_routes[] = { - { "LEFT", NULL, "DAC" }, - { "RIGHT", NULL, "DAC" }, - { "SUB", NULL, "DAC" }, -}; - -/* MCLK interpolation ratio per fs */ -static struct { - int fs; - int ir; -} interpolation_ratios[] = { - { 32000, 0 }, - { 44100, 0 }, - { 48000, 0 }, - { 88200, 1 }, - { 96000, 1 }, - { 176400, 2 }, - { 192000, 2 }, -}; - -/* MCLK to fs clock ratios */ -static struct { - int ratio; - int mcs; -} mclk_ratios[3][7] = { - { { 768, 0 }, { 512, 1 }, { 384, 2 }, { 256, 3 }, - { 128, 4 }, { 576, 5 }, { 0, 0 } }, - { { 384, 2 }, { 256, 3 }, { 192, 4 }, { 128, 5 }, {64, 0 }, { 0, 0 } }, - { { 384, 2 }, { 256, 3 }, { 192, 4 }, { 128, 5 }, {64, 0 }, { 0, 0 } }, -}; - - -/** - * sta32x_set_dai_sysclk - configure MCLK - * @codec_dai: the codec DAI - * @clk_id: the clock ID (ignored) - * @freq: the MCLK input frequency - * @dir: the clock direction (ignored) - * - * The value of MCLK is used to determine which sample rates are supported - * by the STA32X, based on the mclk_ratios table. - * - * This function must be called by the machine driver's 'startup' function, - * otherwise the list of supported sample rates will not be available in - * time for ALSA. - * - * For setups with variable MCLKs, pass 0 as 'freq' argument. This will cause - * theoretically possible sample rates to be enabled. Call it again with a - * proper value set one the external clock is set (most probably you would do - * that from a machine's driver 'hw_param' hook. - */ -static int sta32x_set_dai_sysclk(struct snd_soc_dai *codec_dai, - int clk_id, unsigned int freq, int dir) -{ - struct snd_soc_codec *codec = codec_dai->codec; - struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); - int i, j, ir, fs; - unsigned int rates = 0; - unsigned int rate_min = -1; - unsigned int rate_max = 0; - - pr_debug("mclk=%u\n", freq); - sta32x->mclk = freq; - - if (sta32x->mclk) { - for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++) { - ir = interpolation_ratios[i].ir; - fs = interpolation_ratios[i].fs; - for (j = 0; mclk_ratios[ir][j].ratio; j++) { - if (mclk_ratios[ir][j].ratio * fs == freq) { - rates |= snd_pcm_rate_to_rate_bit(fs); - if (fs < rate_min) - rate_min = fs; - if (fs > rate_max) - rate_max = fs; - } - } - } - /* FIXME: soc should support a rate list */ - rates &= ~SNDRV_PCM_RATE_KNOT; - - if (!rates) { - dev_err(codec->dev, "could not find a valid sample rate\n"); - return -EINVAL; - } - } else { - /* enable all possible rates */ - rates = STA32X_RATES; - rate_min = 32000; - rate_max = 192000; - } - - codec_dai->driver->playback.rates = rates; - codec_dai->driver->playback.rate_min = rate_min; - codec_dai->driver->playback.rate_max = rate_max; - return 0; -} - -/** - * sta32x_set_dai_fmt - configure the codec for the selected audio format - * @codec_dai: the codec DAI - * @fmt: a SND_SOC_DAIFMT_x value indicating the data format - * - * This function takes a bitmask of SND_SOC_DAIFMT_x bits and programs the - * codec accordingly. - */ -static int sta32x_set_dai_fmt(struct snd_soc_dai *codec_dai, - unsigned int fmt) -{ - struct snd_soc_codec *codec = codec_dai->codec; - struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); - u8 confb = snd_soc_read(codec, STA32X_CONFB); - - pr_debug("\n"); - confb &= ~(STA32X_CONFB_C1IM | STA32X_CONFB_C2IM); - - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - break; - default: - return -EINVAL; - } - - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - case SND_SOC_DAIFMT_RIGHT_J: - case SND_SOC_DAIFMT_LEFT_J: - sta32x->format = fmt & SND_SOC_DAIFMT_FORMAT_MASK; - break; - default: - return -EINVAL; - } - - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - confb |= STA32X_CONFB_C2IM; - break; - case SND_SOC_DAIFMT_NB_IF: - confb |= STA32X_CONFB_C1IM; - break; - default: - return -EINVAL; - } - - snd_soc_write(codec, STA32X_CONFB, confb); - return 0; -} - -/** - * sta32x_hw_params - program the STA32X with the given hardware parameters. - * @substream: the audio stream - * @params: the hardware parameters to set - * @dai: the SOC DAI (ignored) - * - * This function programs the hardware with the values provided. - * Specifically, the sample rate and the data format. - */ -static int sta32x_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_codec *codec = rtd->codec; - struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); - unsigned int rate; - int i, mcs = -1, ir = -1; - u8 confa, confb; - - rate = params_rate(params); - pr_debug("rate: %u\n", rate); - for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++) - if (interpolation_ratios[i].fs == rate) - ir = interpolation_ratios[i].ir; - if (ir < 0) - return -EINVAL; - for (i = 0; mclk_ratios[ir][i].ratio; i++) - if (mclk_ratios[ir][i].ratio * rate == sta32x->mclk) - mcs = mclk_ratios[ir][i].mcs; - if (mcs < 0) - return -EINVAL; - - confa = snd_soc_read(codec, STA32X_CONFA); - confa &= ~(STA32X_CONFA_MCS_MASK | STA32X_CONFA_IR_MASK); - confa |= (ir << STA32X_CONFA_IR_SHIFT) | (mcs << STA32X_CONFA_MCS_SHIFT); - - confb = snd_soc_read(codec, STA32X_CONFB); - confb &= ~(STA32X_CONFB_SAI_MASK | STA32X_CONFB_SAIFB); - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S24_LE: - case SNDRV_PCM_FORMAT_S24_BE: - case SNDRV_PCM_FORMAT_S24_3LE: - case SNDRV_PCM_FORMAT_S24_3BE: - pr_debug("24bit\n"); - /* fall through */ - case SNDRV_PCM_FORMAT_S32_LE: - case SNDRV_PCM_FORMAT_S32_BE: - pr_debug("24bit or 32bit\n"); - switch (sta32x->format) { - case SND_SOC_DAIFMT_I2S: - confb |= 0x0; - break; - case SND_SOC_DAIFMT_LEFT_J: - confb |= 0x1; - break; - case SND_SOC_DAIFMT_RIGHT_J: - confb |= 0x2; - break; - } - - break; - case SNDRV_PCM_FORMAT_S20_3LE: - case SNDRV_PCM_FORMAT_S20_3BE: - pr_debug("20bit\n"); - switch (sta32x->format) { - case SND_SOC_DAIFMT_I2S: - confb |= 0x4; - break; - case SND_SOC_DAIFMT_LEFT_J: - confb |= 0x5; - break; - case SND_SOC_DAIFMT_RIGHT_J: - confb |= 0x6; - break; - } - - break; - case SNDRV_PCM_FORMAT_S18_3LE: - case SNDRV_PCM_FORMAT_S18_3BE: - pr_debug("18bit\n"); - switch (sta32x->format) { - case SND_SOC_DAIFMT_I2S: - confb |= 0x8; - break; - case SND_SOC_DAIFMT_LEFT_J: - confb |= 0x9; - break; - case SND_SOC_DAIFMT_RIGHT_J: - confb |= 0xa; - break; - } - - break; - case SNDRV_PCM_FORMAT_S16_LE: - case SNDRV_PCM_FORMAT_S16_BE: - pr_debug("16bit\n"); - switch (sta32x->format) { - case SND_SOC_DAIFMT_I2S: - confb |= 0x0; - break; - case SND_SOC_DAIFMT_LEFT_J: - confb |= 0xd; - break; - case SND_SOC_DAIFMT_RIGHT_J: - confb |= 0xe; - break; - } - - break; - default: - return -EINVAL; - } - - snd_soc_write(codec, STA32X_CONFA, confa); - snd_soc_write(codec, STA32X_CONFB, confb); - return 0; -} - -/** - * sta32x_set_bias_level - DAPM callback - * @codec: the codec device - * @level: DAPM power level - * - * This is called by ALSA to put the codec into low power mode - * or to wake it up. If the codec is powered off completely - * all registers must be restored after power on. - */ -static int sta32x_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) -{ - int ret; - struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); - - pr_debug("level = %d\n", level); - switch (level) { - case SND_SOC_BIAS_ON: - break; - - case SND_SOC_BIAS_PREPARE: - /* Full power on */ - snd_soc_update_bits(codec, STA32X_CONFF, - STA32X_CONFF_PWDN | STA32X_CONFF_EAPD, - STA32X_CONFF_PWDN | STA32X_CONFF_EAPD); - break; - - case SND_SOC_BIAS_STANDBY: - if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { - ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies), - sta32x->supplies); - if (ret != 0) { - dev_err(codec->dev, - "Failed to enable supplies: %d\n", ret); - return ret; - } - - snd_soc_cache_sync(codec); - } - - /* Power up to mute */ - /* FIXME */ - snd_soc_update_bits(codec, STA32X_CONFF, - STA32X_CONFF_PWDN | STA32X_CONFF_EAPD, - STA32X_CONFF_PWDN | STA32X_CONFF_EAPD); - - break; - - case SND_SOC_BIAS_OFF: - /* The chip runs through the power down sequence for us. */ - snd_soc_update_bits(codec, STA32X_CONFF, - STA32X_CONFF_PWDN | STA32X_CONFF_EAPD, - STA32X_CONFF_PWDN); - msleep(300); - - regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), - sta32x->supplies); - break; - } - codec->dapm.bias_level = level; - return 0; -} - -static struct snd_soc_dai_ops sta32x_dai_ops = { - .hw_params = sta32x_hw_params, - .set_sysclk = sta32x_set_dai_sysclk, - .set_fmt = sta32x_set_dai_fmt, -}; - -static struct snd_soc_dai_driver sta32x_dai = { - .name = "STA32X", - .playback = { - .stream_name = "Playback", - .channels_min = 2, - .channels_max = 2, - .rates = STA32X_RATES, - .formats = STA32X_FORMATS, - }, - .ops = &sta32x_dai_ops, -}; - -#ifdef CONFIG_PM -static int sta32x_suspend(struct snd_soc_codec *codec, pm_message_t state) -{ - sta32x_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int sta32x_resume(struct snd_soc_codec *codec) -{ - sta32x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} -#else -#define sta32x_suspend NULL -#define sta32x_resume NULL -#endif - -static int sta32x_probe(struct snd_soc_codec *codec) -{ - struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); - int i, ret = 0; - - sta32x->codec = codec; - - /* regulators */ - for (i = 0; i < ARRAY_SIZE(sta32x->supplies); i++) - sta32x->supplies[i].supply = sta32x_supply_names[i]; - - ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(sta32x->supplies), - sta32x->supplies); - if (ret != 0) { - dev_err(codec->dev, "Failed to request supplies: %d\n", ret); - goto err; - } - - ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies), - sta32x->supplies); - if (ret != 0) { - dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); - goto err_get; - } - - /* Tell ASoC what kind of I/O to use to read the registers. ASoC will - * then do the I2C transactions itself. - */ - ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C); - if (ret < 0) { - dev_err(codec->dev, "failed to set cache I/O (ret=%i)\n", ret); - return ret; - } - - /* read reg reset values into cache */ - for (i = 0; i < STA32X_REGISTER_COUNT; i++) - snd_soc_cache_write(codec, i, sta32x_regs[i]); - - /* preserve reset values of reserved register bits */ - snd_soc_cache_write(codec, STA32X_CONFC, - codec->hw_read(codec, STA32X_CONFC)); - snd_soc_cache_write(codec, STA32X_CONFE, - codec->hw_read(codec, STA32X_CONFE)); - snd_soc_cache_write(codec, STA32X_CONFF, - codec->hw_read(codec, STA32X_CONFF)); - snd_soc_cache_write(codec, STA32X_MMUTE, - codec->hw_read(codec, STA32X_MMUTE)); - snd_soc_cache_write(codec, STA32X_AUTO1, - codec->hw_read(codec, STA32X_AUTO1)); - snd_soc_cache_write(codec, STA32X_AUTO3, - codec->hw_read(codec, STA32X_AUTO3)); - snd_soc_cache_write(codec, STA32X_C3CFG, - codec->hw_read(codec, STA32X_C3CFG)); - - /* FIXME enable thermal warning adjustment and recovery */ - snd_soc_update_bits(codec, STA32X_CONFA, - STA32X_CONFA_TWAB | STA32X_CONFA_TWRB, 0); - - /* FIXME select 2.1 mode */ - snd_soc_update_bits(codec, STA32X_CONFF, - STA32X_CONFF_OCFG_MASK, - 1 << STA32X_CONFF_OCFG_SHIFT); - - /* FIXME channel to output mapping */ - snd_soc_update_bits(codec, STA32X_C1CFG, - STA32X_CxCFG_OM_MASK, - 0 << STA32X_CxCFG_OM_SHIFT); - snd_soc_update_bits(codec, STA32X_C2CFG, - STA32X_CxCFG_OM_MASK, - 1 << STA32X_CxCFG_OM_SHIFT); - snd_soc_update_bits(codec, STA32X_C3CFG, - STA32X_CxCFG_OM_MASK, - 2 << STA32X_CxCFG_OM_SHIFT); - - sta32x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - /* Bias level configuration will have done an extra enable */ - regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); - - return 0; - -err_get: - regulator_bulk_free(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); -err: - return ret; -} - -static int sta32x_remove(struct snd_soc_codec *codec) -{ - struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); - - regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); - regulator_bulk_free(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); - - return 0; -} - -static int sta32x_reg_is_volatile(struct snd_soc_codec *codec, - unsigned int reg) -{ - switch (reg) { - case STA32X_CONFA ... STA32X_L2ATRT: - case STA32X_MPCC1 ... STA32X_FDRC2: - return 0; - } - return 1; -} - -static const struct snd_soc_codec_driver sta32x_codec = { - .probe = sta32x_probe, - .remove = sta32x_remove, - .suspend = sta32x_suspend, - .resume = sta32x_resume, - .reg_cache_size = STA32X_REGISTER_COUNT, - .reg_word_size = sizeof(u8), - .volatile_register = sta32x_reg_is_volatile, - .set_bias_level = sta32x_set_bias_level, - .controls = sta32x_snd_controls, - .num_controls = ARRAY_SIZE(sta32x_snd_controls), - .dapm_widgets = sta32x_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(sta32x_dapm_widgets), - .dapm_routes = sta32x_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(sta32x_dapm_routes), -}; - -static __devinit int sta32x_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) -{ - struct sta32x_priv *sta32x; - int ret; - - sta32x = kzalloc(sizeof(struct sta32x_priv), GFP_KERNEL); - if (!sta32x) - return -ENOMEM; - - i2c_set_clientdata(i2c, sta32x); - - ret = snd_soc_register_codec(&i2c->dev, &sta32x_codec, &sta32x_dai, 1); - if (ret != 0) { - dev_err(&i2c->dev, "Failed to register codec (%d)\n", ret); - return ret; - } - - return 0; -} - -static __devexit int sta32x_i2c_remove(struct i2c_client *client) -{ - struct sta32x_priv *sta32x = i2c_get_clientdata(client); - struct snd_soc_codec *codec = sta32x->codec; - - if (codec) - sta32x_set_bias_level(codec, SND_SOC_BIAS_OFF); - - regulator_bulk_free(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); - - if (codec) { - snd_soc_unregister_codec(&client->dev); - snd_soc_codec_set_drvdata(codec, NULL); - } - - kfree(sta32x); - return 0; -} - -static const struct i2c_device_id sta32x_i2c_id[] = { - { "sta326", 0 }, - { "sta328", 0 }, - { "sta329", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, sta32x_i2c_id); - -static struct i2c_driver sta32x_i2c_driver = { - .driver = { - .name = "sta32x", - .owner = THIS_MODULE, - }, - .probe = sta32x_i2c_probe, - .remove = __devexit_p(sta32x_i2c_remove), - .id_table = sta32x_i2c_id, -}; - -static int __init sta32x_init(void) -{ - return i2c_add_driver(&sta32x_i2c_driver); -} -module_init(sta32x_init); - -static void __exit sta32x_exit(void) -{ - i2c_del_driver(&sta32x_i2c_driver); -} -module_exit(sta32x_exit); - -MODULE_DESCRIPTION("ASoC STA32X driver"); -MODULE_AUTHOR("Johannes Stezenbach "); -MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/codecs/sta32x.h b/trunk/sound/soc/codecs/sta32x.h deleted file mode 100644 index b97ee5a75667..000000000000 --- a/trunk/sound/soc/codecs/sta32x.h +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Codec driver for ST STA32x 2.1-channel high-efficiency digital audio system - * - * Copyright: 2011 Raumfeld GmbH - * Author: Johannes Stezenbach - * - * based on code from: - * Wolfson Microelectronics PLC. - * Mark Brown - * - * 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 _ASOC_STA_32X_H -#define _ASOC_STA_32X_H - -/* STA326 register addresses */ - -#define STA32X_REGISTER_COUNT 0x2d - -#define STA32X_CONFA 0x00 -#define STA32X_CONFB 0x01 -#define STA32X_CONFC 0x02 -#define STA32X_CONFD 0x03 -#define STA32X_CONFE 0x04 -#define STA32X_CONFF 0x05 -#define STA32X_MMUTE 0x06 -#define STA32X_MVOL 0x07 -#define STA32X_C1VOL 0x08 -#define STA32X_C2VOL 0x09 -#define STA32X_C3VOL 0x0a -#define STA32X_AUTO1 0x0b -#define STA32X_AUTO2 0x0c -#define STA32X_AUTO3 0x0d -#define STA32X_C1CFG 0x0e -#define STA32X_C2CFG 0x0f -#define STA32X_C3CFG 0x10 -#define STA32X_TONE 0x11 -#define STA32X_L1AR 0x12 -#define STA32X_L1ATRT 0x13 -#define STA32X_L2AR 0x14 -#define STA32X_L2ATRT 0x15 -#define STA32X_CFADDR2 0x16 -#define STA32X_B1CF1 0x17 -#define STA32X_B1CF2 0x18 -#define STA32X_B1CF3 0x19 -#define STA32X_B2CF1 0x1a -#define STA32X_B2CF2 0x1b -#define STA32X_B2CF3 0x1c -#define STA32X_A1CF1 0x1d -#define STA32X_A1CF2 0x1e -#define STA32X_A1CF3 0x1f -#define STA32X_A2CF1 0x20 -#define STA32X_A2CF2 0x21 -#define STA32X_A2CF3 0x22 -#define STA32X_B0CF1 0x23 -#define STA32X_B0CF2 0x24 -#define STA32X_B0CF3 0x25 -#define STA32X_CFUD 0x26 -#define STA32X_MPCC1 0x27 -#define STA32X_MPCC2 0x28 -/* Reserved 0x29 */ -/* Reserved 0x2a */ -#define STA32X_Reserved 0x2a -#define STA32X_FDRC1 0x2b -#define STA32X_FDRC2 0x2c -/* Reserved 0x2d */ - - -/* STA326 register field definitions */ - -/* 0x00 CONFA */ -#define STA32X_CONFA_MCS_MASK 0x03 -#define STA32X_CONFA_MCS_SHIFT 0 -#define STA32X_CONFA_IR_MASK 0x18 -#define STA32X_CONFA_IR_SHIFT 3 -#define STA32X_CONFA_TWRB 0x20 -#define STA32X_CONFA_TWAB 0x40 -#define STA32X_CONFA_FDRB 0x80 - -/* 0x01 CONFB */ -#define STA32X_CONFB_SAI_MASK 0x0f -#define STA32X_CONFB_SAI_SHIFT 0 -#define STA32X_CONFB_SAIFB 0x10 -#define STA32X_CONFB_DSCKE 0x20 -#define STA32X_CONFB_C1IM 0x40 -#define STA32X_CONFB_C2IM 0x80 - -/* 0x02 CONFC */ -#define STA32X_CONFC_OM_MASK 0x03 -#define STA32X_CONFC_OM_SHIFT 0 -#define STA32X_CONFC_CSZ_MASK 0x7c -#define STA32X_CONFC_CSZ_SHIFT 2 - -/* 0x03 CONFD */ -#define STA32X_CONFD_HPB 0x01 -#define STA32X_CONFD_HPB_SHIFT 0 -#define STA32X_CONFD_DEMP 0x02 -#define STA32X_CONFD_DEMP_SHIFT 1 -#define STA32X_CONFD_DSPB 0x04 -#define STA32X_CONFD_DSPB_SHIFT 2 -#define STA32X_CONFD_PSL 0x08 -#define STA32X_CONFD_PSL_SHIFT 3 -#define STA32X_CONFD_BQL 0x10 -#define STA32X_CONFD_BQL_SHIFT 4 -#define STA32X_CONFD_DRC 0x20 -#define STA32X_CONFD_DRC_SHIFT 5 -#define STA32X_CONFD_ZDE 0x40 -#define STA32X_CONFD_ZDE_SHIFT 6 -#define STA32X_CONFD_MME 0x80 -#define STA32X_CONFD_MME_SHIFT 7 - -/* 0x04 CONFE */ -#define STA32X_CONFE_MPCV 0x01 -#define STA32X_CONFE_MPCV_SHIFT 0 -#define STA32X_CONFE_MPC 0x02 -#define STA32X_CONFE_MPC_SHIFT 1 -#define STA32X_CONFE_AME 0x08 -#define STA32X_CONFE_AME_SHIFT 3 -#define STA32X_CONFE_PWMS 0x10 -#define STA32X_CONFE_PWMS_SHIFT 4 -#define STA32X_CONFE_ZCE 0x40 -#define STA32X_CONFE_ZCE_SHIFT 6 -#define STA32X_CONFE_SVE 0x80 -#define STA32X_CONFE_SVE_SHIFT 7 - -/* 0x05 CONFF */ -#define STA32X_CONFF_OCFG_MASK 0x03 -#define STA32X_CONFF_OCFG_SHIFT 0 -#define STA32X_CONFF_IDE 0x04 -#define STA32X_CONFF_IDE_SHIFT 3 -#define STA32X_CONFF_BCLE 0x08 -#define STA32X_CONFF_ECLE 0x20 -#define STA32X_CONFF_PWDN 0x40 -#define STA32X_CONFF_EAPD 0x80 - -/* 0x06 MMUTE */ -#define STA32X_MMUTE_MMUTE 0x01 - -/* 0x0b AUTO1 */ -#define STA32X_AUTO1_AMEQ_MASK 0x03 -#define STA32X_AUTO1_AMEQ_SHIFT 0 -#define STA32X_AUTO1_AMV_MASK 0xc0 -#define STA32X_AUTO1_AMV_SHIFT 2 -#define STA32X_AUTO1_AMGC_MASK 0x30 -#define STA32X_AUTO1_AMGC_SHIFT 4 -#define STA32X_AUTO1_AMPS 0x80 - -/* 0x0c AUTO2 */ -#define STA32X_AUTO2_AMAME 0x01 -#define STA32X_AUTO2_AMAM_MASK 0x0e -#define STA32X_AUTO2_AMAM_SHIFT 1 -#define STA32X_AUTO2_XO_MASK 0xf0 -#define STA32X_AUTO2_XO_SHIFT 4 - -/* 0x0d AUTO3 */ -#define STA32X_AUTO3_PEQ_MASK 0x1f -#define STA32X_AUTO3_PEQ_SHIFT 0 - -/* 0x0e 0x0f 0x10 CxCFG */ -#define STA32X_CxCFG_TCB 0x01 /* only C1 and C2 */ -#define STA32X_CxCFG_TCB_SHIFT 0 -#define STA32X_CxCFG_EQBP 0x02 /* only C1 and C2 */ -#define STA32X_CxCFG_EQBP_SHIFT 1 -#define STA32X_CxCFG_VBP 0x03 -#define STA32X_CxCFG_VBP_SHIFT 2 -#define STA32X_CxCFG_BO 0x04 -#define STA32X_CxCFG_LS_MASK 0x30 -#define STA32X_CxCFG_LS_SHIFT 4 -#define STA32X_CxCFG_OM_MASK 0xc0 -#define STA32X_CxCFG_OM_SHIFT 6 - -/* 0x11 TONE */ -#define STA32X_TONE_BTC_SHIFT 0 -#define STA32X_TONE_TTC_SHIFT 4 - -/* 0x12 0x13 0x14 0x15 limiter attack/release */ -#define STA32X_LxA_SHIFT 0 -#define STA32X_LxR_SHIFT 4 - -/* 0x26 CFUD */ -#define STA32X_CFUD_W1 0x01 -#define STA32X_CFUD_WA 0x02 -#define STA32X_CFUD_R1 0x04 -#define STA32X_CFUD_RA 0x08 - - -/* biquad filter coefficient table offsets */ -#define STA32X_C1_BQ_BASE 0 -#define STA32X_C2_BQ_BASE 20 -#define STA32X_CH_BQ_NUM 4 -#define STA32X_BQ_NUM_COEF 5 -#define STA32X_XO_HP_BQ_BASE 40 -#define STA32X_XO_LP_BQ_BASE 45 -#define STA32X_C1_PRESCALE 50 -#define STA32X_C2_PRESCALE 51 -#define STA32X_C1_POSTSCALE 52 -#define STA32X_C2_POSTSCALE 53 -#define STA32X_C3_POSTSCALE 54 -#define STA32X_TW_POSTSCALE 55 -#define STA32X_C1_MIX1 56 -#define STA32X_C1_MIX2 57 -#define STA32X_C2_MIX1 58 -#define STA32X_C2_MIX2 59 -#define STA32X_C3_MIX1 60 -#define STA32X_C3_MIX2 61 - -#endif /* _ASOC_STA_32X_H */ diff --git a/trunk/sound/soc/codecs/tlv320aic3x.c b/trunk/sound/soc/codecs/tlv320aic3x.c index 0963c4c7a83f..789453d44ec5 100644 --- a/trunk/sound/soc/codecs/tlv320aic3x.c +++ b/trunk/sound/soc/codecs/tlv320aic3x.c @@ -226,13 +226,11 @@ static const char *aic3x_adc_hpf[] = #define RDAC_ENUM 1 #define LHPCOM_ENUM 2 #define RHPCOM_ENUM 3 -#define LINE1L_2_L_ENUM 4 -#define LINE1L_2_R_ENUM 5 -#define LINE1R_2_L_ENUM 6 -#define LINE1R_2_R_ENUM 7 -#define LINE2L_ENUM 8 -#define LINE2R_ENUM 9 -#define ADC_HPF_ENUM 10 +#define LINE1L_ENUM 4 +#define LINE1R_ENUM 5 +#define LINE2L_ENUM 6 +#define LINE2R_ENUM 7 +#define ADC_HPF_ENUM 8 static const struct soc_enum aic3x_enum[] = { SOC_ENUM_SINGLE(DAC_LINE_MUX, 6, 3, aic3x_left_dac_mux), @@ -240,8 +238,6 @@ static const struct soc_enum aic3x_enum[] = { SOC_ENUM_SINGLE(HPLCOM_CFG, 4, 3, aic3x_left_hpcom_mux), SOC_ENUM_SINGLE(HPRCOM_CFG, 3, 5, aic3x_right_hpcom_mux), SOC_ENUM_SINGLE(LINE1L_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux), - SOC_ENUM_SINGLE(LINE1L_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux), - SOC_ENUM_SINGLE(LINE1R_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux), SOC_ENUM_SINGLE(LINE1R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux), SOC_ENUM_SINGLE(LINE2L_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux), SOC_ENUM_SINGLE(LINE2R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux), @@ -494,16 +490,12 @@ static const struct snd_kcontrol_new aic3x_right_pga_mixer_controls[] = { }; /* Left Line1 Mux */ -static const struct snd_kcontrol_new aic3x_left_line1l_mux_controls = -SOC_DAPM_ENUM("Route", aic3x_enum[LINE1L_2_L_ENUM]); -static const struct snd_kcontrol_new aic3x_right_line1l_mux_controls = -SOC_DAPM_ENUM("Route", aic3x_enum[LINE1L_2_R_ENUM]); +static const struct snd_kcontrol_new aic3x_left_line1_mux_controls = +SOC_DAPM_ENUM("Route", aic3x_enum[LINE1L_ENUM]); /* Right Line1 Mux */ -static const struct snd_kcontrol_new aic3x_right_line1r_mux_controls = -SOC_DAPM_ENUM("Route", aic3x_enum[LINE1R_2_R_ENUM]); -static const struct snd_kcontrol_new aic3x_left_line1r_mux_controls = -SOC_DAPM_ENUM("Route", aic3x_enum[LINE1R_2_L_ENUM]); +static const struct snd_kcontrol_new aic3x_right_line1_mux_controls = +SOC_DAPM_ENUM("Route", aic3x_enum[LINE1R_ENUM]); /* Left Line2 Mux */ static const struct snd_kcontrol_new aic3x_left_line2_mux_controls = @@ -543,9 +535,9 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { &aic3x_left_pga_mixer_controls[0], ARRAY_SIZE(aic3x_left_pga_mixer_controls)), SND_SOC_DAPM_MUX("Left Line1L Mux", SND_SOC_NOPM, 0, 0, - &aic3x_left_line1l_mux_controls), + &aic3x_left_line1_mux_controls), SND_SOC_DAPM_MUX("Left Line1R Mux", SND_SOC_NOPM, 0, 0, - &aic3x_left_line1r_mux_controls), + &aic3x_left_line1_mux_controls), SND_SOC_DAPM_MUX("Left Line2L Mux", SND_SOC_NOPM, 0, 0, &aic3x_left_line2_mux_controls), @@ -556,9 +548,9 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { &aic3x_right_pga_mixer_controls[0], ARRAY_SIZE(aic3x_right_pga_mixer_controls)), SND_SOC_DAPM_MUX("Right Line1L Mux", SND_SOC_NOPM, 0, 0, - &aic3x_right_line1l_mux_controls), + &aic3x_right_line1_mux_controls), SND_SOC_DAPM_MUX("Right Line1R Mux", SND_SOC_NOPM, 0, 0, - &aic3x_right_line1r_mux_controls), + &aic3x_right_line1_mux_controls), SND_SOC_DAPM_MUX("Right Line2R Mux", SND_SOC_NOPM, 0, 0, &aic3x_right_line2_mux_controls), diff --git a/trunk/sound/soc/codecs/twl6040.c b/trunk/sound/soc/codecs/twl6040.c index cd63bba623df..4c336636d4f5 100644 --- a/trunk/sound/soc/codecs/twl6040.c +++ b/trunk/sound/soc/codecs/twl6040.c @@ -954,9 +954,9 @@ static DECLARE_TLV_DB_SCALE(mic_preamp_tlv, -600, 600, 0); /* * MICGAIN volume control: - * from 6 to 30 dB in 6 dB steps + * from -6 to 30 dB in 6 dB steps */ -static DECLARE_TLV_DB_SCALE(mic_amp_tlv, 600, 600, 0); +static DECLARE_TLV_DB_SCALE(mic_amp_tlv, -600, 600, 0); /* * AFMGAIN volume control: diff --git a/trunk/sound/soc/codecs/wm8782.c b/trunk/sound/soc/codecs/wm8782.c deleted file mode 100644 index a2a09f85ea99..000000000000 --- a/trunk/sound/soc/codecs/wm8782.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * sound/soc/codecs/wm8782.c - * simple, strap-pin configured 24bit 2ch ADC - * - * Copyright: 2011 Raumfeld GmbH - * Author: Johannes Stezenbach - * - * based on ad73311.c - * Copyright: Analog Device Inc. - * Author: Cliff Cai - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct snd_soc_dai_driver wm8782_dai = { - .name = "wm8782", - .capture = { - .stream_name = "Capture", - .channels_min = 2, - .channels_max = 2, - /* For configurations with FSAMPEN=0 */ - .rates = SNDRV_PCM_RATE_8000_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S20_3LE | - SNDRV_PCM_FMTBIT_S24_LE, - }, -}; - -static struct snd_soc_codec_driver soc_codec_dev_wm8782; - -static __devinit int wm8782_probe(struct platform_device *pdev) -{ - return snd_soc_register_codec(&pdev->dev, - &soc_codec_dev_wm8782, &wm8782_dai, 1); -} - -static int __devexit wm8782_remove(struct platform_device *pdev) -{ - snd_soc_unregister_codec(&pdev->dev); - return 0; -} - -static struct platform_driver wm8782_codec_driver = { - .driver = { - .name = "wm8782", - .owner = THIS_MODULE, - }, - .probe = wm8782_probe, - .remove = wm8782_remove, -}; - -static int __init wm8782_init(void) -{ - return platform_driver_register(&wm8782_codec_driver); -} -module_init(wm8782_init); - -static void __exit wm8782_exit(void) -{ - platform_driver_unregister(&wm8782_codec_driver); -} -module_exit(wm8782_exit); - -MODULE_DESCRIPTION("ASoC WM8782 driver"); -MODULE_AUTHOR("Johannes Stezenbach "); -MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/codecs/wm8900.c b/trunk/sound/soc/codecs/wm8900.c index 082040eda8a2..449ea09a193d 100644 --- a/trunk/sound/soc/codecs/wm8900.c +++ b/trunk/sound/soc/codecs/wm8900.c @@ -1167,7 +1167,6 @@ static int wm8900_resume(struct snd_soc_codec *codec) ret = wm8900_set_fll(codec, 0, fll_in, fll_out); if (ret != 0) { dev_err(codec->dev, "Failed to restart FLL\n"); - kfree(cache); return ret; } } diff --git a/trunk/sound/soc/codecs/wm8904.c b/trunk/sound/soc/codecs/wm8904.c index b085575d4aa5..9b3bba4df5b3 100644 --- a/trunk/sound/soc/codecs/wm8904.c +++ b/trunk/sound/soc/codecs/wm8904.c @@ -2560,7 +2560,6 @@ static __devexit int wm8904_i2c_remove(struct i2c_client *client) static const struct i2c_device_id wm8904_i2c_id[] = { { "wm8904", WM8904 }, { "wm8912", WM8912 }, - { "wm8918", WM8904 }, /* Actually a subset, updates to follow */ { } }; MODULE_DEVICE_TABLE(i2c, wm8904_i2c_id); diff --git a/trunk/sound/soc/codecs/wm8915.c b/trunk/sound/soc/codecs/wm8915.c index 423baa9be241..e2ab4fac2819 100644 --- a/trunk/sound/soc/codecs/wm8915.c +++ b/trunk/sound/soc/codecs/wm8915.c @@ -41,12 +41,14 @@ #define HPOUT2L 4 #define HPOUT2R 8 -#define WM8915_NUM_SUPPLIES 4 +#define WM8915_NUM_SUPPLIES 6 static const char *wm8915_supply_names[WM8915_NUM_SUPPLIES] = { + "DCVDD", "DBVDD", "AVDD1", "AVDD2", "CPVDD", + "MICVDD", }; struct wm8915_priv { @@ -55,7 +57,6 @@ struct wm8915_priv { int ldo1ena; int sysclk; - int sysclk_src; int fll_src; int fll_fref; @@ -75,7 +76,6 @@ struct wm8915_priv { struct wm8915_pdata pdata; int rx_rate[WM8915_AIFS]; - int bclk_rate[WM8915_AIFS]; /* Platform dependant ReTune mobile configuration */ int num_retune_mobile_texts; @@ -113,6 +113,8 @@ WM8915_REGULATOR_EVENT(0) WM8915_REGULATOR_EVENT(1) WM8915_REGULATOR_EVENT(2) WM8915_REGULATOR_EVENT(3) +WM8915_REGULATOR_EVENT(4) +WM8915_REGULATOR_EVENT(5) static const u16 wm8915_reg[WM8915_MAX_REGISTER] = { [WM8915_SOFTWARE_RESET] = 0x8915, @@ -1563,50 +1565,6 @@ static int wm8915_reset(struct snd_soc_codec *codec) return snd_soc_write(codec, WM8915_SOFTWARE_RESET, 0x8915); } -static const int bclk_divs[] = { - 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96 -}; - -static void wm8915_update_bclk(struct snd_soc_codec *codec) -{ - struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); - int aif, best, cur_val, bclk_rate, bclk_reg, i; - - /* Don't bother if we're in a low frequency idle mode that - * can't support audio. - */ - if (wm8915->sysclk < 64000) - return; - - for (aif = 0; aif < WM8915_AIFS; aif++) { - switch (aif) { - case 0: - bclk_reg = WM8915_AIF1_BCLK; - break; - case 1: - bclk_reg = WM8915_AIF2_BCLK; - break; - } - - bclk_rate = wm8915->bclk_rate[aif]; - - /* Pick a divisor for BCLK as close as we can get to ideal */ - best = 0; - for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) { - cur_val = (wm8915->sysclk / bclk_divs[i]) - bclk_rate; - if (cur_val < 0) /* BCLK table is sorted */ - break; - best = i; - } - bclk_rate = wm8915->sysclk / bclk_divs[best]; - dev_dbg(codec->dev, "Using BCLK_DIV %d for actual BCLK %dHz\n", - bclk_divs[best], bclk_rate); - - snd_soc_update_bits(codec, bclk_reg, - WM8915_AIF1_BCLK_DIV_MASK, best); - } -} - static int wm8915_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { @@ -1759,6 +1717,10 @@ static int wm8915_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } +static const int bclk_divs[] = { + 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96 +}; + static const int dsp_divs[] = { 48000, 32000, 16000, 8000 }; @@ -1769,11 +1731,17 @@ static int wm8915_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_codec *codec = dai->codec; struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); - int bits, i, bclk_rate; + int bits, i, bclk_rate, best, cur_val; int aifdata = 0; + int bclk = 0; int lrclk = 0; int dsp = 0; - int aifdata_reg, lrclk_reg, dsp_shift; + int aifdata_reg, bclk_reg, lrclk_reg, dsp_shift; + + if (!wm8915->sysclk) { + dev_err(codec->dev, "SYSCLK not configured\n"); + return -EINVAL; + } switch (dai->id) { case 0: @@ -1785,6 +1753,7 @@ static int wm8915_hw_params(struct snd_pcm_substream *substream, aifdata_reg = WM8915_AIF1TX_DATA_CONFIGURATION_1; lrclk_reg = WM8915_AIF1_TX_LRCLK_1; } + bclk_reg = WM8915_AIF1_BCLK; dsp_shift = 0; break; case 1: @@ -1796,6 +1765,7 @@ static int wm8915_hw_params(struct snd_pcm_substream *substream, aifdata_reg = WM8915_AIF2TX_DATA_CONFIGURATION_1; lrclk_reg = WM8915_AIF2_TX_LRCLK_1; } + bclk_reg = WM8915_AIF2_BCLK; dsp_shift = WM8915_DSP2_DIV_SHIFT; break; default: @@ -1809,9 +1779,6 @@ static int wm8915_hw_params(struct snd_pcm_substream *substream, return bclk_rate; } - wm8915->bclk_rate[dai->id] = bclk_rate; - wm8915->rx_rate[dai->id] = params_rate(params); - /* Needs looking at for TDM */ bits = snd_pcm_format_width(params_format(params)); if (bits < 0) @@ -1829,7 +1796,18 @@ static int wm8915_hw_params(struct snd_pcm_substream *substream, } dsp |= i << dsp_shift; - wm8915_update_bclk(codec); + /* Pick a divisor for BCLK as close as we can get to ideal */ + best = 0; + for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) { + cur_val = (wm8915->sysclk / bclk_divs[i]) - bclk_rate; + if (cur_val < 0) /* BCLK table is sorted */ + break; + best = i; + } + bclk_rate = wm8915->sysclk / bclk_divs[best]; + dev_dbg(dai->dev, "Using BCLK_DIV %d for actual BCLK %dHz\n", + bclk_divs[best], bclk_rate); + bclk |= best; lrclk = bclk_rate / params_rate(params); dev_dbg(dai->dev, "Using LRCLK rate %d for actual LRCLK %dHz\n", @@ -1839,11 +1817,14 @@ static int wm8915_hw_params(struct snd_pcm_substream *substream, WM8915_AIF1TX_WL_MASK | WM8915_AIF1TX_SLOT_LEN_MASK, aifdata); + snd_soc_update_bits(codec, bclk_reg, WM8915_AIF1_BCLK_DIV_MASK, bclk); snd_soc_update_bits(codec, lrclk_reg, WM8915_AIF1RX_RATE_MASK, lrclk); snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_2, WM8915_DSP1_DIV_SHIFT << dsp_shift, dsp); + wm8915->rx_rate[dai->id] = params_rate(params); + return 0; } @@ -1857,9 +1838,6 @@ static int wm8915_set_sysclk(struct snd_soc_dai *dai, int src; int old; - if (freq == wm8915->sysclk && clk_id == wm8915->sysclk_src) - return 0; - /* Disable SYSCLK while we reconfigure */ old = snd_soc_read(codec, WM8915_AIF_CLOCKING_1) & WM8915_SYSCLK_ENA; snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1, @@ -1904,8 +1882,6 @@ static int wm8915_set_sysclk(struct snd_soc_dai *dai, return -EINVAL; } - wm8915_update_bclk(codec); - snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1, WM8915_SYSCLK_SRC_MASK | WM8915_SYSCLK_DIV_MASK, src << WM8915_SYSCLK_SRC_SHIFT | ratediv); @@ -1913,8 +1889,6 @@ static int wm8915_set_sysclk(struct snd_soc_dai *dai, snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1, WM8915_SYSCLK_ENA, old); - wm8915->sysclk_src = clk_id; - return 0; } @@ -2033,7 +2007,6 @@ static int wm8915_set_fll(struct snd_soc_codec *codec, int fll_id, int source, unsigned int Fref, unsigned int Fout) { struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); - struct i2c_client *i2c = to_i2c_client(codec->dev); struct _fll_div fll_div; unsigned long timeout; int ret, reg; @@ -2120,18 +2093,7 @@ static int wm8915_set_fll(struct snd_soc_codec *codec, int fll_id, int source, else timeout = msecs_to_jiffies(2); - /* Allow substantially longer if we've actually got the IRQ */ - if (i2c->irq) - timeout *= 1000; - - ret = wait_for_completion_timeout(&wm8915->fll_lock, timeout); - - if (ret == 0 && i2c->irq) { - dev_err(codec->dev, "Timed out waiting for FLL\n"); - ret = -ETIMEDOUT; - } else { - ret = 0; - } + wait_for_completion_timeout(&wm8915->fll_lock, timeout); dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout); @@ -2139,7 +2101,7 @@ static int wm8915_set_fll(struct snd_soc_codec *codec, int fll_id, int source, wm8915->fll_fout = Fout; wm8915->fll_src = source; - return ret; + return 0; } #ifdef CONFIG_GPIOLIB @@ -2331,12 +2293,6 @@ static void wm8915_micd(struct snd_soc_codec *codec) SND_JACK_HEADSET | SND_JACK_BTN_0); wm8915->jack_mic = true; wm8915->detecting = false; - - /* Increase poll rate to give better responsiveness - * for buttons */ - snd_soc_update_bits(codec, WM8915_MIC_DETECT_1, - WM8915_MICD_RATE_MASK, - 5 << WM8915_MICD_RATE_SHIFT); } /* If we detected a lower impedence during initial startup @@ -2377,17 +2333,15 @@ static void wm8915_micd(struct snd_soc_codec *codec) SND_JACK_HEADPHONE, SND_JACK_HEADSET | SND_JACK_BTN_0); - - /* Increase the detection rate a bit for - * responsiveness. - */ - snd_soc_update_bits(codec, WM8915_MIC_DETECT_1, - WM8915_MICD_RATE_MASK, - 7 << WM8915_MICD_RATE_SHIFT); - wm8915->detecting = false; } } + + /* Increase poll rate to give better responsiveness for buttons */ + if (!wm8915->detecting) + snd_soc_update_bits(codec, WM8915_MIC_DETECT_1, + WM8915_MICD_RATE_MASK, + 5 << WM8915_MICD_RATE_SHIFT); } static irqreturn_t wm8915_irq(int irq, void *data) @@ -2429,20 +2383,6 @@ static irqreturn_t wm8915_irq(int irq, void *data) } } -static irqreturn_t wm8915_edge_irq(int irq, void *data) -{ - irqreturn_t ret = IRQ_NONE; - irqreturn_t val; - - do { - val = wm8915_irq(irq, data); - if (val != IRQ_NONE) - ret = val; - } while (val != IRQ_NONE); - - return ret; -} - static void wm8915_retune_mobile_pdata(struct snd_soc_codec *codec) { struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); @@ -2542,6 +2482,8 @@ static int wm8915_probe(struct snd_soc_codec *codec) wm8915->disable_nb[1].notifier_call = wm8915_regulator_event_1; wm8915->disable_nb[2].notifier_call = wm8915_regulator_event_2; wm8915->disable_nb[3].notifier_call = wm8915_regulator_event_3; + wm8915->disable_nb[4].notifier_call = wm8915_regulator_event_4; + wm8915->disable_nb[5].notifier_call = wm8915_regulator_event_5; /* This should really be moved into the regulator core */ for (i = 0; i < ARRAY_SIZE(wm8915->supplies); i++) { @@ -2767,14 +2709,8 @@ static int wm8915_probe(struct snd_soc_codec *codec) irq_flags |= IRQF_ONESHOT; - if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) - ret = request_threaded_irq(i2c->irq, NULL, - wm8915_edge_irq, - irq_flags, "wm8915", codec); - else - ret = request_threaded_irq(i2c->irq, NULL, wm8915_irq, - irq_flags, "wm8915", codec); - + ret = request_threaded_irq(i2c->irq, NULL, wm8915_irq, + irq_flags, "wm8915", codec); if (ret == 0) { /* Unmask the interrupt */ snd_soc_update_bits(codec, WM8915_INTERRUPT_CONTROL, diff --git a/trunk/sound/soc/codecs/wm8940.c b/trunk/sound/soc/codecs/wm8940.c index 056daa0010f9..25580e3ee7c4 100644 --- a/trunk/sound/soc/codecs/wm8940.c +++ b/trunk/sound/soc/codecs/wm8940.c @@ -297,6 +297,8 @@ static int wm8940_add_widgets(struct snd_soc_codec *codec) if (ret) goto error_ret; ret = snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); + if (ret) + goto error_ret; error_ret: return ret; @@ -681,6 +683,8 @@ static int wm8940_resume(struct snd_soc_codec *codec) } } ret = wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + if (ret) + goto error_ret; error_ret: return ret; @@ -726,6 +730,9 @@ static int wm8940_probe(struct snd_soc_codec *codec) if (ret) return ret; ret = wm8940_add_widgets(codec); + if (ret) + return ret; + return ret; } diff --git a/trunk/sound/soc/codecs/wm8962.c b/trunk/sound/soc/codecs/wm8962.c index 8499c563a9b5..5e05eed96c38 100644 --- a/trunk/sound/soc/codecs/wm8962.c +++ b/trunk/sound/soc/codecs/wm8962.c @@ -78,8 +78,6 @@ struct wm8962_priv { #ifdef CONFIG_GPIOLIB struct gpio_chip gpio_chip; #endif - - int irq; }; /* We can't use the same notifier block for more than one supply and @@ -1984,7 +1982,6 @@ static const unsigned int classd_tlv[] = { 0, 6, TLV_DB_SCALE_ITEM(0, 150, 0), 7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0), }; -static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); /* The VU bits for the headphones are in a different register to the mute * bits and only take effect on the PGA if it is actually powered. @@ -2122,18 +2119,6 @@ SOC_SINGLE_TLV("HPMIXR MIXINR Volume", WM8962_HEADPHONE_MIXER_4, SOC_SINGLE_TLV("Speaker Boost Volume", WM8962_CLASS_D_CONTROL_2, 0, 7, 0, classd_tlv), - -SOC_SINGLE("EQ Switch", WM8962_EQ1, WM8962_EQ_ENA_SHIFT, 1, 0), -SOC_DOUBLE_R_TLV("EQ1 Volume", WM8962_EQ2, WM8962_EQ22, - WM8962_EQL_B1_GAIN_SHIFT, 31, 0, eq_tlv), -SOC_DOUBLE_R_TLV("EQ2 Volume", WM8962_EQ2, WM8962_EQ22, - WM8962_EQL_B2_GAIN_SHIFT, 31, 0, eq_tlv), -SOC_DOUBLE_R_TLV("EQ3 Volume", WM8962_EQ2, WM8962_EQ22, - WM8962_EQL_B3_GAIN_SHIFT, 31, 0, eq_tlv), -SOC_DOUBLE_R_TLV("EQ4 Volume", WM8962_EQ3, WM8962_EQ23, - WM8962_EQL_B4_GAIN_SHIFT, 31, 0, eq_tlv), -SOC_DOUBLE_R_TLV("EQ5 Volume", WM8962_EQ3, WM8962_EQ23, - WM8962_EQL_B5_GAIN_SHIFT, 31, 0, eq_tlv), }; static const struct snd_kcontrol_new wm8962_spk_mono_controls[] = { @@ -2199,8 +2184,6 @@ static int sysclk_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = w->codec; - struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); - unsigned long timeout; int src; int fll; @@ -2220,19 +2203,9 @@ static int sysclk_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: - if (fll) { + if (fll) snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1, WM8962_FLL_ENA, WM8962_FLL_ENA); - if (wm8962->irq) { - timeout = msecs_to_jiffies(5); - timeout = wait_for_completion_timeout(&wm8962->fll_lock, - timeout); - - if (timeout == 0) - dev_err(codec->dev, - "Timed out starting FLL\n"); - } - } break; case SND_SOC_DAPM_POST_PMD: @@ -2790,44 +2763,18 @@ static const int bclk_divs[] = { 1, -1, 2, 3, 4, -1, 6, 8, -1, 12, 16, 24, -1, 32, 32, 32 }; -static const int sysclk_rates[] = { - 64, 128, 192, 256, 384, 512, 768, 1024, 1408, 1536, -}; - static void wm8962_configure_bclk(struct snd_soc_codec *codec) { struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); int dspclk, i; int clocking2 = 0; - int clocking4 = 0; int aif2 = 0; - if (!wm8962->sysclk_rate) { - dev_dbg(codec->dev, "No SYSCLK configured\n"); - return; - } - - if (!wm8962->bclk || !wm8962->lrclk) { - dev_dbg(codec->dev, "No audio clocks configured\n"); + if (!wm8962->bclk) { + dev_dbg(codec->dev, "No BCLK rate configured\n"); return; } - for (i = 0; i < ARRAY_SIZE(sysclk_rates); i++) { - if (sysclk_rates[i] == wm8962->sysclk_rate / wm8962->lrclk) { - clocking4 |= i << WM8962_SYSCLK_RATE_SHIFT; - break; - } - } - - if (i == ARRAY_SIZE(sysclk_rates)) { - dev_err(codec->dev, "Unsupported sysclk ratio %d\n", - wm8962->sysclk_rate / wm8962->lrclk); - return; - } - - snd_soc_update_bits(codec, WM8962_CLOCKING_4, - WM8962_SYSCLK_RATE_MASK, clocking4); - dspclk = snd_soc_read(codec, WM8962_CLOCKING1); if (dspclk < 0) { dev_err(codec->dev, "Failed to read DSPCLK: %d\n", dspclk); @@ -2897,8 +2844,6 @@ static int wm8962_set_bias_level(struct snd_soc_codec *codec, /* VMID 2*50k */ snd_soc_update_bits(codec, WM8962_PWR_MGMT_1, WM8962_VMID_SEL_MASK, 0x80); - - wm8962_configure_bclk(codec); break; case SND_SOC_BIAS_STANDBY: @@ -2931,6 +2876,8 @@ static int wm8962_set_bias_level(struct snd_soc_codec *codec, snd_soc_update_bits(codec, WM8962_CLOCKING2, WM8962_CLKREG_OVD, WM8962_CLKREG_OVD); + + wm8962_configure_bclk(codec); } /* VMID 2*250k */ @@ -2971,6 +2918,10 @@ static const struct { { 96000, 6 }, }; +static const int sysclk_rates[] = { + 64, 128, 192, 256, 384, 512, 768, 1024, 1408, 1536, +}; + static int wm8962_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -2978,27 +2929,41 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_codec *codec = rtd->codec; struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); + int rate = params_rate(params); int i; int aif0 = 0; int adctl3 = 0; + int clocking4 = 0; wm8962->bclk = snd_soc_params_to_bclk(params); wm8962->lrclk = params_rate(params); for (i = 0; i < ARRAY_SIZE(sr_vals); i++) { - if (sr_vals[i].rate == wm8962->lrclk) { + if (sr_vals[i].rate == rate) { adctl3 |= sr_vals[i].reg; break; } } if (i == ARRAY_SIZE(sr_vals)) { - dev_err(codec->dev, "Unsupported rate %dHz\n", wm8962->lrclk); + dev_err(codec->dev, "Unsupported rate %dHz\n", rate); return -EINVAL; } - if (wm8962->lrclk % 8000 == 0) + if (rate % 8000 == 0) adctl3 |= WM8962_SAMPLE_RATE_INT_MODE; + for (i = 0; i < ARRAY_SIZE(sysclk_rates); i++) { + if (sysclk_rates[i] == wm8962->sysclk_rate / rate) { + clocking4 |= i << WM8962_SYSCLK_RATE_SHIFT; + break; + } + } + if (i == ARRAY_SIZE(sysclk_rates)) { + dev_err(codec->dev, "Unsupported sysclk ratio %d\n", + wm8962->sysclk_rate / rate); + return -EINVAL; + } + switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: break; @@ -3020,6 +2985,8 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream, snd_soc_update_bits(codec, WM8962_ADDITIONAL_CONTROL_3, WM8962_SAMPLE_RATE_INT_MODE | WM8962_SAMPLE_RATE_MASK, adctl3); + snd_soc_update_bits(codec, WM8962_CLOCKING_4, + WM8962_SYSCLK_RATE_MASK, clocking4); wm8962_configure_bclk(codec); @@ -3294,31 +3261,16 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source, dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout); - ret = 0; - - if (fll1 & WM8962_FLL_ENA) { - /* This should be a massive overestimate but go even - * higher if we'll error out - */ - if (wm8962->irq) - timeout = msecs_to_jiffies(5); - else - timeout = msecs_to_jiffies(1); - - timeout = wait_for_completion_timeout(&wm8962->fll_lock, - timeout); + /* This should be a massive overestimate */ + timeout = msecs_to_jiffies(1); - if (timeout == 0 && wm8962->irq) { - dev_err(codec->dev, "FLL lock timed out"); - ret = -ETIMEDOUT; - } - } + wait_for_completion_timeout(&wm8962->fll_lock, timeout); wm8962->fll_fref = Fref; wm8962->fll_fout = Fout; wm8962->fll_src = source; - return ret; + return 0; } static int wm8962_mute(struct snd_soc_dai *dai, int mute) @@ -3779,6 +3731,8 @@ static int wm8962_probe(struct snd_soc_codec *codec) int ret; struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); struct wm8962_pdata *pdata = dev_get_platdata(codec->dev); + struct i2c_client *i2c = container_of(codec->dev, struct i2c_client, + dev); u16 *reg_cache = codec->reg_cache; int i, trigger, irq_pol; bool dmicclk, dmicdat; @@ -3917,9 +3871,6 @@ static int wm8962_probe(struct snd_soc_codec *codec) snd_soc_update_bits(codec, WM8962_HPOUTR_VOLUME, WM8962_HPOUT_VU, WM8962_HPOUT_VU); - /* Stereo control for EQ */ - snd_soc_update_bits(codec, WM8962_EQ1, WM8962_EQ_SHARED_COEFF, 0); - wm8962_add_widgets(codec); /* Save boards having to disable DMIC when not in use */ @@ -3948,7 +3899,7 @@ static int wm8962_probe(struct snd_soc_codec *codec) wm8962_init_beep(codec); wm8962_init_gpio(codec); - if (wm8962->irq) { + if (i2c->irq) { if (pdata && pdata->irq_active_low) { trigger = IRQF_TRIGGER_LOW; irq_pol = WM8962_IRQ_POL; @@ -3960,13 +3911,12 @@ static int wm8962_probe(struct snd_soc_codec *codec) snd_soc_update_bits(codec, WM8962_INTERRUPT_CONTROL, WM8962_IRQ_POL, irq_pol); - ret = request_threaded_irq(wm8962->irq, NULL, wm8962_irq, + ret = request_threaded_irq(i2c->irq, NULL, wm8962_irq, trigger | IRQF_ONESHOT, "wm8962", codec); if (ret != 0) { dev_err(codec->dev, "Failed to request IRQ %d: %d\n", - wm8962->irq, ret); - wm8962->irq = 0; + i2c->irq, ret); /* Non-fatal */ } else { /* Enable some IRQs by default */ @@ -3991,10 +3941,12 @@ static int wm8962_probe(struct snd_soc_codec *codec) static int wm8962_remove(struct snd_soc_codec *codec) { struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); + struct i2c_client *i2c = container_of(codec->dev, struct i2c_client, + dev); int i; - if (wm8962->irq) - free_irq(wm8962->irq, codec); + if (i2c->irq) + free_irq(i2c->irq, codec); cancel_delayed_work_sync(&wm8962->mic_work); @@ -4034,8 +3986,6 @@ static __devinit int wm8962_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, wm8962); - wm8962->irq = i2c->irq; - ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8962, &wm8962_dai, 1); if (ret < 0) diff --git a/trunk/sound/soc/codecs/wm8983.c b/trunk/sound/soc/codecs/wm8983.c deleted file mode 100644 index 17f04ec2b940..000000000000 --- a/trunk/sound/soc/codecs/wm8983.c +++ /dev/null @@ -1,1203 +0,0 @@ -/* - * wm8983.c -- WM8983 ALSA SoC Audio driver - * - * Copyright 2011 Wolfson Microelectronics plc - * - * Author: Dimitris Papastamos - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "wm8983.h" - -static const u16 wm8983_reg_defs[WM8983_MAX_REGISTER + 1] = { - [0x00] = 0x0000, /* R0 - Software Reset */ - [0x01] = 0x0000, /* R1 - Power management 1 */ - [0x02] = 0x0000, /* R2 - Power management 2 */ - [0x03] = 0x0000, /* R3 - Power management 3 */ - [0x04] = 0x0050, /* R4 - Audio Interface */ - [0x05] = 0x0000, /* R5 - Companding control */ - [0x06] = 0x0140, /* R6 - Clock Gen control */ - [0x07] = 0x0000, /* R7 - Additional control */ - [0x08] = 0x0000, /* R8 - GPIO Control */ - [0x09] = 0x0000, /* R9 - Jack Detect Control 1 */ - [0x0A] = 0x0000, /* R10 - DAC Control */ - [0x0B] = 0x00FF, /* R11 - Left DAC digital Vol */ - [0x0C] = 0x00FF, /* R12 - Right DAC digital vol */ - [0x0D] = 0x0000, /* R13 - Jack Detect Control 2 */ - [0x0E] = 0x0100, /* R14 - ADC Control */ - [0x0F] = 0x00FF, /* R15 - Left ADC Digital Vol */ - [0x10] = 0x00FF, /* R16 - Right ADC Digital Vol */ - [0x12] = 0x012C, /* R18 - EQ1 - low shelf */ - [0x13] = 0x002C, /* R19 - EQ2 - peak 1 */ - [0x14] = 0x002C, /* R20 - EQ3 - peak 2 */ - [0x15] = 0x002C, /* R21 - EQ4 - peak 3 */ - [0x16] = 0x002C, /* R22 - EQ5 - high shelf */ - [0x18] = 0x0032, /* R24 - DAC Limiter 1 */ - [0x19] = 0x0000, /* R25 - DAC Limiter 2 */ - [0x1B] = 0x0000, /* R27 - Notch Filter 1 */ - [0x1C] = 0x0000, /* R28 - Notch Filter 2 */ - [0x1D] = 0x0000, /* R29 - Notch Filter 3 */ - [0x1E] = 0x0000, /* R30 - Notch Filter 4 */ - [0x20] = 0x0038, /* R32 - ALC control 1 */ - [0x21] = 0x000B, /* R33 - ALC control 2 */ - [0x22] = 0x0032, /* R34 - ALC control 3 */ - [0x23] = 0x0000, /* R35 - Noise Gate */ - [0x24] = 0x0008, /* R36 - PLL N */ - [0x25] = 0x000C, /* R37 - PLL K 1 */ - [0x26] = 0x0093, /* R38 - PLL K 2 */ - [0x27] = 0x00E9, /* R39 - PLL K 3 */ - [0x29] = 0x0000, /* R41 - 3D control */ - [0x2A] = 0x0000, /* R42 - OUT4 to ADC */ - [0x2B] = 0x0000, /* R43 - Beep control */ - [0x2C] = 0x0033, /* R44 - Input ctrl */ - [0x2D] = 0x0010, /* R45 - Left INP PGA gain ctrl */ - [0x2E] = 0x0010, /* R46 - Right INP PGA gain ctrl */ - [0x2F] = 0x0100, /* R47 - Left ADC BOOST ctrl */ - [0x30] = 0x0100, /* R48 - Right ADC BOOST ctrl */ - [0x31] = 0x0002, /* R49 - Output ctrl */ - [0x32] = 0x0001, /* R50 - Left mixer ctrl */ - [0x33] = 0x0001, /* R51 - Right mixer ctrl */ - [0x34] = 0x0039, /* R52 - LOUT1 (HP) volume ctrl */ - [0x35] = 0x0039, /* R53 - ROUT1 (HP) volume ctrl */ - [0x36] = 0x0039, /* R54 - LOUT2 (SPK) volume ctrl */ - [0x37] = 0x0039, /* R55 - ROUT2 (SPK) volume ctrl */ - [0x38] = 0x0001, /* R56 - OUT3 mixer ctrl */ - [0x39] = 0x0001, /* R57 - OUT4 (MONO) mix ctrl */ - [0x3D] = 0x0000 /* R61 - BIAS CTRL */ -}; - -static const struct wm8983_reg_access { - u16 read; /* Mask of readable bits */ - u16 write; /* Mask of writable bits */ -} wm8983_access_masks[WM8983_MAX_REGISTER + 1] = { - [0x00] = { 0x0000, 0x01FF }, /* R0 - Software Reset */ - [0x01] = { 0x0000, 0x01FF }, /* R1 - Power management 1 */ - [0x02] = { 0x0000, 0x01FF }, /* R2 - Power management 2 */ - [0x03] = { 0x0000, 0x01EF }, /* R3 - Power management 3 */ - [0x04] = { 0x0000, 0x01FF }, /* R4 - Audio Interface */ - [0x05] = { 0x0000, 0x003F }, /* R5 - Companding control */ - [0x06] = { 0x0000, 0x01FD }, /* R6 - Clock Gen control */ - [0x07] = { 0x0000, 0x000F }, /* R7 - Additional control */ - [0x08] = { 0x0000, 0x003F }, /* R8 - GPIO Control */ - [0x09] = { 0x0000, 0x0070 }, /* R9 - Jack Detect Control 1 */ - [0x0A] = { 0x0000, 0x004F }, /* R10 - DAC Control */ - [0x0B] = { 0x0000, 0x01FF }, /* R11 - Left DAC digital Vol */ - [0x0C] = { 0x0000, 0x01FF }, /* R12 - Right DAC digital vol */ - [0x0D] = { 0x0000, 0x00FF }, /* R13 - Jack Detect Control 2 */ - [0x0E] = { 0x0000, 0x01FB }, /* R14 - ADC Control */ - [0x0F] = { 0x0000, 0x01FF }, /* R15 - Left ADC Digital Vol */ - [0x10] = { 0x0000, 0x01FF }, /* R16 - Right ADC Digital Vol */ - [0x12] = { 0x0000, 0x017F }, /* R18 - EQ1 - low shelf */ - [0x13] = { 0x0000, 0x017F }, /* R19 - EQ2 - peak 1 */ - [0x14] = { 0x0000, 0x017F }, /* R20 - EQ3 - peak 2 */ - [0x15] = { 0x0000, 0x017F }, /* R21 - EQ4 - peak 3 */ - [0x16] = { 0x0000, 0x007F }, /* R22 - EQ5 - high shelf */ - [0x18] = { 0x0000, 0x01FF }, /* R24 - DAC Limiter 1 */ - [0x19] = { 0x0000, 0x007F }, /* R25 - DAC Limiter 2 */ - [0x1B] = { 0x0000, 0x01FF }, /* R27 - Notch Filter 1 */ - [0x1C] = { 0x0000, 0x017F }, /* R28 - Notch Filter 2 */ - [0x1D] = { 0x0000, 0x017F }, /* R29 - Notch Filter 3 */ - [0x1E] = { 0x0000, 0x017F }, /* R30 - Notch Filter 4 */ - [0x20] = { 0x0000, 0x01BF }, /* R32 - ALC control 1 */ - [0x21] = { 0x0000, 0x00FF }, /* R33 - ALC control 2 */ - [0x22] = { 0x0000, 0x01FF }, /* R34 - ALC control 3 */ - [0x23] = { 0x0000, 0x000F }, /* R35 - Noise Gate */ - [0x24] = { 0x0000, 0x001F }, /* R36 - PLL N */ - [0x25] = { 0x0000, 0x003F }, /* R37 - PLL K 1 */ - [0x26] = { 0x0000, 0x01FF }, /* R38 - PLL K 2 */ - [0x27] = { 0x0000, 0x01FF }, /* R39 - PLL K 3 */ - [0x29] = { 0x0000, 0x000F }, /* R41 - 3D control */ - [0x2A] = { 0x0000, 0x01E7 }, /* R42 - OUT4 to ADC */ - [0x2B] = { 0x0000, 0x01BF }, /* R43 - Beep control */ - [0x2C] = { 0x0000, 0x0177 }, /* R44 - Input ctrl */ - [0x2D] = { 0x0000, 0x01FF }, /* R45 - Left INP PGA gain ctrl */ - [0x2E] = { 0x0000, 0x01FF }, /* R46 - Right INP PGA gain ctrl */ - [0x2F] = { 0x0000, 0x0177 }, /* R47 - Left ADC BOOST ctrl */ - [0x30] = { 0x0000, 0x0177 }, /* R48 - Right ADC BOOST ctrl */ - [0x31] = { 0x0000, 0x007F }, /* R49 - Output ctrl */ - [0x32] = { 0x0000, 0x01FF }, /* R50 - Left mixer ctrl */ - [0x33] = { 0x0000, 0x01FF }, /* R51 - Right mixer ctrl */ - [0x34] = { 0x0000, 0x01FF }, /* R52 - LOUT1 (HP) volume ctrl */ - [0x35] = { 0x0000, 0x01FF }, /* R53 - ROUT1 (HP) volume ctrl */ - [0x36] = { 0x0000, 0x01FF }, /* R54 - LOUT2 (SPK) volume ctrl */ - [0x37] = { 0x0000, 0x01FF }, /* R55 - ROUT2 (SPK) volume ctrl */ - [0x38] = { 0x0000, 0x004F }, /* R56 - OUT3 mixer ctrl */ - [0x39] = { 0x0000, 0x00FF }, /* R57 - OUT4 (MONO) mix ctrl */ - [0x3D] = { 0x0000, 0x0100 } /* R61 - BIAS CTRL */ -}; - -/* vol/gain update regs */ -static const int vol_update_regs[] = { - WM8983_LEFT_DAC_DIGITAL_VOL, - WM8983_RIGHT_DAC_DIGITAL_VOL, - WM8983_LEFT_ADC_DIGITAL_VOL, - WM8983_RIGHT_ADC_DIGITAL_VOL, - WM8983_LOUT1_HP_VOLUME_CTRL, - WM8983_ROUT1_HP_VOLUME_CTRL, - WM8983_LOUT2_SPK_VOLUME_CTRL, - WM8983_ROUT2_SPK_VOLUME_CTRL, - WM8983_LEFT_INP_PGA_GAIN_CTRL, - WM8983_RIGHT_INP_PGA_GAIN_CTRL -}; - -struct wm8983_priv { - enum snd_soc_control_type control_type; - u32 sysclk; - u32 bclk; -}; - -static const struct { - int div; - int ratio; -} fs_ratios[] = { - { 10, 128 }, - { 15, 192 }, - { 20, 256 }, - { 30, 384 }, - { 40, 512 }, - { 60, 768 }, - { 80, 1024 }, - { 120, 1536 } -}; - -static const int srates[] = { 48000, 32000, 24000, 16000, 12000, 8000 }; - -static const int bclk_divs[] = { - 1, 2, 4, 8, 16, 32 -}; - -static int eqmode_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); -static int eqmode_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); - -static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 50, 1); -static const DECLARE_TLV_DB_SCALE(adc_tlv, -12700, 50, 1); -static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0); -static const DECLARE_TLV_DB_SCALE(lim_thresh_tlv, -600, 100, 0); -static const DECLARE_TLV_DB_SCALE(lim_boost_tlv, 0, 100, 0); -static const DECLARE_TLV_DB_SCALE(alc_min_tlv, -1200, 600, 0); -static const DECLARE_TLV_DB_SCALE(alc_max_tlv, -675, 600, 0); -static const DECLARE_TLV_DB_SCALE(alc_tar_tlv, -2250, 150, 0); -static const DECLARE_TLV_DB_SCALE(pga_vol_tlv, -1200, 75, 0); -static const DECLARE_TLV_DB_SCALE(boost_tlv, -1200, 300, 1); -static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); -static const DECLARE_TLV_DB_SCALE(aux_tlv, -1500, 300, 0); -static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0); -static const DECLARE_TLV_DB_SCALE(pga_boost_tlv, 0, 2000, 0); - -static const char *alc_sel_text[] = { "Off", "Right", "Left", "Stereo" }; -static const SOC_ENUM_SINGLE_DECL(alc_sel, WM8983_ALC_CONTROL_1, 7, - alc_sel_text); - -static const char *alc_mode_text[] = { "ALC", "Limiter" }; -static const SOC_ENUM_SINGLE_DECL(alc_mode, WM8983_ALC_CONTROL_3, 8, - alc_mode_text); - -static const char *filter_mode_text[] = { "Audio", "Application" }; -static const SOC_ENUM_SINGLE_DECL(filter_mode, WM8983_ADC_CONTROL, 7, - filter_mode_text); - -static const char *eq_bw_text[] = { "Narrow", "Wide" }; -static const char *eqmode_text[] = { "Capture", "Playback" }; -static const SOC_ENUM_SINGLE_EXT_DECL(eqmode, eqmode_text); - -static const char *eq1_cutoff_text[] = { - "80Hz", "105Hz", "135Hz", "175Hz" -}; -static const SOC_ENUM_SINGLE_DECL(eq1_cutoff, WM8983_EQ1_LOW_SHELF, 5, - eq1_cutoff_text); -static const char *eq2_cutoff_text[] = { - "230Hz", "300Hz", "385Hz", "500Hz" -}; -static const SOC_ENUM_SINGLE_DECL(eq2_bw, WM8983_EQ2_PEAK_1, 8, eq_bw_text); -static const SOC_ENUM_SINGLE_DECL(eq2_cutoff, WM8983_EQ2_PEAK_1, 5, - eq2_cutoff_text); -static const char *eq3_cutoff_text[] = { - "650Hz", "850Hz", "1.1kHz", "1.4kHz" -}; -static const SOC_ENUM_SINGLE_DECL(eq3_bw, WM8983_EQ3_PEAK_2, 8, eq_bw_text); -static const SOC_ENUM_SINGLE_DECL(eq3_cutoff, WM8983_EQ3_PEAK_2, 5, - eq3_cutoff_text); -static const char *eq4_cutoff_text[] = { - "1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz" -}; -static const SOC_ENUM_SINGLE_DECL(eq4_bw, WM8983_EQ4_PEAK_3, 8, eq_bw_text); -static const SOC_ENUM_SINGLE_DECL(eq4_cutoff, WM8983_EQ4_PEAK_3, 5, - eq4_cutoff_text); -static const char *eq5_cutoff_text[] = { - "5.3kHz", "6.9kHz", "9kHz", "11.7kHz" -}; -static const SOC_ENUM_SINGLE_DECL(eq5_cutoff, WM8983_EQ5_HIGH_SHELF, 5, - eq5_cutoff_text); - -static const char *speaker_mode_text[] = { "Class A/B", "Class D" }; -static const SOC_ENUM_SINGLE_DECL(speaker_mode, 0x17, 8, speaker_mode_text); - -static const char *depth_3d_text[] = { - "Off", - "6.67%", - "13.3%", - "20%", - "26.7%", - "33.3%", - "40%", - "46.6%", - "53.3%", - "60%", - "66.7%", - "73.3%", - "80%", - "86.7%", - "93.3%", - "100%" -}; -static const SOC_ENUM_SINGLE_DECL(depth_3d, WM8983_3D_CONTROL, 0, - depth_3d_text); - -static const struct snd_kcontrol_new wm8983_snd_controls[] = { - SOC_SINGLE("Digital Loopback Switch", WM8983_COMPANDING_CONTROL, - 0, 1, 0), - - SOC_ENUM("ALC Capture Function", alc_sel), - SOC_SINGLE_TLV("ALC Capture Max Volume", WM8983_ALC_CONTROL_1, - 3, 7, 0, alc_max_tlv), - SOC_SINGLE_TLV("ALC Capture Min Volume", WM8983_ALC_CONTROL_1, - 0, 7, 0, alc_min_tlv), - SOC_SINGLE_TLV("ALC Capture Target Volume", WM8983_ALC_CONTROL_2, - 0, 15, 0, alc_tar_tlv), - SOC_SINGLE("ALC Capture Attack", WM8983_ALC_CONTROL_3, 0, 10, 0), - SOC_SINGLE("ALC Capture Hold", WM8983_ALC_CONTROL_2, 4, 10, 0), - SOC_SINGLE("ALC Capture Decay", WM8983_ALC_CONTROL_3, 4, 10, 0), - SOC_ENUM("ALC Mode", alc_mode), - SOC_SINGLE("ALC Capture NG Switch", WM8983_NOISE_GATE, - 3, 1, 0), - SOC_SINGLE("ALC Capture NG Threshold", WM8983_NOISE_GATE, - 0, 7, 1), - - SOC_DOUBLE_R_TLV("Capture Volume", WM8983_LEFT_ADC_DIGITAL_VOL, - WM8983_RIGHT_ADC_DIGITAL_VOL, 0, 255, 0, adc_tlv), - SOC_DOUBLE_R("Capture PGA ZC Switch", WM8983_LEFT_INP_PGA_GAIN_CTRL, - WM8983_RIGHT_INP_PGA_GAIN_CTRL, 7, 1, 0), - SOC_DOUBLE_R_TLV("Capture PGA Volume", WM8983_LEFT_INP_PGA_GAIN_CTRL, - WM8983_RIGHT_INP_PGA_GAIN_CTRL, 0, 63, 0, pga_vol_tlv), - - SOC_DOUBLE_R_TLV("Capture PGA Boost Volume", - WM8983_LEFT_ADC_BOOST_CTRL, WM8983_RIGHT_ADC_BOOST_CTRL, - 8, 1, 0, pga_boost_tlv), - - SOC_DOUBLE("ADC Inversion Switch", WM8983_ADC_CONTROL, 0, 1, 1, 0), - SOC_SINGLE("ADC 128x Oversampling Switch", WM8983_ADC_CONTROL, 8, 1, 0), - - SOC_DOUBLE_R_TLV("Playback Volume", WM8983_LEFT_DAC_DIGITAL_VOL, - WM8983_RIGHT_DAC_DIGITAL_VOL, 0, 255, 0, dac_tlv), - - SOC_SINGLE("DAC Playback Limiter Switch", WM8983_DAC_LIMITER_1, 8, 1, 0), - SOC_SINGLE("DAC Playback Limiter Decay", WM8983_DAC_LIMITER_1, 4, 10, 0), - SOC_SINGLE("DAC Playback Limiter Attack", WM8983_DAC_LIMITER_1, 0, 11, 0), - SOC_SINGLE_TLV("DAC Playback Limiter Threshold", WM8983_DAC_LIMITER_2, - 4, 7, 1, lim_thresh_tlv), - SOC_SINGLE_TLV("DAC Playback Limiter Boost Volume", WM8983_DAC_LIMITER_2, - 0, 12, 0, lim_boost_tlv), - SOC_DOUBLE("DAC Inversion Switch", WM8983_DAC_CONTROL, 0, 1, 1, 0), - SOC_SINGLE("DAC Auto Mute Switch", WM8983_DAC_CONTROL, 2, 1, 0), - SOC_SINGLE("DAC 128x Oversampling Switch", WM8983_DAC_CONTROL, 3, 1, 0), - - SOC_DOUBLE_R_TLV("Headphone Playback Volume", WM8983_LOUT1_HP_VOLUME_CTRL, - WM8983_ROUT1_HP_VOLUME_CTRL, 0, 63, 0, out_tlv), - SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8983_LOUT1_HP_VOLUME_CTRL, - WM8983_ROUT1_HP_VOLUME_CTRL, 7, 1, 0), - SOC_DOUBLE_R("Headphone Switch", WM8983_LOUT1_HP_VOLUME_CTRL, - WM8983_ROUT1_HP_VOLUME_CTRL, 6, 1, 1), - - SOC_DOUBLE_R_TLV("Speaker Playback Volume", WM8983_LOUT2_SPK_VOLUME_CTRL, - WM8983_ROUT2_SPK_VOLUME_CTRL, 0, 63, 0, out_tlv), - SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8983_LOUT2_SPK_VOLUME_CTRL, - WM8983_ROUT2_SPK_VOLUME_CTRL, 7, 1, 0), - SOC_DOUBLE_R("Speaker Switch", WM8983_LOUT2_SPK_VOLUME_CTRL, - WM8983_ROUT2_SPK_VOLUME_CTRL, 6, 1, 1), - - SOC_SINGLE("OUT3 Switch", WM8983_OUT3_MIXER_CTRL, - 6, 1, 1), - - SOC_SINGLE("OUT4 Switch", WM8983_OUT4_MONO_MIX_CTRL, - 6, 1, 1), - - SOC_SINGLE("High Pass Filter Switch", WM8983_ADC_CONTROL, 8, 1, 0), - SOC_ENUM("High Pass Filter Mode", filter_mode), - SOC_SINGLE("High Pass Filter Cutoff", WM8983_ADC_CONTROL, 4, 7, 0), - - SOC_DOUBLE_R_TLV("Aux Bypass Volume", - WM8983_LEFT_MIXER_CTRL, WM8983_RIGHT_MIXER_CTRL, 6, 7, 0, - aux_tlv), - - SOC_DOUBLE_R_TLV("Input PGA Bypass Volume", - WM8983_LEFT_MIXER_CTRL, WM8983_RIGHT_MIXER_CTRL, 2, 7, 0, - bypass_tlv), - - SOC_ENUM_EXT("Equalizer Function", eqmode, eqmode_get, eqmode_put), - SOC_ENUM("EQ1 Cutoff", eq1_cutoff), - SOC_SINGLE_TLV("EQ1 Volume", WM8983_EQ1_LOW_SHELF, 0, 24, 1, eq_tlv), - SOC_ENUM("EQ2 Bandwith", eq2_bw), - SOC_ENUM("EQ2 Cutoff", eq2_cutoff), - SOC_SINGLE_TLV("EQ2 Volume", WM8983_EQ2_PEAK_1, 0, 24, 1, eq_tlv), - SOC_ENUM("EQ3 Bandwith", eq3_bw), - SOC_ENUM("EQ3 Cutoff", eq3_cutoff), - SOC_SINGLE_TLV("EQ3 Volume", WM8983_EQ3_PEAK_2, 0, 24, 1, eq_tlv), - SOC_ENUM("EQ4 Bandwith", eq4_bw), - SOC_ENUM("EQ4 Cutoff", eq4_cutoff), - SOC_SINGLE_TLV("EQ4 Volume", WM8983_EQ4_PEAK_3, 0, 24, 1, eq_tlv), - SOC_ENUM("EQ5 Cutoff", eq5_cutoff), - SOC_SINGLE_TLV("EQ5 Volume", WM8983_EQ5_HIGH_SHELF, 0, 24, 1, eq_tlv), - - SOC_ENUM("3D Depth", depth_3d), - - SOC_ENUM("Speaker Mode", speaker_mode) -}; - -static const struct snd_kcontrol_new left_out_mixer[] = { - SOC_DAPM_SINGLE("Line Switch", WM8983_LEFT_MIXER_CTRL, 1, 1, 0), - SOC_DAPM_SINGLE("Aux Switch", WM8983_LEFT_MIXER_CTRL, 5, 1, 0), - SOC_DAPM_SINGLE("PCM Switch", WM8983_LEFT_MIXER_CTRL, 0, 1, 0), -}; - -static const struct snd_kcontrol_new right_out_mixer[] = { - SOC_DAPM_SINGLE("Line Switch", WM8983_RIGHT_MIXER_CTRL, 1, 1, 0), - SOC_DAPM_SINGLE("Aux Switch", WM8983_RIGHT_MIXER_CTRL, 5, 1, 0), - SOC_DAPM_SINGLE("PCM Switch", WM8983_RIGHT_MIXER_CTRL, 0, 1, 0), -}; - -static const struct snd_kcontrol_new left_input_mixer[] = { - SOC_DAPM_SINGLE("L2 Switch", WM8983_INPUT_CTRL, 2, 1, 0), - SOC_DAPM_SINGLE("MicN Switch", WM8983_INPUT_CTRL, 1, 1, 0), - SOC_DAPM_SINGLE("MicP Switch", WM8983_INPUT_CTRL, 0, 1, 0), -}; - -static const struct snd_kcontrol_new right_input_mixer[] = { - SOC_DAPM_SINGLE("R2 Switch", WM8983_INPUT_CTRL, 6, 1, 0), - SOC_DAPM_SINGLE("MicN Switch", WM8983_INPUT_CTRL, 5, 1, 0), - SOC_DAPM_SINGLE("MicP Switch", WM8983_INPUT_CTRL, 4, 1, 0), -}; - -static const struct snd_kcontrol_new left_boost_mixer[] = { - SOC_DAPM_SINGLE_TLV("L2 Volume", WM8983_LEFT_ADC_BOOST_CTRL, - 4, 7, 0, boost_tlv), - SOC_DAPM_SINGLE_TLV("AUXL Volume", WM8983_LEFT_ADC_BOOST_CTRL, - 0, 7, 0, boost_tlv) -}; - -static const struct snd_kcontrol_new out3_mixer[] = { - SOC_DAPM_SINGLE("LMIX2OUT3 Switch", WM8983_OUT3_MIXER_CTRL, - 1, 1, 0), - SOC_DAPM_SINGLE("LDAC2OUT3 Switch", WM8983_OUT3_MIXER_CTRL, - 0, 1, 0), -}; - -static const struct snd_kcontrol_new out4_mixer[] = { - SOC_DAPM_SINGLE("LMIX2OUT4 Switch", WM8983_OUT4_MONO_MIX_CTRL, - 4, 1, 0), - SOC_DAPM_SINGLE("RMIX2OUT4 Switch", WM8983_OUT4_MONO_MIX_CTRL, - 1, 1, 0), - SOC_DAPM_SINGLE("LDAC2OUT4 Switch", WM8983_OUT4_MONO_MIX_CTRL, - 3, 1, 0), - SOC_DAPM_SINGLE("RDAC2OUT4 Switch", WM8983_OUT4_MONO_MIX_CTRL, - 0, 1, 0), -}; - -static const struct snd_kcontrol_new right_boost_mixer[] = { - SOC_DAPM_SINGLE_TLV("R2 Volume", WM8983_RIGHT_ADC_BOOST_CTRL, - 4, 7, 0, boost_tlv), - SOC_DAPM_SINGLE_TLV("AUXR Volume", WM8983_RIGHT_ADC_BOOST_CTRL, - 0, 7, 0, boost_tlv) -}; - -static const struct snd_soc_dapm_widget wm8983_dapm_widgets[] = { - SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8983_POWER_MANAGEMENT_3, - 0, 0), - SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8983_POWER_MANAGEMENT_3, - 1, 0), - SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8983_POWER_MANAGEMENT_2, - 0, 0), - SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8983_POWER_MANAGEMENT_2, - 1, 0), - - SND_SOC_DAPM_MIXER("Left Output Mixer", WM8983_POWER_MANAGEMENT_3, - 2, 0, left_out_mixer, ARRAY_SIZE(left_out_mixer)), - SND_SOC_DAPM_MIXER("Right Output Mixer", WM8983_POWER_MANAGEMENT_3, - 3, 0, right_out_mixer, ARRAY_SIZE(right_out_mixer)), - - SND_SOC_DAPM_MIXER("Left Input Mixer", WM8983_POWER_MANAGEMENT_2, - 2, 0, left_input_mixer, ARRAY_SIZE(left_input_mixer)), - SND_SOC_DAPM_MIXER("Right Input Mixer", WM8983_POWER_MANAGEMENT_2, - 3, 0, right_input_mixer, ARRAY_SIZE(right_input_mixer)), - - SND_SOC_DAPM_MIXER("Left Boost Mixer", WM8983_POWER_MANAGEMENT_2, - 4, 0, left_boost_mixer, ARRAY_SIZE(left_boost_mixer)), - SND_SOC_DAPM_MIXER("Right Boost Mixer", WM8983_POWER_MANAGEMENT_2, - 5, 0, right_boost_mixer, ARRAY_SIZE(right_boost_mixer)), - - SND_SOC_DAPM_MIXER("OUT3 Mixer", WM8983_POWER_MANAGEMENT_1, - 6, 0, out3_mixer, ARRAY_SIZE(out3_mixer)), - - SND_SOC_DAPM_MIXER("OUT4 Mixer", WM8983_POWER_MANAGEMENT_1, - 7, 0, out4_mixer, ARRAY_SIZE(out4_mixer)), - - SND_SOC_DAPM_PGA("Left Capture PGA", WM8983_LEFT_INP_PGA_GAIN_CTRL, - 6, 1, NULL, 0), - SND_SOC_DAPM_PGA("Right Capture PGA", WM8983_RIGHT_INP_PGA_GAIN_CTRL, - 6, 1, NULL, 0), - - SND_SOC_DAPM_PGA("Left Headphone Out", WM8983_POWER_MANAGEMENT_2, - 7, 0, NULL, 0), - SND_SOC_DAPM_PGA("Right Headphone Out", WM8983_POWER_MANAGEMENT_2, - 8, 0, NULL, 0), - - SND_SOC_DAPM_PGA("Left Speaker Out", WM8983_POWER_MANAGEMENT_3, - 5, 0, NULL, 0), - SND_SOC_DAPM_PGA("Right Speaker Out", WM8983_POWER_MANAGEMENT_3, - 6, 0, NULL, 0), - - SND_SOC_DAPM_PGA("OUT3 Out", WM8983_POWER_MANAGEMENT_3, - 7, 0, NULL, 0), - - SND_SOC_DAPM_PGA("OUT4 Out", WM8983_POWER_MANAGEMENT_3, - 8, 0, NULL, 0), - - SND_SOC_DAPM_MICBIAS("Mic Bias", WM8983_POWER_MANAGEMENT_1, 4, 0), - - SND_SOC_DAPM_INPUT("LIN"), - SND_SOC_DAPM_INPUT("LIP"), - SND_SOC_DAPM_INPUT("RIN"), - SND_SOC_DAPM_INPUT("RIP"), - SND_SOC_DAPM_INPUT("AUXL"), - SND_SOC_DAPM_INPUT("AUXR"), - SND_SOC_DAPM_INPUT("L2"), - SND_SOC_DAPM_INPUT("R2"), - SND_SOC_DAPM_OUTPUT("HPL"), - SND_SOC_DAPM_OUTPUT("HPR"), - SND_SOC_DAPM_OUTPUT("SPKL"), - SND_SOC_DAPM_OUTPUT("SPKR"), - SND_SOC_DAPM_OUTPUT("OUT3"), - SND_SOC_DAPM_OUTPUT("OUT4") -}; - -static const struct snd_soc_dapm_route wm8983_audio_map[] = { - { "OUT3 Mixer", "LMIX2OUT3 Switch", "Left Output Mixer" }, - { "OUT3 Mixer", "LDAC2OUT3 Switch", "Left DAC" }, - - { "OUT3 Out", NULL, "OUT3 Mixer" }, - { "OUT3", NULL, "OUT3 Out" }, - - { "OUT4 Mixer", "LMIX2OUT4 Switch", "Left Output Mixer" }, - { "OUT4 Mixer", "RMIX2OUT4 Switch", "Right Output Mixer" }, - { "OUT4 Mixer", "LDAC2OUT4 Switch", "Left DAC" }, - { "OUT4 Mixer", "RDAC2OUT4 Switch", "Right DAC" }, - - { "OUT4 Out", NULL, "OUT4 Mixer" }, - { "OUT4", NULL, "OUT4 Out" }, - - { "Right Output Mixer", "PCM Switch", "Right DAC" }, - { "Right Output Mixer", "Aux Switch", "AUXR" }, - { "Right Output Mixer", "Line Switch", "Right Boost Mixer" }, - - { "Left Output Mixer", "PCM Switch", "Left DAC" }, - { "Left Output Mixer", "Aux Switch", "AUXL" }, - { "Left Output Mixer", "Line Switch", "Left Boost Mixer" }, - - { "Right Headphone Out", NULL, "Right Output Mixer" }, - { "HPR", NULL, "Right Headphone Out" }, - - { "Left Headphone Out", NULL, "Left Output Mixer" }, - { "HPL", NULL, "Left Headphone Out" }, - - { "Right Speaker Out", NULL, "Right Output Mixer" }, - { "SPKR", NULL, "Right Speaker Out" }, - - { "Left Speaker Out", NULL, "Left Output Mixer" }, - { "SPKL", NULL, "Left Speaker Out" }, - - { "Right ADC", NULL, "Right Boost Mixer" }, - - { "Right Boost Mixer", "AUXR Volume", "AUXR" }, - { "Right Boost Mixer", NULL, "Right Capture PGA" }, - { "Right Boost Mixer", "R2 Volume", "R2" }, - - { "Left ADC", NULL, "Left Boost Mixer" }, - - { "Left Boost Mixer", "AUXL Volume", "AUXL" }, - { "Left Boost Mixer", NULL, "Left Capture PGA" }, - { "Left Boost Mixer", "L2 Volume", "L2" }, - - { "Right Capture PGA", NULL, "Right Input Mixer" }, - { "Left Capture PGA", NULL, "Left Input Mixer" }, - - { "Right Input Mixer", "R2 Switch", "R2" }, - { "Right Input Mixer", "MicN Switch", "RIN" }, - { "Right Input Mixer", "MicP Switch", "RIP" }, - - { "Left Input Mixer", "L2 Switch", "L2" }, - { "Left Input Mixer", "MicN Switch", "LIN" }, - { "Left Input Mixer", "MicP Switch", "LIP" }, -}; - -static int eqmode_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int reg; - - reg = snd_soc_read(codec, WM8983_EQ1_LOW_SHELF); - if (reg & WM8983_EQ3DMODE) - ucontrol->value.integer.value[0] = 1; - else - ucontrol->value.integer.value[0] = 0; - - return 0; -} - -static int eqmode_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int regpwr2, regpwr3; - unsigned int reg_eq; - - if (ucontrol->value.integer.value[0] != 0 - && ucontrol->value.integer.value[0] != 1) - return -EINVAL; - - reg_eq = snd_soc_read(codec, WM8983_EQ1_LOW_SHELF); - switch ((reg_eq & WM8983_EQ3DMODE) >> WM8983_EQ3DMODE_SHIFT) { - case 0: - if (!ucontrol->value.integer.value[0]) - return 0; - break; - case 1: - if (ucontrol->value.integer.value[0]) - return 0; - break; - } - - regpwr2 = snd_soc_read(codec, WM8983_POWER_MANAGEMENT_2); - regpwr3 = snd_soc_read(codec, WM8983_POWER_MANAGEMENT_3); - /* disable the DACs and ADCs */ - snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_2, - WM8983_ADCENR_MASK | WM8983_ADCENL_MASK, 0); - snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_3, - WM8983_DACENR_MASK | WM8983_DACENL_MASK, 0); - /* set the desired eqmode */ - snd_soc_update_bits(codec, WM8983_EQ1_LOW_SHELF, - WM8983_EQ3DMODE_MASK, - ucontrol->value.integer.value[0] - << WM8983_EQ3DMODE_SHIFT); - /* restore DAC/ADC configuration */ - snd_soc_write(codec, WM8983_POWER_MANAGEMENT_2, regpwr2); - snd_soc_write(codec, WM8983_POWER_MANAGEMENT_3, regpwr3); - return 0; -} - -static int wm8983_readable(struct snd_soc_codec *codec, unsigned int reg) -{ - if (reg > WM8983_MAX_REGISTER) - return 0; - - return wm8983_access_masks[reg].read != 0; -} - -static int wm8983_dac_mute(struct snd_soc_dai *dai, int mute) -{ - struct snd_soc_codec *codec = dai->codec; - - return snd_soc_update_bits(codec, WM8983_DAC_CONTROL, - WM8983_SOFTMUTE_MASK, - !!mute << WM8983_SOFTMUTE_SHIFT); -} - -static int wm8983_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) -{ - struct snd_soc_codec *codec = dai->codec; - u16 format, master, bcp, lrp; - - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - format = 0x2; - break; - case SND_SOC_DAIFMT_RIGHT_J: - format = 0x0; - break; - case SND_SOC_DAIFMT_LEFT_J: - format = 0x1; - break; - case SND_SOC_DAIFMT_DSP_A: - case SND_SOC_DAIFMT_DSP_B: - format = 0x3; - break; - default: - dev_err(dai->dev, "Unknown dai format\n"); - return -EINVAL; - } - - snd_soc_update_bits(codec, WM8983_AUDIO_INTERFACE, - WM8983_FMT_MASK, format << WM8983_FMT_SHIFT); - - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - master = 1; - break; - case SND_SOC_DAIFMT_CBS_CFS: - master = 0; - break; - default: - dev_err(dai->dev, "Unknown master/slave configuration\n"); - return -EINVAL; - } - - snd_soc_update_bits(codec, WM8983_CLOCK_GEN_CONTROL, - WM8983_MS_MASK, master << WM8983_MS_SHIFT); - - /* FIXME: We don't currently support DSP A/B modes */ - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_DSP_A: - case SND_SOC_DAIFMT_DSP_B: - dev_err(dai->dev, "DSP A/B modes are not supported\n"); - return -EINVAL; - default: - break; - } - - bcp = lrp = 0; - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - break; - case SND_SOC_DAIFMT_IB_IF: - bcp = lrp = 1; - break; - case SND_SOC_DAIFMT_IB_NF: - bcp = 1; - break; - case SND_SOC_DAIFMT_NB_IF: - lrp = 1; - break; - default: - dev_err(dai->dev, "Unknown polarity configuration\n"); - return -EINVAL; - } - - snd_soc_update_bits(codec, WM8983_AUDIO_INTERFACE, - WM8983_LRCP_MASK, lrp << WM8983_LRCP_SHIFT); - snd_soc_update_bits(codec, WM8983_AUDIO_INTERFACE, - WM8983_BCP_MASK, bcp << WM8983_BCP_SHIFT); - return 0; -} - -static int wm8983_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - int i; - struct snd_soc_codec *codec = dai->codec; - struct wm8983_priv *wm8983 = snd_soc_codec_get_drvdata(codec); - u16 blen, srate_idx; - u32 tmp; - int srate_best; - int ret; - - ret = snd_soc_params_to_bclk(params); - if (ret < 0) { - dev_err(codec->dev, "Failed to convert params to bclk: %d\n", ret); - return ret; - } - - wm8983->bclk = ret; - - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: - blen = 0x0; - break; - case SNDRV_PCM_FORMAT_S20_3LE: - blen = 0x1; - break; - case SNDRV_PCM_FORMAT_S24_LE: - blen = 0x2; - break; - case SNDRV_PCM_FORMAT_S32_LE: - blen = 0x3; - break; - default: - dev_err(dai->dev, "Unsupported word length %u\n", - params_format(params)); - return -EINVAL; - } - - snd_soc_update_bits(codec, WM8983_AUDIO_INTERFACE, - WM8983_WL_MASK, blen << WM8983_WL_SHIFT); - - /* - * match to the nearest possible sample rate and rely - * on the array index to configure the SR register - */ - srate_idx = 0; - srate_best = abs(srates[0] - params_rate(params)); - for (i = 1; i < ARRAY_SIZE(srates); ++i) { - if (abs(srates[i] - params_rate(params)) >= srate_best) - continue; - srate_idx = i; - srate_best = abs(srates[i] - params_rate(params)); - } - - dev_dbg(dai->dev, "Selected SRATE = %d\n", srates[srate_idx]); - snd_soc_update_bits(codec, WM8983_ADDITIONAL_CONTROL, - WM8983_SR_MASK, srate_idx << WM8983_SR_SHIFT); - - dev_dbg(dai->dev, "Target BCLK = %uHz\n", wm8983->bclk); - dev_dbg(dai->dev, "SYSCLK = %uHz\n", wm8983->sysclk); - - for (i = 0; i < ARRAY_SIZE(fs_ratios); ++i) { - if (wm8983->sysclk / params_rate(params) - == fs_ratios[i].ratio) - break; - } - - if (i == ARRAY_SIZE(fs_ratios)) { - dev_err(dai->dev, "Unable to configure MCLK ratio %u/%u\n", - wm8983->sysclk, params_rate(params)); - return -EINVAL; - } - - dev_dbg(dai->dev, "MCLK ratio = %dfs\n", fs_ratios[i].ratio); - snd_soc_update_bits(codec, WM8983_CLOCK_GEN_CONTROL, - WM8983_MCLKDIV_MASK, i << WM8983_MCLKDIV_SHIFT); - - /* select the appropriate bclk divider */ - tmp = (wm8983->sysclk / fs_ratios[i].div) * 10; - for (i = 0; i < ARRAY_SIZE(bclk_divs); ++i) { - if (wm8983->bclk == tmp / bclk_divs[i]) - break; - } - - if (i == ARRAY_SIZE(bclk_divs)) { - dev_err(dai->dev, "No matching BCLK divider found\n"); - return -EINVAL; - } - - dev_dbg(dai->dev, "BCLK div = %d\n", i); - snd_soc_update_bits(codec, WM8983_CLOCK_GEN_CONTROL, - WM8983_BCLKDIV_MASK, i << WM8983_BCLKDIV_SHIFT); - - return 0; -} - -struct pll_div { - u32 div2:1; - u32 n:4; - u32 k:24; -}; - -#define FIXED_PLL_SIZE ((1ULL << 24) * 10) -static int pll_factors(struct pll_div *pll_div, unsigned int target, - unsigned int source) -{ - u64 Kpart; - unsigned long int K, Ndiv, Nmod; - - pll_div->div2 = 0; - Ndiv = target / source; - if (Ndiv < 6) { - source >>= 1; - pll_div->div2 = 1; - Ndiv = target / source; - } - - if (Ndiv < 6 || Ndiv > 12) { - printk(KERN_ERR "%s: WM8983 N value is not within" - " the recommended range: %lu\n", __func__, Ndiv); - return -EINVAL; - } - pll_div->n = Ndiv; - - Nmod = target % source; - Kpart = FIXED_PLL_SIZE * (u64)Nmod; - - do_div(Kpart, source); - - K = Kpart & 0xffffffff; - if ((K % 10) >= 5) - K += 5; - K /= 10; - pll_div->k = K; - return 0; -} - -static int wm8983_set_pll(struct snd_soc_dai *dai, int pll_id, - int source, unsigned int freq_in, - unsigned int freq_out) -{ - int ret; - struct snd_soc_codec *codec; - struct pll_div pll_div; - - codec = dai->codec; - if (freq_in && freq_out) { - ret = pll_factors(&pll_div, freq_out * 4 * 2, freq_in); - if (ret) - return ret; - } - - /* disable the PLL before re-programming it */ - snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1, - WM8983_PLLEN_MASK, 0); - - if (!freq_in || !freq_out) - return 0; - - /* set PLLN and PRESCALE */ - snd_soc_write(codec, WM8983_PLL_N, - (pll_div.div2 << WM8983_PLL_PRESCALE_SHIFT) - | pll_div.n); - /* set PLLK */ - snd_soc_write(codec, WM8983_PLL_K_3, pll_div.k & 0x1ff); - snd_soc_write(codec, WM8983_PLL_K_2, (pll_div.k >> 9) & 0x1ff); - snd_soc_write(codec, WM8983_PLL_K_1, (pll_div.k >> 18)); - /* enable the PLL */ - snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1, - WM8983_PLLEN_MASK, WM8983_PLLEN); - return 0; -} - -static int wm8983_set_sysclk(struct snd_soc_dai *dai, - int clk_id, unsigned int freq, int dir) -{ - struct snd_soc_codec *codec = dai->codec; - struct wm8983_priv *wm8983 = snd_soc_codec_get_drvdata(codec); - - switch (clk_id) { - case WM8983_CLKSRC_MCLK: - snd_soc_update_bits(codec, WM8983_CLOCK_GEN_CONTROL, - WM8983_CLKSEL_MASK, 0); - break; - case WM8983_CLKSRC_PLL: - snd_soc_update_bits(codec, WM8983_CLOCK_GEN_CONTROL, - WM8983_CLKSEL_MASK, WM8983_CLKSEL); - break; - default: - dev_err(dai->dev, "Unknown clock source: %d\n", clk_id); - return -EINVAL; - } - - wm8983->sysclk = freq; - return 0; -} - -static int wm8983_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) -{ - int ret; - - switch (level) { - case SND_SOC_BIAS_ON: - case SND_SOC_BIAS_PREPARE: - /* VMID at 100k */ - snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1, - WM8983_VMIDSEL_MASK, - 1 << WM8983_VMIDSEL_SHIFT); - break; - case SND_SOC_BIAS_STANDBY: - if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { - ret = snd_soc_cache_sync(codec); - if (ret < 0) { - dev_err(codec->dev, "Failed to sync cache: %d\n", ret); - return ret; - } - /* enable anti-pop features */ - snd_soc_update_bits(codec, WM8983_OUT4_TO_ADC, - WM8983_POBCTRL_MASK | WM8983_DELEN_MASK, - WM8983_POBCTRL | WM8983_DELEN); - /* enable thermal shutdown */ - snd_soc_update_bits(codec, WM8983_OUTPUT_CTRL, - WM8983_TSDEN_MASK, WM8983_TSDEN); - /* enable BIASEN */ - snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1, - WM8983_BIASEN_MASK, WM8983_BIASEN); - /* VMID at 100k */ - snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1, - WM8983_VMIDSEL_MASK, - 1 << WM8983_VMIDSEL_SHIFT); - msleep(250); - /* disable anti-pop features */ - snd_soc_update_bits(codec, WM8983_OUT4_TO_ADC, - WM8983_POBCTRL_MASK | - WM8983_DELEN_MASK, 0); - } - - /* VMID at 500k */ - snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1, - WM8983_VMIDSEL_MASK, - 2 << WM8983_VMIDSEL_SHIFT); - break; - case SND_SOC_BIAS_OFF: - /* disable thermal shutdown */ - snd_soc_update_bits(codec, WM8983_OUTPUT_CTRL, - WM8983_TSDEN_MASK, 0); - /* disable VMIDSEL and BIASEN */ - snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1, - WM8983_VMIDSEL_MASK | WM8983_BIASEN_MASK, - 0); - /* wait for VMID to discharge */ - msleep(100); - snd_soc_write(codec, WM8983_POWER_MANAGEMENT_1, 0); - snd_soc_write(codec, WM8983_POWER_MANAGEMENT_2, 0); - snd_soc_write(codec, WM8983_POWER_MANAGEMENT_3, 0); - break; - } - - codec->dapm.bias_level = level; - return 0; -} - -#ifdef CONFIG_PM -static int wm8983_suspend(struct snd_soc_codec *codec, pm_message_t state) -{ - wm8983_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int wm8983_resume(struct snd_soc_codec *codec) -{ - wm8983_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} -#else -#define wm8983_suspend NULL -#define wm8983_resume NULL -#endif - -static int wm8983_remove(struct snd_soc_codec *codec) -{ - wm8983_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int wm8983_probe(struct snd_soc_codec *codec) -{ - int ret; - struct wm8983_priv *wm8983 = snd_soc_codec_get_drvdata(codec); - int i; - - ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8983->control_type); - if (ret < 0) { - dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret); - return ret; - } - - ret = snd_soc_write(codec, WM8983_SOFTWARE_RESET, 0x8983); - if (ret < 0) { - dev_err(codec->dev, "Failed to issue reset: %d\n", ret); - return ret; - } - - /* set the vol/gain update bits */ - for (i = 0; i < ARRAY_SIZE(vol_update_regs); ++i) - snd_soc_update_bits(codec, vol_update_regs[i], - 0x100, 0x100); - - /* mute all outputs and set PGAs to minimum gain */ - for (i = WM8983_LOUT1_HP_VOLUME_CTRL; - i <= WM8983_OUT4_MONO_MIX_CTRL; ++i) - snd_soc_update_bits(codec, i, 0x40, 0x40); - - /* enable soft mute */ - snd_soc_update_bits(codec, WM8983_DAC_CONTROL, - WM8983_SOFTMUTE_MASK, - WM8983_SOFTMUTE); - - /* enable BIASCUT */ - snd_soc_update_bits(codec, WM8983_BIAS_CTRL, - WM8983_BIASCUT, WM8983_BIASCUT); - return 0; -} - -static struct snd_soc_dai_ops wm8983_dai_ops = { - .digital_mute = wm8983_dac_mute, - .hw_params = wm8983_hw_params, - .set_fmt = wm8983_set_fmt, - .set_sysclk = wm8983_set_sysclk, - .set_pll = wm8983_set_pll -}; - -#define WM8983_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) - -static struct snd_soc_dai_driver wm8983_dai = { - .name = "wm8983-hifi", - .playback = { - .stream_name = "Playback", - .channels_min = 2, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_48000, - .formats = WM8983_FORMATS, - }, - .capture = { - .stream_name = "Capture", - .channels_min = 2, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_48000, - .formats = WM8983_FORMATS, - }, - .ops = &wm8983_dai_ops, - .symmetric_rates = 1 -}; - -static struct snd_soc_codec_driver soc_codec_dev_wm8983 = { - .probe = wm8983_probe, - .remove = wm8983_remove, - .suspend = wm8983_suspend, - .resume = wm8983_resume, - .set_bias_level = wm8983_set_bias_level, - .reg_cache_size = ARRAY_SIZE(wm8983_reg_defs), - .reg_word_size = sizeof(u16), - .reg_cache_default = wm8983_reg_defs, - .controls = wm8983_snd_controls, - .num_controls = ARRAY_SIZE(wm8983_snd_controls), - .dapm_widgets = wm8983_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8983_dapm_widgets), - .dapm_routes = wm8983_audio_map, - .num_dapm_routes = ARRAY_SIZE(wm8983_audio_map), - .readable_register = wm8983_readable -}; - -#if defined(CONFIG_SPI_MASTER) -static int __devinit wm8983_spi_probe(struct spi_device *spi) -{ - struct wm8983_priv *wm8983; - int ret; - - wm8983 = kzalloc(sizeof *wm8983, GFP_KERNEL); - if (!wm8983) - return -ENOMEM; - - wm8983->control_type = SND_SOC_SPI; - spi_set_drvdata(spi, wm8983); - - ret = snd_soc_register_codec(&spi->dev, - &soc_codec_dev_wm8983, &wm8983_dai, 1); - if (ret < 0) - kfree(wm8983); - return ret; -} - -static int __devexit wm8983_spi_remove(struct spi_device *spi) -{ - snd_soc_unregister_codec(&spi->dev); - kfree(spi_get_drvdata(spi)); - return 0; -} - -static struct spi_driver wm8983_spi_driver = { - .driver = { - .name = "wm8983", - .owner = THIS_MODULE, - }, - .probe = wm8983_spi_probe, - .remove = __devexit_p(wm8983_spi_remove) -}; -#endif - -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -static __devinit int wm8983_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) -{ - struct wm8983_priv *wm8983; - int ret; - - wm8983 = kzalloc(sizeof *wm8983, GFP_KERNEL); - if (!wm8983) - return -ENOMEM; - - wm8983->control_type = SND_SOC_I2C; - i2c_set_clientdata(i2c, wm8983); - - ret = snd_soc_register_codec(&i2c->dev, - &soc_codec_dev_wm8983, &wm8983_dai, 1); - if (ret < 0) - kfree(wm8983); - return ret; -} - -static __devexit int wm8983_i2c_remove(struct i2c_client *client) -{ - snd_soc_unregister_codec(&client->dev); - kfree(i2c_get_clientdata(client)); - return 0; -} - -static const struct i2c_device_id wm8983_i2c_id[] = { - { "wm8983", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, wm8983_i2c_id); - -static struct i2c_driver wm8983_i2c_driver = { - .driver = { - .name = "wm8983", - .owner = THIS_MODULE, - }, - .probe = wm8983_i2c_probe, - .remove = __devexit_p(wm8983_i2c_remove), - .id_table = wm8983_i2c_id -}; -#endif - -static int __init wm8983_modinit(void) -{ - int ret = 0; - -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - ret = i2c_add_driver(&wm8983_i2c_driver); - if (ret) { - printk(KERN_ERR "Failed to register wm8983 I2C driver: %d\n", - ret); - } -#endif -#if defined(CONFIG_SPI_MASTER) - ret = spi_register_driver(&wm8983_spi_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register wm8983 SPI driver: %d\n", - ret); - } -#endif - return ret; -} -module_init(wm8983_modinit); - -static void __exit wm8983_exit(void) -{ -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - i2c_del_driver(&wm8983_i2c_driver); -#endif -#if defined(CONFIG_SPI_MASTER) - spi_unregister_driver(&wm8983_spi_driver); -#endif -} -module_exit(wm8983_exit); - -MODULE_DESCRIPTION("ASoC WM8983 driver"); -MODULE_AUTHOR("Dimitris Papastamos "); -MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/codecs/wm8983.h b/trunk/sound/soc/codecs/wm8983.h deleted file mode 100644 index 71ee619c2742..000000000000 --- a/trunk/sound/soc/codecs/wm8983.h +++ /dev/null @@ -1,1029 +0,0 @@ -/* - * wm8983.h -- WM8983 ALSA SoC Audio driver - * - * Copyright 2011 Wolfson Microelectronics plc - * - * Author: Dimitris Papastamos - * - * 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. - */ - -#ifndef _WM8983_H -#define _WM8983_H - -/* - * Register values. - */ -#define WM8983_SOFTWARE_RESET 0x00 -#define WM8983_POWER_MANAGEMENT_1 0x01 -#define WM8983_POWER_MANAGEMENT_2 0x02 -#define WM8983_POWER_MANAGEMENT_3 0x03 -#define WM8983_AUDIO_INTERFACE 0x04 -#define WM8983_COMPANDING_CONTROL 0x05 -#define WM8983_CLOCK_GEN_CONTROL 0x06 -#define WM8983_ADDITIONAL_CONTROL 0x07 -#define WM8983_GPIO_CONTROL 0x08 -#define WM8983_JACK_DETECT_CONTROL_1 0x09 -#define WM8983_DAC_CONTROL 0x0A -#define WM8983_LEFT_DAC_DIGITAL_VOL 0x0B -#define WM8983_RIGHT_DAC_DIGITAL_VOL 0x0C -#define WM8983_JACK_DETECT_CONTROL_2 0x0D -#define WM8983_ADC_CONTROL 0x0E -#define WM8983_LEFT_ADC_DIGITAL_VOL 0x0F -#define WM8983_RIGHT_ADC_DIGITAL_VOL 0x10 -#define WM8983_EQ1_LOW_SHELF 0x12 -#define WM8983_EQ2_PEAK_1 0x13 -#define WM8983_EQ3_PEAK_2 0x14 -#define WM8983_EQ4_PEAK_3 0x15 -#define WM8983_EQ5_HIGH_SHELF 0x16 -#define WM8983_DAC_LIMITER_1 0x18 -#define WM8983_DAC_LIMITER_2 0x19 -#define WM8983_NOTCH_FILTER_1 0x1B -#define WM8983_NOTCH_FILTER_2 0x1C -#define WM8983_NOTCH_FILTER_3 0x1D -#define WM8983_NOTCH_FILTER_4 0x1E -#define WM8983_ALC_CONTROL_1 0x20 -#define WM8983_ALC_CONTROL_2 0x21 -#define WM8983_ALC_CONTROL_3 0x22 -#define WM8983_NOISE_GATE 0x23 -#define WM8983_PLL_N 0x24 -#define WM8983_PLL_K_1 0x25 -#define WM8983_PLL_K_2 0x26 -#define WM8983_PLL_K_3 0x27 -#define WM8983_3D_CONTROL 0x29 -#define WM8983_OUT4_TO_ADC 0x2A -#define WM8983_BEEP_CONTROL 0x2B -#define WM8983_INPUT_CTRL 0x2C -#define WM8983_LEFT_INP_PGA_GAIN_CTRL 0x2D -#define WM8983_RIGHT_INP_PGA_GAIN_CTRL 0x2E -#define WM8983_LEFT_ADC_BOOST_CTRL 0x2F -#define WM8983_RIGHT_ADC_BOOST_CTRL 0x30 -#define WM8983_OUTPUT_CTRL 0x31 -#define WM8983_LEFT_MIXER_CTRL 0x32 -#define WM8983_RIGHT_MIXER_CTRL 0x33 -#define WM8983_LOUT1_HP_VOLUME_CTRL 0x34 -#define WM8983_ROUT1_HP_VOLUME_CTRL 0x35 -#define WM8983_LOUT2_SPK_VOLUME_CTRL 0x36 -#define WM8983_ROUT2_SPK_VOLUME_CTRL 0x37 -#define WM8983_OUT3_MIXER_CTRL 0x38 -#define WM8983_OUT4_MONO_MIX_CTRL 0x39 -#define WM8983_BIAS_CTRL 0x3D - -#define WM8983_REGISTER_COUNT 59 -#define WM8983_MAX_REGISTER 0x3F - -/* - * Field Definitions. - */ - -/* - * R0 (0x00) - Software Reset - */ -#define WM8983_SOFTWARE_RESET_MASK 0x01FF /* SOFTWARE_RESET - [8:0] */ -#define WM8983_SOFTWARE_RESET_SHIFT 0 /* SOFTWARE_RESET - [8:0] */ -#define WM8983_SOFTWARE_RESET_WIDTH 9 /* SOFTWARE_RESET - [8:0] */ - -/* - * R1 (0x01) - Power management 1 - */ -#define WM8983_BUFDCOPEN 0x0100 /* BUFDCOPEN */ -#define WM8983_BUFDCOPEN_MASK 0x0100 /* BUFDCOPEN */ -#define WM8983_BUFDCOPEN_SHIFT 8 /* BUFDCOPEN */ -#define WM8983_BUFDCOPEN_WIDTH 1 /* BUFDCOPEN */ -#define WM8983_OUT4MIXEN 0x0080 /* OUT4MIXEN */ -#define WM8983_OUT4MIXEN_MASK 0x0080 /* OUT4MIXEN */ -#define WM8983_OUT4MIXEN_SHIFT 7 /* OUT4MIXEN */ -#define WM8983_OUT4MIXEN_WIDTH 1 /* OUT4MIXEN */ -#define WM8983_OUT3MIXEN 0x0040 /* OUT3MIXEN */ -#define WM8983_OUT3MIXEN_MASK 0x0040 /* OUT3MIXEN */ -#define WM8983_OUT3MIXEN_SHIFT 6 /* OUT3MIXEN */ -#define WM8983_OUT3MIXEN_WIDTH 1 /* OUT3MIXEN */ -#define WM8983_PLLEN 0x0020 /* PLLEN */ -#define WM8983_PLLEN_MASK 0x0020 /* PLLEN */ -#define WM8983_PLLEN_SHIFT 5 /* PLLEN */ -#define WM8983_PLLEN_WIDTH 1 /* PLLEN */ -#define WM8983_MICBEN 0x0010 /* MICBEN */ -#define WM8983_MICBEN_MASK 0x0010 /* MICBEN */ -#define WM8983_MICBEN_SHIFT 4 /* MICBEN */ -#define WM8983_MICBEN_WIDTH 1 /* MICBEN */ -#define WM8983_BIASEN 0x0008 /* BIASEN */ -#define WM8983_BIASEN_MASK 0x0008 /* BIASEN */ -#define WM8983_BIASEN_SHIFT 3 /* BIASEN */ -#define WM8983_BIASEN_WIDTH 1 /* BIASEN */ -#define WM8983_BUFIOEN 0x0004 /* BUFIOEN */ -#define WM8983_BUFIOEN_MASK 0x0004 /* BUFIOEN */ -#define WM8983_BUFIOEN_SHIFT 2 /* BUFIOEN */ -#define WM8983_BUFIOEN_WIDTH 1 /* BUFIOEN */ -#define WM8983_VMIDSEL_MASK 0x0003 /* VMIDSEL - [1:0] */ -#define WM8983_VMIDSEL_SHIFT 0 /* VMIDSEL - [1:0] */ -#define WM8983_VMIDSEL_WIDTH 2 /* VMIDSEL - [1:0] */ - -/* - * R2 (0x02) - Power management 2 - */ -#define WM8983_ROUT1EN 0x0100 /* ROUT1EN */ -#define WM8983_ROUT1EN_MASK 0x0100 /* ROUT1EN */ -#define WM8983_ROUT1EN_SHIFT 8 /* ROUT1EN */ -#define WM8983_ROUT1EN_WIDTH 1 /* ROUT1EN */ -#define WM8983_LOUT1EN 0x0080 /* LOUT1EN */ -#define WM8983_LOUT1EN_MASK 0x0080 /* LOUT1EN */ -#define WM8983_LOUT1EN_SHIFT 7 /* LOUT1EN */ -#define WM8983_LOUT1EN_WIDTH 1 /* LOUT1EN */ -#define WM8983_SLEEP 0x0040 /* SLEEP */ -#define WM8983_SLEEP_MASK 0x0040 /* SLEEP */ -#define WM8983_SLEEP_SHIFT 6 /* SLEEP */ -#define WM8983_SLEEP_WIDTH 1 /* SLEEP */ -#define WM8983_BOOSTENR 0x0020 /* BOOSTENR */ -#define WM8983_BOOSTENR_MASK 0x0020 /* BOOSTENR */ -#define WM8983_BOOSTENR_SHIFT 5 /* BOOSTENR */ -#define WM8983_BOOSTENR_WIDTH 1 /* BOOSTENR */ -#define WM8983_BOOSTENL 0x0010 /* BOOSTENL */ -#define WM8983_BOOSTENL_MASK 0x0010 /* BOOSTENL */ -#define WM8983_BOOSTENL_SHIFT 4 /* BOOSTENL */ -#define WM8983_BOOSTENL_WIDTH 1 /* BOOSTENL */ -#define WM8983_INPGAENR 0x0008 /* INPGAENR */ -#define WM8983_INPGAENR_MASK 0x0008 /* INPGAENR */ -#define WM8983_INPGAENR_SHIFT 3 /* INPGAENR */ -#define WM8983_INPGAENR_WIDTH 1 /* INPGAENR */ -#define WM8983_INPPGAENL 0x0004 /* INPPGAENL */ -#define WM8983_INPPGAENL_MASK 0x0004 /* INPPGAENL */ -#define WM8983_INPPGAENL_SHIFT 2 /* INPPGAENL */ -#define WM8983_INPPGAENL_WIDTH 1 /* INPPGAENL */ -#define WM8983_ADCENR 0x0002 /* ADCENR */ -#define WM8983_ADCENR_MASK 0x0002 /* ADCENR */ -#define WM8983_ADCENR_SHIFT 1 /* ADCENR */ -#define WM8983_ADCENR_WIDTH 1 /* ADCENR */ -#define WM8983_ADCENL 0x0001 /* ADCENL */ -#define WM8983_ADCENL_MASK 0x0001 /* ADCENL */ -#define WM8983_ADCENL_SHIFT 0 /* ADCENL */ -#define WM8983_ADCENL_WIDTH 1 /* ADCENL */ - -/* - * R3 (0x03) - Power management 3 - */ -#define WM8983_OUT4EN 0x0100 /* OUT4EN */ -#define WM8983_OUT4EN_MASK 0x0100 /* OUT4EN */ -#define WM8983_OUT4EN_SHIFT 8 /* OUT4EN */ -#define WM8983_OUT4EN_WIDTH 1 /* OUT4EN */ -#define WM8983_OUT3EN 0x0080 /* OUT3EN */ -#define WM8983_OUT3EN_MASK 0x0080 /* OUT3EN */ -#define WM8983_OUT3EN_SHIFT 7 /* OUT3EN */ -#define WM8983_OUT3EN_WIDTH 1 /* OUT3EN */ -#define WM8983_LOUT2EN 0x0040 /* LOUT2EN */ -#define WM8983_LOUT2EN_MASK 0x0040 /* LOUT2EN */ -#define WM8983_LOUT2EN_SHIFT 6 /* LOUT2EN */ -#define WM8983_LOUT2EN_WIDTH 1 /* LOUT2EN */ -#define WM8983_ROUT2EN 0x0020 /* ROUT2EN */ -#define WM8983_ROUT2EN_MASK 0x0020 /* ROUT2EN */ -#define WM8983_ROUT2EN_SHIFT 5 /* ROUT2EN */ -#define WM8983_ROUT2EN_WIDTH 1 /* ROUT2EN */ -#define WM8983_RMIXEN 0x0008 /* RMIXEN */ -#define WM8983_RMIXEN_MASK 0x0008 /* RMIXEN */ -#define WM8983_RMIXEN_SHIFT 3 /* RMIXEN */ -#define WM8983_RMIXEN_WIDTH 1 /* RMIXEN */ -#define WM8983_LMIXEN 0x0004 /* LMIXEN */ -#define WM8983_LMIXEN_MASK 0x0004 /* LMIXEN */ -#define WM8983_LMIXEN_SHIFT 2 /* LMIXEN */ -#define WM8983_LMIXEN_WIDTH 1 /* LMIXEN */ -#define WM8983_DACENR 0x0002 /* DACENR */ -#define WM8983_DACENR_MASK 0x0002 /* DACENR */ -#define WM8983_DACENR_SHIFT 1 /* DACENR */ -#define WM8983_DACENR_WIDTH 1 /* DACENR */ -#define WM8983_DACENL 0x0001 /* DACENL */ -#define WM8983_DACENL_MASK 0x0001 /* DACENL */ -#define WM8983_DACENL_SHIFT 0 /* DACENL */ -#define WM8983_DACENL_WIDTH 1 /* DACENL */ - -/* - * R4 (0x04) - Audio Interface - */ -#define WM8983_BCP 0x0100 /* BCP */ -#define WM8983_BCP_MASK 0x0100 /* BCP */ -#define WM8983_BCP_SHIFT 8 /* BCP */ -#define WM8983_BCP_WIDTH 1 /* BCP */ -#define WM8983_LRCP 0x0080 /* LRCP */ -#define WM8983_LRCP_MASK 0x0080 /* LRCP */ -#define WM8983_LRCP_SHIFT 7 /* LRCP */ -#define WM8983_LRCP_WIDTH 1 /* LRCP */ -#define WM8983_WL_MASK 0x0060 /* WL - [6:5] */ -#define WM8983_WL_SHIFT 5 /* WL - [6:5] */ -#define WM8983_WL_WIDTH 2 /* WL - [6:5] */ -#define WM8983_FMT_MASK 0x0018 /* FMT - [4:3] */ -#define WM8983_FMT_SHIFT 3 /* FMT - [4:3] */ -#define WM8983_FMT_WIDTH 2 /* FMT - [4:3] */ -#define WM8983_DLRSWAP 0x0004 /* DLRSWAP */ -#define WM8983_DLRSWAP_MASK 0x0004 /* DLRSWAP */ -#define WM8983_DLRSWAP_SHIFT 2 /* DLRSWAP */ -#define WM8983_DLRSWAP_WIDTH 1 /* DLRSWAP */ -#define WM8983_ALRSWAP 0x0002 /* ALRSWAP */ -#define WM8983_ALRSWAP_MASK 0x0002 /* ALRSWAP */ -#define WM8983_ALRSWAP_SHIFT 1 /* ALRSWAP */ -#define WM8983_ALRSWAP_WIDTH 1 /* ALRSWAP */ -#define WM8983_MONO 0x0001 /* MONO */ -#define WM8983_MONO_MASK 0x0001 /* MONO */ -#define WM8983_MONO_SHIFT 0 /* MONO */ -#define WM8983_MONO_WIDTH 1 /* MONO */ - -/* - * R5 (0x05) - Companding control - */ -#define WM8983_WL8 0x0020 /* WL8 */ -#define WM8983_WL8_MASK 0x0020 /* WL8 */ -#define WM8983_WL8_SHIFT 5 /* WL8 */ -#define WM8983_WL8_WIDTH 1 /* WL8 */ -#define WM8983_DAC_COMP_MASK 0x0018 /* DAC_COMP - [4:3] */ -#define WM8983_DAC_COMP_SHIFT 3 /* DAC_COMP - [4:3] */ -#define WM8983_DAC_COMP_WIDTH 2 /* DAC_COMP - [4:3] */ -#define WM8983_ADC_COMP_MASK 0x0006 /* ADC_COMP - [2:1] */ -#define WM8983_ADC_COMP_SHIFT 1 /* ADC_COMP - [2:1] */ -#define WM8983_ADC_COMP_WIDTH 2 /* ADC_COMP - [2:1] */ -#define WM8983_LOOPBACK 0x0001 /* LOOPBACK */ -#define WM8983_LOOPBACK_MASK 0x0001 /* LOOPBACK */ -#define WM8983_LOOPBACK_SHIFT 0 /* LOOPBACK */ -#define WM8983_LOOPBACK_WIDTH 1 /* LOOPBACK */ - -/* - * R6 (0x06) - Clock Gen control - */ -#define WM8983_CLKSEL 0x0100 /* CLKSEL */ -#define WM8983_CLKSEL_MASK 0x0100 /* CLKSEL */ -#define WM8983_CLKSEL_SHIFT 8 /* CLKSEL */ -#define WM8983_CLKSEL_WIDTH 1 /* CLKSEL */ -#define WM8983_MCLKDIV_MASK 0x00E0 /* MCLKDIV - [7:5] */ -#define WM8983_MCLKDIV_SHIFT 5 /* MCLKDIV - [7:5] */ -#define WM8983_MCLKDIV_WIDTH 3 /* MCLKDIV - [7:5] */ -#define WM8983_BCLKDIV_MASK 0x001C /* BCLKDIV - [4:2] */ -#define WM8983_BCLKDIV_SHIFT 2 /* BCLKDIV - [4:2] */ -#define WM8983_BCLKDIV_WIDTH 3 /* BCLKDIV - [4:2] */ -#define WM8983_MS 0x0001 /* MS */ -#define WM8983_MS_MASK 0x0001 /* MS */ -#define WM8983_MS_SHIFT 0 /* MS */ -#define WM8983_MS_WIDTH 1 /* MS */ - -/* - * R7 (0x07) - Additional control - */ -#define WM8983_SR_MASK 0x000E /* SR - [3:1] */ -#define WM8983_SR_SHIFT 1 /* SR - [3:1] */ -#define WM8983_SR_WIDTH 3 /* SR - [3:1] */ -#define WM8983_SLOWCLKEN 0x0001 /* SLOWCLKEN */ -#define WM8983_SLOWCLKEN_MASK 0x0001 /* SLOWCLKEN */ -#define WM8983_SLOWCLKEN_SHIFT 0 /* SLOWCLKEN */ -#define WM8983_SLOWCLKEN_WIDTH 1 /* SLOWCLKEN */ - -/* - * R8 (0x08) - GPIO Control - */ -#define WM8983_OPCLKDIV_MASK 0x0030 /* OPCLKDIV - [5:4] */ -#define WM8983_OPCLKDIV_SHIFT 4 /* OPCLKDIV - [5:4] */ -#define WM8983_OPCLKDIV_WIDTH 2 /* OPCLKDIV - [5:4] */ -#define WM8983_GPIO1POL 0x0008 /* GPIO1POL */ -#define WM8983_GPIO1POL_MASK 0x0008 /* GPIO1POL */ -#define WM8983_GPIO1POL_SHIFT 3 /* GPIO1POL */ -#define WM8983_GPIO1POL_WIDTH 1 /* GPIO1POL */ -#define WM8983_GPIO1SEL_MASK 0x0007 /* GPIO1SEL - [2:0] */ -#define WM8983_GPIO1SEL_SHIFT 0 /* GPIO1SEL - [2:0] */ -#define WM8983_GPIO1SEL_WIDTH 3 /* GPIO1SEL - [2:0] */ - -/* - * R9 (0x09) - Jack Detect Control 1 - */ -#define WM8983_JD_VMID1 0x0100 /* JD_VMID1 */ -#define WM8983_JD_VMID1_MASK 0x0100 /* JD_VMID1 */ -#define WM8983_JD_VMID1_SHIFT 8 /* JD_VMID1 */ -#define WM8983_JD_VMID1_WIDTH 1 /* JD_VMID1 */ -#define WM8983_JD_VMID0 0x0080 /* JD_VMID0 */ -#define WM8983_JD_VMID0_MASK 0x0080 /* JD_VMID0 */ -#define WM8983_JD_VMID0_SHIFT 7 /* JD_VMID0 */ -#define WM8983_JD_VMID0_WIDTH 1 /* JD_VMID0 */ -#define WM8983_JD_EN 0x0040 /* JD_EN */ -#define WM8983_JD_EN_MASK 0x0040 /* JD_EN */ -#define WM8983_JD_EN_SHIFT 6 /* JD_EN */ -#define WM8983_JD_EN_WIDTH 1 /* JD_EN */ -#define WM8983_JD_SEL_MASK 0x0030 /* JD_SEL - [5:4] */ -#define WM8983_JD_SEL_SHIFT 4 /* JD_SEL - [5:4] */ -#define WM8983_JD_SEL_WIDTH 2 /* JD_SEL - [5:4] */ - -/* - * R10 (0x0A) - DAC Control - */ -#define WM8983_SOFTMUTE 0x0040 /* SOFTMUTE */ -#define WM8983_SOFTMUTE_MASK 0x0040 /* SOFTMUTE */ -#define WM8983_SOFTMUTE_SHIFT 6 /* SOFTMUTE */ -#define WM8983_SOFTMUTE_WIDTH 1 /* SOFTMUTE */ -#define WM8983_DACOSR128 0x0008 /* DACOSR128 */ -#define WM8983_DACOSR128_MASK 0x0008 /* DACOSR128 */ -#define WM8983_DACOSR128_SHIFT 3 /* DACOSR128 */ -#define WM8983_DACOSR128_WIDTH 1 /* DACOSR128 */ -#define WM8983_AMUTE 0x0004 /* AMUTE */ -#define WM8983_AMUTE_MASK 0x0004 /* AMUTE */ -#define WM8983_AMUTE_SHIFT 2 /* AMUTE */ -#define WM8983_AMUTE_WIDTH 1 /* AMUTE */ -#define WM8983_DACRPOL 0x0002 /* DACRPOL */ -#define WM8983_DACRPOL_MASK 0x0002 /* DACRPOL */ -#define WM8983_DACRPOL_SHIFT 1 /* DACRPOL */ -#define WM8983_DACRPOL_WIDTH 1 /* DACRPOL */ -#define WM8983_DACLPOL 0x0001 /* DACLPOL */ -#define WM8983_DACLPOL_MASK 0x0001 /* DACLPOL */ -#define WM8983_DACLPOL_SHIFT 0 /* DACLPOL */ -#define WM8983_DACLPOL_WIDTH 1 /* DACLPOL */ - -/* - * R11 (0x0B) - Left DAC digital Vol - */ -#define WM8983_DACVU 0x0100 /* DACVU */ -#define WM8983_DACVU_MASK 0x0100 /* DACVU */ -#define WM8983_DACVU_SHIFT 8 /* DACVU */ -#define WM8983_DACVU_WIDTH 1 /* DACVU */ -#define WM8983_DACLVOL_MASK 0x00FF /* DACLVOL - [7:0] */ -#define WM8983_DACLVOL_SHIFT 0 /* DACLVOL - [7:0] */ -#define WM8983_DACLVOL_WIDTH 8 /* DACLVOL - [7:0] */ - -/* - * R12 (0x0C) - Right DAC digital vol - */ -#define WM8983_DACVU 0x0100 /* DACVU */ -#define WM8983_DACVU_MASK 0x0100 /* DACVU */ -#define WM8983_DACVU_SHIFT 8 /* DACVU */ -#define WM8983_DACVU_WIDTH 1 /* DACVU */ -#define WM8983_DACRVOL_MASK 0x00FF /* DACRVOL - [7:0] */ -#define WM8983_DACRVOL_SHIFT 0 /* DACRVOL - [7:0] */ -#define WM8983_DACRVOL_WIDTH 8 /* DACRVOL - [7:0] */ - -/* - * R13 (0x0D) - Jack Detect Control 2 - */ -#define WM8983_JD_EN1_MASK 0x00F0 /* JD_EN1 - [7:4] */ -#define WM8983_JD_EN1_SHIFT 4 /* JD_EN1 - [7:4] */ -#define WM8983_JD_EN1_WIDTH 4 /* JD_EN1 - [7:4] */ -#define WM8983_JD_EN0_MASK 0x000F /* JD_EN0 - [3:0] */ -#define WM8983_JD_EN0_SHIFT 0 /* JD_EN0 - [3:0] */ -#define WM8983_JD_EN0_WIDTH 4 /* JD_EN0 - [3:0] */ - -/* - * R14 (0x0E) - ADC Control - */ -#define WM8983_HPFEN 0x0100 /* HPFEN */ -#define WM8983_HPFEN_MASK 0x0100 /* HPFEN */ -#define WM8983_HPFEN_SHIFT 8 /* HPFEN */ -#define WM8983_HPFEN_WIDTH 1 /* HPFEN */ -#define WM8983_HPFAPP 0x0080 /* HPFAPP */ -#define WM8983_HPFAPP_MASK 0x0080 /* HPFAPP */ -#define WM8983_HPFAPP_SHIFT 7 /* HPFAPP */ -#define WM8983_HPFAPP_WIDTH 1 /* HPFAPP */ -#define WM8983_HPFCUT_MASK 0x0070 /* HPFCUT - [6:4] */ -#define WM8983_HPFCUT_SHIFT 4 /* HPFCUT - [6:4] */ -#define WM8983_HPFCUT_WIDTH 3 /* HPFCUT - [6:4] */ -#define WM8983_ADCOSR128 0x0008 /* ADCOSR128 */ -#define WM8983_ADCOSR128_MASK 0x0008 /* ADCOSR128 */ -#define WM8983_ADCOSR128_SHIFT 3 /* ADCOSR128 */ -#define WM8983_ADCOSR128_WIDTH 1 /* ADCOSR128 */ -#define WM8983_ADCRPOL 0x0002 /* ADCRPOL */ -#define WM8983_ADCRPOL_MASK 0x0002 /* ADCRPOL */ -#define WM8983_ADCRPOL_SHIFT 1 /* ADCRPOL */ -#define WM8983_ADCRPOL_WIDTH 1 /* ADCRPOL */ -#define WM8983_ADCLPOL 0x0001 /* ADCLPOL */ -#define WM8983_ADCLPOL_MASK 0x0001 /* ADCLPOL */ -#define WM8983_ADCLPOL_SHIFT 0 /* ADCLPOL */ -#define WM8983_ADCLPOL_WIDTH 1 /* ADCLPOL */ - -/* - * R15 (0x0F) - Left ADC Digital Vol - */ -#define WM8983_ADCVU 0x0100 /* ADCVU */ -#define WM8983_ADCVU_MASK 0x0100 /* ADCVU */ -#define WM8983_ADCVU_SHIFT 8 /* ADCVU */ -#define WM8983_ADCVU_WIDTH 1 /* ADCVU */ -#define WM8983_ADCLVOL_MASK 0x00FF /* ADCLVOL - [7:0] */ -#define WM8983_ADCLVOL_SHIFT 0 /* ADCLVOL - [7:0] */ -#define WM8983_ADCLVOL_WIDTH 8 /* ADCLVOL - [7:0] */ - -/* - * R16 (0x10) - Right ADC Digital Vol - */ -#define WM8983_ADCVU 0x0100 /* ADCVU */ -#define WM8983_ADCVU_MASK 0x0100 /* ADCVU */ -#define WM8983_ADCVU_SHIFT 8 /* ADCVU */ -#define WM8983_ADCVU_WIDTH 1 /* ADCVU */ -#define WM8983_ADCRVOL_MASK 0x00FF /* ADCRVOL - [7:0] */ -#define WM8983_ADCRVOL_SHIFT 0 /* ADCRVOL - [7:0] */ -#define WM8983_ADCRVOL_WIDTH 8 /* ADCRVOL - [7:0] */ - -/* - * R18 (0x12) - EQ1 - low shelf - */ -#define WM8983_EQ3DMODE 0x0100 /* EQ3DMODE */ -#define WM8983_EQ3DMODE_MASK 0x0100 /* EQ3DMODE */ -#define WM8983_EQ3DMODE_SHIFT 8 /* EQ3DMODE */ -#define WM8983_EQ3DMODE_WIDTH 1 /* EQ3DMODE */ -#define WM8983_EQ1C_MASK 0x0060 /* EQ1C - [6:5] */ -#define WM8983_EQ1C_SHIFT 5 /* EQ1C - [6:5] */ -#define WM8983_EQ1C_WIDTH 2 /* EQ1C - [6:5] */ -#define WM8983_EQ1G_MASK 0x001F /* EQ1G - [4:0] */ -#define WM8983_EQ1G_SHIFT 0 /* EQ1G - [4:0] */ -#define WM8983_EQ1G_WIDTH 5 /* EQ1G - [4:0] */ - -/* - * R19 (0x13) - EQ2 - peak 1 - */ -#define WM8983_EQ2BW 0x0100 /* EQ2BW */ -#define WM8983_EQ2BW_MASK 0x0100 /* EQ2BW */ -#define WM8983_EQ2BW_SHIFT 8 /* EQ2BW */ -#define WM8983_EQ2BW_WIDTH 1 /* EQ2BW */ -#define WM8983_EQ2C_MASK 0x0060 /* EQ2C - [6:5] */ -#define WM8983_EQ2C_SHIFT 5 /* EQ2C - [6:5] */ -#define WM8983_EQ2C_WIDTH 2 /* EQ2C - [6:5] */ -#define WM8983_EQ2G_MASK 0x001F /* EQ2G - [4:0] */ -#define WM8983_EQ2G_SHIFT 0 /* EQ2G - [4:0] */ -#define WM8983_EQ2G_WIDTH 5 /* EQ2G - [4:0] */ - -/* - * R20 (0x14) - EQ3 - peak 2 - */ -#define WM8983_EQ3BW 0x0100 /* EQ3BW */ -#define WM8983_EQ3BW_MASK 0x0100 /* EQ3BW */ -#define WM8983_EQ3BW_SHIFT 8 /* EQ3BW */ -#define WM8983_EQ3BW_WIDTH 1 /* EQ3BW */ -#define WM8983_EQ3C_MASK 0x0060 /* EQ3C - [6:5] */ -#define WM8983_EQ3C_SHIFT 5 /* EQ3C - [6:5] */ -#define WM8983_EQ3C_WIDTH 2 /* EQ3C - [6:5] */ -#define WM8983_EQ3G_MASK 0x001F /* EQ3G - [4:0] */ -#define WM8983_EQ3G_SHIFT 0 /* EQ3G - [4:0] */ -#define WM8983_EQ3G_WIDTH 5 /* EQ3G - [4:0] */ - -/* - * R21 (0x15) - EQ4 - peak 3 - */ -#define WM8983_EQ4BW 0x0100 /* EQ4BW */ -#define WM8983_EQ4BW_MASK 0x0100 /* EQ4BW */ -#define WM8983_EQ4BW_SHIFT 8 /* EQ4BW */ -#define WM8983_EQ4BW_WIDTH 1 /* EQ4BW */ -#define WM8983_EQ4C_MASK 0x0060 /* EQ4C - [6:5] */ -#define WM8983_EQ4C_SHIFT 5 /* EQ4C - [6:5] */ -#define WM8983_EQ4C_WIDTH 2 /* EQ4C - [6:5] */ -#define WM8983_EQ4G_MASK 0x001F /* EQ4G - [4:0] */ -#define WM8983_EQ4G_SHIFT 0 /* EQ4G - [4:0] */ -#define WM8983_EQ4G_WIDTH 5 /* EQ4G - [4:0] */ - -/* - * R22 (0x16) - EQ5 - high shelf - */ -#define WM8983_EQ5C_MASK 0x0060 /* EQ5C - [6:5] */ -#define WM8983_EQ5C_SHIFT 5 /* EQ5C - [6:5] */ -#define WM8983_EQ5C_WIDTH 2 /* EQ5C - [6:5] */ -#define WM8983_EQ5G_MASK 0x001F /* EQ5G - [4:0] */ -#define WM8983_EQ5G_SHIFT 0 /* EQ5G - [4:0] */ -#define WM8983_EQ5G_WIDTH 5 /* EQ5G - [4:0] */ - -/* - * R24 (0x18) - DAC Limiter 1 - */ -#define WM8983_LIMEN 0x0100 /* LIMEN */ -#define WM8983_LIMEN_MASK 0x0100 /* LIMEN */ -#define WM8983_LIMEN_SHIFT 8 /* LIMEN */ -#define WM8983_LIMEN_WIDTH 1 /* LIMEN */ -#define WM8983_LIMDCY_MASK 0x00F0 /* LIMDCY - [7:4] */ -#define WM8983_LIMDCY_SHIFT 4 /* LIMDCY - [7:4] */ -#define WM8983_LIMDCY_WIDTH 4 /* LIMDCY - [7:4] */ -#define WM8983_LIMATK_MASK 0x000F /* LIMATK - [3:0] */ -#define WM8983_LIMATK_SHIFT 0 /* LIMATK - [3:0] */ -#define WM8983_LIMATK_WIDTH 4 /* LIMATK - [3:0] */ - -/* - * R25 (0x19) - DAC Limiter 2 - */ -#define WM8983_LIMLVL_MASK 0x0070 /* LIMLVL - [6:4] */ -#define WM8983_LIMLVL_SHIFT 4 /* LIMLVL - [6:4] */ -#define WM8983_LIMLVL_WIDTH 3 /* LIMLVL - [6:4] */ -#define WM8983_LIMBOOST_MASK 0x000F /* LIMBOOST - [3:0] */ -#define WM8983_LIMBOOST_SHIFT 0 /* LIMBOOST - [3:0] */ -#define WM8983_LIMBOOST_WIDTH 4 /* LIMBOOST - [3:0] */ - -/* - * R27 (0x1B) - Notch Filter 1 - */ -#define WM8983_NFU 0x0100 /* NFU */ -#define WM8983_NFU_MASK 0x0100 /* NFU */ -#define WM8983_NFU_SHIFT 8 /* NFU */ -#define WM8983_NFU_WIDTH 1 /* NFU */ -#define WM8983_NFEN 0x0080 /* NFEN */ -#define WM8983_NFEN_MASK 0x0080 /* NFEN */ -#define WM8983_NFEN_SHIFT 7 /* NFEN */ -#define WM8983_NFEN_WIDTH 1 /* NFEN */ -#define WM8983_NFA0_13_7_MASK 0x007F /* NFA0(13:7) - [6:0] */ -#define WM8983_NFA0_13_7_SHIFT 0 /* NFA0(13:7) - [6:0] */ -#define WM8983_NFA0_13_7_WIDTH 7 /* NFA0(13:7) - [6:0] */ - -/* - * R28 (0x1C) - Notch Filter 2 - */ -#define WM8983_NFU 0x0100 /* NFU */ -#define WM8983_NFU_MASK 0x0100 /* NFU */ -#define WM8983_NFU_SHIFT 8 /* NFU */ -#define WM8983_NFU_WIDTH 1 /* NFU */ -#define WM8983_NFA0_6_0_MASK 0x007F /* NFA0(6:0) - [6:0] */ -#define WM8983_NFA0_6_0_SHIFT 0 /* NFA0(6:0) - [6:0] */ -#define WM8983_NFA0_6_0_WIDTH 7 /* NFA0(6:0) - [6:0] */ - -/* - * R29 (0x1D) - Notch Filter 3 - */ -#define WM8983_NFU 0x0100 /* NFU */ -#define WM8983_NFU_MASK 0x0100 /* NFU */ -#define WM8983_NFU_SHIFT 8 /* NFU */ -#define WM8983_NFU_WIDTH 1 /* NFU */ -#define WM8983_NFA1_13_7_MASK 0x007F /* NFA1(13:7) - [6:0] */ -#define WM8983_NFA1_13_7_SHIFT 0 /* NFA1(13:7) - [6:0] */ -#define WM8983_NFA1_13_7_WIDTH 7 /* NFA1(13:7) - [6:0] */ - -/* - * R30 (0x1E) - Notch Filter 4 - */ -#define WM8983_NFU 0x0100 /* NFU */ -#define WM8983_NFU_MASK 0x0100 /* NFU */ -#define WM8983_NFU_SHIFT 8 /* NFU */ -#define WM8983_NFU_WIDTH 1 /* NFU */ -#define WM8983_NFA1_6_0_MASK 0x007F /* NFA1(6:0) - [6:0] */ -#define WM8983_NFA1_6_0_SHIFT 0 /* NFA1(6:0) - [6:0] */ -#define WM8983_NFA1_6_0_WIDTH 7 /* NFA1(6:0) - [6:0] */ - -/* - * R32 (0x20) - ALC control 1 - */ -#define WM8983_ALCSEL_MASK 0x0180 /* ALCSEL - [8:7] */ -#define WM8983_ALCSEL_SHIFT 7 /* ALCSEL - [8:7] */ -#define WM8983_ALCSEL_WIDTH 2 /* ALCSEL - [8:7] */ -#define WM8983_ALCMAX_MASK 0x0038 /* ALCMAX - [5:3] */ -#define WM8983_ALCMAX_SHIFT 3 /* ALCMAX - [5:3] */ -#define WM8983_ALCMAX_WIDTH 3 /* ALCMAX - [5:3] */ -#define WM8983_ALCMIN_MASK 0x0007 /* ALCMIN - [2:0] */ -#define WM8983_ALCMIN_SHIFT 0 /* ALCMIN - [2:0] */ -#define WM8983_ALCMIN_WIDTH 3 /* ALCMIN - [2:0] */ - -/* - * R33 (0x21) - ALC control 2 - */ -#define WM8983_ALCHLD_MASK 0x00F0 /* ALCHLD - [7:4] */ -#define WM8983_ALCHLD_SHIFT 4 /* ALCHLD - [7:4] */ -#define WM8983_ALCHLD_WIDTH 4 /* ALCHLD - [7:4] */ -#define WM8983_ALCLVL_MASK 0x000F /* ALCLVL - [3:0] */ -#define WM8983_ALCLVL_SHIFT 0 /* ALCLVL - [3:0] */ -#define WM8983_ALCLVL_WIDTH 4 /* ALCLVL - [3:0] */ - -/* - * R34 (0x22) - ALC control 3 - */ -#define WM8983_ALCMODE 0x0100 /* ALCMODE */ -#define WM8983_ALCMODE_MASK 0x0100 /* ALCMODE */ -#define WM8983_ALCMODE_SHIFT 8 /* ALCMODE */ -#define WM8983_ALCMODE_WIDTH 1 /* ALCMODE */ -#define WM8983_ALCDCY_MASK 0x00F0 /* ALCDCY - [7:4] */ -#define WM8983_ALCDCY_SHIFT 4 /* ALCDCY - [7:4] */ -#define WM8983_ALCDCY_WIDTH 4 /* ALCDCY - [7:4] */ -#define WM8983_ALCATK_MASK 0x000F /* ALCATK - [3:0] */ -#define WM8983_ALCATK_SHIFT 0 /* ALCATK - [3:0] */ -#define WM8983_ALCATK_WIDTH 4 /* ALCATK - [3:0] */ - -/* - * R35 (0x23) - Noise Gate - */ -#define WM8983_NGEN 0x0008 /* NGEN */ -#define WM8983_NGEN_MASK 0x0008 /* NGEN */ -#define WM8983_NGEN_SHIFT 3 /* NGEN */ -#define WM8983_NGEN_WIDTH 1 /* NGEN */ -#define WM8983_NGTH_MASK 0x0007 /* NGTH - [2:0] */ -#define WM8983_NGTH_SHIFT 0 /* NGTH - [2:0] */ -#define WM8983_NGTH_WIDTH 3 /* NGTH - [2:0] */ - -/* - * R36 (0x24) - PLL N - */ -#define WM8983_PLL_PRESCALE 0x0010 /* PLL_PRESCALE */ -#define WM8983_PLL_PRESCALE_MASK 0x0010 /* PLL_PRESCALE */ -#define WM8983_PLL_PRESCALE_SHIFT 4 /* PLL_PRESCALE */ -#define WM8983_PLL_PRESCALE_WIDTH 1 /* PLL_PRESCALE */ -#define WM8983_PLLN_MASK 0x000F /* PLLN - [3:0] */ -#define WM8983_PLLN_SHIFT 0 /* PLLN - [3:0] */ -#define WM8983_PLLN_WIDTH 4 /* PLLN - [3:0] */ - -/* - * R37 (0x25) - PLL K 1 - */ -#define WM8983_PLLK_23_18_MASK 0x003F /* PLLK(23:18) - [5:0] */ -#define WM8983_PLLK_23_18_SHIFT 0 /* PLLK(23:18) - [5:0] */ -#define WM8983_PLLK_23_18_WIDTH 6 /* PLLK(23:18) - [5:0] */ - -/* - * R38 (0x26) - PLL K 2 - */ -#define WM8983_PLLK_17_9_MASK 0x01FF /* PLLK(17:9) - [8:0] */ -#define WM8983_PLLK_17_9_SHIFT 0 /* PLLK(17:9) - [8:0] */ -#define WM8983_PLLK_17_9_WIDTH 9 /* PLLK(17:9) - [8:0] */ - -/* - * R39 (0x27) - PLL K 3 - */ -#define WM8983_PLLK_8_0_MASK 0x01FF /* PLLK(8:0) - [8:0] */ -#define WM8983_PLLK_8_0_SHIFT 0 /* PLLK(8:0) - [8:0] */ -#define WM8983_PLLK_8_0_WIDTH 9 /* PLLK(8:0) - [8:0] */ - -/* - * R41 (0x29) - 3D control - */ -#define WM8983_DEPTH3D_MASK 0x000F /* DEPTH3D - [3:0] */ -#define WM8983_DEPTH3D_SHIFT 0 /* DEPTH3D - [3:0] */ -#define WM8983_DEPTH3D_WIDTH 4 /* DEPTH3D - [3:0] */ - -/* - * R42 (0x2A) - OUT4 to ADC - */ -#define WM8983_OUT4_2ADCVOL_MASK 0x01C0 /* OUT4_2ADCVOL - [8:6] */ -#define WM8983_OUT4_2ADCVOL_SHIFT 6 /* OUT4_2ADCVOL - [8:6] */ -#define WM8983_OUT4_2ADCVOL_WIDTH 3 /* OUT4_2ADCVOL - [8:6] */ -#define WM8983_OUT4_2LNR 0x0020 /* OUT4_2LNR */ -#define WM8983_OUT4_2LNR_MASK 0x0020 /* OUT4_2LNR */ -#define WM8983_OUT4_2LNR_SHIFT 5 /* OUT4_2LNR */ -#define WM8983_OUT4_2LNR_WIDTH 1 /* OUT4_2LNR */ -#define WM8983_POBCTRL 0x0004 /* POBCTRL */ -#define WM8983_POBCTRL_MASK 0x0004 /* POBCTRL */ -#define WM8983_POBCTRL_SHIFT 2 /* POBCTRL */ -#define WM8983_POBCTRL_WIDTH 1 /* POBCTRL */ -#define WM8983_DELEN 0x0002 /* DELEN */ -#define WM8983_DELEN_MASK 0x0002 /* DELEN */ -#define WM8983_DELEN_SHIFT 1 /* DELEN */ -#define WM8983_DELEN_WIDTH 1 /* DELEN */ -#define WM8983_OUT1DEL 0x0001 /* OUT1DEL */ -#define WM8983_OUT1DEL_MASK 0x0001 /* OUT1DEL */ -#define WM8983_OUT1DEL_SHIFT 0 /* OUT1DEL */ -#define WM8983_OUT1DEL_WIDTH 1 /* OUT1DEL */ - -/* - * R43 (0x2B) - Beep control - */ -#define WM8983_BYPL2RMIX 0x0100 /* BYPL2RMIX */ -#define WM8983_BYPL2RMIX_MASK 0x0100 /* BYPL2RMIX */ -#define WM8983_BYPL2RMIX_SHIFT 8 /* BYPL2RMIX */ -#define WM8983_BYPL2RMIX_WIDTH 1 /* BYPL2RMIX */ -#define WM8983_BYPR2LMIX 0x0080 /* BYPR2LMIX */ -#define WM8983_BYPR2LMIX_MASK 0x0080 /* BYPR2LMIX */ -#define WM8983_BYPR2LMIX_SHIFT 7 /* BYPR2LMIX */ -#define WM8983_BYPR2LMIX_WIDTH 1 /* BYPR2LMIX */ -#define WM8983_MUTERPGA2INV 0x0020 /* MUTERPGA2INV */ -#define WM8983_MUTERPGA2INV_MASK 0x0020 /* MUTERPGA2INV */ -#define WM8983_MUTERPGA2INV_SHIFT 5 /* MUTERPGA2INV */ -#define WM8983_MUTERPGA2INV_WIDTH 1 /* MUTERPGA2INV */ -#define WM8983_INVROUT2 0x0010 /* INVROUT2 */ -#define WM8983_INVROUT2_MASK 0x0010 /* INVROUT2 */ -#define WM8983_INVROUT2_SHIFT 4 /* INVROUT2 */ -#define WM8983_INVROUT2_WIDTH 1 /* INVROUT2 */ -#define WM8983_BEEPVOL_MASK 0x000E /* BEEPVOL - [3:1] */ -#define WM8983_BEEPVOL_SHIFT 1 /* BEEPVOL - [3:1] */ -#define WM8983_BEEPVOL_WIDTH 3 /* BEEPVOL - [3:1] */ -#define WM8983_BEEPEN 0x0001 /* BEEPEN */ -#define WM8983_BEEPEN_MASK 0x0001 /* BEEPEN */ -#define WM8983_BEEPEN_SHIFT 0 /* BEEPEN */ -#define WM8983_BEEPEN_WIDTH 1 /* BEEPEN */ - -/* - * R44 (0x2C) - Input ctrl - */ -#define WM8983_MBVSEL 0x0100 /* MBVSEL */ -#define WM8983_MBVSEL_MASK 0x0100 /* MBVSEL */ -#define WM8983_MBVSEL_SHIFT 8 /* MBVSEL */ -#define WM8983_MBVSEL_WIDTH 1 /* MBVSEL */ -#define WM8983_R2_2INPPGA 0x0040 /* R2_2INPPGA */ -#define WM8983_R2_2INPPGA_MASK 0x0040 /* R2_2INPPGA */ -#define WM8983_R2_2INPPGA_SHIFT 6 /* R2_2INPPGA */ -#define WM8983_R2_2INPPGA_WIDTH 1 /* R2_2INPPGA */ -#define WM8983_RIN2INPPGA 0x0020 /* RIN2INPPGA */ -#define WM8983_RIN2INPPGA_MASK 0x0020 /* RIN2INPPGA */ -#define WM8983_RIN2INPPGA_SHIFT 5 /* RIN2INPPGA */ -#define WM8983_RIN2INPPGA_WIDTH 1 /* RIN2INPPGA */ -#define WM8983_RIP2INPPGA 0x0010 /* RIP2INPPGA */ -#define WM8983_RIP2INPPGA_MASK 0x0010 /* RIP2INPPGA */ -#define WM8983_RIP2INPPGA_SHIFT 4 /* RIP2INPPGA */ -#define WM8983_RIP2INPPGA_WIDTH 1 /* RIP2INPPGA */ -#define WM8983_L2_2INPPGA 0x0004 /* L2_2INPPGA */ -#define WM8983_L2_2INPPGA_MASK 0x0004 /* L2_2INPPGA */ -#define WM8983_L2_2INPPGA_SHIFT 2 /* L2_2INPPGA */ -#define WM8983_L2_2INPPGA_WIDTH 1 /* L2_2INPPGA */ -#define WM8983_LIN2INPPGA 0x0002 /* LIN2INPPGA */ -#define WM8983_LIN2INPPGA_MASK 0x0002 /* LIN2INPPGA */ -#define WM8983_LIN2INPPGA_SHIFT 1 /* LIN2INPPGA */ -#define WM8983_LIN2INPPGA_WIDTH 1 /* LIN2INPPGA */ -#define WM8983_LIP2INPPGA 0x0001 /* LIP2INPPGA */ -#define WM8983_LIP2INPPGA_MASK 0x0001 /* LIP2INPPGA */ -#define WM8983_LIP2INPPGA_SHIFT 0 /* LIP2INPPGA */ -#define WM8983_LIP2INPPGA_WIDTH 1 /* LIP2INPPGA */ - -/* - * R45 (0x2D) - Left INP PGA gain ctrl - */ -#define WM8983_INPGAVU 0x0100 /* INPGAVU */ -#define WM8983_INPGAVU_MASK 0x0100 /* INPGAVU */ -#define WM8983_INPGAVU_SHIFT 8 /* INPGAVU */ -#define WM8983_INPGAVU_WIDTH 1 /* INPGAVU */ -#define WM8983_INPPGAZCL 0x0080 /* INPPGAZCL */ -#define WM8983_INPPGAZCL_MASK 0x0080 /* INPPGAZCL */ -#define WM8983_INPPGAZCL_SHIFT 7 /* INPPGAZCL */ -#define WM8983_INPPGAZCL_WIDTH 1 /* INPPGAZCL */ -#define WM8983_INPPGAMUTEL 0x0040 /* INPPGAMUTEL */ -#define WM8983_INPPGAMUTEL_MASK 0x0040 /* INPPGAMUTEL */ -#define WM8983_INPPGAMUTEL_SHIFT 6 /* INPPGAMUTEL */ -#define WM8983_INPPGAMUTEL_WIDTH 1 /* INPPGAMUTEL */ -#define WM8983_INPPGAVOLL_MASK 0x003F /* INPPGAVOLL - [5:0] */ -#define WM8983_INPPGAVOLL_SHIFT 0 /* INPPGAVOLL - [5:0] */ -#define WM8983_INPPGAVOLL_WIDTH 6 /* INPPGAVOLL - [5:0] */ - -/* - * R46 (0x2E) - Right INP PGA gain ctrl - */ -#define WM8983_INPGAVU 0x0100 /* INPGAVU */ -#define WM8983_INPGAVU_MASK 0x0100 /* INPGAVU */ -#define WM8983_INPGAVU_SHIFT 8 /* INPGAVU */ -#define WM8983_INPGAVU_WIDTH 1 /* INPGAVU */ -#define WM8983_INPPGAZCR 0x0080 /* INPPGAZCR */ -#define WM8983_INPPGAZCR_MASK 0x0080 /* INPPGAZCR */ -#define WM8983_INPPGAZCR_SHIFT 7 /* INPPGAZCR */ -#define WM8983_INPPGAZCR_WIDTH 1 /* INPPGAZCR */ -#define WM8983_INPPGAMUTER 0x0040 /* INPPGAMUTER */ -#define WM8983_INPPGAMUTER_MASK 0x0040 /* INPPGAMUTER */ -#define WM8983_INPPGAMUTER_SHIFT 6 /* INPPGAMUTER */ -#define WM8983_INPPGAMUTER_WIDTH 1 /* INPPGAMUTER */ -#define WM8983_INPPGAVOLR_MASK 0x003F /* INPPGAVOLR - [5:0] */ -#define WM8983_INPPGAVOLR_SHIFT 0 /* INPPGAVOLR - [5:0] */ -#define WM8983_INPPGAVOLR_WIDTH 6 /* INPPGAVOLR - [5:0] */ - -/* - * R47 (0x2F) - Left ADC BOOST ctrl - */ -#define WM8983_PGABOOSTL 0x0100 /* PGABOOSTL */ -#define WM8983_PGABOOSTL_MASK 0x0100 /* PGABOOSTL */ -#define WM8983_PGABOOSTL_SHIFT 8 /* PGABOOSTL */ -#define WM8983_PGABOOSTL_WIDTH 1 /* PGABOOSTL */ -#define WM8983_L2_2BOOSTVOL_MASK 0x0070 /* L2_2BOOSTVOL - [6:4] */ -#define WM8983_L2_2BOOSTVOL_SHIFT 4 /* L2_2BOOSTVOL - [6:4] */ -#define WM8983_L2_2BOOSTVOL_WIDTH 3 /* L2_2BOOSTVOL - [6:4] */ -#define WM8983_AUXL2BOOSTVOL_MASK 0x0007 /* AUXL2BOOSTVOL - [2:0] */ -#define WM8983_AUXL2BOOSTVOL_SHIFT 0 /* AUXL2BOOSTVOL - [2:0] */ -#define WM8983_AUXL2BOOSTVOL_WIDTH 3 /* AUXL2BOOSTVOL - [2:0] */ - -/* - * R48 (0x30) - Right ADC BOOST ctrl - */ -#define WM8983_PGABOOSTR 0x0100 /* PGABOOSTR */ -#define WM8983_PGABOOSTR_MASK 0x0100 /* PGABOOSTR */ -#define WM8983_PGABOOSTR_SHIFT 8 /* PGABOOSTR */ -#define WM8983_PGABOOSTR_WIDTH 1 /* PGABOOSTR */ -#define WM8983_R2_2BOOSTVOL_MASK 0x0070 /* R2_2BOOSTVOL - [6:4] */ -#define WM8983_R2_2BOOSTVOL_SHIFT 4 /* R2_2BOOSTVOL - [6:4] */ -#define WM8983_R2_2BOOSTVOL_WIDTH 3 /* R2_2BOOSTVOL - [6:4] */ -#define WM8983_AUXR2BOOSTVOL_MASK 0x0007 /* AUXR2BOOSTVOL - [2:0] */ -#define WM8983_AUXR2BOOSTVOL_SHIFT 0 /* AUXR2BOOSTVOL - [2:0] */ -#define WM8983_AUXR2BOOSTVOL_WIDTH 3 /* AUXR2BOOSTVOL - [2:0] */ - -/* - * R49 (0x31) - Output ctrl - */ -#define WM8983_DACL2RMIX 0x0040 /* DACL2RMIX */ -#define WM8983_DACL2RMIX_MASK 0x0040 /* DACL2RMIX */ -#define WM8983_DACL2RMIX_SHIFT 6 /* DACL2RMIX */ -#define WM8983_DACL2RMIX_WIDTH 1 /* DACL2RMIX */ -#define WM8983_DACR2LMIX 0x0020 /* DACR2LMIX */ -#define WM8983_DACR2LMIX_MASK 0x0020 /* DACR2LMIX */ -#define WM8983_DACR2LMIX_SHIFT 5 /* DACR2LMIX */ -#define WM8983_DACR2LMIX_WIDTH 1 /* DACR2LMIX */ -#define WM8983_OUT4BOOST 0x0010 /* OUT4BOOST */ -#define WM8983_OUT4BOOST_MASK 0x0010 /* OUT4BOOST */ -#define WM8983_OUT4BOOST_SHIFT 4 /* OUT4BOOST */ -#define WM8983_OUT4BOOST_WIDTH 1 /* OUT4BOOST */ -#define WM8983_OUT3BOOST 0x0008 /* OUT3BOOST */ -#define WM8983_OUT3BOOST_MASK 0x0008 /* OUT3BOOST */ -#define WM8983_OUT3BOOST_SHIFT 3 /* OUT3BOOST */ -#define WM8983_OUT3BOOST_WIDTH 1 /* OUT3BOOST */ -#define WM8983_SPKBOOST 0x0004 /* SPKBOOST */ -#define WM8983_SPKBOOST_MASK 0x0004 /* SPKBOOST */ -#define WM8983_SPKBOOST_SHIFT 2 /* SPKBOOST */ -#define WM8983_SPKBOOST_WIDTH 1 /* SPKBOOST */ -#define WM8983_TSDEN 0x0002 /* TSDEN */ -#define WM8983_TSDEN_MASK 0x0002 /* TSDEN */ -#define WM8983_TSDEN_SHIFT 1 /* TSDEN */ -#define WM8983_TSDEN_WIDTH 1 /* TSDEN */ -#define WM8983_VROI 0x0001 /* VROI */ -#define WM8983_VROI_MASK 0x0001 /* VROI */ -#define WM8983_VROI_SHIFT 0 /* VROI */ -#define WM8983_VROI_WIDTH 1 /* VROI */ - -/* - * R50 (0x32) - Left mixer ctrl - */ -#define WM8983_AUXLMIXVOL_MASK 0x01C0 /* AUXLMIXVOL - [8:6] */ -#define WM8983_AUXLMIXVOL_SHIFT 6 /* AUXLMIXVOL - [8:6] */ -#define WM8983_AUXLMIXVOL_WIDTH 3 /* AUXLMIXVOL - [8:6] */ -#define WM8983_AUXL2LMIX 0x0020 /* AUXL2LMIX */ -#define WM8983_AUXL2LMIX_MASK 0x0020 /* AUXL2LMIX */ -#define WM8983_AUXL2LMIX_SHIFT 5 /* AUXL2LMIX */ -#define WM8983_AUXL2LMIX_WIDTH 1 /* AUXL2LMIX */ -#define WM8983_BYPLMIXVOL_MASK 0x001C /* BYPLMIXVOL - [4:2] */ -#define WM8983_BYPLMIXVOL_SHIFT 2 /* BYPLMIXVOL - [4:2] */ -#define WM8983_BYPLMIXVOL_WIDTH 3 /* BYPLMIXVOL - [4:2] */ -#define WM8983_BYPL2LMIX 0x0002 /* BYPL2LMIX */ -#define WM8983_BYPL2LMIX_MASK 0x0002 /* BYPL2LMIX */ -#define WM8983_BYPL2LMIX_SHIFT 1 /* BYPL2LMIX */ -#define WM8983_BYPL2LMIX_WIDTH 1 /* BYPL2LMIX */ -#define WM8983_DACL2LMIX 0x0001 /* DACL2LMIX */ -#define WM8983_DACL2LMIX_MASK 0x0001 /* DACL2LMIX */ -#define WM8983_DACL2LMIX_SHIFT 0 /* DACL2LMIX */ -#define WM8983_DACL2LMIX_WIDTH 1 /* DACL2LMIX */ - -/* - * R51 (0x33) - Right mixer ctrl - */ -#define WM8983_AUXRMIXVOL_MASK 0x01C0 /* AUXRMIXVOL - [8:6] */ -#define WM8983_AUXRMIXVOL_SHIFT 6 /* AUXRMIXVOL - [8:6] */ -#define WM8983_AUXRMIXVOL_WIDTH 3 /* AUXRMIXVOL - [8:6] */ -#define WM8983_AUXR2RMIX 0x0020 /* AUXR2RMIX */ -#define WM8983_AUXR2RMIX_MASK 0x0020 /* AUXR2RMIX */ -#define WM8983_AUXR2RMIX_SHIFT 5 /* AUXR2RMIX */ -#define WM8983_AUXR2RMIX_WIDTH 1 /* AUXR2RMIX */ -#define WM8983_BYPRMIXVOL_MASK 0x001C /* BYPRMIXVOL - [4:2] */ -#define WM8983_BYPRMIXVOL_SHIFT 2 /* BYPRMIXVOL - [4:2] */ -#define WM8983_BYPRMIXVOL_WIDTH 3 /* BYPRMIXVOL - [4:2] */ -#define WM8983_BYPR2RMIX 0x0002 /* BYPR2RMIX */ -#define WM8983_BYPR2RMIX_MASK 0x0002 /* BYPR2RMIX */ -#define WM8983_BYPR2RMIX_SHIFT 1 /* BYPR2RMIX */ -#define WM8983_BYPR2RMIX_WIDTH 1 /* BYPR2RMIX */ -#define WM8983_DACR2RMIX 0x0001 /* DACR2RMIX */ -#define WM8983_DACR2RMIX_MASK 0x0001 /* DACR2RMIX */ -#define WM8983_DACR2RMIX_SHIFT 0 /* DACR2RMIX */ -#define WM8983_DACR2RMIX_WIDTH 1 /* DACR2RMIX */ - -/* - * R52 (0x34) - LOUT1 (HP) volume ctrl - */ -#define WM8983_OUT1VU 0x0100 /* OUT1VU */ -#define WM8983_OUT1VU_MASK 0x0100 /* OUT1VU */ -#define WM8983_OUT1VU_SHIFT 8 /* OUT1VU */ -#define WM8983_OUT1VU_WIDTH 1 /* OUT1VU */ -#define WM8983_LOUT1ZC 0x0080 /* LOUT1ZC */ -#define WM8983_LOUT1ZC_MASK 0x0080 /* LOUT1ZC */ -#define WM8983_LOUT1ZC_SHIFT 7 /* LOUT1ZC */ -#define WM8983_LOUT1ZC_WIDTH 1 /* LOUT1ZC */ -#define WM8983_LOUT1MUTE 0x0040 /* LOUT1MUTE */ -#define WM8983_LOUT1MUTE_MASK 0x0040 /* LOUT1MUTE */ -#define WM8983_LOUT1MUTE_SHIFT 6 /* LOUT1MUTE */ -#define WM8983_LOUT1MUTE_WIDTH 1 /* LOUT1MUTE */ -#define WM8983_LOUT1VOL_MASK 0x003F /* LOUT1VOL - [5:0] */ -#define WM8983_LOUT1VOL_SHIFT 0 /* LOUT1VOL - [5:0] */ -#define WM8983_LOUT1VOL_WIDTH 6 /* LOUT1VOL - [5:0] */ - -/* - * R53 (0x35) - ROUT1 (HP) volume ctrl - */ -#define WM8983_OUT1VU 0x0100 /* OUT1VU */ -#define WM8983_OUT1VU_MASK 0x0100 /* OUT1VU */ -#define WM8983_OUT1VU_SHIFT 8 /* OUT1VU */ -#define WM8983_OUT1VU_WIDTH 1 /* OUT1VU */ -#define WM8983_ROUT1ZC 0x0080 /* ROUT1ZC */ -#define WM8983_ROUT1ZC_MASK 0x0080 /* ROUT1ZC */ -#define WM8983_ROUT1ZC_SHIFT 7 /* ROUT1ZC */ -#define WM8983_ROUT1ZC_WIDTH 1 /* ROUT1ZC */ -#define WM8983_ROUT1MUTE 0x0040 /* ROUT1MUTE */ -#define WM8983_ROUT1MUTE_MASK 0x0040 /* ROUT1MUTE */ -#define WM8983_ROUT1MUTE_SHIFT 6 /* ROUT1MUTE */ -#define WM8983_ROUT1MUTE_WIDTH 1 /* ROUT1MUTE */ -#define WM8983_ROUT1VOL_MASK 0x003F /* ROUT1VOL - [5:0] */ -#define WM8983_ROUT1VOL_SHIFT 0 /* ROUT1VOL - [5:0] */ -#define WM8983_ROUT1VOL_WIDTH 6 /* ROUT1VOL - [5:0] */ - -/* - * R54 (0x36) - LOUT2 (SPK) volume ctrl - */ -#define WM8983_OUT2VU 0x0100 /* OUT2VU */ -#define WM8983_OUT2VU_MASK 0x0100 /* OUT2VU */ -#define WM8983_OUT2VU_SHIFT 8 /* OUT2VU */ -#define WM8983_OUT2VU_WIDTH 1 /* OUT2VU */ -#define WM8983_LOUT2ZC 0x0080 /* LOUT2ZC */ -#define WM8983_LOUT2ZC_MASK 0x0080 /* LOUT2ZC */ -#define WM8983_LOUT2ZC_SHIFT 7 /* LOUT2ZC */ -#define WM8983_LOUT2ZC_WIDTH 1 /* LOUT2ZC */ -#define WM8983_LOUT2MUTE 0x0040 /* LOUT2MUTE */ -#define WM8983_LOUT2MUTE_MASK 0x0040 /* LOUT2MUTE */ -#define WM8983_LOUT2MUTE_SHIFT 6 /* LOUT2MUTE */ -#define WM8983_LOUT2MUTE_WIDTH 1 /* LOUT2MUTE */ -#define WM8983_LOUT2VOL_MASK 0x003F /* LOUT2VOL - [5:0] */ -#define WM8983_LOUT2VOL_SHIFT 0 /* LOUT2VOL - [5:0] */ -#define WM8983_LOUT2VOL_WIDTH 6 /* LOUT2VOL - [5:0] */ - -/* - * R55 (0x37) - ROUT2 (SPK) volume ctrl - */ -#define WM8983_OUT2VU 0x0100 /* OUT2VU */ -#define WM8983_OUT2VU_MASK 0x0100 /* OUT2VU */ -#define WM8983_OUT2VU_SHIFT 8 /* OUT2VU */ -#define WM8983_OUT2VU_WIDTH 1 /* OUT2VU */ -#define WM8983_ROUT2ZC 0x0080 /* ROUT2ZC */ -#define WM8983_ROUT2ZC_MASK 0x0080 /* ROUT2ZC */ -#define WM8983_ROUT2ZC_SHIFT 7 /* ROUT2ZC */ -#define WM8983_ROUT2ZC_WIDTH 1 /* ROUT2ZC */ -#define WM8983_ROUT2MUTE 0x0040 /* ROUT2MUTE */ -#define WM8983_ROUT2MUTE_MASK 0x0040 /* ROUT2MUTE */ -#define WM8983_ROUT2MUTE_SHIFT 6 /* ROUT2MUTE */ -#define WM8983_ROUT2MUTE_WIDTH 1 /* ROUT2MUTE */ -#define WM8983_ROUT2VOL_MASK 0x003F /* ROUT2VOL - [5:0] */ -#define WM8983_ROUT2VOL_SHIFT 0 /* ROUT2VOL - [5:0] */ -#define WM8983_ROUT2VOL_WIDTH 6 /* ROUT2VOL - [5:0] */ - -/* - * R56 (0x38) - OUT3 mixer ctrl - */ -#define WM8983_OUT3MUTE 0x0040 /* OUT3MUTE */ -#define WM8983_OUT3MUTE_MASK 0x0040 /* OUT3MUTE */ -#define WM8983_OUT3MUTE_SHIFT 6 /* OUT3MUTE */ -#define WM8983_OUT3MUTE_WIDTH 1 /* OUT3MUTE */ -#define WM8983_OUT4_2OUT3 0x0008 /* OUT4_2OUT3 */ -#define WM8983_OUT4_2OUT3_MASK 0x0008 /* OUT4_2OUT3 */ -#define WM8983_OUT4_2OUT3_SHIFT 3 /* OUT4_2OUT3 */ -#define WM8983_OUT4_2OUT3_WIDTH 1 /* OUT4_2OUT3 */ -#define WM8983_BYPL2OUT3 0x0004 /* BYPL2OUT3 */ -#define WM8983_BYPL2OUT3_MASK 0x0004 /* BYPL2OUT3 */ -#define WM8983_BYPL2OUT3_SHIFT 2 /* BYPL2OUT3 */ -#define WM8983_BYPL2OUT3_WIDTH 1 /* BYPL2OUT3 */ -#define WM8983_LMIX2OUT3 0x0002 /* LMIX2OUT3 */ -#define WM8983_LMIX2OUT3_MASK 0x0002 /* LMIX2OUT3 */ -#define WM8983_LMIX2OUT3_SHIFT 1 /* LMIX2OUT3 */ -#define WM8983_LMIX2OUT3_WIDTH 1 /* LMIX2OUT3 */ -#define WM8983_LDAC2OUT3 0x0001 /* LDAC2OUT3 */ -#define WM8983_LDAC2OUT3_MASK 0x0001 /* LDAC2OUT3 */ -#define WM8983_LDAC2OUT3_SHIFT 0 /* LDAC2OUT3 */ -#define WM8983_LDAC2OUT3_WIDTH 1 /* LDAC2OUT3 */ - -/* - * R57 (0x39) - OUT4 (MONO) mix ctrl - */ -#define WM8983_OUT3_2OUT4 0x0080 /* OUT3_2OUT4 */ -#define WM8983_OUT3_2OUT4_MASK 0x0080 /* OUT3_2OUT4 */ -#define WM8983_OUT3_2OUT4_SHIFT 7 /* OUT3_2OUT4 */ -#define WM8983_OUT3_2OUT4_WIDTH 1 /* OUT3_2OUT4 */ -#define WM8983_OUT4MUTE 0x0040 /* OUT4MUTE */ -#define WM8983_OUT4MUTE_MASK 0x0040 /* OUT4MUTE */ -#define WM8983_OUT4MUTE_SHIFT 6 /* OUT4MUTE */ -#define WM8983_OUT4MUTE_WIDTH 1 /* OUT4MUTE */ -#define WM8983_OUT4ATTN 0x0020 /* OUT4ATTN */ -#define WM8983_OUT4ATTN_MASK 0x0020 /* OUT4ATTN */ -#define WM8983_OUT4ATTN_SHIFT 5 /* OUT4ATTN */ -#define WM8983_OUT4ATTN_WIDTH 1 /* OUT4ATTN */ -#define WM8983_LMIX2OUT4 0x0010 /* LMIX2OUT4 */ -#define WM8983_LMIX2OUT4_MASK 0x0010 /* LMIX2OUT4 */ -#define WM8983_LMIX2OUT4_SHIFT 4 /* LMIX2OUT4 */ -#define WM8983_LMIX2OUT4_WIDTH 1 /* LMIX2OUT4 */ -#define WM8983_LDAC2OUT4 0x0008 /* LDAC2OUT4 */ -#define WM8983_LDAC2OUT4_MASK 0x0008 /* LDAC2OUT4 */ -#define WM8983_LDAC2OUT4_SHIFT 3 /* LDAC2OUT4 */ -#define WM8983_LDAC2OUT4_WIDTH 1 /* LDAC2OUT4 */ -#define WM8983_BYPR2OUT4 0x0004 /* BYPR2OUT4 */ -#define WM8983_BYPR2OUT4_MASK 0x0004 /* BYPR2OUT4 */ -#define WM8983_BYPR2OUT4_SHIFT 2 /* BYPR2OUT4 */ -#define WM8983_BYPR2OUT4_WIDTH 1 /* BYPR2OUT4 */ -#define WM8983_RMIX2OUT4 0x0002 /* RMIX2OUT4 */ -#define WM8983_RMIX2OUT4_MASK 0x0002 /* RMIX2OUT4 */ -#define WM8983_RMIX2OUT4_SHIFT 1 /* RMIX2OUT4 */ -#define WM8983_RMIX2OUT4_WIDTH 1 /* RMIX2OUT4 */ -#define WM8983_RDAC2OUT4 0x0001 /* RDAC2OUT4 */ -#define WM8983_RDAC2OUT4_MASK 0x0001 /* RDAC2OUT4 */ -#define WM8983_RDAC2OUT4_SHIFT 0 /* RDAC2OUT4 */ -#define WM8983_RDAC2OUT4_WIDTH 1 /* RDAC2OUT4 */ - -/* - * R61 (0x3D) - BIAS CTRL - */ -#define WM8983_BIASCUT 0x0100 /* BIASCUT */ -#define WM8983_BIASCUT_MASK 0x0100 /* BIASCUT */ -#define WM8983_BIASCUT_SHIFT 8 /* BIASCUT */ -#define WM8983_BIASCUT_WIDTH 1 /* BIASCUT */ -#define WM8983_HALFIPBIAS 0x0080 /* HALFIPBIAS */ -#define WM8983_HALFIPBIAS_MASK 0x0080 /* HALFIPBIAS */ -#define WM8983_HALFIPBIAS_SHIFT 7 /* HALFIPBIAS */ -#define WM8983_HALFIPBIAS_WIDTH 1 /* HALFIPBIAS */ -#define WM8983_VBBIASTST_MASK 0x0060 /* VBBIASTST - [6:5] */ -#define WM8983_VBBIASTST_SHIFT 5 /* VBBIASTST - [6:5] */ -#define WM8983_VBBIASTST_WIDTH 2 /* VBBIASTST - [6:5] */ -#define WM8983_BUFBIAS_MASK 0x0018 /* BUFBIAS - [4:3] */ -#define WM8983_BUFBIAS_SHIFT 3 /* BUFBIAS - [4:3] */ -#define WM8983_BUFBIAS_WIDTH 2 /* BUFBIAS - [4:3] */ -#define WM8983_ADCBIAS_MASK 0x0006 /* ADCBIAS - [2:1] */ -#define WM8983_ADCBIAS_SHIFT 1 /* ADCBIAS - [2:1] */ -#define WM8983_ADCBIAS_WIDTH 2 /* ADCBIAS - [2:1] */ -#define WM8983_HALFOPBIAS 0x0001 /* HALFOPBIAS */ -#define WM8983_HALFOPBIAS_MASK 0x0001 /* HALFOPBIAS */ -#define WM8983_HALFOPBIAS_SHIFT 0 /* HALFOPBIAS */ -#define WM8983_HALFOPBIAS_WIDTH 1 /* HALFOPBIAS */ - -enum clk_src { - WM8983_CLKSRC_MCLK, - WM8983_CLKSRC_PLL -}; - -#endif /* _WM8983_H */ diff --git a/trunk/sound/soc/codecs/wm8993.c b/trunk/sound/soc/codecs/wm8993.c index 6e85b8869af7..9e5ff789b805 100644 --- a/trunk/sound/soc/codecs/wm8993.c +++ b/trunk/sound/soc/codecs/wm8993.c @@ -876,7 +876,7 @@ SND_SOC_DAPM_MIXER("SPKL", WM8993_POWER_MANAGEMENT_3, 8, 0, left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)), SND_SOC_DAPM_MIXER("SPKR", WM8993_POWER_MANAGEMENT_3, 9, 0, right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)), -SND_SOC_DAPM_PGA("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0), + }; static const struct snd_soc_dapm_route routes[] = { @@ -1434,7 +1434,6 @@ static int wm8993_probe(struct snd_soc_codec *codec) wm8993->hubs_data.hp_startup_mode = 1; wm8993->hubs_data.dcs_codes = -2; - wm8993->hubs_data.series_startup = 1; ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); if (ret != 0) { diff --git a/trunk/sound/soc/codecs/wm8994.c b/trunk/sound/soc/codecs/wm8994.c index 09e680ae88b2..83014a7c2e14 100644 --- a/trunk/sound/soc/codecs/wm8994.c +++ b/trunk/sound/soc/codecs/wm8994.c @@ -195,6 +195,10 @@ static int configure_aif_clock(struct snd_soc_codec *codec, int aif) aif + 1, rate); } + if (rate && rate < 3000000) + dev_warn(codec->dev, "AIF%dCLK is %dHz, should be >=3MHz for optimal performance\n", + aif + 1, rate); + wm8994->aifclk[aif] = rate; snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1 + offset, @@ -1142,33 +1146,13 @@ SND_SOC_DAPM_PGA_E("Late DAC2L Enable PGA", SND_SOC_NOPM, 0, 0, NULL, 0, late_enable_ev, SND_SOC_DAPM_PRE_PMU), SND_SOC_DAPM_PGA_E("Late DAC2R Enable PGA", SND_SOC_NOPM, 0, 0, NULL, 0, late_enable_ev, SND_SOC_DAPM_PRE_PMU), -SND_SOC_DAPM_PGA_E("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0, - late_enable_ev, SND_SOC_DAPM_PRE_PMU), - -SND_SOC_DAPM_MIXER_E("SPKL", WM8994_POWER_MANAGEMENT_3, 8, 0, - left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer), - late_enable_ev, SND_SOC_DAPM_PRE_PMU), -SND_SOC_DAPM_MIXER_E("SPKR", WM8994_POWER_MANAGEMENT_3, 9, 0, - right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer), - late_enable_ev, SND_SOC_DAPM_PRE_PMU), -SND_SOC_DAPM_MUX_E("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux, - late_enable_ev, SND_SOC_DAPM_PRE_PMU), -SND_SOC_DAPM_MUX_E("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux, - late_enable_ev, SND_SOC_DAPM_PRE_PMU), SND_SOC_DAPM_POST("Late Disable PGA", late_disable_ev) }; static const struct snd_soc_dapm_widget wm8994_lateclk_widgets[] = { SND_SOC_DAPM_SUPPLY("AIF1CLK", WM8994_AIF1_CLOCKING_1, 0, 0, NULL, 0), -SND_SOC_DAPM_SUPPLY("AIF2CLK", WM8994_AIF2_CLOCKING_1, 0, 0, NULL, 0), -SND_SOC_DAPM_PGA("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0), -SND_SOC_DAPM_MIXER("SPKL", WM8994_POWER_MANAGEMENT_3, 8, 0, - left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)), -SND_SOC_DAPM_MIXER("SPKR", WM8994_POWER_MANAGEMENT_3, 9, 0, - right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)), -SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux), -SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux), +SND_SOC_DAPM_SUPPLY("AIF2CLK", WM8994_AIF2_CLOCKING_1, 0, 0, NULL, 0) }; static const struct snd_soc_dapm_widget wm8994_dac_revd_widgets[] = { @@ -1298,6 +1282,14 @@ SND_SOC_DAPM_ADC("DMIC1R", NULL, WM8994_POWER_MANAGEMENT_4, 2, 0), SND_SOC_DAPM_ADC("ADCL", NULL, SND_SOC_NOPM, 1, 0), SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux), +SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux), + +SND_SOC_DAPM_MIXER("SPKL", WM8994_POWER_MANAGEMENT_3, 8, 0, + left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)), +SND_SOC_DAPM_MIXER("SPKR", WM8994_POWER_MANAGEMENT_3, 9, 0, + right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)), + SND_SOC_DAPM_POST("Debug log", post_ev), }; @@ -1632,7 +1624,6 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src, int reg_offset, ret; struct fll_div fll; u16 reg, aif1, aif2; - unsigned long timeout; aif1 = snd_soc_read(codec, WM8994_AIF1_CLOCKING_1) & WM8994_AIF1CLK_ENA; @@ -1714,9 +1705,6 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src, (fll.clk_ref_div << WM8994_FLL1_REFCLK_DIV_SHIFT) | (src - 1)); - /* Clear any pending completion from a previous failure */ - try_wait_for_completion(&wm8994->fll_locked[id]); - /* Enable (with fractional mode if required) */ if (freq_out) { if (fll.k) @@ -1727,15 +1715,7 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src, WM8994_FLL1_ENA | WM8994_FLL1_FRAC, reg); - if (wm8994->fll_locked_irq) { - timeout = wait_for_completion_timeout(&wm8994->fll_locked[id], - msecs_to_jiffies(10)); - if (timeout == 0) - dev_warn(codec->dev, - "Timed out waiting for FLL lock\n"); - } else { - msleep(5); - } + msleep(5); } wm8994->fll[id].in = freq_in; @@ -1753,14 +1733,6 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src, return 0; } -static irqreturn_t wm8994_fll_locked_irq(int irq, void *data) -{ - struct completion *completion = data; - - complete(completion); - - return IRQ_HANDLED; -} static int opclk_divs[] = { 10, 20, 30, 40, 55, 60, 80, 120, 160 }; @@ -2300,33 +2272,6 @@ static int wm8994_aif3_hw_params(struct snd_pcm_substream *substream, return snd_soc_update_bits(codec, aif1_reg, WM8994_AIF1_WL_MASK, aif1); } -static void wm8994_aif_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_codec *codec = dai->codec; - int rate_reg = 0; - - switch (dai->id) { - case 1: - rate_reg = WM8994_AIF1_RATE; - break; - case 2: - rate_reg = WM8994_AIF1_RATE; - break; - default: - break; - } - - /* If the DAI is idle then configure the divider tree for the - * lowest output rate to save a little power if the clock is - * still active (eg, because it is system clock). - */ - if (rate_reg && !dai->playback_active && !dai->capture_active) - snd_soc_update_bits(codec, rate_reg, - WM8994_AIF1_SR_MASK | - WM8994_AIF1CLK_RATE_MASK, 0x9); -} - static int wm8994_aif_mute(struct snd_soc_dai *codec_dai, int mute) { struct snd_soc_codec *codec = codec_dai->codec; @@ -2393,7 +2338,6 @@ static struct snd_soc_dai_ops wm8994_aif1_dai_ops = { .set_sysclk = wm8994_set_dai_sysclk, .set_fmt = wm8994_set_dai_fmt, .hw_params = wm8994_hw_params, - .shutdown = wm8994_aif_shutdown, .digital_mute = wm8994_aif_mute, .set_pll = wm8994_set_fll, .set_tristate = wm8994_set_tristate, @@ -2403,7 +2347,6 @@ static struct snd_soc_dai_ops wm8994_aif2_dai_ops = { .set_sysclk = wm8994_set_dai_sysclk, .set_fmt = wm8994_set_dai_fmt, .hw_params = wm8994_hw_params, - .shutdown = wm8994_aif_shutdown, .digital_mute = wm8994_aif_mute, .set_pll = wm8994_set_fll, .set_tristate = wm8994_set_tristate, @@ -2907,15 +2850,6 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data) return IRQ_HANDLED; } -static irqreturn_t wm8994_fifo_error(int irq, void *data) -{ - struct snd_soc_codec *codec = data; - - dev_err(codec->dev, "FIFO error\n"); - - return IRQ_HANDLED; -} - static int wm8994_codec_probe(struct snd_soc_codec *codec) { struct wm8994 *control; @@ -2934,9 +2868,6 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) wm8994->pdata = dev_get_platdata(codec->dev->parent); wm8994->codec = codec; - for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++) - init_completion(&wm8994->fll_locked[i]); - if (wm8994->pdata && wm8994->pdata->micdet_irq) wm8994->micdet_irq = wm8994->pdata->micdet_irq; else if (wm8994->pdata && wm8994->pdata->irq_base) @@ -2975,7 +2906,6 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) wm8994->hubs.dcs_codes = -5; wm8994->hubs.hp_startup_mode = 1; wm8994->hubs.dcs_readback_mode = 1; - wm8994->hubs.series_startup = 1; break; default: wm8994->hubs.dcs_readback_mode = 1; @@ -2990,15 +2920,6 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) break; } - wm8994_request_irq(codec->control_data, WM8994_IRQ_FIFOS_ERR, - wm8994_fifo_error, "FIFO error", codec); - - ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_DCS_DONE, - wm_hubs_dcs_done, "DC servo done", - &wm8994->hubs); - if (ret == 0) - wm8994->hubs.dcs_done_irq = true; - switch (control->type) { case WM8994: if (wm8994->micdet_irq) { @@ -3055,16 +2976,6 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) } } - wm8994->fll_locked_irq = true; - for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++) { - ret = wm8994_request_irq(codec->control_data, - WM8994_IRQ_FLL1_LOCK + i, - wm8994_fll_locked_irq, "FLL lock", - &wm8994->fll_locked[i]); - if (ret != 0) - wm8994->fll_locked_irq = false; - } - /* Remember if AIFnLRCLK is configured as a GPIO. This should be * configured on init - if a system wants to do this dynamically * at runtime we can deal with that then. @@ -3140,18 +3051,10 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) 1 << WM8994_AIF2DAC_3D_GAIN_SHIFT, 1 << WM8994_AIF2DAC_3D_GAIN_SHIFT); - /* Unconditionally enable AIF1 ADC TDM mode on chips which can - * use this; it only affects behaviour on idle TDM clock - * cycles. */ - switch (control->type) { - case WM8994: - case WM8958: - snd_soc_update_bits(codec, WM8994_AIF1_CONTROL_1, - WM8994_AIF1ADC_TDM, WM8994_AIF1ADC_TDM); - break; - default: - break; - } + /* Unconditionally enable AIF1 ADC TDM mode; it only affects + * behaviour on idle TDM clock cycles. */ + snd_soc_update_bits(codec, WM8994_AIF1_CONTROL_1, + WM8994_AIF1ADC_TDM, WM8994_AIF1ADC_TDM); wm8994_update_class_w(codec); @@ -3250,12 +3153,6 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT, wm8994); if (wm8994->micdet_irq) free_irq(wm8994->micdet_irq, wm8994); - for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++) - wm8994_free_irq(codec->control_data, WM8994_IRQ_FLL1_LOCK + i, - &wm8994->fll_locked[i]); - wm8994_free_irq(codec->control_data, WM8994_IRQ_DCS_DONE, - &wm8994->hubs); - wm8994_free_irq(codec->control_data, WM8994_IRQ_FIFOS_ERR, codec); err: kfree(wm8994); return ret; @@ -3265,20 +3162,11 @@ static int wm8994_codec_remove(struct snd_soc_codec *codec) { struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994 *control = codec->control_data; - int i; wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF); pm_runtime_disable(codec->dev); - for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++) - wm8994_free_irq(codec->control_data, WM8994_IRQ_FLL1_LOCK + i, - &wm8994->fll_locked[i]); - - wm8994_free_irq(codec->control_data, WM8994_IRQ_DCS_DONE, - &wm8994->hubs); - wm8994_free_irq(codec->control_data, WM8994_IRQ_FIFOS_ERR, codec); - switch (control->type) { case WM8994: if (wm8994->micdet_irq) diff --git a/trunk/sound/soc/codecs/wm8994.h b/trunk/sound/soc/codecs/wm8994.h index 1ab2266039f7..0a1db04b73bd 100644 --- a/trunk/sound/soc/codecs/wm8994.h +++ b/trunk/sound/soc/codecs/wm8994.h @@ -11,7 +11,6 @@ #include #include -#include #include "wm_hubs.h" @@ -80,8 +79,6 @@ struct wm8994_priv { int mclk[2]; int aifclk[2]; struct wm8994_fll_config fll[2], fll_suspend[2]; - struct completion fll_locked[2]; - bool fll_locked_irq; int dac_rates[2]; int lrclk_shared[2]; diff --git a/trunk/sound/soc/codecs/wm9081.c b/trunk/sound/soc/codecs/wm9081.c index a4691321f9b3..91c6b39de50c 100644 --- a/trunk/sound/soc/codecs/wm9081.c +++ b/trunk/sound/soc/codecs/wm9081.c @@ -727,7 +727,7 @@ SND_SOC_DAPM_MIXER_NAMED_CTL("Mixer", SND_SOC_NOPM, 0, 0, SND_SOC_DAPM_PGA("LINEOUT PGA", WM9081_POWER_MANAGEMENT, 4, 0, NULL, 0), SND_SOC_DAPM_PGA("Speaker PGA", WM9081_POWER_MANAGEMENT, 2, 0, NULL, 0), -SND_SOC_DAPM_OUT_DRV("Speaker", WM9081_POWER_MANAGEMENT, 1, 0, NULL, 0), +SND_SOC_DAPM_PGA("Speaker", WM9081_POWER_MANAGEMENT, 1, 0, NULL, 0), SND_SOC_DAPM_OUTPUT("LINEOUT"), SND_SOC_DAPM_OUTPUT("SPKN"), diff --git a/trunk/sound/soc/codecs/wm_hubs.c b/trunk/sound/soc/codecs/wm_hubs.c index 4cc2d567f22f..9e370d14ad88 100644 --- a/trunk/sound/soc/codecs/wm_hubs.c +++ b/trunk/sound/soc/codecs/wm_hubs.c @@ -63,10 +63,8 @@ static const struct soc_enum speaker_mode = static void wait_for_dc_servo(struct snd_soc_codec *codec, unsigned int op) { - struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec); unsigned int reg; int count = 0; - int timeout; unsigned int val; val = op | WM8993_DCS_ENA_CHAN_0 | WM8993_DCS_ENA_CHAN_1; @@ -76,39 +74,18 @@ static void wait_for_dc_servo(struct snd_soc_codec *codec, unsigned int op) dev_dbg(codec->dev, "Waiting for DC servo...\n"); - if (hubs->dcs_done_irq) - timeout = 4; - else - timeout = 400; - do { count++; - - if (hubs->dcs_done_irq) - wait_for_completion_timeout(&hubs->dcs_done, - msecs_to_jiffies(250)); - else - msleep(1); - + msleep(1); reg = snd_soc_read(codec, WM8993_DC_SERVO_0); dev_dbg(codec->dev, "DC servo: %x\n", reg); - } while (reg & op && count < timeout); + } while (reg & op && count < 400); if (reg & op) dev_err(codec->dev, "Timed out waiting for DC Servo %x\n", op); } -irqreturn_t wm_hubs_dcs_done(int irq, void *data) -{ - struct wm_hubs_data *hubs = data; - - complete(&hubs->dcs_done); - - return IRQ_HANDLED; -} -EXPORT_SYMBOL_GPL(wm_hubs_dcs_done); - /* * Startup calibration of the DC servo */ @@ -130,7 +107,8 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec) return; } - if (hubs->series_startup) { + /* Devices not using a DCS code correction have startup mode */ + if (hubs->dcs_codes) { /* Set for 32 series updates */ snd_soc_update_bits(codec, WM8993_DC_SERVO_1, WM8993_DCS_SERIES_NO_01_MASK, @@ -156,9 +134,9 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec) break; case 1: reg = snd_soc_read(codec, WM8993_DC_SERVO_3); - reg_r = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK) + reg_l = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK) >> WM8993_DCS_DAC_WR_VAL_1_SHIFT; - reg_l = reg & WM8993_DCS_DAC_WR_VAL_0_MASK; + reg_r = reg & WM8993_DCS_DAC_WR_VAL_0_MASK; break; default: WARN(1, "Unknown DCS readback method\n"); @@ -172,13 +150,13 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec) dev_dbg(codec->dev, "Applying %d code DC servo correction\n", hubs->dcs_codes); - /* HPOUT1R */ - offset = reg_r; + /* HPOUT1L */ + offset = reg_l; offset += hubs->dcs_codes; dcs_cfg = (u8)offset << WM8993_DCS_DAC_WR_VAL_1_SHIFT; - /* HPOUT1L */ - offset = reg_l; + /* HPOUT1R */ + offset = reg_r; offset += hubs->dcs_codes; dcs_cfg |= (u8)offset; @@ -190,8 +168,8 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec) WM8993_DCS_TRIG_DAC_WR_0 | WM8993_DCS_TRIG_DAC_WR_1); } else { - dcs_cfg = reg_r << WM8993_DCS_DAC_WR_VAL_1_SHIFT; - dcs_cfg |= reg_l; + dcs_cfg = reg_l << WM8993_DCS_DAC_WR_VAL_1_SHIFT; + dcs_cfg |= reg_r; } /* Save the callibrated offset if we're in class W mode and @@ -217,7 +195,7 @@ static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol, /* If we're applying an offset correction then updating the * callibration would be likely to introduce further offsets. */ - if (hubs->dcs_codes || hubs->no_series_update) + if (hubs->dcs_codes) return ret; /* Only need to do this if the outputs are active */ @@ -621,6 +599,9 @@ SND_SOC_DAPM_MIXER("IN2L PGA", WM8993_POWER_MANAGEMENT_2, 7, 0, SND_SOC_DAPM_MIXER("IN2R PGA", WM8993_POWER_MANAGEMENT_2, 5, 0, in2r_pga, ARRAY_SIZE(in2r_pga)), +/* Dummy widgets to represent differential paths */ +SND_SOC_DAPM_PGA("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("MIXINL", WM8993_POWER_MANAGEMENT_2, 9, 0, mixinl, ARRAY_SIZE(mixinl)), SND_SOC_DAPM_MIXER("MIXINR", WM8993_POWER_MANAGEMENT_2, 8, 0, @@ -886,11 +867,8 @@ EXPORT_SYMBOL_GPL(wm_hubs_add_analogue_controls); int wm_hubs_add_analogue_routes(struct snd_soc_codec *codec, int lineout1_diff, int lineout2_diff) { - struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec); struct snd_soc_dapm_context *dapm = &codec->dapm; - init_completion(&hubs->dcs_done); - snd_soc_dapm_add_routes(dapm, analogue_routes, ARRAY_SIZE(analogue_routes)); diff --git a/trunk/sound/soc/codecs/wm_hubs.h b/trunk/sound/soc/codecs/wm_hubs.h index 676b1252ab91..f8a5e976b5e6 100644 --- a/trunk/sound/soc/codecs/wm_hubs.h +++ b/trunk/sound/soc/codecs/wm_hubs.h @@ -14,9 +14,6 @@ #ifndef _WM_HUBS_H #define _WM_HUBS_H -#include -#include - struct snd_soc_codec; extern const unsigned int wm_hubs_spkmix_tlv[]; @@ -26,14 +23,9 @@ struct wm_hubs_data { int dcs_codes; int dcs_readback_mode; int hp_startup_mode; - int series_startup; - int no_series_update; bool class_w; u16 class_w_dcs; - - bool dcs_done_irq; - struct completion dcs_done; }; extern int wm_hubs_add_analogue_controls(struct snd_soc_codec *); @@ -44,6 +36,4 @@ extern int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *, int jd_scthr, int jd_thr, int micbias1_lvl, int micbias2_lvl); -extern irqreturn_t wm_hubs_dcs_done(int irq, void *data); - #endif diff --git a/trunk/sound/soc/davinci/davinci-pcm.c b/trunk/sound/soc/davinci/davinci-pcm.c index a49e667373bc..9d35b8c1a624 100644 --- a/trunk/sound/soc/davinci/davinci-pcm.c +++ b/trunk/sound/soc/davinci/davinci-pcm.c @@ -46,28 +46,11 @@ static void print_buf_info(int slot, char *name) } #endif -#define DAVINCI_PCM_FMTBITS (\ - SNDRV_PCM_FMTBIT_S8 |\ - SNDRV_PCM_FMTBIT_U8 |\ - SNDRV_PCM_FMTBIT_S16_LE |\ - SNDRV_PCM_FMTBIT_S16_BE |\ - SNDRV_PCM_FMTBIT_U16_LE |\ - SNDRV_PCM_FMTBIT_U16_BE |\ - SNDRV_PCM_FMTBIT_S24_LE |\ - SNDRV_PCM_FMTBIT_S24_BE |\ - SNDRV_PCM_FMTBIT_U24_LE |\ - SNDRV_PCM_FMTBIT_U24_BE |\ - SNDRV_PCM_FMTBIT_S32_LE |\ - SNDRV_PCM_FMTBIT_S32_BE |\ - SNDRV_PCM_FMTBIT_U32_LE |\ - SNDRV_PCM_FMTBIT_U32_BE) - static struct snd_pcm_hardware pcm_hardware_playback = { .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME| - SNDRV_PCM_INFO_BATCH), - .formats = DAVINCI_PCM_FMTBITS, + SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME), + .formats = (SNDRV_PCM_FMTBIT_S16_LE), .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | @@ -76,7 +59,7 @@ static struct snd_pcm_hardware pcm_hardware_playback = { .rate_min = 8000, .rate_max = 96000, .channels_min = 2, - .channels_max = 384, + .channels_max = 2, .buffer_bytes_max = 128 * 1024, .period_bytes_min = 32, .period_bytes_max = 8 * 1024, @@ -88,9 +71,8 @@ static struct snd_pcm_hardware pcm_hardware_playback = { static struct snd_pcm_hardware pcm_hardware_capture = { .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_BATCH), - .formats = DAVINCI_PCM_FMTBITS, + SNDRV_PCM_INFO_PAUSE), + .formats = (SNDRV_PCM_FMTBIT_S16_LE), .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | @@ -99,7 +81,7 @@ static struct snd_pcm_hardware pcm_hardware_capture = { .rate_min = 8000, .rate_max = 96000, .channels_min = 2, - .channels_max = 384, + .channels_max = 2, .buffer_bytes_max = 128 * 1024, .period_bytes_min = 32, .period_bytes_max = 8 * 1024, @@ -157,22 +139,6 @@ struct davinci_runtime_data { struct edmacc_param ram_params; }; -static void davinci_pcm_period_elapsed(struct snd_pcm_substream *substream) -{ - struct davinci_runtime_data *prtd = substream->runtime->private_data; - struct snd_pcm_runtime *runtime = substream->runtime; - - prtd->period++; - if (unlikely(prtd->period >= runtime->periods)) - prtd->period = 0; -} - -static void davinci_pcm_period_reset(struct snd_pcm_substream *substream) -{ - struct davinci_runtime_data *prtd = substream->runtime->private_data; - - prtd->period = 0; -} /* * Not used with ping/pong */ @@ -233,6 +199,10 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream) else edma_set_transfer_params(link, acnt, fifo_level, count, fifo_level, ABSYNC); + + prtd->period++; + if (unlikely(prtd->period >= runtime->periods)) + prtd->period = 0; } static void davinci_pcm_dma_irq(unsigned link, u16 ch_status, void *data) @@ -247,13 +217,12 @@ static void davinci_pcm_dma_irq(unsigned link, u16 ch_status, void *data) return; if (snd_pcm_running(substream)) { - spin_lock(&prtd->lock); if (prtd->ram_channel < 0) { /* No ping/pong must fix up link dma data*/ + spin_lock(&prtd->lock); davinci_pcm_enqueue_dma(substream); + spin_unlock(&prtd->lock); } - davinci_pcm_period_elapsed(substream); - spin_unlock(&prtd->lock); snd_pcm_period_elapsed(substream); } } @@ -456,8 +425,7 @@ static int request_ping_pong(struct snd_pcm_substream *substream, edma_read_slot(link, &prtd->asp_params); prtd->asp_params.opt &= ~(TCCMODE | EDMA_TCC(0x3f) | TCINTEN); - prtd->asp_params.opt |= TCCHEN | - EDMA_TCC(prtd->ram_channel & 0x3f); + prtd->asp_params.opt |= TCCHEN | EDMA_TCC(prtd->ram_channel & 0x3f); edma_write_slot(link, &prtd->asp_params); /* pong */ @@ -471,7 +439,7 @@ static int request_ping_pong(struct snd_pcm_substream *substream, prtd->asp_params.opt &= ~(TCCMODE | EDMA_TCC(0x3f)); /* interrupt after every pong completion */ prtd->asp_params.opt |= TCINTEN | TCCHEN | - EDMA_TCC(prtd->ram_channel & 0x3f); + EDMA_TCC(EDMA_CHAN_SLOT(prtd->ram_channel)); edma_write_slot(link, &prtd->asp_params); /* ram */ @@ -559,13 +527,6 @@ static int davinci_pcm_trigger(struct snd_pcm_substream *substream, int cmd) switch (cmd) { case SNDRV_PCM_TRIGGER_START: - edma_start(prtd->asp_channel); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && - prtd->ram_channel >= 0) { - /* copy 1st iram buffer */ - edma_start(prtd->ram_channel); - } - break; case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: edma_resume(prtd->asp_channel); @@ -589,7 +550,6 @@ static int davinci_pcm_prepare(struct snd_pcm_substream *substream) { struct davinci_runtime_data *prtd = substream->runtime->private_data; - davinci_pcm_period_reset(substream); if (prtd->ram_channel >= 0) { int ret = ping_pong_dma_setup(substream); if (ret < 0) @@ -605,31 +565,21 @@ static int davinci_pcm_prepare(struct snd_pcm_substream *substream) print_buf_info(prtd->asp_link[0], "asp_link[0]"); print_buf_info(prtd->asp_link[1], "asp_link[1]"); - /* - * There is a phase offset of 2 periods between the position - * used by dma setup and the position reported in the pointer - * function. - * - * The phase offset, when not using ping-pong buffers, is due to - * the two consecutive calls to davinci_pcm_enqueue_dma() below. - * - * Whereas here, with ping-pong buffers, the phase is due to - * there being an entire buffer transfer complete before the - * first dma completion event triggers davinci_pcm_dma_irq(). - */ - davinci_pcm_period_elapsed(substream); - davinci_pcm_period_elapsed(substream); - + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + /* copy 1st iram buffer */ + edma_start(prtd->ram_channel); + } + edma_start(prtd->asp_channel); return 0; } + prtd->period = 0; davinci_pcm_enqueue_dma(substream); - davinci_pcm_period_elapsed(substream); /* Copy self-linked parameter RAM entry into master channel */ edma_read_slot(prtd->asp_link[0], &prtd->asp_params); edma_write_slot(prtd->asp_channel, &prtd->asp_params); davinci_pcm_enqueue_dma(substream); - davinci_pcm_period_elapsed(substream); + edma_start(prtd->asp_channel); return 0; } @@ -641,23 +591,51 @@ davinci_pcm_pointer(struct snd_pcm_substream *substream) struct davinci_runtime_data *prtd = runtime->private_data; unsigned int offset; int asp_count; - unsigned int period_size = snd_pcm_lib_period_bytes(substream); - - /* - * There is a phase offset of 2 periods between the position used by dma - * setup and the position reported in the pointer function. Either +2 in - * the dma setup or -2 here in the pointer function (with wrapping, - * both) accounts for this offset -- choose the latter since it makes - * the first-time setup clearer. - */ + dma_addr_t asp_src, asp_dst; + spin_lock(&prtd->lock); - asp_count = prtd->period - 2; + if (prtd->ram_channel >= 0) { + int ram_count; + int mod_ram; + dma_addr_t ram_src, ram_dst; + unsigned int period_size = snd_pcm_lib_period_bytes(substream); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + /* reading ram before asp should be safe + * as long as the asp transfers less than a ping size + * of bytes between the 2 reads + */ + edma_get_position(prtd->ram_channel, + &ram_src, &ram_dst); + edma_get_position(prtd->asp_channel, + &asp_src, &asp_dst); + asp_count = asp_src - prtd->asp_params.src; + ram_count = ram_src - prtd->ram_params.src; + mod_ram = ram_count % period_size; + mod_ram -= asp_count; + if (mod_ram < 0) + mod_ram += period_size; + else if (mod_ram == 0) { + if (snd_pcm_running(substream)) + mod_ram += period_size; + } + ram_count -= mod_ram; + if (ram_count < 0) + ram_count += period_size * runtime->periods; + } else { + edma_get_position(prtd->ram_channel, + &ram_src, &ram_dst); + ram_count = ram_dst - prtd->ram_params.dst; + } + asp_count = ram_count; + } else { + edma_get_position(prtd->asp_channel, &asp_src, &asp_dst); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + asp_count = asp_src - runtime->dma_addr; + else + asp_count = asp_dst - runtime->dma_addr; + } spin_unlock(&prtd->lock); - if (asp_count < 0) - asp_count += runtime->periods; - asp_count *= period_size; - offset = bytes_to_frames(runtime, asp_count); if (offset >= runtime->buffer_size) offset = 0; @@ -833,11 +811,9 @@ static void davinci_pcm_free(struct snd_pcm *pcm) static u64 davinci_pcm_dmamask = 0xffffffff; -static int davinci_pcm_new(struct snd_soc_pcm_runtime *rtd) +static int davinci_pcm_new(struct snd_card *card, + struct snd_soc_dai *dai, struct snd_pcm *pcm) { - struct snd_card *card = rtd->card->snd_card; - struct snd_soc_dai *dai = rtd->cpu_dai; - struct snd_pcm *pcm = rtd->pcm; int ret; if (!card->dev->dma_mask) diff --git a/trunk/sound/soc/ep93xx/ep93xx-pcm.c b/trunk/sound/soc/ep93xx/ep93xx-pcm.c index dd7ac5374cef..a07f99c9c375 100644 --- a/trunk/sound/soc/ep93xx/ep93xx-pcm.c +++ b/trunk/sound/soc/ep93xx/ep93xx-pcm.c @@ -283,11 +283,9 @@ static void ep93xx_pcm_free_dma_buffers(struct snd_pcm *pcm) static u64 ep93xx_pcm_dmamask = 0xffffffff; -static int ep93xx_pcm_new(struct snd_soc_pcm_runtime *rtd) +static int ep93xx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, + struct snd_pcm *pcm) { - struct snd_card *card = rtd->card->snd_card; - struct snd_soc_dai *dai = rtd->cpu_dai; - struct snd_pcm *pcm = rtd->pcm; int ret = 0; if (!card->dev->dma_mask) diff --git a/trunk/sound/soc/fsl/fsl_dma.c b/trunk/sound/soc/fsl/fsl_dma.c index 732208c8c0b4..6680c0b4d203 100644 --- a/trunk/sound/soc/fsl/fsl_dma.c +++ b/trunk/sound/soc/fsl/fsl_dma.c @@ -294,11 +294,9 @@ static irqreturn_t fsl_dma_isr(int irq, void *dev_id) * Regardless of where the memory is actually allocated, since the device can * technically DMA to any 36-bit address, we do need to set the DMA mask to 36. */ -static int fsl_dma_new(struct snd_soc_pcm_runtime *rtd) +static int fsl_dma_new(struct snd_card *card, struct snd_soc_dai *dai, + struct snd_pcm *pcm) { - struct snd_card *card = rtd->card->snd_card; - struct snd_soc_dai *dai = rtd->cpu_dai; - struct snd_pcm *pcm = rtd->pcm; static u64 fsl_dma_dmamask = DMA_BIT_MASK(36); int ret; @@ -941,7 +939,7 @@ static int __devinit fsl_soc_dma_probe(struct platform_device *pdev) iprop = of_get_property(ssi_np, "fsl,fifo-depth", NULL); if (iprop) - dma->ssi_fifo_depth = be32_to_cpup(iprop); + dma->ssi_fifo_depth = *iprop; else /* Older 8610 DTs didn't have the fifo-depth property */ dma->ssi_fifo_depth = 8; diff --git a/trunk/sound/soc/fsl/fsl_ssi.c b/trunk/sound/soc/fsl/fsl_ssi.c index d48afea5d93d..313e0ccedd5b 100644 --- a/trunk/sound/soc/fsl/fsl_ssi.c +++ b/trunk/sound/soc/fsl/fsl_ssi.c @@ -678,12 +678,7 @@ static int __devinit fsl_ssi_probe(struct platform_device *pdev) kfree(ssi_private); return ret; } - ssi_private->ssi = of_iomap(np, 0); - if (!ssi_private->ssi) { - dev_err(&pdev->dev, "could not map device resources\n"); - kfree(ssi_private); - return -ENOMEM; - } + ssi_private->ssi = ioremap(res.start, 1 + res.end - res.start); ssi_private->ssi_phys = res.start; ssi_private->irq = irq_of_parse_and_map(np, 0); @@ -696,7 +691,7 @@ static int __devinit fsl_ssi_probe(struct platform_device *pdev) /* Determine the FIFO depth. */ iprop = of_get_property(np, "fsl,fifo-depth", NULL); if (iprop) - ssi_private->fifo_depth = be32_to_cpup(iprop); + ssi_private->fifo_depth = *iprop; else /* Older 8610 DTs didn't have the fifo-depth property */ ssi_private->fifo_depth = 8; diff --git a/trunk/sound/soc/fsl/mpc5200_dma.c b/trunk/sound/soc/fsl/mpc5200_dma.c index 19ad0c1be67e..fff695ccdd3e 100644 --- a/trunk/sound/soc/fsl/mpc5200_dma.c +++ b/trunk/sound/soc/fsl/mpc5200_dma.c @@ -299,11 +299,10 @@ static struct snd_pcm_ops psc_dma_ops = { }; static u64 psc_dma_dmamask = 0xffffffff; -static int psc_dma_new(struct snd_soc_pcm_runtime *rtd) +static int psc_dma_new(struct snd_card *card, struct snd_soc_dai *dai, + struct snd_pcm *pcm) { - struct snd_card *card = rtd->card->snd_card; - struct snd_soc_dai *dai = rtd->cpu_dai; - struct snd_pcm *pcm = rtd->pcm; + struct snd_soc_pcm_runtime *rtd = pcm->private_data; struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai); size_t size = psc_dma_hardware.buffer_bytes_max; int rc = 0; diff --git a/trunk/sound/soc/fsl/mpc8610_hpcd.c b/trunk/sound/soc/fsl/mpc8610_hpcd.c index a19297959587..c16c6b2eff95 100644 --- a/trunk/sound/soc/fsl/mpc8610_hpcd.c +++ b/trunk/sound/soc/fsl/mpc8610_hpcd.c @@ -233,7 +233,7 @@ static int get_parent_cell_index(struct device_node *np) if (!iprop) return -1; - return be32_to_cpup(iprop); + return *iprop; } /** @@ -258,7 +258,7 @@ static int codec_node_dev_name(struct device_node *np, char *buf, size_t len) if (!iprop) return -EINVAL; - addr = be32_to_cpup(iprop); + addr = *iprop; bus = get_parent_cell_index(np); if (bus < 0) @@ -305,7 +305,7 @@ static int get_dma_channel(struct device_node *ssi_np, return -EINVAL; } - *dma_channel_id = be32_to_cpup(iprop); + *dma_channel_id = *iprop; *dma_id = get_parent_cell_index(dma_channel_np); of_node_put(dma_channel_np); @@ -379,7 +379,7 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev) ret = -EINVAL; goto error; } - machine_data->ssi_id = be32_to_cpup(iprop); + machine_data->ssi_id = *iprop; /* Get the serial format and clock direction. */ sprop = of_get_property(np, "fsl,mode", NULL); @@ -405,7 +405,7 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev) ret = -EINVAL; goto error; } - machine_data->clk_frequency = be32_to_cpup(iprop); + machine_data->clk_frequency = *iprop; } else if (strcasecmp(sprop, "i2s-master") == 0) { machine_data->dai_format = SND_SOC_DAIFMT_I2S; machine_data->codec_clk_direction = SND_SOC_CLOCK_IN; diff --git a/trunk/sound/soc/fsl/p1022_ds.c b/trunk/sound/soc/fsl/p1022_ds.c index 8fa4d5f8eda1..66e0b68af147 100644 --- a/trunk/sound/soc/fsl/p1022_ds.c +++ b/trunk/sound/soc/fsl/p1022_ds.c @@ -232,7 +232,7 @@ static int get_parent_cell_index(struct device_node *np) iprop = of_get_property(parent, "cell-index", NULL); if (iprop) - ret = be32_to_cpup(iprop); + ret = *iprop; of_node_put(parent); @@ -261,7 +261,7 @@ static int codec_node_dev_name(struct device_node *np, char *buf, size_t len) if (!iprop) return -EINVAL; - addr = be32_to_cpup(iprop); + addr = *iprop; bus = get_parent_cell_index(np); if (bus < 0) @@ -308,7 +308,7 @@ static int get_dma_channel(struct device_node *ssi_np, return -EINVAL; } - *dma_channel_id = be32_to_cpup(iprop); + *dma_channel_id = *iprop; *dma_id = get_parent_cell_index(dma_channel_np); of_node_put(dma_channel_np); @@ -379,7 +379,7 @@ static int p1022_ds_probe(struct platform_device *pdev) ret = -EINVAL; goto error; } - mdata->ssi_id = be32_to_cpup(iprop); + mdata->ssi_id = *iprop; /* Get the serial format and clock direction. */ sprop = of_get_property(np, "fsl,mode", NULL); @@ -405,7 +405,7 @@ static int p1022_ds_probe(struct platform_device *pdev) ret = -EINVAL; goto error; } - mdata->clk_frequency = be32_to_cpup(iprop); + mdata->clk_frequency = *iprop; } else if (strcasecmp(sprop, "i2s-master") == 0) { mdata->dai_format = SND_SOC_DAIFMT_I2S; mdata->codec_clk_direction = SND_SOC_CLOCK_IN; diff --git a/trunk/sound/soc/imx/imx-pcm-fiq.c b/trunk/sound/soc/imx/imx-pcm-fiq.c index 309c59e6fb6c..413b78da248f 100644 --- a/trunk/sound/soc/imx/imx-pcm-fiq.c +++ b/trunk/sound/soc/imx/imx-pcm-fiq.c @@ -238,14 +238,12 @@ static struct snd_pcm_ops imx_pcm_ops = { static int ssi_irq = 0; -static int imx_pcm_fiq_new(struct snd_soc_pcm_runtime *rtd) +static int imx_pcm_fiq_new(struct snd_card *card, struct snd_soc_dai *dai, + struct snd_pcm *pcm) { - struct snd_card *card = rtd->card->snd_card; - struct snd_soc_dai *dai = rtd->cpu_dai; - struct snd_pcm *pcm = rtd->pcm; int ret; - ret = imx_pcm_new(rtd); + ret = imx_pcm_new(card, dai, pcm); if (ret) return ret; diff --git a/trunk/sound/soc/imx/imx-ssi.c b/trunk/sound/soc/imx/imx-ssi.c index 10a8e2783751..61fceb09cdb5 100644 --- a/trunk/sound/soc/imx/imx-ssi.c +++ b/trunk/sound/soc/imx/imx-ssi.c @@ -388,11 +388,10 @@ static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) static u64 imx_pcm_dmamask = DMA_BIT_MASK(32); -int imx_pcm_new(struct snd_soc_pcm_runtime *rtd) +int imx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, + struct snd_pcm *pcm) { - struct snd_card *card = rtd->card->snd_card; - struct snd_soc_dai *dai = rtd->cpu_dai; - struct snd_pcm *pcm = rtd->pcm; + int ret = 0; if (!card->dev->dma_mask) diff --git a/trunk/sound/soc/imx/imx-ssi.h b/trunk/sound/soc/imx/imx-ssi.h index 0a84cec3599e..dc8a87530e3e 100644 --- a/trunk/sound/soc/imx/imx-ssi.h +++ b/trunk/sound/soc/imx/imx-ssi.h @@ -225,7 +225,8 @@ struct snd_soc_platform *imx_ssi_dma_mx2_init(struct platform_device *pdev, struct imx_ssi *ssi); int snd_imx_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma); -int imx_pcm_new(struct snd_soc_pcm_runtime *rtd); +int imx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, + struct snd_pcm *pcm); void imx_pcm_free(struct snd_pcm *pcm); /* diff --git a/trunk/sound/soc/jz4740/jz4740-pcm.c b/trunk/sound/soc/jz4740/jz4740-pcm.c index a7c9578be983..fb1483f7c966 100644 --- a/trunk/sound/soc/jz4740/jz4740-pcm.c +++ b/trunk/sound/soc/jz4740/jz4740-pcm.c @@ -299,11 +299,9 @@ static void jz4740_pcm_free(struct snd_pcm *pcm) static u64 jz4740_pcm_dmamask = DMA_BIT_MASK(32); -int jz4740_pcm_new(struct snd_soc_pcm_runtime *rtd) +int jz4740_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, + struct snd_pcm *pcm) { - struct snd_card *card = rtd->card->snd_card; - struct snd_soc_dai *dai = rtd->cpu_dai; - struct snd_pcm *pcm = rtd->pcm; int ret = 0; if (!card->dev->dma_mask) diff --git a/trunk/sound/soc/kirkwood/kirkwood-dma.c b/trunk/sound/soc/kirkwood/kirkwood-dma.c index cd33de1c5b7a..e13c6ce46328 100644 --- a/trunk/sound/soc/kirkwood/kirkwood-dma.c +++ b/trunk/sound/soc/kirkwood/kirkwood-dma.c @@ -312,11 +312,9 @@ static int kirkwood_dma_preallocate_dma_buffer(struct snd_pcm *pcm, return 0; } -static int kirkwood_dma_new(struct snd_soc_pcm_runtime *rtd) +static int kirkwood_dma_new(struct snd_card *card, + struct snd_soc_dai *dai, struct snd_pcm *pcm) { - struct snd_card *card = rtd->card->snd_card; - struct snd_soc_dai *dai = rtd->cpu_dai; - struct snd_pcm *pcm = rtd->pcm; int ret; if (!card->dev->dma_mask) diff --git a/trunk/sound/soc/mid-x86/sst_platform.c b/trunk/sound/soc/mid-x86/sst_platform.c index 3e7826058efe..5a946b4115a2 100644 --- a/trunk/sound/soc/mid-x86/sst_platform.c +++ b/trunk/sound/soc/mid-x86/sst_platform.c @@ -402,10 +402,9 @@ static void sst_pcm_free(struct snd_pcm *pcm) snd_pcm_lib_preallocate_free_for_all(pcm); } -int sst_pcm_new(struct snd_soc_pcm_runtime *rtd) +int sst_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, + struct snd_pcm *pcm) { - struct snd_soc_dai *dai = rtd->cpu_dai; - struct snd_pcm *pcm = rtd->pcm; int retval = 0; pr_debug("sst_pcm_new called\n"); diff --git a/trunk/sound/soc/nuc900/nuc900-ac97.c b/trunk/sound/soc/nuc900/nuc900-ac97.c index 9c0edad90d8b..dac6732da969 100644 --- a/trunk/sound/soc/nuc900/nuc900-ac97.c +++ b/trunk/sound/soc/nuc900/nuc900-ac97.c @@ -356,7 +356,7 @@ static int __devinit nuc900_ac97_drvprobe(struct platform_device *pdev) nuc900_audio->irq_num = platform_get_irq(pdev, 0); if (!nuc900_audio->irq_num) { ret = -EBUSY; - goto out3; + goto out2; } nuc900_ac97_data = nuc900_audio; diff --git a/trunk/sound/soc/nuc900/nuc900-pcm.c b/trunk/sound/soc/nuc900/nuc900-pcm.c index d589ef14e917..8263f56dc665 100644 --- a/trunk/sound/soc/nuc900/nuc900-pcm.c +++ b/trunk/sound/soc/nuc900/nuc900-pcm.c @@ -315,12 +315,9 @@ static void nuc900_dma_free_dma_buffers(struct snd_pcm *pcm) } static u64 nuc900_pcm_dmamask = DMA_BIT_MASK(32); -static int nuc900_dma_new(struct snd_soc_pcm_runtime *rtd) +static int nuc900_dma_new(struct snd_card *card, + struct snd_soc_dai *dai, struct snd_pcm *pcm) { - struct snd_card *card = rtd->card->snd_card; - struct snd_soc_dai *dai = rtd->cpu_dai; - struct snd_pcm *pcm = rtd->pcm; - if (!card->dev->dma_mask) card->dev->dma_mask = &nuc900_pcm_dmamask; if (!card->dev->coherent_dma_mask) diff --git a/trunk/sound/soc/omap/Kconfig b/trunk/sound/soc/omap/Kconfig index fe83d0d176be..99054cf1f68f 100644 --- a/trunk/sound/soc/omap/Kconfig +++ b/trunk/sound/soc/omap/Kconfig @@ -9,9 +9,6 @@ config SND_OMAP_SOC_MCBSP config SND_OMAP_SOC_MCPDM tristate -config SND_OMAP_SOC_HDMI - tristate - config SND_OMAP_SOC_N810 tristate "SoC Audio support for Nokia N810" depends on SND_OMAP_SOC && MACH_NOKIA_N810 && I2C @@ -103,14 +100,6 @@ config SND_OMAP_SOC_SDP4430 Say Y if you want to add support for SoC audio on Texas Instruments SDP4430. -config SND_OMAP_SOC_OMAP4_HDMI - tristate "SoC Audio support for Texas Instruments OMAP4 HDMI" - depends on SND_OMAP_SOC && OMAP4_DSS_HDMI && OMAP2_DSS && ARCH_OMAP4 - select SND_OMAP_SOC_HDMI - help - Say Y if you want to add support for SoC HDMI audio on Texas Instruments - OMAP4 chips - config SND_OMAP_SOC_OMAP3_PANDORA tristate "SoC Audio support for OMAP3 Pandora" depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP3_PANDORA diff --git a/trunk/sound/soc/omap/Makefile b/trunk/sound/soc/omap/Makefile index 59e2c8d1e38d..6c2c87eed5bb 100644 --- a/trunk/sound/soc/omap/Makefile +++ b/trunk/sound/soc/omap/Makefile @@ -2,12 +2,10 @@ snd-soc-omap-objs := omap-pcm.o snd-soc-omap-mcbsp-objs := omap-mcbsp.o snd-soc-omap-mcpdm-objs := omap-mcpdm.o mcpdm.o -snd-soc-omap-hdmi-objs := omap-hdmi.o obj-$(CONFIG_SND_OMAP_SOC) += snd-soc-omap.o obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o obj-$(CONFIG_SND_OMAP_SOC_MCPDM) += snd-soc-omap-mcpdm.o -obj-$(CONFIG_SND_OMAP_SOC_HDMI) += snd-soc-omap-hdmi.o # OMAP Machine Support snd-soc-n810-objs := n810.o @@ -23,7 +21,6 @@ snd-soc-omap3pandora-objs := omap3pandora.o snd-soc-omap3beagle-objs := omap3beagle.o snd-soc-zoom2-objs := zoom2.o snd-soc-igep0020-objs := igep0020.o -snd-soc-omap4-hdmi-objs := omap4-hdmi-card.o obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o obj-$(CONFIG_SND_OMAP_SOC_RX51) += snd-soc-rx51.o @@ -39,4 +36,3 @@ obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o obj-$(CONFIG_SND_OMAP_SOC_ZOOM2) += snd-soc-zoom2.o obj-$(CONFIG_SND_OMAP_SOC_IGEP0020) += snd-soc-igep0020.o -obj-$(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) += snd-soc-omap4-hdmi.o diff --git a/trunk/sound/soc/omap/ams-delta.c b/trunk/sound/soc/omap/ams-delta.c index b40095a19883..462cbcbea74a 100644 --- a/trunk/sound/soc/omap/ams-delta.c +++ b/trunk/sound/soc/omap/ams-delta.c @@ -427,8 +427,7 @@ static struct snd_soc_ops ams_delta_ops = { /* Board specific codec bias level control */ static int ams_delta_set_bias_level(struct snd_soc_card *card, - struct snd_soc_dapm_context *dapm, - enum snd_soc_bias_level level) + enum snd_soc_bias_level level) { struct snd_soc_codec *codec = card->rtd->codec; diff --git a/trunk/sound/soc/omap/omap-hdmi.c b/trunk/sound/soc/omap/omap-hdmi.c deleted file mode 100644 index 36c6eaeffb02..000000000000 --- a/trunk/sound/soc/omap/omap-hdmi.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * omap-hdmi.c - * - * OMAP ALSA SoC DAI driver for HDMI audio on OMAP4 processors. - * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/ - * Authors: Jorge Candelaria - * Ricardo Neri - * - * 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. - * - * 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 St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "omap-pcm.h" -#include "omap-hdmi.h" - -#define DRV_NAME "hdmi-audio-dai" - -static struct omap_pcm_dma_data omap_hdmi_dai_dma_params = { - .name = "HDMI playback", - .sync_mode = OMAP_DMA_SYNC_PACKET, -}; - -static int omap_hdmi_dai_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - int err; - /* - * Make sure that the period bytes are multiple of the DMA packet size. - * Largest packet size we use is 32 32-bit words = 128 bytes - */ - err = snd_pcm_hw_constraint_step(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128); - if (err < 0) - return err; - - return 0; -} - -static int omap_hdmi_dai_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - int err = 0; - - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: - omap_hdmi_dai_dma_params.packet_size = 16; - break; - case SNDRV_PCM_FORMAT_S24_LE: - omap_hdmi_dai_dma_params.packet_size = 32; - break; - default: - err = -EINVAL; - } - - omap_hdmi_dai_dma_params.data_type = OMAP_DMA_DATA_TYPE_S32; - - snd_soc_dai_set_dma_data(dai, substream, - &omap_hdmi_dai_dma_params); - - return err; -} - -static struct snd_soc_dai_ops omap_hdmi_dai_ops = { - .startup = omap_hdmi_dai_startup, - .hw_params = omap_hdmi_dai_hw_params, -}; - -static struct snd_soc_dai_driver omap_hdmi_dai = { - .playback = { - .channels_min = 2, - .channels_max = 2, - .rates = OMAP_HDMI_RATES, - .formats = OMAP_HDMI_FORMATS, - }, - .ops = &omap_hdmi_dai_ops, -}; - -static __devinit int omap_hdmi_probe(struct platform_device *pdev) -{ - int ret; - struct resource *hdmi_rsrc; - - hdmi_rsrc = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!hdmi_rsrc) { - dev_err(&pdev->dev, "Cannot obtain IORESOURCE_MEM HDMI\n"); - return -EINVAL; - } - - omap_hdmi_dai_dma_params.port_addr = hdmi_rsrc->start - + OMAP_HDMI_AUDIO_DMA_PORT; - - hdmi_rsrc = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (!hdmi_rsrc) { - dev_err(&pdev->dev, "Cannot obtain IORESOURCE_DMA HDMI\n"); - return -EINVAL; - } - - omap_hdmi_dai_dma_params.dma_req = hdmi_rsrc->start; - - ret = snd_soc_register_dai(&pdev->dev, &omap_hdmi_dai); - return ret; -} - -static int __devexit omap_hdmi_remove(struct platform_device *pdev) -{ - snd_soc_unregister_dai(&pdev->dev); - return 0; -} - -static struct platform_driver hdmi_dai_driver = { - .driver = { - .name = DRV_NAME, - .owner = THIS_MODULE, - }, - .probe = omap_hdmi_probe, - .remove = __devexit_p(omap_hdmi_remove), -}; - -static int __init hdmi_dai_init(void) -{ - return platform_driver_register(&hdmi_dai_driver); -} -module_init(hdmi_dai_init); - -static void __exit hdmi_dai_exit(void) -{ - platform_driver_unregister(&hdmi_dai_driver); -} -module_exit(hdmi_dai_exit); - -MODULE_AUTHOR("Jorge Candelaria "); -MODULE_AUTHOR("Ricardo Neri "); -MODULE_DESCRIPTION("OMAP HDMI SoC Interface"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" DRV_NAME); diff --git a/trunk/sound/soc/omap/omap-hdmi.h b/trunk/sound/soc/omap/omap-hdmi.h deleted file mode 100644 index 34c298d5057e..000000000000 --- a/trunk/sound/soc/omap/omap-hdmi.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * omap-hdmi.h - * - * Definitions for OMAP ALSA SoC DAI driver for HDMI audio on OMAP4 processors. - * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/ - * Authors: Jorge Candelaria - * Ricardo Neri - * - * 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. - * - * 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 St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __OMAP_HDMI_H__ -#define __OMAP_HDMI_H__ - -#define OMAP_HDMI_AUDIO_DMA_PORT 0x8c - -#define OMAP_HDMI_RATES (SNDRV_PCM_RATE_32000 | \ - SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) - -#define OMAP_HDMI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ - SNDRV_PCM_FMTBIT_S24_LE) - -#endif diff --git a/trunk/sound/soc/omap/omap-pcm.c b/trunk/sound/soc/omap/omap-pcm.c index b2f5751edae3..e6a6b991d05f 100644 --- a/trunk/sound/soc/omap/omap-pcm.c +++ b/trunk/sound/soc/omap/omap-pcm.c @@ -366,11 +366,9 @@ static void omap_pcm_free_dma_buffers(struct snd_pcm *pcm) } } -static int omap_pcm_new(struct snd_soc_pcm_runtime *rtd) +static int omap_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, + struct snd_pcm *pcm) { - struct snd_card *card = rtd->card->snd_card; - struct snd_soc_dai *dai = rtd->cpu_dai; - struct snd_pcm *pcm = rtd->pcm; int ret = 0; if (!card->dev->dma_mask) diff --git a/trunk/sound/soc/omap/omap4-hdmi-card.c b/trunk/sound/soc/omap/omap4-hdmi-card.c deleted file mode 100644 index 9f32615b81f7..000000000000 --- a/trunk/sound/soc/omap/omap4-hdmi-card.c +++ /dev/null @@ -1,129 +0,0 @@ -/* - * omap4-hdmi-card.c - * - * OMAP ALSA SoC machine driver for TI OMAP4 HDMI - * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ - * Author: Ricardo Neri - * - * 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. - * - * 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 St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include -#include -#include -#include